function DataType = float( TotalBits, ExpBits )
%% Create Simulink.NumericType object describing floating-point data type
%
%    This function is obsolete. 
%
%    You can replace
%       FLOAT('single')
%    with
%       FIXDT('single')
%
%    You can replace
%       FLOAT('double')
%    with
%       FIXDT('double')
%
%    You can replace
%       FLOAT('half')
%    with
%       FIXDT('half')
%
%    Note: Support for custom floating point data types has been removed.
%      To handle this removal, either:
%      - Replace calls to FLOAT( TotalBits, ExpBits ) with calls to 
%        FIXDT('double'), FIXDT('single'), or FIXDT('half')
%      - Write a function custom_float_user_replacement.m and place this 
%        file on your MATLAB path. This function must take TotalBits and
%        ExpBits as input arguments and return a supported numerictype object,
%        for example, FIXDT('double') or FIXDT('single'). If 
%        custom_float_user_replacement.m exists, calls to 
%        FLOAT( TotalBits, ExpBits ) automatically call 
%        custom_float_user_replacement( TotalBits, ExpBits ) and return the 
%        numerictype object that it outputs. This replacement mechanism will 
%        continue to work in future releases if custom_float_user_replacement.m
%        is on your MATLAB path.
%
%    See also FIXDT, NUMERICTYPE.

% Copyright 1994-2020 The MathWorks, Inc.

    if (nargin == 0)
        DAStudio.error('modelexplorer:numericType:floatNoArg');
    end

    if nargin > 0
        TotalBits = convertStringsToChars(TotalBits);
    end

    %Validate inputs
    fcn_name = 'float';
    if nargin == 1
        % only one input argument for the function needs to be char
        validateattributes(TotalBits, {'char', 'string'}, {'scalartext'}, fcn_name, 'TOTALBITS');       
    elseif nargin == 2
        validateattributes(TotalBits, {'numeric'}, {'real', 'scalar', 'positive'}, fcn_name, 'TOTALBITS');
        validateattributes(ExpBits, {'numeric'}, {'real', 'scalar', 'positive'}, fcn_name, 'EXPBITS');
    end

    if (nargin == 1)
        floats  = float_type_names();
        key = lower(TotalBits);
        if ~isKey(floats, key)
            DAStudio.error('modelexplorer:numericType:floatUnrecognizedDataTypeName',TotalBits);
        end
        DataType = floats(key);
    else
        assert(nargin == 2);
        % get bit pattern map
        floats = float_type_bitpattern();
        key = hash(TotalBits, ExpBits);
        
        if isKey(floats, key)
            % found match
            DataType = floats(key);
            return;            
        end
        
        % check for custom replacement
        if exist('custom_float_user_replacement','file')
            DataType = custom_float_user_replacement( TotalBits, ExpBits );
            return;
        end
        % No matching data type
        DAStudio.error('modelexplorer:numericType:customFloatSupportRemove', TotalBits, ExpBits );
    end
        
end

function [float_map] = float_type_names()
%% float_types map key properties to "named floating point types"

    persistent MapByFloatName

    if isempty(MapByFloatName)
        keys = {'half','binary16','float16', 'single','binary32','float32','double','binary64','float64'};
        values = {
            fixdt('half'), fixdt('half'), fixdt('half'), ...
            fixdt('single'), fixdt('single'), fixdt('single'), ...
            fixdt('double'), fixdt('double'), fixdt('double')};

        MapByFloatName = containers.Map(keys, values);
    end

    float_map = MapByFloatName;

            end

function [float_map] = float_type_bitpattern()
%% float_type_bitpattern map key properties to "float bit pattern"

    persistent MapByFloatBitPattern

    if isempty(MapByFloatBitPattern)
        keys = {hash(16, 5), hash(32, 8), hash(64, 11)};
        values = {fixdt('half'), fixdt('single'), fixdt('double')};

        MapByFloatBitPattern = containers.Map(keys, values);
    end

    float_map = MapByFloatBitPattern;

    end  

function y = hash(a, b)
%% Cantor pairing hash function:(a + b) * (a + b + 1) / 2 + a; where a, b >= 0
    assert(a > 0 && b > 0);
    y = (a + b) * (a + b + 1) / 2 + a;
end

% LocalWords:  Un
