function [LP, codistr] = hColonImpl(codistr, a, d, b) 
; %#ok<NOSEM> % Undocumented
% Implementation of hColonImpl for codistributor1d.

%   Copyright 2009-2022 The MathWorks, Inc.

% Get the expected length and complete the codistributor. The length can be
% returned as NaN indicating an error. In that case the result is scalar
% NaN but we can fall through to the "on one worker" case to ensure correct
% distribution and type.
len = parallel.internal.array.colonLength(a,d,b);
if ~isfinite(len)
    len = 1;
end
codistr = codistr.hGetCompleteForSize([1 len]);

% Stop now if the result is going to be empty.
if len == 0
    LP = zeros(codistr.hLocalSize(), "like", iDominantType(a,d,b));
    return;
end

% Determine whether we need to form a distributed vector.
if codistr.Dimension==2 && nnz(codistr.Partition)>1
    LP = iBuildDistributedColon(codistr, a, d, b);
else
    LP = iBuildColonOnOneWorker(codistr, a, d, b);
end
end % hColonImpl


function LP = iBuildColonOnOneWorker(codistr, a, d, b)
% Build the colon vector on a single worker.
if codistr.Partition(spmdIndex) > 0
    LP = a:d:b;
else
    % This worker gets nothing.
    LP = zeros(codistr.hLocalSize(), "like", iDominantType(a,d,b));
end
end % iBuildColonOnOneWorker

function LP = iBuildDistributedColon(codistr, a, d, b)
% Build the colon vector split across workers.
last = sum(codistr.Partition(1:spmdIndex));
first = last - codistr.Partition(spmdIndex) + 1;
outProto = iDominantType(a,d,b);

if last<first
    LP = zeros(codistr.hLocalSize(), "like", outProto);
    return;
end

% There are two cases where we can get exact values without expanding out
% the whole vector. For the general case MATLAB has lots of code to
% minimize rounding error and we can only match the results without
% communication by expanding the vector on all workers.
if iIsFlint(a) && iIsFlint(d) && iIsFlint(b)
    % Use the efficient colon since this can be indexed without forming the
    % whole vector. We have to cast the result as ColonDescriptor always
    % returns doubles.
    v = matlab.internal.ColonDescriptor(a,d,b);
    LP = v(first:last);

elseif d==1
    % Special case of step==1 where we don't need to worry about rounding.
    LP = a - 1 + first:last;

else
    % General case. Matching MATLAB results requires building the vector.
    v = a:d:b;
    LP = v(first:last);

end
LP = cast(LP, "like", outProto);
end % iBuildDistributedColon


function tf = iIsFlint(x)
tf = isinteger(x) || islogical(x) ...
    || (x==round(x) && abs(x)<=flintmax(underlyingType(x)));
end

function proto = iDominantType(a,d,b)
% Return an empty prototype with the right type fopr the colon output. We
% use ones here to ensure we are combining scalars.
proto = ones("like",a)+ones("like",d)+ones("like",b);
proto = proto([]);
end