All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.refinitiv.eta.codec.RealImpl Maven / Gradle / Ivy

/*|-----------------------------------------------------------------------------
 *|            This source code is provided under the Apache 2.0 license      --
 *|  and is provided AS IS with no warranty or guarantee of fit for purpose.  --
 *|                See the project's LICENSE.md for details.                  --
 *|           Copyright (C) 2019-2022 Refinitiv. All rights reserved.         --
 *|-----------------------------------------------------------------------------
 */

package com.refinitiv.eta.codec;

import java.lang.Double;
import java.math.BigDecimal;

class RealImpl implements Real
{
    static final byte BLANK_REAL = 0x20;
    static final double powHintsExp[] = { 100000000000000.0, 10000000000000.0, 1000000000000.0, 100000000000.0, 10000000000.0,
                                          1000000000.0, 100000000.0, 10000000.0, 1000000.0, 100000.0, 10000.0, 1000.0, 100.0,
                                          10.0, 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 1, 2, 4, 8, 16, 32, 64, 128, 256 };
    static final String zeroDisplayStrings[] = { "0.0E-14", "0.0E-13", "0.0E-12", "0.0E-11", "0.0E-10", "0.0E-9", "0.0E-8", "0.0E-7",
                                                 "0.0E-6", "0.0E-5", "0.0E-4", "0.000", "0.00", "0.0", "0", "0", "0", "0", "0", "0",
                                                 "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" };
    
    static final String decimalStringFormat[] = {"%.14f","%.13f","%.12f", "%.11f", "%.10f", "%.9f", "%.8f", "%.7f", "%.6f", "%.5f", "%.4f", "%.3f", "%.2f", "%.1f"};

    boolean     _isBlank;
    int         _hint;
    long        _value;
	
    // for toString() method so don't have to re-convert if set by string
    private String _stringVal;
	
    // for value(String) method
    private String trimmedVal;
    static private String infinity = "Inf";
    static private String negInfinity = "-Inf";
    static private String notANumber = "NaN";
    private final int MAX_STRLEN = 20;
    UInt valueUInt = CodecFactory.createUInt();
    UInt tempValue = CodecFactory.createUInt();
    Int trailzerovalue = CodecFactory.createInt();
    Int trailzerocount = CodecFactory.createInt();
    Int foundDigit = CodecFactory.createInt();
    Int nextDigit = CodecFactory.createInt();
    UInt denominator = CodecFactory.createUInt();
    Int expdiff = CodecFactory.createInt();
    UInt numerator = CodecFactory.createUInt();

    @Override
    public void clear()
    {
        _isBlank = false;
        _hint = RealHints.EXPONENT0;
        _value = 0;
        _stringVal = null;
    }

    @Override
    public void blank()
    {
        _isBlank = true;
        _hint = RealHints.EXPONENT_14;
        _value = 0;
        _stringVal = null;
    }

    public int copy(Real destReal)
    {
        if (null == destReal)
            return CodecReturnCodes.INVALID_ARGUMENT;

        ((RealImpl)destReal)._value = _value;
        ((RealImpl)destReal)._hint = _hint;
        ((RealImpl)destReal)._isBlank = _isBlank;

        ((RealImpl)destReal)._stringVal = null;

        return CodecReturnCodes.SUCCESS;
    }

    @Override
    public int value(double value, int hint)
    {
        if (!(hint >= RealHints.EXPONENT_14 && hint <= RealHints.NOT_A_NUMBER && hint != 31)) // 31 is 'reserved'
        {
            return CodecReturnCodes.INVALID_ARGUMENT;
        }

        if (java.lang.Double.isNaN(value))
        {
            _value = 0;
            _hint = RealHints.NOT_A_NUMBER;
        }
        else if (value == java.lang.Double.POSITIVE_INFINITY)
        {
            _value = 0;
            _hint = RealHints.INFINITY;
        }
        else if (value == java.lang.Double.NEGATIVE_INFINITY)
        {
            _value = 0;
            _hint = RealHints.NEG_INFINITY;
        }
        else
        {
            _hint = hint;

            double res;
            if (value > 0)
                res = value * powHintsExp[hint] + 0.5;
            else
                res = value * powHintsExp[hint] - 0.5;

            if (res < Long.MIN_VALUE || Long.MAX_VALUE < res) {
                return CodecReturnCodes.INVALID_ARGUMENT;
            }

            // Checks the corner cases.
            // Uses direct assignment value Long.MAX_VALUE (64 bits) and prohibits the conversation from double value (53 bits).
            if (Long.MAX_VALUE == res)
                _value = Long.MAX_VALUE;
            else if (Long.MIN_VALUE == res)
                _value = Long.MIN_VALUE;
            else
                _value = (long)res;
        }
        _isBlank = false;
        _stringVal = null;
        return CodecReturnCodes.SUCCESS;
    }

    @Override
    public int value(float value, int hint)
    {
        if (!(hint >= RealHints.EXPONENT_14 && hint <= RealHints.NOT_A_NUMBER && hint != 31)) // 31 is 'reserved'
        {
            return CodecReturnCodes.INVALID_ARGUMENT;
        }

        if (java.lang.Float.isNaN(value))
        {
            _value = 0;
            _hint = RealHints.NOT_A_NUMBER;
        }
        else if (value == java.lang.Float.POSITIVE_INFINITY)
        {
            _value = 0;
            _hint = RealHints.INFINITY;
        }
        else if (value == java.lang.Float.NEGATIVE_INFINITY)
        {
            _value = 0;
            _hint = RealHints.NEG_INFINITY;
        }
        else
        {
            _hint = hint;

            float res;
            if (value > 0)
                res = (float)(value * powHintsExp[hint]) + 0.5f;
            else
                res = (float)(value * powHintsExp[hint]) - 0.5f;

            if (res < Long.MIN_VALUE || Long.MAX_VALUE < res) {
                return CodecReturnCodes.INVALID_ARGUMENT;
            }

            // Checks the corner cases.
            // Uses direct assignment value Long.MAX_VALUE (64 bits) and prohibits the conversation from float value (24 bits).
            if (Long.MAX_VALUE == res)
                _value = Long.MAX_VALUE;
            else if (Long.MIN_VALUE == res)
                _value = Long.MIN_VALUE;
            else
                _value = (long)res;
        }
        _isBlank = false;
        _stringVal = null;

        return CodecReturnCodes.SUCCESS;
    }

    @Override
    public int value(long value, int hint)
    {
        if (!(hint >= RealHints.EXPONENT_14 && hint <= RealHints.NOT_A_NUMBER && hint != 31 && hint != 32)) // 31 is 'reserved'
        {
            return CodecReturnCodes.INVALID_ARGUMENT;
        }

        _value = value;
        _hint = hint;
        _isBlank = false;
        _stringVal = null;

        return CodecReturnCodes.SUCCESS;
    }

    @Override
    public double toDouble()
    {
        if (_isBlank == true)
            return 0;
        switch (_hint)
        {
            case RealHints.NOT_A_NUMBER:
                return java.lang.Double.NaN;
            case RealHints.INFINITY:
                return java.lang.Double.POSITIVE_INFINITY;
            case RealHints.NEG_INFINITY:
                return java.lang.Double.NEGATIVE_INFINITY;
            default:
                return _value / powHintsExp[_hint];
        }
    }

    @Override
    public BigDecimal toBigDecimal()
    {
        if(_isBlank)
            return null;
        switch (_hint)
        {
            case RealHints.NOT_A_NUMBER:
            case RealHints.INFINITY:
            case RealHints.NEG_INFINITY:
                return null;
            default:
                return BigDecimal.valueOf(_value).divide(BigDecimal.valueOf(powHintsExp[_hint]));
        }
    }

    @Override
    public long toLong()
    {
        return _value;
    }

    @Override
    public int hint()
    {
        return _hint;
    }

    @Override
    public boolean isBlank()
    {
        return _isBlank;
    }
    
    @Override
    public boolean equals(Real thatReal)
    {
        if (thatReal != null)
        {
            if ((_value == thatReal.toLong()) &&
                    (_hint == thatReal.hint()) &&
                    (_isBlank == thatReal.isBlank()))
                return true;
            else
                return ((toDouble() == thatReal.toDouble()) && (_isBlank == thatReal.isBlank()));
        }
        else
            return false;
    }

    boolean isHintBlank()
    {
        return (_hint & BLANK_REAL) > 0 ? true : false;
    }

    @Override
    public int encode(EncodeIterator iter)
    {
        return Encoders.PrimitiveEncoder.encodeReal((EncodeIteratorImpl)iter, this);
    }

    @Override
    public int decode(DecodeIterator iter)
    {
        return Decoders.decodeReal(iter, this);
    }

    @Override
    public String toString()
    {
        if (_stringVal == null)
        {
            switch (_hint)
            {
                case RealHints.INFINITY:
                {
                    _stringVal = infinity;
                    return "Inf";
                }
                case RealHints.NEG_INFINITY:
                {
                    _stringVal = negInfinity;
                    return "-Inf";
                }
                case RealHints.NOT_A_NUMBER:
                {
                    _stringVal = notANumber;
                    return "NaN";
                }
                default:
                    break;
            }

            if (_value != 0)
            {
            	/* Handles number of decimal places according to the hint value. */
            	if(RealHints.EXPONENT_14 <= _hint && _hint <= RealHints.EXPONENT_1)
            	{
            		return String.format(decimalStringFormat[_hint],toDouble());
            	}
            	else
            	{
            		return Double.toString(toDouble());
            	}
            }
            else
            {
                return zeroDisplayStrings[_hint];
            }
        }
        else
        {
            return _stringVal;
        }
    }

    @Override
    public int value(String value)
    {
        if (value == null)
        {
            return CodecReturnCodes.INVALID_ARGUMENT;
        }

        int maxStringLen = MAX_STRLEN;
        boolean isNeg = false;
        int valIdx = 0;
        int ret = CodecReturnCodes.SUCCESS;
        _stringVal = null;

        valueUInt.clear();
        tempValue.clear();
        trailzerovalue.clear();
        trailzerocount.clear();
        foundDigit.clear();
        nextDigit.clear();
        denominator.clear();
        expdiff.clear();
        numerator.clear();

        trimmedVal = value.trim();

        if (valIdx == trimmedVal.length())
        {
            blank();
            _stringVal = trimmedVal;
            return CodecReturnCodes.SUCCESS;
        }

        if (trimmedVal.equalsIgnoreCase(infinity))
        {
            _isBlank = false;
            _value = 0;
            _stringVal = infinity;
            _hint = RealHints.INFINITY;
            return CodecReturnCodes.SUCCESS;
        }
        else if (trimmedVal.equalsIgnoreCase(negInfinity))
        {
            _isBlank = false;
            _value = 0;
            _stringVal = negInfinity;
            _hint = RealHints.NEG_INFINITY;
            return CodecReturnCodes.SUCCESS;
        }
        else if (trimmedVal.equalsIgnoreCase(notANumber))
        {
            _isBlank = false;
            _value = 0;
            _stringVal = notANumber;
            _hint = RealHints.NOT_A_NUMBER;
            return CodecReturnCodes.SUCCESS;
        }

        // check if blank
        if (trimmedVal.charAt(valIdx) == '+')
        {
            boolean isAllZeroes = true;
            for (int i = valIdx + 1; i < trimmedVal.length(); i++)
            {
                if (trimmedVal.charAt(i) != '0' && trimmedVal.charAt(i) != '.')
                {
                    isAllZeroes = false;
                    break;
                }
            }
            if (isAllZeroes)
            {
                blank();
                _stringVal = trimmedVal;
                return CodecReturnCodes.SUCCESS;
            }
        }

        // check if negative
        if (trimmedVal.charAt(valIdx) == '-')
        {
            isNeg = true;
            maxStringLen++;
            valIdx++;
        }
        else if (trimmedVal.charAt(valIdx) == '+')
        {
            valIdx++;
        }

        valIdx = rwf_atonumber_end_trailzero(trimmedVal, valIdx, valueUInt, foundDigit, trailzerovalue, trailzerocount, nextDigit, tempValue);
        
        // Checks for overflow condition of the long data type
        long longValue = valueUInt.toLong();
    	
    	if(longValue < 0)
    	{
    		if(!isNeg)
    		{
    			return CodecReturnCodes.INVALID_ARGUMENT;
    		}
    		else 
    		{
    			if(longValue == Long.MIN_VALUE)
    			{
    				isNeg = false;
    			}
    			else
    			{
    				return CodecReturnCodes.INVALID_ARGUMENT;
    			}
    		}
    	}

        if (valIdx == trimmedVal.length())
        {
            // number must be no bigger than max string length
            if (trimmedVal.length() <= maxStringLen)
            {
                ret = value(!isNeg ? longValue : -longValue, RealHints.EXPONENT0);
                
                if(ret != CodecReturnCodes.SUCCESS)
                	return ret;
                
                _isBlank = false;
            }
            else
            {
                // error
                return CodecReturnCodes.INVALID_ARGUMENT;
            }
            _stringVal = trimmedVal;
            return CodecReturnCodes.SUCCESS;
        }

        /* Check for decimal value */
        if (trimmedVal.charAt(valIdx) == '.')
        {
            /* It is a decimal value */
            int startdec = ++valIdx;
            int exponent;
            maxStringLen++;

            if (trimmedVal.length() > maxStringLen)
            {
                // error
                return CodecReturnCodes.INVALID_ARGUMENT;
            }

            valIdx = rwf_atonumber_end(trimmedVal, valIdx, valueUInt, foundDigit, nextDigit, tempValue);

            exponent = valIdx - startdec;

            if (exponent == 0)
            {
                // error
                return CodecReturnCodes.INVALID_ARGUMENT;
            }
            
            // Checks for overflow condition of the long data type
            longValue = valueUInt.toLong();
        	
            if(longValue < 0)
        	{
        		if(!isNeg)
        		{
        			return CodecReturnCodes.INVALID_ARGUMENT;
        		}
        		else 
        		{
        			if(longValue == Long.MIN_VALUE)
        			{
        				isNeg = false;
        			}
        			else
        			{
        				return CodecReturnCodes.INVALID_ARGUMENT;
        			}
        		}
        	}

            ret = value(!isNeg ? longValue: -longValue, RealHints.EXPONENT0 - exponent);
            
            if(ret != CodecReturnCodes.SUCCESS)
            	return ret;
            
            if (trimmedVal.charAt(0) != '+')
            {
                _isBlank = false;
            }
        }
        else if (trimmedVal.charAt(valIdx) == ' ')
        {
            valIdx++;
            maxStringLen++;

            /* Check for another digit. Then it might be a fraction. */
            if ((trimmedVal.charAt(valIdx) >= '0' && trimmedVal.charAt(valIdx) <= '9'))
            {
                tempValue.clear();
                denominator.clear();

                valIdx = rwf_atonumber_end(trimmedVal, valIdx, numerator, foundDigit, nextDigit, tempValue);

                /* Verify fraction */
                if (trimmedVal.charAt(valIdx) != '/')
                {
                    // error
                    return CodecReturnCodes.INVALID_ARGUMENT;
                }

                maxStringLen++;
                if (trimmedVal.length() >= maxStringLen)
                {
                    // error
                    return CodecReturnCodes.INVALID_ARGUMENT;
                }

                valIdx++;
                valIdx = rwf_atonumber_end(trimmedVal, valIdx, denominator, foundDigit, nextDigit, tempValue);

                int hint = rwf_SetFractionHint((int)denominator.toLong());
                if (hint == 0)
                {
                    // error
                    return CodecReturnCodes.INVALID_ARGUMENT;
                }

                valueUInt.value((valueUInt.toLong() * denominator.toLong()) + numerator.toLong());
                ret = value(!isNeg ? valueUInt.toLong() : -valueUInt.toLong(), hint);
                
                if(ret != CodecReturnCodes.SUCCESS)
                	return ret;
                
                _isBlank = false;
            }
            else if (valIdx == trimmedVal.length())
            {
                ret = value(!isNeg ? valueUInt.toLong() : -valueUInt.toLong(), RealHints.EXPONENT0);
                
                if(ret != CodecReturnCodes.SUCCESS)
                	return ret;
                
                _isBlank = false;
            }
            else
            {
                // error
                return CodecReturnCodes.INVALID_ARGUMENT;
            }
        }
        else if (trimmedVal.charAt(valIdx) == '/')
        {
            tempValue.clear();
            denominator.clear();

            valIdx++;
            valIdx = rwf_atonumber_end(trimmedVal, valIdx, denominator, foundDigit, nextDigit, tempValue);

            int hint = rwf_SetFractionHint((int)denominator.toLong());
            if (hint == 0)
            {
                // error
                return CodecReturnCodes.INVALID_ARGUMENT;
            }

            /* value stays as value */
            ret = value(!isNeg ? valueUInt.toLong() : -valueUInt.toLong(), hint);
            
            if(ret != CodecReturnCodes.SUCCESS)
            	return ret;
            
            _isBlank = false;
        }
        else
        {
            // error
            return CodecReturnCodes.INVALID_ARGUMENT;
        }

        return CodecReturnCodes.SUCCESS;
    }

    private int rwf_atonumber_end_trailzero(String str, int index, UInt result, Int foundDigit, Int trailzerovalue, Int trailzerocount,
                                            Int nextDigit, UInt tempValue)
    {
        while ((index < str.length()) && (str.charAt(index) >= '0' && str.charAt(index) <= '9'))
        {
            tempValue.value(result.toLong() * 10);
            nextDigit.value((str.charAt(index) - 0x30));
            if (str.charAt(index) == '0')
            {
                if (trailzerocount.toLong() == 0)
                    trailzerovalue.value(result.toLong());
                trailzerocount.value(trailzerocount.toLong() + 1);
            }
            else
                trailzerocount.value(0);
            foundDigit.value(1);
            result.value(tempValue.toLong() + nextDigit.toLong());
            index++;
        }

        return index;
    }

    private int rwf_atonumber_end(String str, int index, UInt result, Int foundDigit, Int nextDigit, UInt tempValue)
    {
        while ((index < str.length()) && (str.charAt(index) >= '0' && str.charAt(index) <= '9'))
        {
            foundDigit.value(1);
            tempValue.value(result.toLong() * 10);
            nextDigit.value((str.charAt(index) - 0x30));
            result.value(tempValue.toLong() + nextDigit.toLong());
            index++;
        }

        return index;
    }

    private int rwf_SetFractionHint(int denom)
    {
        int retval = 0;
        switch (denom)
        {
            case 1:
                retval = RealHints.FRACTION_1;
                break;
            case 2:
                retval = RealHints.FRACTION_2;
                break;
            case 4:
                retval = RealHints.FRACTION_4;
                break;
            case 8:
                retval = RealHints.FRACTION_8;
                break;
            case 16:
                retval = RealHints.FRACTION_16;
                break;
            case 32:
                retval = RealHints.FRACTION_32;
                break;
            case 64:
                retval = RealHints.FRACTION_64;
                break;
            case 128:
                retval = RealHints.FRACTION_128;
                break;
            case 256:
                retval = RealHints.FRACTION_256;
                break;
            default:
                break;
        }
        return retval;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy