function [i,j,v] = find(x,varargin)
%MATLAB Code Generation Library Function

%   Limitations:
%   There are no limitations for fixed-size x. For variable-size x, FIND
%   returns column vectors unless x is a fixed-size row vector or a
%   variable-length row vector (1-by-?).

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

coder.internal.allowEnumInputs;
coder.inline('always'); % for shrinktypes on index outputs
narginchk(1,3);
coder.internal.assert(~iscell(x), ...
    'Coder:toolbox:unsupportedClass', mfilename,class(x));
if ~coder.target('MATLAB') && ...
        coder.internal.isConst(x) && coder.internal.isConst(varargin)
    % Use extrinsic calls.
    if nargout == 3
        [i,j,v] = coder.const(@feval,'find',x,varargin{:});
    elseif nargout == 2
        [i,j] = coder.const(@feval,'find',x,varargin{:});
    else
        i = coder.const(@feval,'find',x,varargin{:});
    end
    return
end
coder.internal.assert(eml_option('VariableSizing'),'Coder:toolbox:find_1');
if nargout == 3
    [ii,jj,v] = eml_find(x,varargin{:});
    i = double(ii);
    j = double(jj);
elseif nargout == 2
    [ii,jj] = eml_find(x,varargin{:});
    i = double(ii);
    j = double(jj);
else
    ii = eml_find(x,varargin{:});
    i = double(ii);
end

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

function [i,j,v] = eml_find(x,kin,opt)
% Outputs i and j are from coder.internal.indexIntClass.
coder.internal.allowEnumInputs;
if issparse(x)
    nx = nnzInt(x);
else
    nx = cast(numel(x),coder.internal.indexIntClass);
end
if issparse(x)
    xZERO = coder.internal.scalarEg(x.d);
else
    xZERO = coder.internal.scalarEg(x);
end
if nargin > 1
    coder.internal.prefer_const(kin);
    coder.internal.assert(isscalar(kin) && ...
        (isnumeric(kin) || islogical(kin)) && ...
        isreal(kin), ...
        'MATLAB:find:NotScalarInt');
    kftmp = full(kin);
    kf = kftmp(1);
    coder.internal.assert((islogical(kf) || floor(kf) == kf) && kf > 0, ...
        'MATLAB:find:NotScalarInt');
    % Note: Using this explicit IF is handled better by range analysis than
    % using min(kf,nx).
    if islogical(kf)
        % false is not a possibility here.
        k = coder.internal.indexInt(1);
    elseif kf <= nx
        k = coder.internal.indexInt(kf);
    else
        k = coder.internal.indexInt(nx);
    end
else
    k = nx;
end
assert(k <= nx); %<HINT>
if nargin == 3
    ntc = eml_max(1,strlength(opt));
    if strncmpi(opt,'first',ntc)
        first = true;
    elseif strncmpi(opt,'last',ntc)
        first = false;
    else
        coder.internal.assert(false, ...
            'Coder:toolbox:find_4', ...
            'IfNotConst','Fail');
    end
else
    first = true;
end
if coder.internal.isConstTrue(@isempty,x)
    if coder.internal.isConstTrue(@isvector,x) || ...
            coder.internal.isConstTrue(@isequal,x,[])
        i = zeros(size(x),coder.internal.indexIntClass);
        j = zeros(size(x),coder.internal.indexIntClass);
        v = full(x);
    else
        i = EMPTY01;
        j = EMPTY01;
        v = reshape(full(x),[0,1]);
    end
    return
end
if coder.internal.isConstTrue(@isscalar,x)
    fx = full(x);
    if (islogical(fx) && fx(1)) || (~islogical(fx) && fx(1) ~= xZERO)
        i = ONE;
        j = ONE;
        v = fx(1);
    else
        i = EMPTY00;
        j = EMPTY00;
        v = fx([]);
    end
    return
end
isRow = coder.internal.isConstTrue(@isrow,x);
if nargout > 1
    [dm,dn] = size(x);
    m = cast(dm,coder.internal.indexIntClass);
    n = cast(dn,coder.internal.indexIntClass);
    if nx == 0
        if isRow
            i = EMPTY10;
            j = EMPTY10;
            v = eml_expand(xZERO,[1,0]);
        else
            i = EMPTY01;
            j = EMPTY01;
            v = eml_expand(xZERO,[0,1]);
        end
    elseif first
        [i,j,v] = find_first_nonempty_triples(x,k,xZERO,m,n);
    else % last
        [i,j,v] = find_last_nonempty_triples(x,k,xZERO,m,n,nx);
    end
else
    if first
        i = find_first_indices(x,k,xZERO,nx);
    else % last
        i = find_last_indices(x,k,xZERO,nx);
    end
end
if isrow(x) && ~isrow(i) && size(x,2) >= 2
    % MATLAB generally returns row vectors when the input is a row vector,
    % except that find(false) --> []. Unless x is fixed-size or is 1-by-:?,
    % our results are column vectors. The warning is suppressed when x is
    % 1-by-0 or 1-by-1. It is not clear that it should be, but the warning
    % replaces an error, and there was previously no error issued when x is
    % variable-size, is not typed as a variable-length row vector, and x =
    % 0 at run time (find(x) --> 0-by-1 in code generation instead of [])
    % or x is 1-by-0 (find(x) --> 0-by-1 instead of 1-by-0).
    coder.internal.warning('Coder:toolbox:FindVectorOrientationMismatch');
end

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

function x = flipv(x)
% Does FLIPLR on row vectors, FLIPUD on column vectors.
coder.internal.allowEnumInputs;
n = cast(numel(x),coder.internal.indexIntClass);
nd2 = coder.internal.indexDivide(n,2);
for j = 1:nd2
    xtmp = x(j);
    x(j) = x(n-j+1);
    x(n-j+1) = xtmp;
end

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

function [i,j,v] = find_first_nonempty_triples(x,k,xZERO,m,n)
coder.inline('always');
coder.internal.allowEnumInputs;
coder.internal.prefer_const(k);
isRow = coder.internal.isConstTrue(@isrow,x);
idx = ZERO;
if isRow
    % Input is a row vector, so return row vectors.
    % coder.varsize('i','j','v',[1,k],[0,1]);
    i = coder.nullcopy(EMPTY10); %#ok<NASGU>
    i = coder.nullcopy(zeros(1,k,coder.internal.indexIntClass));
    j = coder.nullcopy(EMPTY10); %#ok<NASGU>
    j = coder.nullcopy(zeros(1,k,coder.internal.indexIntClass));
    v = coder.nullcopy(eml_expand(xZERO,[1,0])); %#ok<NASGU>
    v = coder.nullcopy(eml_expand(xZERO,[1,k]));
else
    % Return column vectors.
    % coder.varsize('i','j','v',[k,1],[1,0]);
    i = coder.nullcopy(EMPTY01); %#ok<NASGU>
    i = coder.nullcopy(zeros(k,1,coder.internal.indexIntClass));
    j = coder.nullcopy(EMPTY01); %#ok<NASGU>
    j = coder.nullcopy(zeros(k,1,coder.internal.indexIntClass));
    v = coder.nullcopy(eml_expand(xZERO,[0,1])); %#ok<NASGU>
    v = coder.nullcopy(eml_expand(xZERO,[k,1]));
end
if issparse(x)
    for idx = 1:k
        i(idx) = x.rowidx(idx);
    end
    for idx1 = 1:k
        v(idx1) = x.d(idx1);
    end
    idx = ZERO;
    col = ONE;
    while idx < k
        if idx == x.colidx(col+1)-1
            col = col+1;
        else
            idx = idx+1;
            j(idx) = col;
        end
    end
else
    ii = ONE;
    jj = ONE;
    while jj <= n
        if (islogical(x) && x(ii,jj)) || ...
                (~islogical(x) && x(ii,jj) ~= xZERO)
            idx = idx+1;
            i(idx) = ii;
            j(idx) = jj;
            v(idx) = x(ii,jj);
            if idx >= k
                break
            end
        end
        ii = ii+1;
        if ii > m
            ii = ONE;
            jj = jj+1;
        end
    end
end
assert(idx <= k); %<HINT>
if k == 1
    if idx == 0
        if isRow
            i = EMPTY10;
            j = EMPTY10;
            v = eml_expand(xZERO,[1,0]);
        else
            i = EMPTY01;
            j = EMPTY01;
            v = eml_expand(xZERO,[0,1]);
        end
    end
else
    i = i(1:idx);
    j = j(1:idx);
    v = v(1:idx);
end

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

function [i,j,v] = find_last_nonempty_triples(x,k,xZERO,m,n,nx)
coder.inline('always');
coder.internal.allowEnumInputs;
coder.internal.prefer_const(k);
isRow = coder.internal.isConstTrue(@isrow,x);
idx = ZERO;
if isRow
    % Input is a row vector, so return row vectors.
    % coder.varsize('i','j','v',[1,k],[0,1]);
    i = coder.nullcopy(EMPTY10); %#ok<NASGU>
    i = coder.nullcopy(zeros(1,k,coder.internal.indexIntClass));
    j = coder.nullcopy(EMPTY10); %#ok<NASGU>
    j = coder.nullcopy(zeros(1,k,coder.internal.indexIntClass));
    v = coder.nullcopy(eml_expand(xZERO,[1,0])); %#ok<NASGU>
    v = coder.nullcopy(eml_expand(xZERO,[1,k]));
else
    % Return column vectors.
    % coder.varsize('i','j','v',[k,1],[1,0]);
    i = coder.nullcopy(EMPTY01); %#ok<NASGU>
    i = coder.nullcopy(zeros(k,1,coder.internal.indexIntClass));
    j = coder.nullcopy(EMPTY01); %#ok<NASGU>
    j = coder.nullcopy(zeros(k,1,coder.internal.indexIntClass));
    v = coder.nullcopy(eml_expand(xZERO,[0,1])); %#ok<NASGU>
    v = coder.nullcopy(eml_expand(xZERO,[k,1]));
end
if issparse(x)
    xidx = nx;
    for idx = 1:k
        i(idx) = x.rowidx(xidx);
        xidx = xidx-1;
    end
    xidx = nx;
    for idx = 1:k
        v(idx) = x.d(xidx);
        xidx = xidx-1;
    end
    idx = ONE;
    xidx = nx;
    col = x.n;
    while idx <= k
        if xidx < x.colidx(col)
            col = col-1;
        else
            j(idx) = col;
            idx = idx+1;
            xidx = xidx-1;
        end
    end
    idx = k;
else
    ii = m;
    jj = n;
    while jj > 0
        if (islogical(x) && x(ii,jj)) || ...
                (~islogical(x) && x(ii,jj) ~= xZERO)
            idx = idx+1;
            i(idx) = ii;
            j(idx) = jj;
            v(idx) = x(ii,jj);
            if idx >= k
                break
            end
        end
        ii = ii-1;
        if ii < 1
            ii = m;
            jj = jj-1;
        end
    end
end
assert(idx <= k); %<HINT>
if k == 1
    if idx == 0
        if isRow
            i = EMPTY10;
            j = EMPTY10;
            v = eml_expand(xZERO,[1,0]);
        else
            i = EMPTY01;
            j = EMPTY01;
            v = eml_expand(xZERO,[0,1]);
        end
    end
else
    i = i(1:idx);
    j = j(1:idx);
    v = v(1:idx);
    i = flipv(i);
    j = flipv(j);
    v = flipv(v);
end

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

function i = find_first_indices(x,k,xZERO,nx)
coder.inline('always');
coder.internal.allowEnumInputs;
coder.internal.prefer_const(k);
isRow = coder.internal.isConstTrue(@isrow,x);
idx = ZERO;
if isRow
    % Input is a row vector, so return row vectors.
    % coder.varsize('i','j','v',[1,k],[0,1]);
    i = coder.nullcopy(EMPTY10); %#ok<NASGU>
    i = coder.nullcopy(zeros(1,k,coder.internal.indexIntClass));
else
    % Return column vectors.
    % coder.varsize('i','j','v',[k,1],[1,0]);
    i = coder.nullcopy(EMPTY01); %#ok<NASGU>
    i = coder.nullcopy(zeros(k,1,coder.internal.indexIntClass));
end
if issparse(x)
    col = ONE;
    while idx < k
        if idx == x.colidx(col+1)-1
            col = col+1;
        else
            idx = idx+1;
            i(idx) = (col-1)*x.m + x.rowidx(idx);
        end
    end
else
    for ii = 1:nx
        if (islogical(x) && x(ii)) || (~islogical(x) && x(ii) ~= xZERO)
            idx = idx+1;
            i(idx) = ii;
            if idx >= k
                break
            end
        end
    end
end
assert(idx <= k); %<HINT>
if k == 1
    if idx == 0
        if isRow
            i = EMPTY10;
        else
            i = EMPTY01;
        end
    end
else
    i = i(1:idx);
end

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

function i = find_last_indices(x,k,xZERO,nx)
coder.inline('always');
coder.internal.allowEnumInputs;
coder.internal.prefer_const(k);
isRow = coder.internal.isConstTrue(@isrow,x);
idx = ZERO;
if isRow
    % Input is a row vector, so return row vectors.
    % coder.varsize('i','j','v',[1,k],[0,1]);
    i = coder.nullcopy(EMPTY10); %#ok<NASGU>
    i = coder.nullcopy(zeros(1,k,coder.internal.indexIntClass));
else
    % Return column vectors.
    % coder.varsize('i','j','v',[k,1],[1,0]);
    i = coder.nullcopy(EMPTY01); %#ok<NASGU>
    i = coder.nullcopy(zeros(k,1,coder.internal.indexIntClass));
end
if issparse(x)
    col = x.n;
    xidx = nx;
    while idx < k
        if xidx < x.colidx(col)
            col = col-1;
        else
            idx = idx+1;
            i(idx) = (col-1)*x.m + x.rowidx(xidx);
            xidx = xidx-1;
        end
    end
else
    for ii = nx:-1:1
        if (islogical(x) && x(ii)) || (~islogical(x) && x(ii) ~= xZERO)
            idx = idx+1;
            i(idx) = ii;
            if idx >= k
                break
            end
        end
    end
end
assert(idx <= k); %<HINT>
if k == 1
    if idx == 0
        if isRow
            i = EMPTY10;
        else
            i = EMPTY01;
        end
    end
else
    i = i(1:idx);
    i = flipv(i);
end

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

function y = ZERO
coder.inline('always');
y = zeros(coder.internal.indexIntClass);

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

function y = ONE
coder.inline('always');
y = ones(coder.internal.indexIntClass);

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

function y = EMPTY00
coder.inline('always');
y = cast([],coder.internal.indexIntClass);

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

function y = EMPTY01
coder.inline('always');
y = zeros(0,1,coder.internal.indexIntClass);

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

function y = EMPTY10
coder.inline('always');
y = zeros(1,0,coder.internal.indexIntClass);

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