function b = permute(a,order)
%MATLAB Code Generation Library Function

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

coder.internal.allowEnumInputs;
coder.internal.allowHalfInputs;
coder.internal.assert(nargin == 2,'MATLAB:minrhs');
coder.internal.assert(~iscell(a),'Coder:toolbox:CellArraysNotSupported',mfilename);
coder.internal.assert(~coder.isenum(order),'Coder:toolbox:permute_2');
coder.internal.prefer_const(order);
coder.internal.assert(coder.internal.isConst(order) || ...
    eml_option('VariableSizing'),'Coder:toolbox:permute_3');
coder.internal.assert(coder.internal.isConst(size(order)), ...
    'Coder:toolbox:permute_4');
if ~isreal(order)
    b = permute(a,real(order));
    return
end
NDA = coder.const(coder.internal.indexInt(eml_ndims(a)));
ND = coder.const(coder.internal.indexInt(numel(order)));
coder.internal.assert(ND >= NDA,'MATLAB:permute:tooFewIndices');
coder.internal.assert(eml_is_permutation(real(order)), ...
    'Coder:toolbox:permute_invalidPermutation');
ONE = coder.internal.indexInt(1);
TWO = coder.internal.indexInt(2);
if numel(order) == 2 && order(ONE) == TWO && order(TWO) == ONE
    b = a.';
    return
end
insz = cell(1,ND);
for k = coder.unroll(1:NDA)
    insz{k} = coder.internal.indexInt(size(a,k));
end
for k = coder.unroll(NDA+1:ND)
    insz{k} = ONE;
end
outsz = cell(1,ND);
for k = coder.unroll(1:ND)
    outsz{k} = insz{order(k)};
end
if nomovement(order,a)
    b = reshape(a,outsz{:});
    return
end
b = coder.nullcopy(reshape(a,outsz{:}));
if coder.isRowMajor
    startDim = ONE;
else
    startDim = ND;
end
b = looper(b,a,order,startDim);

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

function b = looper(b,a,order,dim,varargin)
coder.internal.allowEnumInputs;
coder.inline('always');
coder.internal.prefer_const(order,dim);
ND = coder.const(coder.internal.indexInt(numel(order)));
ONE = coder.internal.indexInt(1);
if dim >= ONE && dim <= ND
    if coder.isRowMajor
        coder.gpu.internal.kernelImpl(false);
        for k = ONE:size(a,dim)
            b = looper(b,a,order,dim + 1,varargin{:},k);
        end
    else
        coder.gpu.internal.kernelImpl(false);
        for k = ONE:size(a,dim)
            b = looper(b,a,order,dim - 1,k,varargin{:});
        end
    end
else
    subsa = varargin;
    subsb = coder.nullcopy(subsa);
    for k = coder.unroll(ONE:ND)
        subsb{k} = subsa{order(k)};
    end
    if iscell(a)
        b{subsb{:}} = a{subsa{:}};
    else
        b(subsb{:}) = a(subsa{:});
    end
end

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

function b = nomovement(perm,a)
% Returns true if the permute operation will not result in data movement.
coder.internal.allowEnumInputs;
ONE = coder.internal.indexInt(1);
b = true;
if ~isempty(a)
    % Determine whether the order of nonsingleton dimensions is changed by
    % the permutation.
    plast = zeros(class(perm));
    for k = ONE:numel(perm) % numel(p) >= eml_ndims(a)
        if size(a,perm(k)) ~= 1
            if plast > perm(k)
                b = false;
                break
            end
            plast = perm(k);
        end
    end
end

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