static long parse()

in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImpl.java [1468:1653]


    static long parse(final CharSequence s, final int si, final int ei, final int roundingMode, final String decimalMarks) {
        char c;
        int p = si;
        boolean sign = false;

        c = s.charAt(p);
        if (c == '+') {
            p += 1;
            c = p < ei ? s.charAt(p) : 0;
        }
        if (c == '-') {
            sign = true;

            p += 1;
            c = p < ei ? s.charAt(p) : 0;
        }

        if (decimalMarks.indexOf(c) < 0 && (c < '0' || c > '9')) {
            if (TextUtils.equalsIgnoringCase(s, p, ei, "Infinity") ||
                TextUtils.equalsIgnoringCase(s, p, ei, "Inf"))
                return sign ? JavaImpl.NEGATIVE_INFINITY : JavaImpl.POSITIVE_INFINITY;
            if (TextUtils.equalsIgnoringCase(s, p, ei, "NaN") ||
                TextUtils.equalsIgnoringCase(s, p, ei, "SNaN"))
                return JavaImpl.NaN;
            throw invalidFormat(s, si, ei);
        }

        boolean seenRadixPoint = false;
        int leadingZerosAfterPoint = 0;

        if (c == '0' || decimalMarks.indexOf(c) >= 0) {
            if (decimalMarks.indexOf(c) >= 0) {
                seenRadixPoint = true;

                p += 1;
                c = p < ei ? s.charAt(p) : 0;
            }

            while (c == '0') {
                p += 1;
                c = p < ei ? s.charAt(p) : 0;

                if (seenRadixPoint)
                    leadingZerosAfterPoint += 1;

                if (decimalMarks.indexOf(c) >= 0) {
                    if (seenRadixPoint)
                        throw invalidFormat(s, si, ei);
                    seenRadixPoint = true;

                    p += 1;
                    c = p < ei ? s.charAt(p) : 0;
                    if (c == 0)
                        return makeZero(sign, EXPONENT_BIAS - leadingZerosAfterPoint);
                } else if (c == 0) {
                    return makeZero(sign, EXPONENT_BIAS - leadingZerosAfterPoint);
                }
            }
        }

        int numberOfDigits = 0;
        int decimalExponentScale = 0;
        long coefficient = 0;
        boolean roundedUp = false, rounded = false, midpoint = false;
        int additionalExponent = 0;

        while ((c >= '0' && c <= '9') || decimalMarks.indexOf(c) >= 0) {
            if (decimalMarks.indexOf(c) >= 0) {
                if (seenRadixPoint)
                    throw invalidFormat(s, si, ei);

                seenRadixPoint = true;

                p += 1;
                c = p < ei ? s.charAt(p) : 0;

                continue;
            }

            if (seenRadixPoint)
                decimalExponentScale += 1;

            numberOfDigits += 1;
            if (numberOfDigits <= 16) {
                coefficient = (coefficient << 1) + (coefficient << 3) + c - '0';
            } else if (numberOfDigits == 17) {
                switch (roundingMode) {
                    case BID_ROUNDING_EXCEPTION:
                        throw new NumberFormatException("Can't convert string(='" + s.subSequence(si, ei) + "') to Decimal64 without precision loss.");

                    case BID_ROUNDING_TO_NEAREST:
                        midpoint = (c == '5' && (coefficient & 1) == 0);
                        if (c > '5' || (c == '5' && (coefficient & 1) != 0)) {
                            coefficient += 1;
                            roundedUp = true;
                        }
                        break;

                    case BID_ROUNDING_DOWN:
                        if (sign) {
                            coefficient += 1;
                            roundedUp = true;
                        }
                        break;

                    case BID_ROUNDING_UP:
                        if (!sign) {
                            coefficient += 1;
                            roundedUp = true;
                        }
                        break;

                    case BID_ROUNDING_TIES_AWAY:
                        if (c >= '5') {
                            coefficient += 1;
                            roundedUp = true;
                        }
                        break;
                }
                if (coefficient == 10000000000000000L) {
                    coefficient = 1000000000000000L;
                    additionalExponent = 1;
                }
                if (c > '0')
                    rounded = true;
                additionalExponent += 1;
            } else {
                additionalExponent += 1;
                if (midpoint && c >= '0') {
                    coefficient += 1;
                    midpoint = false;
                    roundedUp = true;
                }
                if (c >= '0')
                    rounded = true;
            }

            p += 1;
            c = p < ei ? s.charAt(p) : 0;
        }

        additionalExponent -= (decimalExponentScale + leadingZerosAfterPoint);

        if (c == 0)
            return fastPackCheckOverflow(sign, additionalExponent + EXPONENT_BIAS, coefficient);

        if (c != 'E' && c != 'e')
            throw invalidFormat(s, si, ei);

        p += 1;
        c = p < ei ? s.charAt(p) : 0;

        final boolean isExponentSigned = c == '-';
        if (c == '-' || c == '+') {
            p += 1;
            c = p < ei ? s.charAt(p) : 0;
        }

        if (c == 0 || c < '0' || c > '9')
            throw invalidFormat(s, si, ei);

        int exponent = 0;
        while (c >= '0' && c <= '9') {
            if (exponent < (1 << 20)) {
                exponent = (exponent << 1) + (exponent << 3) + (c - '0');

                p += 1;
                c = p < ei ? s.charAt(p) : 0;
            }
        }

        if (c != 0)
            throw invalidFormat(s, si, ei);

        if (isExponentSigned)
            exponent = -exponent;
        exponent += additionalExponent + EXPONENT_BIAS;

        if (exponent < 0) {
            if (roundedUp)
                coefficient -= 1;
            return packUnderflow(sign, exponent, coefficient, rounded, BID_ROUNDING_TO_NEAREST);
        }

        return pack(sign ? MASK_SIGN : 0, exponent, coefficient, BID_ROUNDING_TO_NEAREST);
    }