// 
// Decompiled by Procyon v0.6.0
// 

package ch.randelshofer.fastdoubleparser;

abstract class AbstractJavaFloatingPointBitsFromByteArray extends AbstractFloatValueParser
{
    private static int skipWhitespace(final byte[] str, int index, final int endIndex) {
        while (index < endIndex && (str[index] & 0xFF) <= 32) {
            ++index;
        }
        return index;
    }
    
    abstract long nan();
    
    abstract long negativeInfinity();
    
    private long parseDecFloatLiteral(final byte[] str, int index, final int startIndex, final int endIndex, final boolean isNegative) {
        long significand = 0L;
        final int significandStartIndex = index;
        int integerDigitCount = -1;
        boolean illegal = false;
        byte ch = 0;
        final int swarLimit = Math.min(endIndex - 4, 1073741824);
        while (index < endIndex) {
            ch = str[index];
            final int digit = (char)(ch - 48);
            if (digit < 10) {
                significand = 10L * significand + digit;
            }
            else {
                if (ch != 46) {
                    break;
                }
                illegal |= (integerDigitCount >= 0);
                integerDigitCount = index - significandStartIndex;
                while (index < swarLimit) {
                    final int digits = FastDoubleSwar.tryToParseFourDigits(str, index + 1);
                    if (digits < 0) {
                        break;
                    }
                    significand = 10000L * significand + digits;
                    index += 4;
                }
            }
            ++index;
        }
        final int significandEndIndex = index;
        int digitCount;
        int exponent;
        if (integerDigitCount < 0) {
            digitCount = (integerDigitCount = index - significandStartIndex);
            exponent = 0;
        }
        else {
            digitCount = index - significandStartIndex - 1;
            exponent = integerDigitCount - digitCount;
        }
        illegal |= (digitCount == 0 && significandEndIndex > significandStartIndex);
        int expNumber = 0;
        if ((ch | 0x20) == 0x65) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            final boolean isExponentNegative = ch == 45;
            if (isExponentNegative || ch == 43) {
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            }
            int digit2 = (char)(ch - 48);
            illegal |= (digit2 >= 10);
            do {
                if (expNumber < 1024) {
                    expNumber = 10 * expNumber + digit2;
                }
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                digit2 = (char)(ch - 48);
            } while (digit2 < 10);
            if (isExponentNegative) {
                expNumber = -expNumber;
            }
            exponent += expNumber;
        }
        if (!illegal && digitCount == 0) {
            return this.parseNaNOrInfinity(str, index, endIndex, isNegative);
        }
        if ((ch | 0x22) == 0x66) {
            ++index;
        }
        index = skipWhitespace(str, index, endIndex);
        if (illegal || index < endIndex) {
            return 9221120237041090561L;
        }
        boolean isSignificandTruncated;
        int exponentOfTruncatedSignificand;
        if (digitCount > 19) {
            int truncatedDigitCount = 0;
            significand = 0L;
            int digit3;
            for (index = significandStartIndex; index < significandEndIndex; ++index) {
                ch = str[index];
                digit3 = (char)(ch - 48);
                if (digit3 < 10) {
                    if (Long.compareUnsigned(significand, 1000000000000000000L) >= 0) {
                        break;
                    }
                    significand = 10L * significand + digit3;
                    ++truncatedDigitCount;
                }
            }
            isSignificandTruncated = (index < significandEndIndex);
            exponentOfTruncatedSignificand = integerDigitCount - truncatedDigitCount + expNumber;
        }
        else {
            isSignificandTruncated = false;
            exponentOfTruncatedSignificand = 0;
        }
        return this.valueOfFloatLiteral(str, startIndex, endIndex, isNegative, significand, exponent, isSignificandTruncated, exponentOfTruncatedSignificand);
    }
    
    public long parseFloatingPointLiteral(final byte[] str, final int offset, final int length) {
        final int endIndex = AbstractNumberParser.checkBounds(str.length, offset, length);
        int index = skipWhitespace(str, offset, endIndex);
        if (index == endIndex) {
            return 9221120237041090561L;
        }
        byte ch = str[index];
        final boolean isNegative = ch == 45;
        if (isNegative || ch == 43) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            if (ch == 0) {
                return 9221120237041090561L;
            }
        }
        final boolean hasLeadingZero = ch == 48;
        if (hasLeadingZero) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            if ((ch | 0x20) == 0x78) {
                return this.parseHexFloatingPointLiteral(str, index + 1, offset, endIndex, isNegative);
            }
            --index;
        }
        return this.parseDecFloatLiteral(str, index, offset, endIndex, isNegative);
    }
    
    private long parseHexFloatingPointLiteral(final byte[] str, int index, final int startIndex, final int endIndex, final boolean isNegative) {
        long significand = 0L;
        int exponent = 0;
        final int significandStartIndex = index;
        int virtualIndexOfPoint = -1;
        boolean illegal = false;
        byte ch = 0;
        while (index < endIndex) {
            ch = str[index];
            final int hexValue = AbstractNumberParser.lookupHex(ch);
            if (hexValue >= 0) {
                significand = (significand << 4 | (long)hexValue);
            }
            else {
                if (hexValue != -4) {
                    break;
                }
                illegal |= (virtualIndexOfPoint >= 0);
                virtualIndexOfPoint = index;
            }
            ++index;
        }
        final int significandEndIndex = index;
        int digitCount;
        if (virtualIndexOfPoint < 0) {
            digitCount = significandEndIndex - significandStartIndex;
            virtualIndexOfPoint = significandEndIndex;
        }
        else {
            digitCount = significandEndIndex - significandStartIndex - 1;
            exponent = Math.min(virtualIndexOfPoint - index + 1, 1024) * 4;
        }
        int expNumber = 0;
        final boolean hasExponent = (ch | 0x20) == 0x70;
        if (hasExponent) {
            ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            final boolean isExponentNegative = ch == 45;
            if (isExponentNegative || ch == 43) {
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
            }
            int digit = (char)(ch - 48);
            illegal |= (digit >= 10);
            do {
                if (expNumber < 1024) {
                    expNumber = 10 * expNumber + digit;
                }
                ch = AbstractNumberParser.charAt(str, ++index, endIndex);
                digit = (char)(ch - 48);
            } while (digit < 10);
            if (isExponentNegative) {
                expNumber = -expNumber;
            }
            exponent += expNumber;
        }
        if ((ch | 0x22) == 0x66) {
            ++index;
        }
        index = skipWhitespace(str, index, endIndex);
        if (illegal || index < endIndex || digitCount == 0 || !hasExponent) {
            return 9221120237041090561L;
        }
        int skipCountInTruncatedDigits = 0;
        boolean isSignificandTruncated;
        if (digitCount > 16) {
            significand = 0L;
            int hexValue2;
            for (index = significandStartIndex; index < significandEndIndex; ++index) {
                ch = str[index];
                hexValue2 = AbstractNumberParser.lookupHex(ch);
                if (hexValue2 >= 0) {
                    if (Long.compareUnsigned(significand, 1000000000000000000L) >= 0) {
                        break;
                    }
                    significand = (significand << 4 | (long)hexValue2);
                }
                else {
                    ++skipCountInTruncatedDigits;
                }
            }
            isSignificandTruncated = (index < significandEndIndex);
        }
        else {
            isSignificandTruncated = false;
        }
        return this.valueOfHexLiteral(str, startIndex, endIndex, isNegative, significand, exponent, isSignificandTruncated, (virtualIndexOfPoint - index + skipCountInTruncatedDigits) * 4 + expNumber);
    }
    
    private long parseNaNOrInfinity(final byte[] str, int index, final int endIndex, final boolean isNegative) {
        if (index < endIndex) {
            if (str[index] == 78) {
                if (index + 2 < endIndex && str[index + 1] == 97 && str[index + 2] == 78) {
                    index = skipWhitespace(str, index + 3, endIndex);
                    if (index == endIndex) {
                        return this.nan();
                    }
                }
            }
            else if (index + 7 < endIndex && FastDoubleSwar.readLongLE(str, index) == 8751735898823355977L) {
                index = skipWhitespace(str, index + 8, endIndex);
                if (index == endIndex) {
                    return isNegative ? this.negativeInfinity() : this.positiveInfinity();
                }
            }
        }
        return 9221120237041090561L;
    }
    
    abstract long positiveInfinity();
    
    abstract long valueOfFloatLiteral(final byte[] p0, final int p1, final int p2, final boolean p3, final long p4, final int p5, final boolean p6, final int p7);
    
    abstract long valueOfHexLiteral(final byte[] p0, final int p1, final int p2, final boolean p3, final long p4, final int p5, final boolean p6, final int p7);
}
