Modified ReaderImpl so it doesn't read lookahead bytes until they're

needed - this will make it possible to read to the end of a packet and
then pass on to the next packet without needing a PushbackInputStream.
This commit is contained in:
akwizgran
2011-08-03 17:12:37 +01:00
parent 7baefb3e7b
commit 7752690b29

View File

@@ -3,6 +3,7 @@ package net.sf.briar.serial;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -22,7 +23,7 @@ class ReaderImpl implements Reader {
private Consumer[] consumers = new Consumer[] {}; private Consumer[] consumers = new Consumer[] {};
private ObjectReader<?>[] objectReaders = new ObjectReader<?>[] {}; private ObjectReader<?>[] objectReaders = new ObjectReader<?>[] {};
private boolean started = false, eof = false; private boolean hasLookahead = false, eof = false;
private byte next, nextNext; private byte next, nextNext;
private byte[] buf = null; private byte[] buf = null;
@@ -31,26 +32,15 @@ class ReaderImpl implements Reader {
} }
public boolean eof() throws IOException { public boolean eof() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
return eof; return eof;
} }
private byte readNext(boolean eofAcceptable) throws IOException { private byte readLookahead(boolean eofAcceptable) throws IOException {
assert !eof; assert !eof;
if(started) { // If one or two lookahead bytes have been read, feed the consumers
for(Consumer c : consumers) { if(hasLookahead) consumeLookahead();
c.write(next); // Read a lookahead byte
if(next == Tag.USER) c.write(nextNext);
}
}
started = true;
readLookahead(eofAcceptable);
return next;
}
private void readLookahead(boolean eofAcceptable) throws IOException {
assert started;
// Read the lookahead byte
int i = in.read(); int i = in.read();
if(i == -1) { if(i == -1) {
if(!eofAcceptable) throw new FormatException(); if(!eofAcceptable) throw new FormatException();
@@ -63,6 +53,17 @@ class ReaderImpl implements Reader {
if(i == -1) throw new FormatException(); if(i == -1) throw new FormatException();
nextNext = (byte) i; nextNext = (byte) i;
} }
hasLookahead = true;
return next;
}
private void consumeLookahead() throws IOException {
assert hasLookahead;
for(Consumer c : consumers) {
c.write(next);
if(next == Tag.USER) c.write(nextNext);
}
hasLookahead = false;
} }
public void close() throws IOException { public void close() throws IOException {
@@ -109,68 +110,65 @@ class ReaderImpl implements Reader {
} }
public boolean hasBoolean() throws IOException { public boolean hasBoolean() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.FALSE || next == Tag.TRUE; return next == Tag.FALSE || next == Tag.TRUE;
} }
public boolean readBoolean() throws IOException { public boolean readBoolean() throws IOException {
if(!hasBoolean()) throw new FormatException(); if(!hasBoolean()) throw new FormatException();
int i = next; consumeLookahead();
readNext(true); return next == Tag.TRUE;
return i == Tag.TRUE;
} }
public boolean hasUint7() throws IOException { public boolean hasUint7() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next >= 0; return next >= 0;
} }
public byte readUint7() throws IOException { public byte readUint7() throws IOException {
if(!hasUint7()) throw new FormatException(); if(!hasUint7()) throw new FormatException();
byte b = next; consumeLookahead();
readNext(true); return next;
return b;
} }
public boolean hasInt8() throws IOException { public boolean hasInt8() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.INT8; return next == Tag.INT8;
} }
public byte readInt8() throws IOException { public byte readInt8() throws IOException {
if(!hasInt8()) throw new FormatException(); if(!hasInt8()) throw new FormatException();
byte b = readNext(false); readLookahead(false);
readNext(true); consumeLookahead();
return b; return next;
} }
public boolean hasInt16() throws IOException { public boolean hasInt16() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.INT16; return next == Tag.INT16;
} }
public short readInt16() throws IOException { public short readInt16() throws IOException {
if(!hasInt16()) throw new FormatException(); if(!hasInt16()) throw new FormatException();
byte b1 = readNext(false); byte b1 = readLookahead(false);
byte b2 = readNext(false); byte b2 = readLookahead(false);
readNext(true); consumeLookahead();
int i = ((b1 & 0xFF) << 8) | (b2 & 0xFF); return (short) (((b1 & 0xFF) << 8) | (b2 & 0xFF));
return (short) i;
} }
public boolean hasInt32() throws IOException { public boolean hasInt32() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.INT32; return next == Tag.INT32;
} }
public int readInt32() throws IOException { public int readInt32() throws IOException {
if(!hasInt32()) throw new FormatException(); if(!hasInt32()) throw new FormatException();
readNext(false); consumeLookahead();
return readInt32Bits(); return readInt32Bits();
} }
@@ -186,12 +184,8 @@ class ReaderImpl implements Reader {
} }
private void readIntoBuffer(byte[] b, int length) throws IOException { private void readIntoBuffer(byte[] b, int length) throws IOException {
b[0] = next; assert !hasLookahead;
int offset = 1; int offset = 0;
if(next == Tag.USER) {
b[1] = nextNext;
offset = 2;
}
while(offset < length) { while(offset < length) {
int read = in.read(b, offset, length - offset); int read = in.read(b, offset, length - offset);
if(read == -1) { if(read == -1) {
@@ -203,18 +197,17 @@ class ReaderImpl implements Reader {
if(offset < length) throw new FormatException(); if(offset < length) throw new FormatException();
// Feed the hungry mouths // Feed the hungry mouths
for(Consumer c : consumers) c.write(b, 0, length); for(Consumer c : consumers) c.write(b, 0, length);
readLookahead(true);
} }
public boolean hasInt64() throws IOException { public boolean hasInt64() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.INT64; return next == Tag.INT64;
} }
public long readInt64() throws IOException { public long readInt64() throws IOException {
if(!hasInt64()) throw new FormatException(); if(!hasInt64()) throw new FormatException();
readNext(false); consumeLookahead();
return readInt64Bits(); return readInt64Bits();
} }
@@ -227,7 +220,7 @@ class ReaderImpl implements Reader {
} }
public boolean hasIntAny() throws IOException { public boolean hasIntAny() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next >= 0 || next == Tag.INT8 || next == Tag.INT16 return next >= 0 || next == Tag.INT8 || next == Tag.INT16
|| next == Tag.INT32 || next == Tag.INT64; || next == Tag.INT32 || next == Tag.INT64;
@@ -244,31 +237,31 @@ class ReaderImpl implements Reader {
} }
public boolean hasFloat32() throws IOException { public boolean hasFloat32() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.FLOAT32; return next == Tag.FLOAT32;
} }
public float readFloat32() throws IOException { public float readFloat32() throws IOException {
if(!hasFloat32()) throw new FormatException(); if(!hasFloat32()) throw new FormatException();
readNext(false); consumeLookahead();
return Float.intBitsToFloat(readInt32Bits()); return Float.intBitsToFloat(readInt32Bits());
} }
public boolean hasFloat64() throws IOException { public boolean hasFloat64() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.FLOAT64; return next == Tag.FLOAT64;
} }
public double readFloat64() throws IOException { public double readFloat64() throws IOException {
if(!hasFloat64()) throw new FormatException(); if(!hasFloat64()) throw new FormatException();
readNext(false); consumeLookahead();
return Double.longBitsToDouble(readInt64Bits()); return Double.longBitsToDouble(readInt64Bits());
} }
public boolean hasString() throws IOException { public boolean hasString() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.STRING return next == Tag.STRING
|| (next & Tag.SHORT_MASK) == Tag.SHORT_STRING; || (next & Tag.SHORT_MASK) == Tag.SHORT_STRING;
@@ -276,12 +269,11 @@ class ReaderImpl implements Reader {
public String readString() throws IOException { public String readString() throws IOException {
if(!hasString()) throw new FormatException(); if(!hasString()) throw new FormatException();
consumeLookahead();
if(next == Tag.STRING) { if(next == Tag.STRING) {
readNext(false);
return readString(readLength()); return readString(readLength());
} else { } else {
int length = 0xFF & next ^ Tag.SHORT_STRING; int length = 0xFF & next ^ Tag.SHORT_STRING;
readNext(length == 0);
return readString(length); return readString(length);
} }
} }
@@ -303,26 +295,25 @@ class ReaderImpl implements Reader {
} }
private boolean hasLength() throws IOException { private boolean hasLength() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next >= 0 || next == Tag.INT8 || next == Tag.INT16 return next >= 0 || next == Tag.INT8 || next == Tag.INT16
|| next == Tag.INT32; || next == Tag.INT32;
} }
public boolean hasBytes() throws IOException { public boolean hasBytes() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.BYTES || (next & Tag.SHORT_MASK) == Tag.SHORT_BYTES; return next == Tag.BYTES || (next & Tag.SHORT_MASK) == Tag.SHORT_BYTES;
} }
public byte[] readBytes() throws IOException { public byte[] readBytes() throws IOException {
if(!hasBytes()) throw new FormatException(); if(!hasBytes()) throw new FormatException();
consumeLookahead();
if(next == Tag.BYTES) { if(next == Tag.BYTES) {
readNext(false);
return readBytes(readLength()); return readBytes(readLength());
} else { } else {
int length = 0xFF & next ^ Tag.SHORT_BYTES; int length = 0xFF & next ^ Tag.SHORT_BYTES;
readNext(length == 0);
return readBytes(length); return readBytes(length);
} }
} }
@@ -336,7 +327,7 @@ class ReaderImpl implements Reader {
} }
public boolean hasList() throws IOException { public boolean hasList() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.LIST || next == Tag.LIST_START return next == Tag.LIST || next == Tag.LIST_START
|| (next & Tag.SHORT_MASK) == Tag.SHORT_LIST; || (next & Tag.SHORT_MASK) == Tag.SHORT_LIST;
@@ -348,43 +339,41 @@ class ReaderImpl implements Reader {
public <E> List<E> readList(Class<E> e) throws IOException { public <E> List<E> readList(Class<E> e) throws IOException {
if(!hasList()) throw new FormatException(); if(!hasList()) throw new FormatException();
consumeLookahead();
if(next == Tag.LIST) { if(next == Tag.LIST) {
readNext(false);
return readList(e, readLength()); return readList(e, readLength());
} else if(next == Tag.LIST_START) { } else if(next == Tag.LIST_START) {
readNext(false);
List<E> list = new ArrayList<E>(); List<E> list = new ArrayList<E>();
while(!hasEnd()) list.add(readObject(e)); while(!hasEnd()) list.add(readObject(e));
readEnd(); readEnd();
return list; return list;
} else { } else {
int length = 0xFF & next ^ Tag.SHORT_LIST; int length = 0xFF & next ^ Tag.SHORT_LIST;
readNext(length == 0);
return readList(e, length); return readList(e, length);
} }
} }
private <E> List<E> readList(Class<E> e, int length) throws IOException { private <E> List<E> readList(Class<E> e, int length) throws IOException {
assert length >= 0; assert length >= 0;
if(length == 0) return Collections.emptyList();
List<E> list = new ArrayList<E>(); List<E> list = new ArrayList<E>();
for(int i = 0; i < length; i++) list.add(readObject(e)); for(int i = 0; i < length; i++) list.add(readObject(e));
return list; return list;
} }
private boolean hasEnd() throws IOException { private boolean hasEnd() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.END; return next == Tag.END;
} }
private void readEnd() throws IOException { private void readEnd() throws IOException {
if(!started) throw new IllegalStateException(); if(!hasLookahead) throw new IllegalStateException();
if(!hasEnd()) throw new FormatException(); if(!hasEnd()) throw new FormatException();
readNext(true); consumeLookahead();
} }
private Object readObject() throws IOException { private Object readObject() throws IOException {
if(!started) throw new IllegalStateException();
if(hasUserDefined()) return readUserDefined(); if(hasUserDefined()) return readUserDefined();
if(hasBoolean()) return Boolean.valueOf(readBoolean()); if(hasBoolean()) return Boolean.valueOf(readBoolean());
if(hasUint7()) return Byte.valueOf(readUint7()); if(hasUint7()) return Byte.valueOf(readUint7());
@@ -406,11 +395,10 @@ class ReaderImpl implements Reader {
} }
private boolean hasUserDefined() throws IOException { private boolean hasUserDefined() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
if(next == Tag.USER) return true; return next == Tag.USER
if((next & Tag.SHORT_USER_MASK) == Tag.SHORT_USER) return true; || (next & Tag.SHORT_USER_MASK) == Tag.SHORT_USER;
return false;
} }
private Object readUserDefined() throws IOException { private Object readUserDefined() throws IOException {
@@ -430,14 +418,14 @@ class ReaderImpl implements Reader {
} }
public boolean hasListStart() throws IOException { public boolean hasListStart() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.LIST_START; return next == Tag.LIST_START;
} }
public void readListStart() throws IOException { public void readListStart() throws IOException {
if(!hasListStart()) throw new FormatException(); if(!hasListStart()) throw new FormatException();
readNext(false); consumeLookahead();
} }
public boolean hasListEnd() throws IOException { public boolean hasListEnd() throws IOException {
@@ -449,7 +437,7 @@ class ReaderImpl implements Reader {
} }
public boolean hasMap() throws IOException { public boolean hasMap() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.MAP || next == Tag.MAP_START return next == Tag.MAP || next == Tag.MAP_START
|| (next & Tag.SHORT_MASK) == Tag.SHORT_MAP; || (next & Tag.SHORT_MASK) == Tag.SHORT_MAP;
@@ -461,18 +449,16 @@ class ReaderImpl implements Reader {
public <K, V> Map<K, V> readMap(Class<K> k, Class<V> v) throws IOException { public <K, V> Map<K, V> readMap(Class<K> k, Class<V> v) throws IOException {
if(!hasMap()) throw new FormatException(); if(!hasMap()) throw new FormatException();
consumeLookahead();
if(next == Tag.MAP) { if(next == Tag.MAP) {
readNext(false);
return readMap(k, v, readLength()); return readMap(k, v, readLength());
} else if(next == Tag.MAP_START) { } else if(next == Tag.MAP_START) {
readNext(false);
Map<K, V> m = new HashMap<K, V>(); Map<K, V> m = new HashMap<K, V>();
while(!hasEnd()) m.put(readObject(k), readObject(v)); while(!hasEnd()) m.put(readObject(k), readObject(v));
readEnd(); readEnd();
return m; return m;
} else { } else {
int size = 0xFF & next ^ Tag.SHORT_MAP; int size = 0xFF & next ^ Tag.SHORT_MAP;
readNext(size == 0);
return readMap(k, v, size); return readMap(k, v, size);
} }
} }
@@ -480,20 +466,21 @@ class ReaderImpl implements Reader {
private <K, V> Map<K, V> readMap(Class<K> k, Class<V> v, int size) private <K, V> Map<K, V> readMap(Class<K> k, Class<V> v, int size)
throws IOException { throws IOException {
assert size >= 0; assert size >= 0;
if(size == 0) return Collections.emptyMap();
Map<K, V> m = new HashMap<K, V>(); Map<K, V> m = new HashMap<K, V>();
for(int i = 0; i < size; i++) m.put(readObject(k), readObject(v)); for(int i = 0; i < size; i++) m.put(readObject(k), readObject(v));
return m; return m;
} }
public boolean hasMapStart() throws IOException { public boolean hasMapStart() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.MAP_START; return next == Tag.MAP_START;
} }
public void readMapStart() throws IOException { public void readMapStart() throws IOException {
if(!hasMapStart()) throw new FormatException(); if(!hasMapStart()) throw new FormatException();
readNext(false); consumeLookahead();
} }
public boolean hasMapEnd() throws IOException { public boolean hasMapEnd() throws IOException {
@@ -505,19 +492,19 @@ class ReaderImpl implements Reader {
} }
public boolean hasNull() throws IOException { public boolean hasNull() throws IOException {
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
return next == Tag.NULL; return next == Tag.NULL;
} }
public void readNull() throws IOException { public void readNull() throws IOException {
if(!hasNull()) throw new FormatException(); if(!hasNull()) throw new FormatException();
readNext(true); consumeLookahead();
} }
public boolean hasUserDefined(int tag) throws IOException { public boolean hasUserDefined(int tag) throws IOException {
if(tag < 0 || tag > 255) throw new IllegalArgumentException(); if(tag < 0 || tag > 255) throw new IllegalArgumentException();
if(!started) readNext(true); if(!hasLookahead) readLookahead(true);
if(eof) return false; if(eof) return false;
if(next == Tag.USER) if(next == Tag.USER)
return tag == (0xFF & nextNext); return tag == (0xFF & nextNext);
@@ -540,6 +527,6 @@ class ReaderImpl implements Reader {
public void readUserDefinedTag(int tag) throws IOException { public void readUserDefinedTag(int tag) throws IOException {
if(!hasUserDefined(tag)) throw new FormatException(); if(!hasUserDefined(tag)) throw new FormatException();
readNext(false); consumeLookahead();
} }
} }