Inline the nesting stack to save ~20% on JsonReader parsing.

This commit is contained in:
Jesse Wilson 2011-12-13 04:08:48 +00:00
parent 61a549b74d
commit 8e8bf934f9

View File

@ -22,8 +22,6 @@ import java.io.Closeable;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/** /**
* Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
@ -221,7 +219,11 @@ public class JsonReader implements Closeable {
private int bufferStartLine = 1; private int bufferStartLine = 1;
private int bufferStartColumn = 1; private int bufferStartColumn = 1;
private final List<JsonScope> stack = new ArrayList<JsonScope>(); /*
* The nesting stack. Using a manual array rather than an ArrayList saves 20%.
*/
private JsonScope[] stack = new JsonScope[32];
private int stackSize = 0;
{ {
push(JsonScope.EMPTY_DOCUMENT); push(JsonScope.EMPTY_DOCUMENT);
} }
@ -355,12 +357,12 @@ public class JsonReader implements Closeable {
return token; return token;
} }
switch (peekStack()) { switch (stack[stackSize - 1]) {
case EMPTY_DOCUMENT: case EMPTY_DOCUMENT:
if (lenient) { if (lenient) {
consumeNonExecutePrefix(); consumeNonExecutePrefix();
} }
replaceTop(JsonScope.NONEMPTY_DOCUMENT); stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT;
JsonToken firstToken = nextValue(); JsonToken firstToken = nextValue();
if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) { if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) {
throw new IOException( throw new IOException(
@ -603,8 +605,8 @@ public class JsonReader implements Closeable {
public void close() throws IOException { public void close() throws IOException {
value = null; value = null;
token = null; token = null;
stack.clear(); stack[0] = JsonScope.CLOSED;
stack.add(JsonScope.CLOSED); stackSize = 1;
in.close(); in.close();
} }
@ -630,34 +632,24 @@ public class JsonReader implements Closeable {
} }
} }
private JsonScope peekStack() {
return stack.get(stack.size() - 1);
}
private JsonScope pop() {
return stack.remove(stack.size() - 1);
}
private void push(JsonScope newTop) { private void push(JsonScope newTop) {
stack.add(newTop); if (stackSize == stack.length) {
} JsonScope[] newStack = new JsonScope[stackSize * 2];
System.arraycopy(stack, 0, newStack, 0, stackSize);
/** stack = newStack;
* Replace the value on the top of the stack with the given value. }
*/ stack[stackSize++] = newTop;
private void replaceTop(JsonScope newTop) {
stack.set(stack.size() - 1, newTop);
} }
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
private JsonToken nextInArray(boolean firstElement) throws IOException { private JsonToken nextInArray(boolean firstElement) throws IOException {
if (firstElement) { if (firstElement) {
replaceTop(JsonScope.NONEMPTY_ARRAY); stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY;
} else { } else {
/* Look for a comma before each element after the first element. */ /* Look for a comma before each element after the first element. */
switch (nextNonWhitespace(true)) { switch (nextNonWhitespace(true)) {
case ']': case ']':
pop(); stackSize--;
return token = JsonToken.END_ARRAY; return token = JsonToken.END_ARRAY;
case ';': case ';':
checkLenient(); // fall-through checkLenient(); // fall-through
@ -671,7 +663,7 @@ public class JsonReader implements Closeable {
switch (nextNonWhitespace(true)) { switch (nextNonWhitespace(true)) {
case ']': case ']':
if (firstElement) { if (firstElement) {
pop(); stackSize--;
return token = JsonToken.END_ARRAY; return token = JsonToken.END_ARRAY;
} }
// fall-through to handle ",]" // fall-through to handle ",]"
@ -699,7 +691,7 @@ public class JsonReader implements Closeable {
/* Peek to see if this is the empty object. */ /* Peek to see if this is the empty object. */
switch (nextNonWhitespace(true)) { switch (nextNonWhitespace(true)) {
case '}': case '}':
pop(); stackSize--;
return token = JsonToken.END_OBJECT; return token = JsonToken.END_OBJECT;
default: default:
pos--; pos--;
@ -707,7 +699,7 @@ public class JsonReader implements Closeable {
} else { } else {
switch (nextNonWhitespace(true)) { switch (nextNonWhitespace(true)) {
case '}': case '}':
pop(); stackSize--;
return token = JsonToken.END_OBJECT; return token = JsonToken.END_OBJECT;
case ';': case ';':
case ',': case ',':
@ -734,7 +726,7 @@ public class JsonReader implements Closeable {
} }
} }
replaceTop(JsonScope.DANGLING_NAME); stack[stackSize - 1] = JsonScope.DANGLING_NAME;
return token = JsonToken.NAME; return token = JsonToken.NAME;
} }
@ -756,7 +748,7 @@ public class JsonReader implements Closeable {
throw syntaxError("Expected ':'"); throw syntaxError("Expected ':'");
} }
replaceTop(JsonScope.NONEMPTY_OBJECT); stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT;
return nextValue(); return nextValue();
} }