function y = diff(x,n,dim)
%MATLAB Code Generation Library Function

%   Copyright 2002-2014 The MathWorks, Inc.
%#codegen

eml_invariant(nargin > 0, ...
    'MATLAB:minrhs');
eml_invariant(coder.internal.isBuiltInNumeric(x) || islogical(x) || ischar(x), ...
    'Coder:toolbox:diff_2', ...
    'IfNotConst','Fail');
ONE = coder.internal.indexInt(1);
if islogical(x) || ischar(x)
    xzero = 0;
else
    xzero = coder.internal.scalarEg(x);
end
if nargin < 2 || isempty(n)
    order = ONE;
else
    coder.internal.prefer_const(n);
    eml_invariant(eml_is_const(n) || coder.const(~coder.internal.eml_option_eq('VariableSizing','DisableInInference')), ...
        'Coder:toolbox:diff_3', ...
        'IfNotConst','Fail');
    order = coder.internal.indexInt(n);
    eml_invariant(isscalar(n) && isreal(n) && n >= 1 && n == order, ...
        'Coder:toolbox:diff_differenceOrderMustBePositiveInteger', ...
        coder.internal.indexIntClass);
end
constsize = eml_is_const(size(x)) && eml_is_const(order);
if nargin < 3
    dim = coder.internal.constNonSingletonDim(x);
    dimSize = coder.internal.indexInt(size(x,dim));
    if dimSize == 0
        xSize = size(x);
        xSize(dim) = 0; % Turns out this is needed for tight bounds.
        y = eml_expand(xzero,xSize);
        return
    end
    orderForDim = eml_min(dimSize - ONE,order);
    if orderForDim < 1
        if constsize
            y = eml_expand(xzero,[0,0]);
        else
            xSize = size(x);
            xSize(dim) = 0;
            y = eml_expand(xzero,xSize);
        end
        return
    end
    eml_invariant(eml_is_const(dimSize) || dimSize ~= 1, ...
        'Coder:toolbox:autoDimIncompatibility');
else
    coder.internal.prefer_const(dim);
    eml_invariant(eml_is_const(dim), ...
        'Coder:toolbox:dimNotConst');
    coder.internal.assertValidDim(dim);
    if dim > coder.internal.ndims(x)  % Matlab N-D behavior.
        idims = dim - (coder.internal.ndims(x) + 1);
        y = eml_expand(xzero,[size(x),ones(1,idims),0]);
        return
    end
    dimSize = coder.internal.indexInt(size(x,dim));
    if dimSize <= order
        xSize = size(x);
        xSize(dim) = 0;
        y = eml_expand(xzero,xSize);
        return
    end
    orderForDim = order;
end
eml_invariant(constsize || orderForDim == order, ...
    'Coder:toolbox:diff_orderLimitForVariableSizedX');
newDimSize = dimSize - orderForDim;
ySize = size(x);
ySize(dim) = newDimSize;
work = coder.nullcopy(eml_expand(xzero,[orderForDim,ONE]));
y1 = coder.nullcopy(eml_expand(xzero,ySize));
if ~isempty(y1)
    stride = coder.internal.prodsize(x,'below',dim);
    nHigh = coder.internal.prodsize(x,'above',dim);
    xNext = stride*dimSize;
    yNext = stride*newDimSize;
    ixStart = ONE;
    iyStart = ONE;
    tmp1 = coder.nullcopy(xzero);
    for r = ONE:nHigh
        ix = ixStart;
        iy = iyStart;
        for s = ONE:stride
            ixLead = ix + stride;
            iyLead = iy;
            work(1) = x(ix);
            if orderForDim >= 2
                for m = ONE:(orderForDim - ONE)
                    tmp1(1) = x(ixLead);
                    for k = ONE:m
                        tmp2 = work(k);
                        work(k) = tmp1;
                        tmp1 = tmp1 - tmp2;
                    end
                    work(m + ONE) = tmp1;
                    ixLead = ixLead + stride;
                end
            end
            for m = (orderForDim + ONE):dimSize
                tmp1(1) = x(ixLead);
                for k = ONE:orderForDim
                    tmp2 = work(k);
                    work(k) = tmp1;
                    tmp1 = tmp1 - tmp2;
                end
                ixLead = ixLead + stride;
                y1(iyLead) = tmp1;
                iyLead = iyLead + stride;
            end
            ix = ix + ONE;
            iy = iy + ONE;
        end
        ixStart = ixStart + xNext;
        iyStart = iyStart + yNext;
    end
end
if constsize && orderForDim < order
    % Diff along another dimension.
    n2 = order - orderForDim;
    y = diff(y1,n2);
else
    y = y1;
end
