function y = repelem(x,varargin)
%MATLAB Code Generation Library Function

%   Limitations:
%   * For code generation, X must be a vector or a matrix. N-D input is not
%     supported.

%   Copyright 1984-2020 The MathWorks, Inc.
%#codegen

coder.internal.allowHalfInputs;
narginchk(2,inf)
coder.internal.prefer_const(varargin);
VECTOR = coder.internal.isConstTrue(@isvector,x);
coder.internal.assert(eml_ndims(x) <= 2, ...
    'Coder:toolbox:RepelemUnsupportedND');
if VECTOR && nargin == 2
    y = repelemVector(x,varargin{1});
else % if ismatrix(a)
    y = repelemMatrix(x,varargin{:});
end

%--------------------------------------------------------------------------

function y = repelemVector(x,n)
coder.inline('always');
coder.internal.prefer_const(n);
ZERO = coder.internal.indexInt(0);
ONE = coder.internal.indexInt(1);
SCALARN = coder.internal.isConstTrue(@isscalar,n);
ROW = coder.internal.isConstTrue(@isrow,x);
na = coder.internal.indexInt(numel(x));
if SCALARN
    len = na*coder.internal.indexInt(n);
else
    coder.internal.assert(isvector(n), ...
        'MATLAB:repelem:invalidReplications');
    coder.internal.assert(numel(n) == na, ...
        'MATLAB:repelem:mismatchedReplicationsVector');
    if coder.internal.isConst(n)
        dlen = coder.const(feval('sum',n(:)));
        len = coder.internal.indexInt(dlen);
    else
        len = coder.internal.indexInt(sum(n(:)));
    end
end
if ROW
    y = coder.nullcopy(eml_expand(coder.internal.scalarEg(x),[1,len]));
else
    y = coder.nullcopy(eml_expand(coder.internal.scalarEg(x),[len,1]));
end
idx = ZERO;
if SCALARN
    for k = ONE:na
        for j = ONE:n
            idx = idx + 1;
            y(idx) = x(k);
        end
    end
else
    for k = ONE:na
        for j = ONE:n(k)
            idx = idx + 1;
            y(idx) = x(k);
        end
    end
end

%--------------------------------------------------------------------------

function y = repelemMatrix(x,varargin)
coder.inline('always');
coder.internal.prefer_const(varargin);
ZERO = coder.internal.indexInt(0);
VECTOR = coder.internal.isConstTrue(@isvector,x);
nv = coder.internal.indexInt(nargin - 1); % length(varargin)
coder.internal.assert(VECTOR || nargin >= 3, ...
    'MATLAB:repelem:twoInputNonVector');
for k = coder.unroll(1:length(varargin))
    coder.internal.assert( ...
        coder.internal.isConstTrue(@isscalar,varargin{k}) || ...
        isvector(varargin{k}), ...
        'MATLAB:repelem:invalidReplications');
    coder.internal.assert( ...
        coder.internal.isConstTrue(@isscalar,varargin{k}) || ...
        numel(varargin{k}) == size(x,k), ...
        'MATLAB:repelem:mismatchedReplications');
end
sz = calcsize(x,varargin{:});
y = coder.nullcopy(eml_expand(coder.internal.scalarEg(x),sz));
if ~isempty(y)
    colIdx = ZERO;
    mrows = coder.internal.indexInt(size(x,1));
    ncols = coder.internal.indexInt(size(x,2));
    for j = 1:ncols
        colreps = coder.internal.indexInt( ...
            eml_scalexp_subsref(varargin{2},j));
        if colreps > 0
            rowIdx = ZERO;
            colIdx = colIdx + 1;
            for i = 1:mrows
                rowreps = coder.internal.indexInt( ...
                    eml_scalexp_subsref(varargin{1},i));
                for k = 1:rowreps
                    rowIdx = rowIdx + 1;
                    y(rowIdx,colIdx) = x(i,j);
                end
            end
            colToCopy = colIdx;
            for k = 2:colreps
                colIdx = colIdx + 1;
                for i = 1:sz(1)
                    y(i,colIdx) = y(i,colToCopy);
                end
            end
        end
    end
    if nv >= 3
        % Replicate the first "page" to fill the higher dimensions.
        pagesize = sz(1)*sz(2);
        npages = coder.internal.prodsize(y,'above',2);
        for j = 1:npages-1
            pageOffset = j*pagesize;
            for k = 1:pagesize
                y(pageOffset + k) = y(k);
            end
        end
    end
end

%--------------------------------------------------------------------------

function sz = calcsize(x,varargin)
coder.inline('always');
coder.internal.prefer_const(varargin);
nd = coder.const(eml_max(eml_ndims(x),length(varargin)));
sz = ones(1,nd,coder.internal.indexIntClass);
nn = coder.internal.indexInt(length(varargin));
for k = coder.unroll(1:nn)
    if coder.internal.isConstTrue(@isscalar,varargin{k})
        sz(k) = coder.internal.indexInt(size(x,k))* ...
            coder.internal.indexInt(varargin{k});
    elseif coder.internal.isConst(varargin{k})
        dlen = coder.const(feval('sum',varargin{k}(:)));
        sz(k) = dlen;
    else
        sz(k) = sum(coder.internal.indexInt(varargin{k}(:)));
    end
end
for k = coder.unroll(nn+1:nd)
    sz(k) = size(x,k);
end

%--------------------------------------------------------------------------
