From 934672dc8d5b9bf7309ab49432815e99d3c4c0cd Mon Sep 17 00:00:00 2001 From: kenKang <31346910+nelsonken@users.noreply.github.com> Date: Wed, 3 Nov 2021 15:30:32 +0800 Subject: [PATCH] Update IterImpl.java --- src/main/java/com/jsoniter/IterImpl.java | 853 ++++++++++++++--------- 1 file changed, 510 insertions(+), 343 deletions(-) diff --git a/src/main/java/com/jsoniter/IterImpl.java b/src/main/java/com/jsoniter/IterImpl.java index 1cd9515e..a2802cc7 100644 --- a/src/main/java/com/jsoniter/IterImpl.java +++ b/src/main/java/com/jsoniter/IterImpl.java @@ -5,487 +5,654 @@ import com.jsoniter.spi.Slice; import java.io.IOException; -import java.math.BigInteger; -class IterImpl { - - private static BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); - private static BigInteger minLong = BigInteger.valueOf(Long.MIN_VALUE); - private static BigInteger maxInt = BigInteger.valueOf(Integer.MAX_VALUE); - private static BigInteger minInt = BigInteger.valueOf(Integer.MIN_VALUE); +class IterImplForStreaming { public static final int readObjectFieldAsHash(JsonIterator iter) throws IOException { - if (readByte(iter) != '"') { - if (nextToken(iter) != '"') { - throw iter.reportError("readObjectFieldAsHash", "expect \""); - } + if (nextToken(iter) != '"') { + throw iter.reportError("readObjectFieldAsHash", "expect \""); } long hash = 0x811c9dc5; - int i = iter.head; - for (; i < iter.tail; i++) { - byte c = iter.buf[i]; + for (; ; ) { + byte c = 0; + int i = iter.head; + for (; i < iter.tail; i++) { + c = iter.buf[i]; + if (c == '"') { + break; + } + hash ^= c; + hash *= 0x1000193; + } if (c == '"') { - break; + iter.head = i + 1; + if (nextToken(iter) != ':') { + throw iter.reportError("readObjectFieldAsHash", "expect :"); + } + return (int) hash; } - hash ^= c; - hash *= 0x1000193; - } - iter.head = i + 1; - if (readByte(iter) != ':') { - if (nextToken(iter) != ':') { - throw iter.reportError("readObjectFieldAsHash", "expect :"); + if (!loadMore(iter)) { + throw iter.reportError("readObjectFieldAsHash", "unmatched quote"); } } - return (int) hash; } public static final Slice readObjectFieldAsSlice(JsonIterator iter) throws IOException { Slice field = readSlice(iter); - if (nextToken(iter) != ':') { + boolean notCopied = field != null; + if (CodegenAccess.skipWhitespacesWithoutLoadMore(iter)) { + if (notCopied) { + int len = field.tail() - field.head(); + byte[] newBuf = new byte[len]; + System.arraycopy(field.data(), field.head(), newBuf, 0, len); + field.reset(newBuf, 0, newBuf.length); + } + if (!loadMore(iter)) { + throw iter.reportError("readObjectFieldAsSlice", "expect : after object field"); + } + } + if (iter.buf[iter.head] != ':') { throw iter.reportError("readObjectFieldAsSlice", "expect : after object field"); } + iter.head++; return field; } final static void skipArray(JsonIterator iter) throws IOException { int level = 1; - for (int i = iter.head; i < iter.tail; i++) { - switch (iter.buf[i]) { - case '"': // If inside string, skip it - iter.head = i + 1; - skipString(iter); - i = iter.head - 1; // it will be i++ soon - break; - case '[': // If open symbol, increase level - level++; - break; - case ']': // If close symbol, increase level - level--; - - // If we have returned to the original level, we're done - if (level == 0) { + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + switch (iter.buf[i]) { + case '"': // If inside string, skip it iter.head = i + 1; - return; - } - break; + skipString(iter); + i = iter.head - 1; // it will be i++ soon + break; + case '[': // If open symbol, increase level + level++; + break; + case ']': // If close symbol, increase level + level--; + + // If we have returned to the original level, we're done + if (level == 0) { + iter.head = i + 1; + return; + } + break; + } + } + if (!loadMore(iter)) { + return; } } - throw iter.reportError("skipArray", "incomplete array"); } final static void skipObject(JsonIterator iter) throws IOException { int level = 1; - for (int i = iter.head; i < iter.tail; i++) { - switch (iter.buf[i]) { - case '"': // If inside string, skip it - iter.head = i + 1; - skipString(iter); - i = iter.head - 1; // it will be i++ soon - break; - case '{': // If open symbol, increase level - level++; - break; - case '}': // If close symbol, increase level - level--; - - // If we have returned to the original level, we're done - if (level == 0) { + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + switch (iter.buf[i]) { + case '"': // If inside string, skip it iter.head = i + 1; - return; - } - break; + skipString(iter); + i = iter.head - 1; // it will be i++ soon + break; + case '{': // If open symbol, increase level + level++; + break; + case '}': // If close symbol, increase level + level--; + + // If we have returned to the original level, we're done + if (level == 0) { + iter.head = i + 1; + return; + } + break; + } + } + if (!loadMore(iter)) { + return; } } - throw iter.reportError("skipObject", "incomplete object"); } final static void skipString(JsonIterator iter) throws IOException { - int end = IterImplSkip.findStringEnd(iter); - if (end == -1) { - throw iter.reportError("skipString", "incomplete string"); - } else { - iter.head = end; + for (; ; ) { + int end = IterImplSkip.findStringEnd(iter); + if (end == -1) { + int j = iter.tail - 1; + boolean escaped = true; + // can not just look the last byte is \ + // because it could be \\ or \\\ + for (; ; ) { + // walk backward until head + if (j < iter.head || iter.buf[j] != '\\') { + // even number of backslashes + // either end of buffer, or " found + escaped = false; + break; + } + j--; + if (j < iter.head || iter.buf[j] != '\\') { + // odd number of backslashes + // it is \" or \\\" + break; + } + j--; + + } + if (!loadMore(iter)) { + throw iter.reportError("skipString", "incomplete string"); + } + if (escaped) { + iter.head = 1; // skip the first char as last char is \ + } + } else { + iter.head = end; + return; + } } } final static void skipUntilBreak(JsonIterator iter) throws IOException { // true, false, null, number - for (int i = iter.head; i < iter.tail; i++) { - byte c = iter.buf[i]; - if (IterImplSkip.breaks[c]) { - iter.head = i; + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + byte c = iter.buf[i]; + if (IterImplSkip.breaks[c]) { + iter.head = i; + return; + } + } + if (!loadMore(iter)) { + iter.head = iter.tail; return; } } - iter.head = iter.tail; } final static boolean skipNumber(JsonIterator iter) throws IOException { // true, false, null, number boolean dotFound = false; - for (int i = iter.head; i < iter.tail; i++) { - byte c = iter.buf[i]; - if (c == '.' || c == 'e' || c == 'E') { - dotFound = true; - continue; - } - if (IterImplSkip.breaks[c]) { - iter.head = i; + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + byte c = iter.buf[i]; + if (c == '.' || c == 'e' || c == 'E') { + dotFound = true; + continue; + } + if (IterImplSkip.breaks[c]) { + iter.head = i; + return dotFound; + } + } + if (!loadMore(iter)) { + iter.head = iter.tail; return dotFound; } } - iter.head = iter.tail; - return dotFound; } // read the bytes between " " - public final static Slice readSlice(JsonIterator iter) throws IOException { + final static Slice readSlice(JsonIterator iter) throws IOException { if (IterImpl.nextToken(iter) != '"') { throw iter.reportError("readSlice", "expect \" for string"); } int end = IterImplString.findSliceEnd(iter); - if (end == -1) { - throw iter.reportError("readSlice", "incomplete string"); - } else { + if (end != -1) { // reuse current buffer iter.reusableSlice.reset(iter.buf, iter.head, end - 1); iter.head = end; return iter.reusableSlice; } + // TODO: avoid small memory allocation + byte[] part1 = new byte[iter.tail - iter.head]; + System.arraycopy(iter.buf, iter.head, part1, 0, part1.length); + for (; ; ) { + if (!loadMore(iter)) { + throw iter.reportError("readSlice", "unmatched quote"); + } + end = IterImplString.findSliceEnd(iter); + if (end == -1) { + byte[] part2 = new byte[part1.length + iter.buf.length]; + System.arraycopy(part1, 0, part2, 0, part1.length); + System.arraycopy(iter.buf, 0, part2, part1.length, iter.buf.length); + part1 = part2; + } else { + byte[] part2 = new byte[part1.length + end - 1]; + System.arraycopy(part1, 0, part2, 0, part1.length); + System.arraycopy(iter.buf, 0, part2, part1.length, end - 1); + iter.head = end; + iter.reusableSlice.reset(part2, 0, part2.length); + return iter.reusableSlice; + } + } } - final static byte nextToken(final JsonIterator iter) throws IOException { - int i = iter.head; + final static byte nextToken(JsonIterator iter) throws IOException { for (; ; ) { - byte c = iter.buf[i++]; - switch (c) { - case ' ': - case '\n': - case '\r': - case '\t': - continue; - default: - iter.head = i; - return c; + for (int i = iter.head; i < iter.tail; i++) { + byte c = iter.buf[i]; + switch (c) { + case ' ': + case '\n': + case '\t': + case '\r': + continue; + default: + iter.head = i + 1; + return c; + } + } + if (!loadMore(iter)) { + return 0; } } } + public final static boolean loadMore(JsonIterator iter) throws IOException { + if (iter.in == null) { + return false; + } + if (iter.skipStartedAt != -1) { + return keepSkippedBytesThenRead(iter); + } + int n = iter.in.read(iter.buf); + if (n < 1) { + if (n == -1) { + return false; + } else { + throw iter.reportError("loadMore", "read from input stream returned " + n); + } + } else { + iter.head = 0; + iter.tail = n; + } + return true; + } + + private static boolean keepSkippedBytesThenRead(JsonIterator iter) throws IOException { + int n; + int offset; + if (iter.skipStartedAt == 0 || iter.skipStartedAt < iter.tail / 2) { + byte[] newBuf = new byte[iter.buf.length * 2]; + offset = iter.tail - iter.skipStartedAt; + System.arraycopy(iter.buf, iter.skipStartedAt, newBuf, 0, offset); + iter.buf = newBuf; + n = iter.in.read(iter.buf, offset, iter.buf.length - offset); + } else { + offset = iter.tail - iter.skipStartedAt; + System.arraycopy(iter.buf, iter.skipStartedAt, iter.buf, 0, offset); + n = iter.in.read(iter.buf, offset, iter.buf.length - offset); + } + iter.skipStartedAt = 0; + if (n < 1) { + if (n == -1) { + return false; + } else { + throw iter.reportError("loadMore", "read from input stream returned " + n); + } + } else { + iter.head = offset; + iter.tail = offset + n; + } + return true; + } + final static byte readByte(JsonIterator iter) throws IOException { + if (iter.head == iter.tail) { + if (!loadMore(iter)) { + throw iter.reportError("readByte", "no more to read"); + } + } return iter.buf[iter.head++]; } public static Any readAny(JsonIterator iter) throws IOException { - int start = iter.head; + // TODO: avoid small memory allocation + iter.skipStartedAt = iter.head; byte c = nextToken(iter); switch (c) { case '"': skipString(iter); - return Any.lazyString(iter.buf, start, iter.head); + byte[] copied = copySkippedBytes(iter); + return Any.lazyString(copied, 0, copied.length); case 't': skipFixedBytes(iter, 3); + iter.skipStartedAt = -1; return Any.wrap(true); case 'f': skipFixedBytes(iter, 4); + iter.skipStartedAt = -1; return Any.wrap(false); case 'n': skipFixedBytes(iter, 3); + iter.skipStartedAt = -1; return Any.wrap((Object) null); case '[': skipArray(iter); - return Any.lazyArray(iter.buf, start, iter.head); + copied = copySkippedBytes(iter); + return Any.lazyArray(copied, 0, copied.length); case '{': skipObject(iter); - return Any.lazyObject(iter.buf, start, iter.head); + copied = copySkippedBytes(iter); + return Any.lazyObject(copied, 0, copied.length); default: if (skipNumber(iter)) { - return Any.lazyDouble(iter.buf, start, iter.head); + copied = copySkippedBytes(iter); + return Any.lazyDouble(copied, 0, copied.length); } else { - return Any.lazyLong(iter.buf, start, iter.head); + copied = copySkippedBytes(iter); + return Any.lazyLong(copied, 0, copied.length); } } } + private static byte[] copySkippedBytes(JsonIterator iter) { + int start = iter.skipStartedAt; + iter.skipStartedAt = -1; + int end = iter.head; + byte[] bytes = new byte[end - start]; + System.arraycopy(iter.buf, start, bytes, 0, bytes.length); + return bytes; + } + public static void skipFixedBytes(JsonIterator iter, int n) throws IOException { iter.head += n; + if (iter.head >= iter.tail) { + int more = iter.head - iter.tail; + if (!loadMore(iter)) { + if (more == 0) { + iter.head = iter.tail; + return; + } + throw iter.reportError("skipFixedBytes", "unexpected end"); + } + iter.head += more; + } } - public final static boolean loadMore(JsonIterator iter) throws IOException { - return false; + public static int updateStringCopyBound(final JsonIterator iter, final int bound) { + if (bound > iter.tail - iter.head) { + return iter.tail - iter.head; + } else { + return bound; + } } public final static int readStringSlowPath(JsonIterator iter, int j) throws IOException { - try { - boolean isExpectingLowSurrogate = false; - for (int i = iter.head; i < iter.tail; ) { - int bc = iter.buf[i++]; - if (bc == '"') { - iter.head = i; - return j; - } - if (bc == '\\') { - bc = iter.buf[i++]; - switch (bc) { - case 'b': - bc = '\b'; - break; - case 't': - bc = '\t'; - break; - case 'n': - bc = '\n'; - break; - case 'f': - bc = '\f'; - break; - case 'r': - bc = '\r'; - break; - case '"': - case '/': - case '\\': - break; - case 'u': - bc = (IterImplString.translateHex(iter.buf[i++]) << 12) + - (IterImplString.translateHex(iter.buf[i++]) << 8) + - (IterImplString.translateHex(iter.buf[i++]) << 4) + - IterImplString.translateHex(iter.buf[i++]); - if (Character.isHighSurrogate((char) bc)) { - if (isExpectingLowSurrogate) { - throw new JsonException("invalid surrogate"); - } else { - isExpectingLowSurrogate = true; - } - } else if (Character.isLowSurrogate((char) bc)) { - if (isExpectingLowSurrogate) { - isExpectingLowSurrogate = false; - } else { - throw new JsonException("invalid surrogate"); - } + boolean isExpectingLowSurrogate = false; + for (;;) { + int bc = readByte(iter); + if (bc == '"') { + return j; + } + if (bc == '\\') { + bc = readByte(iter); + switch (bc) { + case 'b': + bc = '\b'; + break; + case 't': + bc = '\t'; + break; + case 'n': + bc = '\n'; + break; + case 'f': + bc = '\f'; + break; + case 'r': + bc = '\r'; + break; + case '"': + case '/': + case '\\': + break; + case 'u': + bc = (IterImplString.translateHex(readByte(iter)) << 12) + + (IterImplString.translateHex(readByte(iter)) << 8) + + (IterImplString.translateHex(readByte(iter)) << 4) + + IterImplString.translateHex(readByte(iter)); + if (Character.isHighSurrogate((char) bc)) { + if (isExpectingLowSurrogate) { + throw new JsonException("invalid surrogate"); } else { - if (isExpectingLowSurrogate) { - throw new JsonException("invalid surrogate"); - } + isExpectingLowSurrogate = true; } - break; + } else if (Character.isLowSurrogate((char) bc)) { + if (isExpectingLowSurrogate) { + isExpectingLowSurrogate = false; + } else { + throw new JsonException("invalid surrogate"); + } + } else { + if (isExpectingLowSurrogate) { + throw new JsonException("invalid surrogate"); + } + } + break; - default: - throw iter.reportError("readStringSlowPath", "invalid escape character: " + bc); - } - } else if ((bc & 0x80) != 0) { - final int u2 = iter.buf[i++]; - if ((bc & 0xE0) == 0xC0) { - bc = ((bc & 0x1F) << 6) + (u2 & 0x3F); + default: + throw iter.reportError("readStringSlowPath", "invalid escape character: " + bc); + } + } else if ((bc & 0x80) != 0) { + final int u2 = readByte(iter); + if ((bc & 0xE0) == 0xC0) { + bc = ((bc & 0x1F) << 6) + (u2 & 0x3F); + } else { + final int u3 = readByte(iter); + if ((bc & 0xF0) == 0xE0) { + bc = ((bc & 0x0F) << 12) + ((u2 & 0x3F) << 6) + (u3 & 0x3F); } else { - final int u3 = iter.buf[i++]; - if ((bc & 0xF0) == 0xE0) { - bc = ((bc & 0x0F) << 12) + ((u2 & 0x3F) << 6) + (u3 & 0x3F); + final int u4 = readByte(iter); + if ((bc & 0xF8) == 0xF0) { + bc = ((bc & 0x07) << 18) + ((u2 & 0x3F) << 12) + ((u3 & 0x3F) << 6) + (u4 & 0x3F); } else { - final int u4 = iter.buf[i++]; - if ((bc & 0xF8) == 0xF0) { - bc = ((bc & 0x07) << 18) + ((u2 & 0x3F) << 12) + ((u3 & 0x3F) << 6) + (u4 & 0x3F); - } else { + throw iter.reportError("readStringSlowPath", "invalid unicode character"); + } + + if (bc >= 0x10000) { + // check if valid unicode + if (bc >= 0x110000) throw iter.reportError("readStringSlowPath", "invalid unicode character"); - } - if (bc >= 0x10000) { - // check if valid unicode - if (bc >= 0x110000) - throw iter.reportError("readStringSlowPath", "invalid unicode character"); - - // split surrogates - final int sup = bc - 0x10000; - if (iter.reusableChars.length == j) { - char[] newBuf = new char[iter.reusableChars.length * 2]; - System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length); - iter.reusableChars = newBuf; - } - iter.reusableChars[j++] = (char) ((sup >>> 10) + 0xd800); - if (iter.reusableChars.length == j) { - char[] newBuf = new char[iter.reusableChars.length * 2]; - System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length); - iter.reusableChars = newBuf; - } - iter.reusableChars[j++] = (char) ((sup & 0x3ff) + 0xdc00); - continue; + // split surrogates + final int sup = bc - 0x10000; + if (iter.reusableChars.length == j) { + char[] newBuf = new char[iter.reusableChars.length * 2]; + System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length); + iter.reusableChars = newBuf; } + iter.reusableChars[j++] = (char) ((sup >>> 10) + 0xd800); + if (iter.reusableChars.length == j) { + char[] newBuf = new char[iter.reusableChars.length * 2]; + System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length); + iter.reusableChars = newBuf; + } + iter.reusableChars[j++] = (char) ((sup & 0x3ff) + 0xdc00); + continue; } } } - if (iter.reusableChars.length == j) { + } + if (iter.reusableChars.length == j) { + char[] newBuf = new char[iter.reusableChars.length * 2]; + System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length); + iter.reusableChars = newBuf; + } + iter.reusableChars[j++] = (char) bc; + } + } + + static long readLongSlowPath(final JsonIterator iter, long value) throws IOException { + value = -value; // add negatives to avoid redundant checks for Long.MIN_VALUE on each iteration + long multmin = -922337203685477580L; // limit / 10 + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + int ind = IterImplNumber.intDigits[iter.buf[i]]; + if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { + iter.head = i; + return value; + } + if (value < multmin) { + throw iter.reportError("readLongSlowPath", "value is too large for long"); + } + value = (value << 3) + (value << 1) - ind; + if (value >= 0) { + throw iter.reportError("readLongSlowPath", "value is too large for long"); + } + } + if (!IterImpl.loadMore(iter)) { + iter.head = iter.tail; + return value; + } + } + } + + static int readIntSlowPath(final JsonIterator iter, int value) throws IOException { + value = -value; // add negatives to avoid redundant checks for Integer.MIN_VALUE on each iteration + int multmin = -214748364; // limit / 10 + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + int ind = IterImplNumber.intDigits[iter.buf[i]]; + if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { + iter.head = i; + return value; + } + if (value < multmin) { + throw iter.reportError("readIntSlowPath", "value is too large for int"); + } + value = (value << 3) + (value << 1) - ind; + if (value >= 0) { + throw iter.reportError("readIntSlowPath", "value is too large for int"); + } + } + if (!IterImpl.loadMore(iter)) { + iter.head = iter.tail; + return value; + } + } + } + + public static final double readDoubleSlowPath(final JsonIterator iter) throws IOException { + try { + numberChars numberChars = readNumber(iter); + if (numberChars.charsLength == 0 && iter.whatIsNext() == ValueType.STRING) { + String possibleInf = iter.readString(); + if ("infinity".equals(possibleInf)) { + return Double.POSITIVE_INFINITY; + } + if ("-infinity".equals(possibleInf)) { + return Double.NEGATIVE_INFINITY; + } + throw iter.reportError("readDoubleSlowPath", "expect number but found string: " + possibleInf); + } + return Double.valueOf(new String(numberChars.chars, 0, numberChars.charsLength)); + } catch (NumberFormatException e) { + throw iter.reportError("readDoubleSlowPath", e.toString()); + } + } + + static class numberChars { + char[] chars; + int charsLength; + boolean dotFound; + } + + public static final numberChars readNumber(final JsonIterator iter) throws IOException { + int j = 0; + boolean dotFound = false; + for (; ; ) { + for (int i = iter.head; i < iter.tail; i++) { + if (j == iter.reusableChars.length) { char[] newBuf = new char[iter.reusableChars.length * 2]; System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length); iter.reusableChars = newBuf; } - iter.reusableChars[j++] = (char) bc; + byte c = iter.buf[i]; + switch (c) { + case '.': + case 'e': + case 'E': + dotFound = true; + // fallthrough + case '-': + case '+': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + iter.reusableChars[j++] = (char) c; + break; + default: + iter.head = i; + numberChars numberChars = new numberChars(); + numberChars.chars = iter.reusableChars; + numberChars.charsLength = j; + numberChars.dotFound = dotFound; + return numberChars; + } + } + if (!IterImpl.loadMore(iter)) { + iter.head = iter.tail; + numberChars numberChars = new numberChars(); + numberChars.chars = iter.reusableChars; + numberChars.charsLength = j; + numberChars.dotFound = dotFound; + return numberChars; } - throw iter.reportError("readStringSlowPath", "incomplete string"); - } catch (IndexOutOfBoundsException e) { - throw iter.reportError("readString", "incomplete string"); } } - public static int updateStringCopyBound(final JsonIterator iter, final int bound) { - return bound; + static final double readDouble(final JsonIterator iter) throws IOException { + return readDoubleSlowPath(iter); } - static final int readInt(final JsonIterator iter, final byte c) throws IOException { - int ind = IterImplNumber.intDigits[c]; + static final long readLong(final JsonIterator iter, final byte c) throws IOException { + long ind = IterImplNumber.intDigits[c]; if (ind == 0) { - IterImplForStreaming.assertNotLeadingZero(iter); + assertNotLeadingZero(iter); return 0; } if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - throw iter.reportError("readInt", "expect 0~9"); - } - if (iter.tail - iter.head > 9) { - int i = iter.head; - int ind2 = IterImplNumber.intDigits[iter.buf[i]]; - if (ind2 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - return -ind; - } - int ind3 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind3 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 10 + ind2; - return -ind; - } - int ind4 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind4 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 100 + ind2 * 10 + ind3; - return -ind; - } - int ind5 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind5 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 1000 + ind2 * 100 + ind3 * 10 + ind4; - return -ind; - } - int ind6 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind6 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 10000 + ind2 * 1000 + ind3 * 100 + ind4 * 10 + ind5; - return -ind; - } - int ind7 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind7 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 100000 + ind2 * 10000 + ind3 * 1000 + ind4 * 100 + ind5 * 10 + ind6; - return -ind; - } - int ind8 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind8 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 1000000 + ind2 * 100000 + ind3 * 10000 + ind4 * 1000 + ind5 * 100 + ind6 * 10 + ind7; - return -ind; - } - int ind9 = IterImplNumber.intDigits[iter.buf[++i]]; - ind = ind * 10000000 + ind2 * 1000000 + ind3 * 100000 + ind4 * 10000 + ind5 * 1000 + ind6 * 100 + ind7 * 10 + ind8; - iter.head = i; - if (ind9 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - return -ind; - } + throw iter.reportError("readLong", "expect 0~9"); } - return IterImplForStreaming.readIntSlowPath(iter, ind); + return IterImplForStreaming.readLongSlowPath(iter, ind); } - static final long readLong(final JsonIterator iter, final byte c) throws IOException { - long ind = IterImplNumber.intDigits[c]; - if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - throw iter.reportError("readLong", "expect 0~9"); + static final int readInt(final JsonIterator iter, final byte c) throws IOException { + int ind = IterImplNumber.intDigits[c]; + if (ind == 0) { + assertNotLeadingZero(iter); + return 0; } - if (iter.tail - iter.head > 9) { - int i = iter.head; - int ind2 = IterImplNumber.intDigits[iter.buf[i]]; - if (ind2 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - return -ind; - } - int ind3 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind3 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 10 + ind2; - return -ind; - } - int ind4 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind4 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 100 + ind2 * 10 + ind3; - return -ind; - } - int ind5 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind5 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 1000 + ind2 * 100 + ind3 * 10 + ind4; - return -ind; - } - int ind6 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind6 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 10000 + ind2 * 1000 + ind3 * 100 + ind4 * 10 + ind5; - return -ind; - } - int ind7 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind7 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 100000 + ind2 * 10000 + ind3 * 1000 + ind4 * 100 + ind5 * 10 + ind6; - return -ind; - } - int ind8 = IterImplNumber.intDigits[iter.buf[++i]]; - if (ind8 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - iter.head = i; - ind = ind * 1000000 + ind2 * 100000 + ind3 * 10000 + ind4 * 1000 + ind5 * 100 + ind6 * 10 + ind7; - return -ind; - } - int ind9 = IterImplNumber.intDigits[iter.buf[++i]]; - ind = ind * 10000000 + ind2 * 1000000 + ind3 * 100000 + ind4 * 10000 + ind5 * 1000 + ind6 * 100 + ind7 * 10 + ind8; - iter.head = i; - if (ind9 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { - return -ind; - } + if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { + throw iter.reportError("readInt", "expect 0~9"); } - return IterImplForStreaming.readLongSlowPath(iter, ind); + return IterImplForStreaming.readIntSlowPath(iter, ind); } - static final double readDouble(final JsonIterator iter) throws IOException { - int oldHead = iter.head; + static void assertNotLeadingZero(JsonIterator iter) throws IOException { try { - try { - long value = IterImplNumber.readLong(iter); // without the dot & sign - if (iter.head == iter.tail) { - return value; - } - byte c = iter.buf[iter.head]; - if (c == '.') { - iter.head++; - int start = iter.head; - c = iter.buf[iter.head++]; - long decimalPart = readLong(iter, c); - if (decimalPart == Long.MIN_VALUE) { - return IterImplForStreaming.readDoubleSlowPath(iter); - } - decimalPart = -decimalPart; - int decimalPlaces = iter.head - start; - if (decimalPlaces > 0 && decimalPlaces < IterImplNumber.POW10.length && (iter.head - oldHead) < 10) { - return value + (decimalPart / (double) IterImplNumber.POW10[decimalPlaces]); - } else { - iter.head = oldHead; - return IterImplForStreaming.readDoubleSlowPath(iter); - } - } else { - return value; - } - } finally { - if (iter.head < iter.tail && (iter.buf[iter.head] == 'e' || iter.buf[iter.head] == 'E')) { - iter.head = oldHead; - return IterImplForStreaming.readDoubleSlowPath(iter); - } + byte nextByte = IterImpl.readByte(iter); + iter.unreadByte(); + int ind2 = IterImplNumber.intDigits[nextByte]; + if (ind2 == IterImplNumber.INVALID_CHAR_FOR_NUMBER) { + return; } - } catch (JsonException e) { - iter.head = oldHead; - return IterImplForStreaming.readDoubleSlowPath(iter); + throw iter.reportError("assertNotLeadingZero", "leading zero is invalid"); + } catch (ArrayIndexOutOfBoundsException e) { + iter.head = iter.tail; + return; } } }