function varargout = gather(varargin)
%GATHER Retrieve contents of a Composite array into a cell array on the client
%   X = GATHER(C) is an in-memory cell array formed from the contents
%   of the Composite array C. Workers with no value for C result in empty
%   cells.
%
%   [X1,X2,...,Xn] = GATHER(C1,C2,...,Cn) gathers multiple arrays
%   C1,C2,...,Cn into the corresponding outputs X1,X2,...,Xn. The number of
%   input arguments and output arguments must match.
%
%   See also COMPOSITE.

% Copyright 2022 The MathWorks, Inc.

if nargout > nargin
    error(message("MATLAB:bigdata:array:GatherInsufficientInputs"));
end

if nargin==1
    % Short-cut for single input since we know it must be Composite and
    % don't need to re-call gather to process other arguments.
    varargout = {iGatherOne(varargin{1})};
    return
end

isArgComposite = cellfun("isclass", varargin, "Composite");
varargin(isArgComposite) = cellfun(@iGatherOne, varargin(isArgComposite), ...
    'UniformOutput', false);

if all(isArgComposite)
    % All arguments were gathered so we are done.
    varargout = varargin;
else
    % If any arguments were not gathered then re-dispatch so that they get a
    % chance.
    [varargout{1:max(1, nargout)}] = gather(varargin{:});
end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ret = iGatherOne(c)
% Gather one Composite into a cell array. If the data does not exist on a
% worker then the corresponding cell is set to missing.empty.

if ~c.isResourceSetOpen()
    error(message('parallel:lang:spmd:InvalidCompositeNoPool'));
end

ret = cell(size(c.KeyVector));
valid = exist(c, 1:numel(c));
for ii=1:length(valid)
    if exist(c, ii)
        keyHolder = c.KeyVector{ii};
        ret{ii} = c.getValOrError(keyHolder, ii);
    else
        ret{ii} = missing.empty(0,0);
    end
end

end
