Merge pull request #147 from square/jwilson_0406_small_optimizations

Small optimizations to JSON parsing.
This commit is contained in:
Jake Wharton
2016-04-06 00:54:57 -04:00
2 changed files with 25 additions and 29 deletions

View File

@@ -304,7 +304,7 @@ final class BufferedSourceJsonReader extends JsonReader {
break; break;
case '=': case '=':
checkLenient(); checkLenient();
if (fillBuffer(1) && buffer.getByte(0) == '>') { if (source.request(1) && buffer.getByte(0) == '>') {
buffer.readByte(); // Consume '>'. buffer.readByte(); // Consume '>'.
} }
break; break;
@@ -400,7 +400,7 @@ final class BufferedSourceJsonReader extends JsonReader {
// Confirm that chars [1..length) match the keyword. // Confirm that chars [1..length) match the keyword.
int length = keyword.length(); int length = keyword.length();
for (int i = 1; i < length; i++) { for (int i = 1; i < length; i++) {
if (!fillBuffer(i + 1)) { if (!source.request(i + 1)) {
return PEEKED_NONE; return PEEKED_NONE;
} }
c = buffer.getByte(i); c = buffer.getByte(i);
@@ -409,7 +409,7 @@ final class BufferedSourceJsonReader extends JsonReader {
} }
} }
if (fillBuffer(length + 1) && isLiteral(buffer.getByte(length))) { if (source.request(length + 1) && isLiteral(buffer.getByte(length))) {
return PEEKED_NONE; // Don't match trues, falsey or nullsoft! return PEEKED_NONE; // Don't match trues, falsey or nullsoft!
} }
@@ -428,7 +428,7 @@ final class BufferedSourceJsonReader extends JsonReader {
charactersOfNumber: charactersOfNumber:
for (; true; i++) { for (; true; i++) {
if (!fillBuffer(i + 1)) { if (!source.request(i + 1)) {
break; break;
} }
@@ -880,15 +880,6 @@ final class BufferedSourceJsonReader extends JsonReader {
stack[stackSize++] = newTop; stack[stackSize++] = newTop;
} }
/**
* Returns true once {@code limit - pos >= minimum}. If the data is
* exhausted before that many characters are available, this returns
* false.
*/
private boolean fillBuffer(int minimum) throws IOException {
return source.request(minimum);
}
/** /**
* Returns the next character in the stream that is neither whitespace nor a * Returns the next character in the stream that is neither whitespace nor a
* part of a comment. When this returns, the returned character is always at * part of a comment. When this returns, the returned character is always at
@@ -905,7 +896,7 @@ final class BufferedSourceJsonReader extends JsonReader {
* 'p' and 'l' after any (potentially indirect) call to the same method. * 'p' and 'l' after any (potentially indirect) call to the same method.
*/ */
int p = 0; int p = 0;
while (fillBuffer(p + 1)) { while (source.request(p + 1)) {
int c = buffer.getByte(p++); int c = buffer.getByte(p++);
if (c == '\n' || c == ' ' || c == '\r' || c == '\t') { if (c == '\n' || c == ' ' || c == '\r' || c == '\t') {
continue; continue;
@@ -913,7 +904,7 @@ final class BufferedSourceJsonReader extends JsonReader {
buffer.skip(p - 1); buffer.skip(p - 1);
if (c == '/') { if (c == '/') {
if (!fillBuffer(2)) { if (!source.request(2)) {
return c; return c;
} }
@@ -981,7 +972,7 @@ final class BufferedSourceJsonReader extends JsonReader {
*/ */
private boolean skipTo(String toFind) throws IOException { private boolean skipTo(String toFind) throws IOException {
outer: outer:
for (; fillBuffer(toFind.length());) { for (; source.request(toFind.length());) {
for (int c = 0; c < toFind.length(); c++) { for (int c = 0; c < toFind.length(); c++) {
if (buffer.getByte(c) != toFind.charAt(c)) { if (buffer.getByte(c) != toFind.charAt(c)) {
buffer.readByte(); buffer.readByte();
@@ -1009,14 +1000,14 @@ final class BufferedSourceJsonReader extends JsonReader {
* @throws IOException if any unicode escape sequences are malformed. * @throws IOException if any unicode escape sequences are malformed.
*/ */
private char readEscapeCharacter() throws IOException { private char readEscapeCharacter() throws IOException {
if (!fillBuffer(1)) { if (!source.request(1)) {
throw syntaxError("Unterminated escape sequence"); throw syntaxError("Unterminated escape sequence");
} }
byte escaped = buffer.readByte(); byte escaped = buffer.readByte();
switch (escaped) { switch (escaped) {
case 'u': case 'u':
if (!fillBuffer(4)) { if (!source.request(4)) {
throw new EOFException("Unterminated escape sequence at path " + getPath()); throw new EOFException("Unterminated escape sequence at path " + getPath());
} }
// Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16); // Equivalent to Integer.parseInt(stringPool.get(buffer, pos, 4), 16);

View File

@@ -21,6 +21,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
@@ -81,11 +82,11 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
// Create the binding between field and JSON. // Create the binding between field and JSON.
field.setAccessible(true); field.setAccessible(true);
FieldBinding<Object> fieldBinding = new FieldBinding<>(field, adapter);
// Store it using the field's name. If there was already a field with this name, fail! // Store it using the field's name. If there was already a field with this name, fail!
Json jsonAnnotation = field.getAnnotation(Json.class); Json jsonAnnotation = field.getAnnotation(Json.class);
String name = jsonAnnotation != null ? jsonAnnotation.name() : field.getName(); String name = jsonAnnotation != null ? jsonAnnotation.name() : field.getName();
FieldBinding<Object> fieldBinding = new FieldBinding<>(name, field, adapter);
FieldBinding<?> replaced = fieldBindings.put(name, fieldBinding); FieldBinding<?> replaced = fieldBindings.put(name, fieldBinding);
if (replaced != null) { if (replaced != null) {
throw new IllegalArgumentException("Conflicting fields:\n" throw new IllegalArgumentException("Conflicting fields:\n"
@@ -113,11 +114,13 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
}; };
private final ClassFactory<T> classFactory; private final ClassFactory<T> classFactory;
private final Map<String, FieldBinding<?>> jsonFields; private final Map<String, FieldBinding<?>> fieldsMap;
private final FieldBinding<?>[] fieldsArray;
ClassJsonAdapter(ClassFactory<T> classFactory, Map<String, FieldBinding<?>> jsonFields) { ClassJsonAdapter(ClassFactory<T> classFactory, Map<String, FieldBinding<?>> fieldsMap) {
this.classFactory = classFactory; this.classFactory = classFactory;
this.jsonFields = jsonFields; this.fieldsMap = new LinkedHashMap<>(fieldsMap);
this.fieldsArray = fieldsMap.values().toArray(new FieldBinding[fieldsMap.size()]);
} }
@Override public T fromJson(JsonReader reader) throws IOException { @Override public T fromJson(JsonReader reader) throws IOException {
@@ -139,7 +142,7 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
reader.beginObject(); reader.beginObject();
while (reader.hasNext()) { while (reader.hasNext()) {
String name = reader.nextName(); String name = reader.nextName();
FieldBinding<?> fieldBinding = jsonFields.get(name); FieldBinding<?> fieldBinding = fieldsMap.get(name);
if (fieldBinding != null) { if (fieldBinding != null) {
fieldBinding.read(reader, result); fieldBinding.read(reader, result);
} else { } else {
@@ -156,9 +159,9 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
@Override public void toJson(JsonWriter writer, T value) throws IOException { @Override public void toJson(JsonWriter writer, T value) throws IOException {
try { try {
writer.beginObject(); writer.beginObject();
for (Map.Entry<String, FieldBinding<?>> entry : jsonFields.entrySet()) { for (FieldBinding<?> fieldBinding : fieldsArray) {
writer.name(entry.getKey()); writer.name(fieldBinding.name);
entry.getValue().write(writer, value); fieldBinding.write(writer, value);
} }
writer.endObject(); writer.endObject();
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
@@ -171,10 +174,12 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
} }
static class FieldBinding<T> { static class FieldBinding<T> {
private final Field field; final String name;
private final JsonAdapter<T> adapter; final Field field;
final JsonAdapter<T> adapter;
public FieldBinding(Field field, JsonAdapter<T> adapter) { public FieldBinding(String name, Field field, JsonAdapter<T> adapter) {
this.name = name;
this.field = field; this.field = field;
this.adapter = adapter; this.adapter = adapter;
} }