com.jsoniter.IterImplForStreaming Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsoniter Show documentation
Show all versions of jsoniter Show documentation
jsoniter (json-iterator) is fast and flexible JSON parser available in Java and Go
package com.jsoniter;
import com.jsoniter.any.Any;
import com.jsoniter.spi.Slice;
import java.io.IOException;
class IterImplForStreaming {
public static final int readObjectFieldAsHash(JsonIterator iter) throws IOException {
if (nextToken(iter) != '"') {
throw iter.reportError("readObjectFieldAsHash", "expect \"");
}
long hash = 0x811c9dc5;
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 == '"') {
iter.head = i + 1;
if (nextToken(iter) != ':') {
throw iter.reportError("readObjectFieldAsHash", "expect :");
}
return (int) hash;
}
if (!loadMore(iter)) {
throw iter.reportError("readObjectFieldAsHash", "unmatched quote");
}
}
}
public static final Slice readObjectFieldAsSlice(JsonIterator iter) throws IOException {
Slice field = readSlice(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 (; ; ) {
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) {
iter.head = i + 1;
return;
}
break;
}
}
if (!loadMore(iter)) {
return;
}
}
}
final static void skipObject(JsonIterator iter) throws IOException {
int level = 1;
for (; ; ) {
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) {
iter.head = i + 1;
return;
}
break;
}
}
if (!loadMore(iter)) {
return;
}
}
}
final static void skipString(JsonIterator iter) throws IOException {
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 (; ; ) {
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;
}
}
}
final static boolean skipNumber(JsonIterator iter) throws IOException {
// true, false, null, number
boolean dotFound = false;
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
byte c = iter.buf[i];
if (c == '.') {
dotFound = true;
continue;
}
if (IterImplSkip.breaks[c]) {
iter.head = i;
return dotFound;
}
}
if (!loadMore(iter)) {
iter.head = iter.tail;
return dotFound;
}
}
}
// read the bytes between " "
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) {
// 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(JsonIterator iter) throws IOException {
for (; ; ) {
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 {
// TODO: avoid small memory allocation
iter.skipStartedAt = iter.head;
byte c = nextToken(iter);
switch (c) {
case '"':
skipString(iter);
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);
copied = copySkippedBytes(iter);
return Any.lazyArray(copied, 0, copied.length);
case '{':
skipObject(iter);
copied = copySkippedBytes(iter);
return Any.lazyObject(copied, 0, copied.length);
default:
if (skipNumber(iter)) {
copied = copySkippedBytes(iter);
return Any.lazyDouble(copied, 0, copied.length);
} else {
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 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 {
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));
break;
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 u4 = readByte(iter);
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");
// 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) {
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(JsonIterator iter, long value) throws IOException {
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;
}
value = (value << 3) + (value << 1) + ind;
if (value < 0) {
// overflow
if (value == Long.MIN_VALUE) {
// if there is more number following, subsequent read will fail anyway
iter.head = i;
return value;
} else {
throw iter.reportError("readPositiveLong", "value is too large for long");
}
}
}
if (!IterImpl.loadMore(iter)) {
iter.head = iter.tail;
return value;
}
}
}
static int readIntSlowPath(JsonIterator iter, int value) throws IOException {
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;
}
value = (value << 3) + (value << 1) + ind;
if (value < 0) {
// overflow
if (value == Integer.MIN_VALUE) {
// if there is more number following, subsequent read will fail anyway
iter.head = i;
return value;
} else {
throw iter.reportError("readPositiveInt", "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 {
return Double.valueOf(readNumber(iter));
} catch (NumberFormatException e) {
throw iter.reportError("readDoubleSlowPath", e.toString());
}
}
public static final String readNumber(final JsonIterator iter) throws IOException {
int j = 0;
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;
}
byte c = iter.buf[i];
switch (c) {
case '-':
case '.':
case 'e':
case 'E':
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;
return new String(iter.reusableChars, 0, j);
}
}
if (!IterImpl.loadMore(iter)) {
iter.head = iter.tail;
return new String(iter.reusableChars, 0, j);
}
}
}
static final double readPositiveDouble(final JsonIterator iter) throws IOException {
return readDoubleSlowPath(iter);
}
static final long readPositiveLong(final JsonIterator iter, byte c) throws IOException {
long ind = IterImplNumber.intDigits[c];
if (ind == 0) {
return 0;
}
if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) {
throw iter.reportError("readPositiveLong", "expect 0~9");
}
return IterImplForStreaming.readLongSlowPath(iter, ind);
}
static final int readPositiveInt(final JsonIterator iter, byte c) throws IOException {
int ind = IterImplNumber.intDigits[c];
if (ind == 0) {
return 0;
}
if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) {
throw iter.reportError("readPositiveInt", "expect 0~9");
}
return IterImplForStreaming.readIntSlowPath(iter, ind);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy