function C = convn(A,B,shapestr)
%MATLAB Code Generation Library Function

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

narginchk(2,3);
if nargin < 3
    shapestr = 'full';
end
assertSupportedType(A);
assertSupportedType(B);
% Deal with non-float input types.
if ~isfloat(A)
    C = convn(double(A),B,shapestr);
    return
elseif ~isfloat(B)
    C = convn(A,double(B),shapestr);
    return
end
ONE = ones(coder.internal.indexIntClass);
nDims = cast(eml_max(coder.internal.ndims(A),coder.internal.ndims(B)),coder.internal.indexIntClass);
shape = coder.internal.convShapeStrToID(shapestr);
C = convAllocateC(A,B,shape);
C = convn_kernel(nDims,C,ONE,A,ONE,B,ONE,shape);

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

function C = convAllocateC(A,B,shape)
% Allocate the output array C for CONV2 and CONVn and fill it with zeros.
coder.inline('always');
coder.internal.prefer_const(shape);
%#codegen
nDimsA = coder.internal.indexInt(coder.internal.ndims(A));
nDimsB = coder.internal.indexInt(coder.internal.ndims(B));
nDims = eml_max(nDimsA,nDimsB);
szC = zeros(1,nDims,coder.internal.indexIntClass);
if shape == FULL
    for k = coder.unroll(1:nDims)
        if size(A,k) > 0 && size(B,k) > 0
            szC(k) = size(A,k) + size(B,k) - 1;
        else
            szC(k) = size(A,k) + size(B,k);
        end
    end
elseif shape == SAME
    for k = coder.unroll(1:nDims)
        szC(k) = size(A,k);
    end
else % if shape == VALID
    IMAX = intmax(coder.internal.indexIntClass());
    for k = coder.unroll(1:nDims)
        if size(B,k) >= 1
            szC(k) = size(A,k) - size(B,k) + 1;
        else
            szC(k) = size(A,k);
        end
        % g1805891: If any size of A is non-constant and has intmax in its range, this implies it is
        % unbounded. We drop the bound here to prevent issues with TUUB-induced matrix copies.
        if (~coder.internal.isConst(size(A,k)) && size(A,k) == IMAX)
            szC(k) = coder.internal.ignoreRange(szC(k));
        end
    end
end
C = eml_expand(coder.internal.scalarEg(A,B),szC);

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

function y = FULL
coder.inline('always');
y = coder.const(coder.internal.convShapeStrToID('f'));

function y = SAME
coder.inline('always');
y = coder.const(coder.internal.convShapeStrToID('s'));

function y = VALID %#ok
coder.inline('always');
y = coder.const(coder.internal.convShapeStrToID('v'));

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

function assertSupportedType(x)
eml_invariant(coder.internal.isBuiltInNumeric(x) || islogical(x), ...
    'Coder:toolbox:unsupportedClass','convn',class(x));

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