From 8e8bf934f905783aa40889ae1bf6f3ff759624d3 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 13 Dec 2011 04:08:48 +0000 Subject: [PATCH] Inline the nesting stack to save ~20% on JsonReader parsing. --- .../com/google/gson/stream/JsonReader.java | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/gson/src/main/java/com/google/gson/stream/JsonReader.java b/gson/src/main/java/com/google/gson/stream/JsonReader.java index d15a71b4..19b21676 100644 --- a/gson/src/main/java/com/google/gson/stream/JsonReader.java +++ b/gson/src/main/java/com/google/gson/stream/JsonReader.java @@ -22,8 +22,6 @@ import java.io.Closeable; import java.io.EOFException; import java.io.IOException; import java.io.Reader; -import java.util.ArrayList; -import java.util.List; /** * Reads a JSON (RFC 4627) @@ -221,7 +219,11 @@ public class JsonReader implements Closeable { private int bufferStartLine = 1; private int bufferStartColumn = 1; - private final List stack = new ArrayList(); + /* + * 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); } @@ -355,12 +357,12 @@ public class JsonReader implements Closeable { return token; } - switch (peekStack()) { + switch (stack[stackSize - 1]) { case EMPTY_DOCUMENT: if (lenient) { consumeNonExecutePrefix(); } - replaceTop(JsonScope.NONEMPTY_DOCUMENT); + stack[stackSize - 1] = JsonScope.NONEMPTY_DOCUMENT; JsonToken firstToken = nextValue(); if (!lenient && token != JsonToken.BEGIN_ARRAY && token != JsonToken.BEGIN_OBJECT) { throw new IOException( @@ -603,8 +605,8 @@ public class JsonReader implements Closeable { public void close() throws IOException { value = null; token = null; - stack.clear(); - stack.add(JsonScope.CLOSED); + stack[0] = JsonScope.CLOSED; + stackSize = 1; 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) { - stack.add(newTop); - } - - /** - * Replace the value on the top of the stack with the given value. - */ - private void replaceTop(JsonScope newTop) { - stack.set(stack.size() - 1, newTop); + if (stackSize == stack.length) { + JsonScope[] newStack = new JsonScope[stackSize * 2]; + System.arraycopy(stack, 0, newStack, 0, stackSize); + stack = newStack; + } + stack[stackSize++] = newTop; } @SuppressWarnings("fallthrough") private JsonToken nextInArray(boolean firstElement) throws IOException { if (firstElement) { - replaceTop(JsonScope.NONEMPTY_ARRAY); + stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY; } else { /* Look for a comma before each element after the first element. */ switch (nextNonWhitespace(true)) { case ']': - pop(); + stackSize--; return token = JsonToken.END_ARRAY; case ';': checkLenient(); // fall-through @@ -671,7 +663,7 @@ public class JsonReader implements Closeable { switch (nextNonWhitespace(true)) { case ']': if (firstElement) { - pop(); + stackSize--; return token = JsonToken.END_ARRAY; } // fall-through to handle ",]" @@ -699,7 +691,7 @@ public class JsonReader implements Closeable { /* Peek to see if this is the empty object. */ switch (nextNonWhitespace(true)) { case '}': - pop(); + stackSize--; return token = JsonToken.END_OBJECT; default: pos--; @@ -707,7 +699,7 @@ public class JsonReader implements Closeable { } else { switch (nextNonWhitespace(true)) { case '}': - pop(); + stackSize--; return token = JsonToken.END_OBJECT; 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; } @@ -756,7 +748,7 @@ public class JsonReader implements Closeable { throw syntaxError("Expected ':'"); } - replaceTop(JsonScope.NONEMPTY_OBJECT); + stack[stackSize - 1] = JsonScope.NONEMPTY_OBJECT; return nextValue(); }