function c = bitset(a,bit,v,assumedtype)
%MATLAB Code Generation Library Function

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

coder.internal.allowEnumInputs;
coder.internal.assert(nargin >= 2,'MATLAB:minrhs');

% Define optional inputs with recursion.
if nargin == 2
    c = bitset(a,bit,true,coder.const(defaultAssumedClass(a)));
    return
end
if nargin == 3
    coder.internal.prefer_const(v);
    if coder.internal.isTextRow(v)
        c = bitset(a,bit,true,v);
    else
        c = bitset(a,bit,v,coder.const(defaultAssumedClass(a)));
    end
    return
end

coder.internal.prefer_const(v,assumedtype);
coder.internal.assert(coder.internal.isConst(assumedtype), ...
    'Coder:toolbox:TrailingStringInputMustBeConstant');

% Handle Simulink size propagation.
if coder.internal.isAmbiguousTypes
    c = coder.internal.scalexpAlloc(0,a,bit,v);
    c(:) = 0;
    return
end

% Constant-fold with an extrinsic call.
if ~coder.target('MATLAB') && ...
        coder.internal.isConst(a) && ...
        coder.internal.isConst(bit) && ...
        coder.internal.isConst(v)
    c = coder.const(feval('bitset',a,bit,v,assumedtype));
    return
end

% Validate input types and determine assumed and output classes.
coder.internal.assert(isinteger(a) || isa(a,'double'), ...
    'Coder:toolbox:unsupportedClass','bitset',class(a));
assumedcls = char(assumedtype);
outputcls = coder.internal.builtinClass(a);
coder.internal.assert(coder.internal.isIntegerClass(assumedcls), ...
    'MATLAB:bitset:unknownTypeString');
coder.internal.assert(~isinteger(a) || isa(a,assumedcls), ...
    'MATLAB:bitset:invalidTypeString');
coder.internal.assert(isreal(a) && isreal(bit) && isreal(v), ...
    'MATLAB:bitset:complexArgs');

% Validate bit values.
IONE = coder.internal.indexInt(1);
nbits = coder.internal.int_nbits(assumedcls);
coder.internal.assert(all_in_integer_range(bit,IONE,nbits), ...
    'MATLAB:bitSetGet:BITOutOfRange');

% Validate double values, if any.
if ~isa(a,assumedcls)
    imin = intmin(assumedcls);
    imax = intmax(assumedcls);
    coder.internal.assert(all_in_integer_range(a,imin,imax), ...
        'MATLAB:bitset:outOfRange');
end

canUseInternalSxfun = coder.internal.get_eml_option('CanGenerateElementwiseCalls');

% Perform the operation.
if coder.target('hdl')
    coder.inline('always');
    c = coder.internal.scalexpAlloc(zeros(outputcls),a,bit,v);
    for k = 1:numel(c)
        c(k) = bitset_scalar( ...
            coder.internal.scalexpSubsref(a,k), ...
            coder.internal.scalexpSubsref(bit,k), ...
            coder.internal.scalexpSubsref(v,k), ...
            assumedcls,outputcls);
    end
elseif coder.internal.isConstTrue(isscalar(a)) && ...
        coder.internal.isConstTrue(isscalar(bit)) && ...
        coder.internal.isConstTrue(isscalar(v))
    coder.inline('always');
    c = bitset_scalar(a(1),bit(1),v(1),assumedcls,outputcls);
elseif canUseInternalSxfun
    f = @(a,bit,v)bitset_scalar(a,bit,v,assumedcls,outputcls);
    c = coder.internal.sxfun('bitset',f,a,bit,v);
else
    % This performs scalar expansion without using elementwise function
    % calls which certain clients can not handle yet (otherwise we should
    % call coder.internal.sxfun as we do above.
    c = coder.internal.scalexpAlloc(coder.internal.scalarEg(a),a,bit,v);
    if isempty(c)
        return
    end
    IONE = coder.internal.indexInt(1);
    nbits = coder.internal.int_nbits(assumedtype);
    eml_invariant(all_in_integer_range(bit,IONE,nbits), ...
        'MATLAB:bitSetGet:BITOutOfRange');
    AONE = ones(assumedtype);
    for k = 1:numel(c)
        if isinteger(a)
            ak = eml_scalexp_subsref(a,k);
        else
            ak = eml_cast(eml_scalexp_subsref(a,k),assumedtype,'to zero','spill');
        end
        bitk = eml_scalexp_subsref(bit,k);
        if isfloat(bitk)
            bitkInt = eml_cast(bitk,'uint8','to zero','spill');
            bm1 = eml_minus(bitkInt,1,'uint8','spill');
        else
            bm1 = eml_minus(bitk,1,class(bitk),'spill');
        end
        mask = eml_lshift(AONE,bm1);
        biton = logical(eml_scalexp_subsref(v,k));
        if biton
            c(k) = eml_bitor(ak,mask);
        else
            c(k) = eml_bitand(ak,eml_bitnot(mask));
        end
    end
end

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

function c = bitset_scalar(a,bit,v,assumedtype,ccls)

coder.internal.prefer_const(v,assumedtype,ccls);
coder.inline('always');
atmp = cast(a,coder.internal.builtinClass(a));
a1 = eml_cast(atmp,assumedtype,'to zero','spill');
btmp = cast(bit,coder.internal.builtinClass(bit));
if isfloat(btmp)
    b1 = eml_cast(btmp,'uint8','to zero','spill');
    bm1 = eml_minus(b1,1,'uint8','spill');
else
    bm1 = eml_minus(btmp,1,class(btmp),'spill');
end
mask = eml_lshift(ones(assumedtype),bm1);
vtmp = cast(v,coder.internal.builtinClass(v));
v1 = logical(vtmp);
if v1
    c = cast(eml_bitor(a1,mask),ccls);
else
    c = cast(eml_bitand(a1,eml_bitnot(mask)),ccls);
end

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

function cls = defaultAssumedClass(a)
if isinteger(a)
    cls = coder.internal.builtinClass(a);
else
    cls = 'uint64';
end

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