function [B,FA] = fillmissing(A,fillMethod,varargin)
%MATLAB Code Generation Library Function

%   Limitations:
%   Requires variable-sizing
%   'makima' fill method is not supported
%   Only 'constant', 'movmean', and 'movmedian' methods supported for
%   datetime sample points
%   Only 'constant' method supported for datetime input data
%   Sparse inputs are not supported

%   Copyright 2018-2023 The MathWorks, Inc.
%#codegen
coder.internal.prefer_const(fillMethod,varargin);
narginchk(2,inf);
ZERO = coder.internal.indexInt(0);
ONE = coder.internal.indexInt(1);
TWO = coder.internal.indexInt(2);
ISTABLEORTIMETABLE = coder.const(isa(A,'table') || isa(A,'timetable'));

% Validate A
coder.internal.assert(~issparse(A), 'Coder:toolbox:SparseNotSupported',mfilename);
coder.internal.assert(isnumeric(A) || islogical(A) || ischar(A) || ...
    ISTABLEORTIMETABLE || isa(A,'duration') || isa(A,'categorical') ||  ...
    iscellstr(A) || isa(A,'datetime'), ...
    'MATLAB:fillmissing:InvalidInputsCodegen') %#ok<ISCLSTR>

% Validate FILL
coder.internal.assert(coder.internal.isConst(fillMethod), ...
    'Coder:toolbox:OptionStringsMustBeConstant');
FILL = coder.const(validatestring(fillMethod,{ ...
    'constant','previous','next','nearest','linear',...
    'spline','pchip','movmean','movmedian','makima' ...
    },mfilename,'Fill',2));

coder.internal.assert(~strcmp(FILL,'makima'),'MATLAB:fillmissing:makimaNotSupported');

nargs = coder.internal.indexInt(nargin - 2);
nextArg = ONE;
lastArg = nargs;
if strcmp(FILL,'movmean') || strcmp(FILL,'movmedian')
    coder.internal.assert(nargs >= 1,['MATLAB:fillmissing:',FILL,'Input']);
    intConstOrWindowSizeTmp = varargin{1};
    nextArg = TWO;
elseif strcmp(FILL,'constant')
    coder.internal.assert(nargs >= 1,['MATLAB:fillmissing:',FILL,'Input']);
    intConstOrWindowSizeTmp = varargin{1};
    nextArg = TWO;
    % Wait to parse constant value until dim is determined
else
    intConstOrWindowSizeTmp = [];
end

% Parse DIM and NV pairs
if nargs >= nextArg && eml_bitand(nargs - nextArg + ONE,ONE) == ONE
    dim = coder.internal.indexInt(varargin{nextArg});
    coder.internal.assert(coder.internal.isConst(dim), ...
        'Coder:toolbox:DimMustBeConstant');
    coder.internal.assert(~ISTABLEORTIMETABLE, ...
        'MATLAB:fillmissing:DimensionTable');
    coder.internal.assertValidDim(dim);
    nextArg = nextArg + 1;
else
    if ISTABLEORTIMETABLE
        dim = ONE;
    else
        dim = coder.internal.constNonSingletonDim(A);
        coder.internal.assert(isscalar(A) || size(A,dim) ~= 1, ...
            'Coder:toolbox:autoDimIncompatibility');
    end
end

coder.internal.assert(eml_bitand(lastArg - nextArg + ONE,ONE) == ZERO, ...
    'MATLAB:fillmissing:NameValuePairs');
spidx = ZERO;
evidx = ZERO;
mlidx = ZERO;
dvidx = ZERO;
rvidx = ZERO;
for k = coder.unroll(nextArg:TWO:lastArg - ONE)
    coder.internal.assert(coder.internal.isConst(varargin{k}), ...
        'Coder:toolbox:OptionStringsMustBeConstant');
    name = validatestring(varargin{k},{'DataVariables','SamplePoints', ...
        'EndValues','MissingLocations','ReplaceValues'}, mfilename,'',k + 2);
    if strcmp(name,'SamplePoints')
        spidx = k + 1;
    elseif strcmp(name,'EndValues')
        evidx = k + 1;
    elseif strcmp(name,'MissingLocations')
        mlidx = k + 1;
    elseif strcmp(name,'DataVariables')
        dvidx = k + 1;
    elseif strcmp(name,'ReplaceValues')
        rvidx = k + 1;
    end
end
SAMPLEPOINTS_SUPPLIED = spidx > ZERO;
ENDVALUES_SUPPLIED = evidx > ZERO;
MISSINGLOCATIONS_SUPPLIED = mlidx > ZERO;
DATAVARIABLES_SUPPLIED = dvidx > ZERO;
REPLACEVALUES_SUPPLIED = rvidx > ZERO;

if SAMPLEPOINTS_SUPPLIED
    coder.internal.assert(~isa(A,'timetable'), ...
        'MATLAB:fillmissing:SamplePointsTimeTable')
    sp = varargin{spidx};
elseif isa(A,'timetable')
    sp = A.Properties.RowTimes;
else
    sp = [];
end

if SAMPLEPOINTS_SUPPLIED || isa(A,'timetable')
    coder.internal.assert(isfloat(sp) || isa(sp,'duration') || ...
        isa(sp,'datetime'), 'Coder:toolbox:SamplePointsMustBeFloat');
    if isfloat(sp)
        validateattributes(sp,{'double','single'}, ...
            {'vector','increasing','finite','real'},...
            mfilename,'SamplePoints',spidx + 2)
    else
        validateattributes(sp,{'duration','datetime'}, ...
            {'vector','finite','real'},...
            mfilename,'SamplePoints',spidx + 2)
        % Check that sample points are strictly increasing
        checkSPSortingDuplicates(sp,'fillmissing');
    end
end

if ENDVALUES_SUPPLIED
    if ischar(varargin{evidx}) || isstring(varargin{evidx})
        ev = validatestring(varargin{evidx},{'extrap','previous','next', ...
            'nearest','none'}, mfilename,'',evidx + 2);
        evValue = [];
    else
        ev = 'value';
        evValue = varargin{evidx};
    end
else
    ev = 'extrap';
    evValue = [];
end
if MISSINGLOCATIONS_SUPPLIED
    mloc = varargin{mlidx};
    coder.internal.assert(islogical(mloc) && isequal(size(A),size(mloc)), ...
        'MATLAB:fillmissing:MissingLocationsInvalid');
else
    mloc = [];
end
if DATAVARIABLES_SUPPLIED
    coder.internal.assert(ISTABLEORTIMETABLE,'MATLAB:fillmissing:DataVariablesArray');
    dataVars = varargin{dvidx};
elseif ISTABLEORTIMETABLE
    dataVars = ONE:coder.internal.indexInt(width(A));
else
    dataVars = [];
end
if REPLACEVALUES_SUPPLIED
    coder.internal.assert(ISTABLEORTIMETABLE,'MATLAB:fillmissing:ReplaceValuesArray');
    replaceValues = varargin{rvidx};
    coder.internal.assert(coder.internal.isConst(replaceValues), ...
        'Coder:toolbox:OptionInputsMustBeConstant','ReplaceValues');
    validateattributes(replaceValues,{'logical'}, ...
        {'scalar'},mfilename,'ReplaceValues',k + 2);
else
    replaceValues = true;
end

% Parse fill constants
if strcmp(FILL,'constant')
    if ~isscalar(intConstOrWindowSizeTmp)
        if dim <= ndims(A)
            nvects = numel(A)/size(A,dim);
        else
            nvects = numel(A);
        end
        coder.internal.assert((isa(A,'categorical') && isa(intConstOrWindowSizeTmp,'char')) ...
            || numel(intConstOrWindowSizeTmp) == nvects, 'MATLAB:fillmissing:SizeConstant',nvects);
    end
    if ~iscell(intConstOrWindowSizeTmp) && ~coder.internal.isTextRow(intConstOrWindowSizeTmp)
        intConstOrWindowSize = intConstOrWindowSizeTmp(:);
    else
        intConstOrWindowSize = intConstOrWindowSizeTmp;
    end
    if isa(A,'categorical')
        coder.internal.assert(isa(intConstOrWindowSizeTmp,'categorical') ...
            || isa(intConstOrWindowSizeTmp,'char') ...
            || isa(intConstOrWindowSizeTmp,'string'), ...
            'MATLAB:fillmissing:ConstantCategorical');
        if isa(intConstOrWindowSizeTmp,'char')
            coder.internal.assert(isrow(intConstOrWindowSizeTmp),'MATLAB:fillmissing:CharRowVector');
        elseif isa(intConstOrWindowSizeTmp,'categorical')
            coder.internal.assert(isordinal(A) == isordinal(intConstOrWindowSizeTmp),'MATLAB:fillmissing:ConstantCategoricalOrdMismatch');
            coder.internal.assert(~isordinal(intConstOrWindowSizeTmp) || isequal(categories(intConstOrWindowSizeTmp),categories(A)), 'MATLAB:fillmissing:ConstantCategoricalCatMismatch');
        end % Strings do not need to be checked since string arrays are not supported for code generation
    end
else
    intConstOrWindowSize = intConstOrWindowSizeTmp;
end

if strcmp(ev,'value')
    if isempty(A)
        coder.internal.assert(isempty(evValue), ...
            'MATLAB:fillmissing:SizeConstantEmptyExtrap');
    end
    if ~isscalar(evValue)
        if dim <= ndims(A)
            nvects = numel(A)/size(A,dim);
        else
            nvects = numel(A);
        end
        coder.internal.assert(numel(evValue) == nvects, ...
            'MATLAB:fillmissing:SizeConstantExtrap',nvects);
    end
    evValue = evValue(:);
    coder.internal.assert(isnumeric(evValue) || islogical(evValue), ...
        'MATLAB:fillmissing:ConstantInvalidTypeExtrap');
    if isnumeric(A)
        coder.internal.assert(isnumeric(evValue) || islogical(evValue), ...
            'MATLAB:fillmissing:ConstantNumericExtrap');
    elseif ischar(A)
        coder.internal.assert(ischar(evValue), ...
            'MATLAB:fillmissing:ConstantCharExtrap');
    end
end

% Check method is valid for integers or logical
VALIDINTEGERMETHOD = coder.const(feval('strcmp', ...
    FILL,{'nearest','next','previous','constant'}));
ANYVALIDINTEGERMETHOD = coder.const(feval('any',VALIDINTEGERMETHOD));
coder.internal.assert(isempty(mloc) || ~(isinteger(A) || islogical(A)) || ...
    ANYVALIDINTEGERMETHOD,'MATLAB:fillmissing:MissingLocationsInteger');

% Fill missing data
if ISTABLEORTIMETABLE
    if strcmp(FILL,'movmean') || strcmp(FILL,'movmedian')
        % intConstOrWindowSize is the window size
        c = {intConstOrWindowSize};
    elseif strcmp(FILL,'constant')
        if iscell(intConstOrWindowSize)
            c = intConstOrWindowSize;
        else
            numConsts = coder.internal.indexInt(numel(intConstOrWindowSize));
            c = cell(1,numConsts);
            for ii = ONE:numConsts
                c{ii} = intConstOrWindowSize(ii);
            end
        end
    else
        c = {[]}; % Empty placeholder
    end

    mlocCell = cell(1,width(A));
    if isempty(mloc)
        for ii = ONE:width(A)
            mlocCell{ii} = false(0,0);
        end
    else
        for ii = ONE:width(A)
            mlocCell{ii} = mloc(:,ii);
        end
    end
    if nargout < 2
        BTmp = coder.internal.applyToTableVariables(A, ...
            @(x,y,mlocVar) fillArray(x,FILL,y,ev,evValue,sp,dim,mlocVar,true), ...
            dataVars, true, true, replaceValues, 'filled', ...
            'MATLAB:fillmissing:DataVariablesTableSubscript', c, mlocCell);
    else
        [BTmp,FATmp] = coder.internal.applyToTableVariables(A, ...
            @(x,y,mlocVar) fillArray(x,FILL,y,ev,evValue,sp,dim,mlocVar,true), ...
            dataVars, [true false], [true true], [replaceValues replaceValues], ...
            'filled', 'MATLAB:fillmissing:DataVariablesTableSubscript', c, mlocCell);
        if isempty(A)
            FA = funSizeOf(@false,A);
        else
            FA = FATmp;
        end
    end
    if istimetable(A)
        B = table2timetableWithDimNames(BTmp, A.Properties.RowTimes, ...
            A.Properties.DimensionNames);
    else
        B = BTmp;
    end
else
    if nargout < 2
        B = fillArray(A,FILL,intConstOrWindowSize,ev,evValue,sp,dim,mloc,false);
    else
        [B,FA] = fillArray(A,FILL,intConstOrWindowSize,ev,evValue,sp,dim,mloc,false);
    end
end
%--------------------------------------------------------------------------
function [BOut,FAReturn] = fillArray(A,FILL,intConstOrWinSize,ev,evValue,sp,dim,mloc,ISTABLE)
coder.internal.prefer_const(FILL,dim)
coder.noImplicitExpansionInFunction; % call to xor with same size: xor(FA(FA),ismissing(B3(FA)));
% Perform FILLMISSING of standard missing entries in an array A

ONE = coder.internal.indexInt(1);
if strcmp(FILL,'constant')
    if isnumeric(A)
        coder.internal.assert(isnumeric(intConstOrWinSize) || ...
            islogical(intConstOrWinSize), ...
            'MATLAB:fillmissing:ConstantNumeric');
    elseif ischar(A)
        coder.internal.assert(ischar(intConstOrWinSize), ...
            'MATLAB:fillmissing:ConstantChar');
    elseif iscellstr(A) %#ok<ISCLSTR>
        coder.internal.assert(ischar(intConstOrWinSize) ...
            || iscellstr(intConstOrWinSize), ...
            'MATLAB:fillmissing:ConstantCellstr'); %#ok<ISCLSTR>
    end
end

if ~isnumeric(A) && ~isa(A,'duration')
    ISVALIDFILL = coder.const(feval('strcmp',FILL,{'nearest','next','previous',...
        'constant'}));
    ANYVALIDFILL = coder.const(feval('any',ISVALIDFILL));
    coder.internal.assert(ANYVALIDFILL,'MATLAB:fillmissing:InterpolationInvalidArray', ...
        FILL,class(A));
end

if isempty(mloc)
    FAtemp = ismissing(A);
    mlocGiven = false;
else
    FAtemp = mloc; % 'MissingLocations' provided
    mlocGiven = true;
end

if iscellstr(A) %#ok<ISCLSTR>
    B1 = coder.nullcopy(funSizeOf(@zeros,A));
    % B must not be an integer type because integers trigger a quick return
    % from fillArrayColumn
    for ii = 1:numel(A)
        B1(ii) = ii;
    end
    if isscalar(intConstOrWinSize)
        % Negative values are used for elements that will be filled to
        % differentiate them from elements that are not filled (specified
        % with positive integers)
        intConstOrWinSizeToUse = -1;
    else
        intConstOrWinSizeToUse = -1:-1:-numel(intConstOrWinSize);
    end
else
    B1 = A;
    intConstOrWinSizeToUse = intConstOrWinSize;
end

ndimsBin = coder.internal.ndims(B1);


% Quick return
extrapolateOnly = false;
if dim > ndimsBin
    if isnumeric(B1) && ~isreal(B1)
        B1(funSizeOf(@true,B1)) = B1;
    end
    B1 = extrapolateWithConstant(B1,FILL,intConstOrWinSizeToUse,ev,evValue,FAtemp,FAtemp);
    FA = FAtemp;
    extrapolateOnly = true;
end

if ~extrapolateOnly
    % Permute and reshape into a matrix
    perm = coder.internal.dimToForePermutation(ndimsBin,dim);
    B2 = permute(B1, perm);
    FAperm = permute(FAtemp, perm);
    ncolsB = coder.internal.prodsize(B2,'above',1);
    % Fill each column
    for jj = 1:ncolsB
        if isa(A,'duration')
            [Btmp,FAtmp] = fillArrayColumn(jj,milliseconds(B2(:,jj)),FAperm(:,jj),FILL,milliseconds(intConstOrWinSizeToUse),ev,evValue,sp,size(A,dim),mlocGiven);
            B2(:,jj) = milliseconds(Btmp);
        else
            [B2(:,jj),FAtmp] = fillArrayColumn(jj,B2(:,jj),FAperm(:,jj),FILL,intConstOrWinSizeToUse,ev,evValue,sp,size(A,dim),mlocGiven);
        end
        if mlocGiven
            FAperm(:,jj) = FAtmp;
        end
    end
    % Reshape and permute back to original size
    B3 = ipermute(B2,perm);
    if nargout > 1
        FA = ipermute(FAperm, perm);
        if ~mlocGiven
            FA(FA) = xor(FA(FA),ismissing(B3(FA)));
        end
    end
else
    B3 = B1;
end

if iscellstr(A) %#ok<ISCLSTR>
    BOut = funSizeOf(@cell,B3);
    for ii = ONE:numel(BOut)
        % Codegen has trouble parsing the conditional logic for reordering
        % Explicitly assigning values to all the elements of BOut before
        % calling reorderCellstr is needed for codegen to take place
        BOut{ii} = '';
    end
    coder.assertDefined(BOut);
    BOut = reorderCellstr(A,BOut,B3,intConstOrWinSize);
else
    BOut = B3;
end

if isa(A,'duration')
    BOut.Format = A.Format;
end

if nargout > 1
    if ISTABLE
        FAReturn = collapseIntoLogicalColumn(FA);
    else
        FAReturn = FA;
    end
end

%--------------------------------------------------------------------------
function B = extrapolateWithConstant(B,FILL,intConst,ev,evValue,lhsIndex,rhsIndex)
% Fill all missing with a constant. Used if B is full of missing data, or
% for array B with dim > ndims(B). rhsIndex may be logical or numeric.
% Fill only when we have specified an extrapolation constant:
if strcmp(ev,'value')
    % Either through EndValues:
    % fillmissing(A,METHOD,'EndValues',ConstVals)
    B = assignConstant(B,evValue,lhsIndex,rhsIndex);
elseif strcmp(FILL,'constant') && strcmp(ev,'extrap')
    % Or through the 'constant' fill method:
    % fillmissing(A,'constant',ConstVals)
    % fillmissing(A,'constant',ConstVals,'EndValues','extrap')
    B = assignConstant(B,intConst,lhsIndex,rhsIndex);
end

%--------------------------------------------------------------------------
function B = assignConstant(B,ConstVals,lhsIndex,rhsIndex)
if isa(B,'categorical') && ~isa(ConstVals,'categorical')
    B(lhsIndex) = char(ConstVals);
elseif isscalar(ConstVals)
    B(lhsIndex) = ConstVals;
else
    B(lhsIndex) = ConstVals(rhsIndex);
end

%--------------------------------------------------------------------------
function [b,ma] = fillArrayColumn(jj,a,ma,FILL,intConstOrWinSize,ev,evValue,sp,lengthSP,mlocGiven)
% Fill one column. Do not error if we cannot fill all missing entries.
% jj = j-th column numeric index. Used to select the j-th fill constant.
% a  = the j-th column itself. Can be numeric, logical, or char.
% ma = logical mask of missing entries found in a.
% FILL = interpolation method.
% intConstOrWinSize = interpolation constant for 'constant' or window size
%      for 'movmean'. [] if intMethod is not 'constant'/'mov*'.
% ev = extrap method. If not a char, it holds the extrap constant.
% sp = the abscissa ('SamplePoints').
coder.noImplicitExpansionInFunction; % multiple calls to xor with same size: xor(ma(ma),ismissing(b(ma)))
b = a;
% Quick return
if ~mlocGiven && (isinteger(b) || islogical(b))
    return
end
nma = find(~ma);
if isempty(nma)
    % Columns full of missing data can only be filled with a constant.
    b = extrapolateWithConstant(b,FILL,intConstOrWinSize,ev,evValue,ma,jj);
    return
end
% (1) Interpolate
if strcmp(FILL,'constant')
    b = assignConstant(b,intConstOrWinSize,ma,jj);
elseif strcmp(FILL,'movmean')
    if mlocGiven
        b(ma) = coder.internal.nan();
    end
    if isempty(sp)
        newb = movmean(b,intConstOrWinSize,'omitnan');
    else
        newb = movmean(b,intConstOrWinSize,'omitnan','SamplePoints',sp);
    end
    b(ma) = newb(ma);
    ma(ma) = xor(ma(ma),ismissing(b(ma)));
elseif strcmp(FILL,'movmedian')
    if mlocGiven
        b(ma) = coder.internal.nan();
    end
    if isempty(sp)
        newb = movmedian(b,intConstOrWinSize,'omitnan');
    else
        newb = movmedian(b,intConstOrWinSize,'omitnan','SamplePoints',sp);
    end
    b(ma) = newb(ma);
    ma(ma) = xor(ma(ma),ismissing(b(ma)));
else
    % griddedInterpolant/interp1 require at least 2 grid points.
    % Do not error if we cannot fill. Instead, return the original array.
    % For example, fillmissing([NaN 1 NaN],'linear') returns [NaN 1 NaN].
    if isempty(sp)
        spValues = (1:lengthSP).';
    else
        spValues = sp;
    end
    if ~isscalar(nma)
        isfloatb = isfloat(b);
        if isfloatb
            b(ma) = interp1(spValues(nma),b(nma),spValues(ma),FILL,'extrap');
        else
            % char
            vq = interp1(spValues(nma),nma,spValues(ma),FILL,'extrap');
            indvq = ~isnan(vq); % vq may have leading or trailing NaN
            iatmp = find(ma);
            b(iatmp(indvq)) = b(vq(indvq)); % copy non-missing to missing
        end
    end
end
% (2) Correct for EndValues
indBeg = nma(1); % numNonMissing > 0
indEnd = nma(end);
if ~strcmp(ev,'value')
    if strcmp(ev,'none')
        b(1:indBeg-1)   = a(1:indBeg-1);
        b(indEnd+1:end) = a(indEnd+1:end);
        ma(1:indBeg-1) = false;
        ma(indEnd+1:end) = false;
    elseif strcmp(ev,'nearest') || (strcmp(ev,'extrap') && strcmp(FILL,'nearest'))
        b(1:indBeg-1)   = a(indBeg);
        b(indEnd+1:end) = a(indEnd);
        ma(1:indBeg-1) = true;
        ma(indEnd+1:end) = true;
    elseif strcmp(ev,'previous') || (strcmp(ev,'extrap') && strcmp(FILL,'previous'))
        b(1:indBeg-1)   = a(1:indBeg-1);
        b(indEnd+1:end) = a(indEnd);
        ma(1:indBeg-1) = false;
        ma(indEnd+1:end) = true;
    elseif strcmp(ev,'next')  || (strcmp(ev,'extrap') && strcmp(FILL,'next'))
        b(1:indBeg-1)   = a(indBeg);
        b(indEnd+1:end) = a(indEnd+1:end);
        ma(1:indBeg-1) = true;
        ma(indEnd+1:end) = false;
    end
else
    if isscalar(evValue)
        b([1:indBeg-1, indEnd+1:end]) = evValue;
    else
        b([1:indBeg-1, indEnd+1:end]) = evValue(jj);
    end
    ma([1:indBeg-1, indEnd+1:end]) = true;
end

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

function out = reorderCellstr(in,out,order,replacement)
coder.internal.prefer_const(replacement)
% Avoid trying to index into a heterogeneous cell array to reorder its
% elements by converting contents into a vector of chars, the writing that
% into a cell array

ONE = coder.internal.indexInt(1);
ZERO = coder.internal.indexInt(0);

% Convert the scalar or vector of replacement values to a char vector
if iscell(replacement)
    [replacementCharVector,replacementCellInfo] = cellstr2charVector(replacement);
else
    replacementCharVector = replacement;
    replacementCellInfo = [ONE;coder.internal.indexInt(size(replacement))'];
end

% Convert the input cell array to a char vector
[charVectorIn,cellInfoIn] = cellstr2charVector(in);

for ii = ONE:numel(out)
    if order(ii) > 0
        currentInd = cellInfoIn(1,order(ii));
        currentSize = cellInfoIn(2:3,order(ii))';
        currentNumel = currentSize(1)*currentSize(2);
        out{ii} = reshape(charVectorIn(currentInd+(ZERO:currentNumel-1)),currentSize);
    else
        if isscalar(replacement)
            out{ii} = reshape(replacementCharVector,replacementCellInfo(2:3)');
        else
            replacementInd = replacementCellInfo(1,-order(ii));
            replacementSize = replacementCellInfo(2:3,-order(ii))';
            replacementNumel = replacementSize(1)*replacementSize(2);
            out{ii} = reshape(char(replacementCharVector(replacementInd+(ZERO:replacementNumel-1))),replacementSize);
        end
    end
end

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

function [charVector,cellInfo] = cellstr2charVector(in)
% Take a cellstr and convert it into a char vector and an integer vector
% that indicates where the contents of each cell are located in the vector
% and what the original size of that element was

ONE = coder.internal.indexInt(1);
numCharIn = coder.internal.indexInt(0);

% Count the characters in the cellstr
for ii = ONE:numel(in)
    numCharIn = numCharIn + coder.internal.indexInt(numel(in{ii}));
end

charVector = coder.nullcopy(char(ones(1,numCharIn)));
cellInfo = coder.nullcopy(coder.internal.indexInt(zeros(3,numel(in))));

% Copy the contents of the cellstr to a char vector
jj = ONE;
for ii = ONE:numel(in)
    cellInfo(1,ii) = jj;
    charsToCopy = in{ii};
    currentNumChars = coder.internal.indexInt(numel(charsToCopy));
    cellInfo(2:3,ii) = coder.internal.indexInt(size(charsToCopy));
    charVector(jj+(ONE:currentNumChars)-ONE) = charsToCopy(:)';
    jj = jj+currentNumChars;
end

% LocalWords:  makima movmean movmedian extrap Ord ismissing BOut Vals jj mov ev sp omitnan
% LocalWords:  Interpolant vq
