function varargout = gather(varargin)
%GATHER Convert a codistributed array into a replicated array
%   X = GATHER(D) is a replicated array formed from the codistributed array D.
%   
%   [X1,X2,...,Xn] = GATHER(D1,D2,...,Dn) gathers multiple arrays
%   D1,D2,...,Dn into the corresponding outputs X1,X2,...,Xn. The number of
%   input arguments and output arguments must match.
%   
%   [...] = GATHER(..., LABTARGET) converts one or more codistributed arrays to 
%   variant arrays, such that all of the data is contained on lab LABTARGET, and
%   local parts are 0x0 empty double on all other labs.
%   
%   D = CODISTRIBUTED(GATHER(D), getCodistributor(D)) returns the original
%   codistributed array D.
%   
%   Example:
%   spmd
%      N = 1000;
%      D = codistributed(magic(N));
%      M = gather(D);
%   end
%   
%   returns M = magic(N) on all labs.
%   
%   See also CODISTRIBUTED, GCAT, GOP.


%   Copyright 2006-2022 The MathWorks, Inc.

% Number of inputs must be same as number of outputs, with optional
% trailing workerIndex.
narginchk(1, inf);
nout = max(1, nargout);
if nout < nargin-1
    error(message("MATLAB:nargoutchk:notEnoughOutputs"));
elseif nout > nargin
    error(message("MATLAB:nargoutchk:tooManyOutputs"));
end

if nargin > nout
    % The trailing input should be the workerIndex. Check it's a scalar
    % before gathering.
    errId = "parallel:distributed:GatherIncorrectWorkerIndex";
    workerTarget = varargin{end};
    varargin(end) = [];
    if ~isscalar(workerTarget)
        error(message(errId));
    end
    % Scalar, so its safe to gather and check fully
    workerTarget = distributedutil.CodistParser.gatherIfCodistributed(workerTarget);
    if ~distributedutil.CodistParser.isValidSPMDIndex(workerTarget)
        error(message(errId));
    end
else
    workerTarget = 0;
end

varargout = varargin;
for ii=1:nout
    if iscodistributed(varargin{ii})
        codistr = getCodistributor(varargin{ii});
        LP = getLocalPart(varargin{ii});
        varargout{ii} = codistr.hGatherImpl(LP, workerTarget);
    end
end
