[Java][FlexBuffers] Abstract buffer access from ByteBuffer (#5743)

To read and build flexbuffers on Java, one needs to wrap the data
using  ByteBuffer. But for the common case of having ByteBuffers
backed by arrays, accessing from a ByteBuffer might be inefficient.

So this change introduces two interfaces: ReadBuf and ReadWriteBuf.
It allows one to read and writes data directly on an array. It also allow
 other buffer implementations to be used with flexbuffers.

Another change is that FlexBuffersBuilder backed by array allows
the buffer to grow with the increase of the message size. Something
that could not be done with ByteBuffer.
This commit is contained in:
Paulo Pinheiro
2020-02-21 20:46:40 +01:00
committed by GitHub
parent 3ec7a53c62
commit cd88e6b2aa
8 changed files with 712 additions and 55 deletions

View File

@@ -0,0 +1,241 @@
package com.google.flatbuffers;
import java.util.Arrays;
/**
* Implements {@code ReadBuf} using an array of bytes
* as a backing storage. Using array of bytes are
* usually faster than {@code ByteBuffer}.
*
* This class is not thread-safe, meaning that
* it must operate on a single thread. Operating from
* multiple thread leads into a undefined behavior
*/
public class ArrayReadWriteBuf implements ReadWriteBuf {
private byte[] buffer;
private int writePos;
public ArrayReadWriteBuf() {
this(10);
}
public ArrayReadWriteBuf(int initialCapacity) {
this(new byte[initialCapacity]);
}
public ArrayReadWriteBuf(byte[] buffer) {
this.buffer = buffer;
this.writePos = 0;
}
public ArrayReadWriteBuf(byte[] buffer, int startPos) {
this.buffer = buffer;
this.writePos = startPos;
}
@Override
public boolean getBoolean(int index) {
return buffer[index] != 0;
}
@Override
public byte get(int index) {
return buffer[index];
}
@Override
public short getShort(int index) {
return (short) ((buffer[index+ 1] << 8) | (buffer[index] & 0xff));
}
@Override
public int getInt(int index) {
return (((buffer[index + 3]) << 24) |
((buffer[index + 2] & 0xff) << 16) |
((buffer[index + 1] & 0xff) << 8) |
((buffer[index] & 0xff)));
}
@Override
public long getLong(int index) {
return ((((long) buffer[index++] & 0xff)) |
(((long) buffer[index++] & 0xff) << 8) |
(((long) buffer[index++] & 0xff) << 16) |
(((long) buffer[index++] & 0xff) << 24) |
(((long) buffer[index++] & 0xff) << 32) |
(((long) buffer[index++] & 0xff) << 40) |
(((long) buffer[index++] & 0xff) << 48) |
(((long) buffer[index]) << 56));
}
@Override
public float getFloat(int index) {
return Float.intBitsToFloat(getInt(index));
}
@Override
public double getDouble(int index) {
return Double.longBitsToDouble(getLong(index));
}
@Override
public String getString(int start, int size) {
return Utf8Safe.decodeUtf8Array(buffer, start, size);
}
@Override
public byte[] data() {
return buffer;
}
@Override
public void putBoolean(boolean value) {
setBoolean(writePos, value);
writePos++;
}
@Override
public void put(byte[] value, int start, int length) {
set(writePos, value, start, length);
writePos+=length;
}
@Override
public void put(byte value) {
set(writePos, value);
writePos++;
}
@Override
public void putShort(short value) {
setShort(writePos, value);
writePos +=2;
}
@Override
public void putInt(int value) {
setInt(writePos, value);
writePos +=4;
}
@Override
public void putLong(long value) {
setLong(writePos, value);
writePos +=8;
}
@Override
public void putFloat(float value) {
setFloat(writePos, value);
writePos +=4;
}
@Override
public void putDouble(double value) {
setDouble(writePos, value);
writePos +=8;
}
@Override
public void setBoolean(int index, boolean value) {
set(index, value ? (byte)1 : (byte)0);
}
@Override
public void set(int index, byte value) {
requestCapacity(index + 1);
buffer[index] = value;
}
@Override
public void set(int index, byte[] toCopy, int start, int length) {
requestCapacity(index + (length - start));
System.arraycopy(toCopy, start, buffer, index, length);
}
@Override
public void setShort(int index, short value) {
requestCapacity(index + 2);
buffer[index++] = (byte) ((value) & 0xff);
buffer[index ] = (byte) ((value >> 8) & 0xff);
}
@Override
public void setInt(int index, int value) {
requestCapacity(index + 4);
buffer[index++] = (byte) ((value) & 0xff);
buffer[index++] = (byte) ((value >> 8) & 0xff);
buffer[index++] = (byte) ((value >> 16) & 0xff);
buffer[index ] = (byte) ((value >> 24) & 0xff);
}
@Override
public void setLong(int index, long value) {
requestCapacity(index + 8);
int i = (int) value;
buffer[index++] = (byte) ((i) & 0xff);
buffer[index++] = (byte) ((i >> 8) & 0xff);
buffer[index++] = (byte) ((i >> 16) & 0xff);
buffer[index++] = (byte) ((i >> 24) & 0xff);
i = (int) (value >> 32);
buffer[index++] = (byte) ((i) & 0xff);
buffer[index++] = (byte) ((i >> 8) & 0xff);
buffer[index++] = (byte) ((i >> 16) & 0xff);
buffer[index ] = (byte) ((i >> 24) & 0xff);
}
@Override
public void setFloat(int index, float value) {
requestCapacity(index + 4);
int iValue = Float.floatToRawIntBits(value);
buffer[index++] = (byte) ((iValue) & 0xff);
buffer[index++] = (byte) ((iValue >> 8) & 0xff);
buffer[index++] = (byte) ((iValue >> 16) & 0xff);
buffer[index ] = (byte) ((iValue >> 24) & 0xff);
}
@Override
public void setDouble(int index, double value) {
requestCapacity(index + 8);
long lValue = Double.doubleToRawLongBits(value);
int i = (int) lValue;
buffer[index++] = (byte) ((i) & 0xff);
buffer[index++] = (byte) ((i >> 8) & 0xff);
buffer[index++] = (byte) ((i >> 16) & 0xff);
buffer[index++] = (byte) ((i >> 24) & 0xff);
i = (int) (lValue >> 32);
buffer[index++] = (byte) ((i) & 0xff);
buffer[index++] = (byte) ((i >> 8) & 0xff);
buffer[index++] = (byte) ((i >> 16) & 0xff);
buffer[index ] = (byte) ((i >> 24) & 0xff);
}
@Override
public int limit() {
return writePos;
}
@Override
public int writePosition() {
return writePos;
}
@Override
public boolean requestCapacity(int capacity) {
if (buffer.length > capacity) {
return true;
}
// implemented in the same growing fashion as ArrayList
int oldCapacity = buffer.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
buffer = Arrays.copyOf(buffer, newCapacity);
return true;
}
}

View File

@@ -0,0 +1,165 @@
package com.google.flatbuffers;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ByteBufferReadWriteBuf implements ReadWriteBuf {
private final ByteBuffer buffer;
public ByteBufferReadWriteBuf(ByteBuffer bb) {
this.buffer = bb;
this.buffer.order(ByteOrder.LITTLE_ENDIAN);
}
@Override
public boolean getBoolean(int index) {
return get(index) != 0;
}
@Override
public byte get(int index) {
return buffer.get(index);
}
@Override
public short getShort(int index) {
return buffer.getShort(index);
}
@Override
public int getInt(int index) {
return buffer.getInt(index);
}
@Override
public long getLong(int index) {
return buffer.getLong(index);
}
@Override
public float getFloat(int index) {
return buffer.getFloat(index);
}
@Override
public double getDouble(int index) {
return buffer.getDouble(index);
}
@Override
public String getString(int start, int size) {
return Utf8Safe.decodeUtf8Buffer(buffer, start, size);
}
@Override
public byte[] data() {
return buffer.array();
}
@Override
public void putBoolean(boolean value) {
buffer.put(value ? (byte)1 : (byte)0);
}
@Override
public void put(byte[] value, int start, int length) {
buffer.put(value, start, length);
}
@Override
public void put(byte value) {
buffer.put(value);
}
@Override
public void putShort(short value) {
buffer.putShort(value);
}
@Override
public void putInt(int value) {
buffer.putInt(value);
}
@Override
public void putLong(long value) {
buffer.putLong(value);
}
@Override
public void putFloat(float value) {
buffer.putFloat(value);
}
@Override
public void putDouble(double value) {
buffer.putDouble(value);
}
@Override
public void setBoolean(int index, boolean value) {
set(index, value ? (byte)1 : (byte)0);
}
@Override
public void set(int index, byte value) {
requestCapacity(index + 1);
buffer.put(index, value);
}
@Override
public void set(int index, byte[] value, int start, int length) {
requestCapacity(index + (length - start));
int curPos = buffer.position();
buffer.position(index);
buffer.put(value, start, length);
buffer.position(curPos);
}
@Override
public void setShort(int index, short value) {
requestCapacity(index + 2);
buffer.putShort(index, value);
}
@Override
public void setInt(int index, int value) {
requestCapacity(index + 4);
buffer.putInt(index, value);
}
@Override
public void setLong(int index, long value) {
requestCapacity(index + 8);
buffer.putLong(index, value);
}
@Override
public void setFloat(int index, float value) {
requestCapacity(index + 4);
buffer.putFloat(index, value);
}
@Override
public void setDouble(int index, double value) {
requestCapacity(index + 8);
buffer.putDouble(index, value);
}
@Override
public int writePosition() {
return buffer.position();
}
@Override
public int limit() {
return buffer.limit();
}
@Override
public boolean requestCapacity(int capacity) {
return capacity <= buffer.limit();
}
}

View File

@@ -36,7 +36,7 @@ import java.nio.charset.StandardCharsets;
* <p>
* Example of usage:
* <pre>
* ByteBuffer bb = ... // load message from file or network
* ReadBuf bb = ... // load message from file or network
* FlexBuffers.Reference r = FlexBuffers.getRoot(bb); // Reads the root element
* FlexBuffers.Map map = r.asMap(); // We assumed root object is a map
* System.out.println(map.get("name").asString()); // prints element with key "name"
@@ -100,7 +100,7 @@ public class FlexBuffers {
/** Represent a vector of booleans type */
public static final int FBT_VECTOR_BOOL = 36; // To Allow the same type of conversion of type to vector type
private static final ByteBuffer EMPTY_BB = ByteBuffer.allocate(1).asReadOnlyBuffer();
private static final ReadBuf EMPTY_BB = new ArrayReadWriteBuf(new byte[] {0}, 1);
/**
* Checks where a type is a typed vector
@@ -151,13 +151,13 @@ public class FlexBuffers {
}
// return position of the element that the offset is pointing to
private static int indirect(ByteBuffer bb, int offset, int byteWidth) {
// we assume all offset fits on a int, since ByteBuffer operates with that assumption
private static int indirect(ReadBuf bb, int offset, int byteWidth) {
// we assume all offset fits on a int, since ReadBuf operates with that assumption
return (int) (offset - readUInt(bb, offset, byteWidth));
}
// read unsigned int with size byteWidth and return as a 64-bit integer
private static long readUInt(ByteBuffer buff, int end, int byteWidth) {
private static long readUInt(ReadBuf buff, int end, int byteWidth) {
switch (byteWidth) {
case 1: return byteToUnsignedInt(buff.get(end));
case 2: return shortToUnsignedInt(buff.getShort(end));
@@ -168,12 +168,12 @@ public class FlexBuffers {
}
// read signed int of size byteWidth and return as 32-bit int
private static int readInt(ByteBuffer buff, int end, int byteWidth) {
private static int readInt(ReadBuf buff, int end, int byteWidth) {
return (int) readLong(buff, end, byteWidth);
}
// read signed int of size byteWidth and return as 64-bit int
private static long readLong(ByteBuffer buff, int end, int byteWidth) {
private static long readLong(ReadBuf buff, int end, int byteWidth) {
switch (byteWidth) {
case 1: return buff.get(end);
case 2: return buff.getShort(end);
@@ -183,7 +183,7 @@ public class FlexBuffers {
}
}
private static double readDouble(ByteBuffer buff, int end, int byteWidth) {
private static double readDouble(ReadBuf buff, int end, int byteWidth) {
switch (byteWidth) {
case 4: return buff.getFloat(end);
case 8: return buff.getDouble(end);
@@ -192,12 +192,23 @@ public class FlexBuffers {
}
/**
* Reads a FlexBuffer message in ByteBuffer and returns {@link Reference} to
* Reads a FlexBuffer message in ReadBuf and returns {@link Reference} to
* the root element.
* @param buffer ByteBuffer containing FlexBuffer message
* @param buffer ReadBuf containing FlexBuffer message
* @return {@link Reference} to the root object
*/
@Deprecated
public static Reference getRoot(ByteBuffer buffer) {
return getRoot( buffer.hasArray() ? new ArrayReadWriteBuf(buffer.array(), buffer.limit()) : new ByteBufferReadWriteBuf(buffer));
}
/**
* Reads a FlexBuffer message in ReadBuf and returns {@link Reference} to
* the root element.
* @param buffer ReadBuf containing FlexBuffer message
* @return {@link Reference} to the root object
*/
public static Reference getRoot(ReadBuf buffer) {
// See Finish() below for the serialization counterpart of this.
// The root ends at the end of the buffer, so we parse backwards from there.
int end = buffer.limit();
@@ -213,17 +224,17 @@ public class FlexBuffers {
public static class Reference {
private static final Reference NULL_REFERENCE = new Reference(EMPTY_BB, 0, 1, 0);
private ByteBuffer bb;
private ReadBuf bb;
private int end;
private int parentWidth;
private int byteWidth;
private int type;
Reference(ByteBuffer bb, int end, int parentWidth, int packedType) {
Reference(ReadBuf bb, int end, int parentWidth, int packedType) {
this(bb, end, parentWidth, (1 << (packedType & 3)), packedType >> 2);
}
Reference(ByteBuffer bb, int end, int parentWidth, int byteWidth, int type) {
Reference(ReadBuf bb, int end, int parentWidth, int byteWidth, int type) {
this.bb = bb;
this.end = end;
this.parentWidth = parentWidth;
@@ -484,13 +495,13 @@ public class FlexBuffers {
if (isString()) {
int start = indirect(bb, end, parentWidth);
int size = (int) readUInt(bb, start - byteWidth, byteWidth);
return Utf8.getDefault().decodeUtf8(bb, start, size);
return bb.getString(start, size);
}
else if (isKey()){
int start = indirect(bb, end, byteWidth);
for (int i = start; ; i++) {
if (bb.get(i) == 0) {
return Utf8.getDefault().decodeUtf8(bb, start, i - start);
return bb.getString(start, i - start);
}
}
} else {
@@ -619,11 +630,11 @@ public class FlexBuffers {
* Points into the data buffer and allows access to one type.
*/
private static abstract class Object {
ByteBuffer bb;
ReadBuf bb;
int end;
int byteWidth;
Object(ByteBuffer buff, int end, int byteWidth) {
Object(ReadBuf buff, int end, int byteWidth) {
this.bb = buff;
this.end = end;
this.byteWidth = byteWidth;
@@ -640,9 +651,9 @@ public class FlexBuffers {
// Stores size in `byte_width_` bytes before end position.
private static abstract class Sized extends Object {
private final int size;
protected final int size;
Sized(ByteBuffer buff, int end, int byteWidth) {
Sized(ReadBuf buff, int end, int byteWidth) {
super(buff, end, byteWidth);
size = readInt(bb, end - byteWidth, byteWidth);
}
@@ -655,14 +666,14 @@ public class FlexBuffers {
/**
* Represents a array of bytes element in the buffer
*
* <p>It can be converted to `ByteBuffer` using {@link data()},
* <p>It can be converted to `ReadBuf` using {@link data()},
* copied into a byte[] using {@link getBytes()} or
* have individual bytes accessed individually using {@link get(int)}</p>
*/
public static class Blob extends Sized {
static final Blob EMPTY = new Blob(EMPTY_BB, 1, 1);
Blob(ByteBuffer buff, int end, int byteWidth) {
Blob(ReadBuf buff, int end, int byteWidth) {
super(buff, end, byteWidth);
}
@@ -672,11 +683,11 @@ public class FlexBuffers {
}
/**
* Return {@link Blob} as `ByteBuffer`
* @return blob as `ByteBuffer`
* Return {@link Blob} as `ReadBuf`
* @return blob as `ReadBuf`
*/
public ByteBuffer data() {
ByteBuffer dup = bb.duplicate();
ByteBuffer dup = ByteBuffer.wrap(bb.data());
dup.position(end);
dup.limit(end + size());
return dup.asReadOnlyBuffer().slice();
@@ -709,7 +720,7 @@ public class FlexBuffers {
*/
@Override
public String toString() {
return Utf8.getDefault().decodeUtf8(bb, end, size());
return bb.getString(end, size());
}
/**
@@ -718,7 +729,7 @@ public class FlexBuffers {
@Override
public StringBuilder toString(StringBuilder sb) {
sb.append('"');
sb.append(Utf8.getDefault().decodeUtf8(bb, end, size()));
sb.append(bb.getString(end, size()));
return sb.append('"');
}
}
@@ -731,7 +742,7 @@ public class FlexBuffers {
private static final Key EMPTY = new Key(EMPTY_BB, 0, 0);
Key(ByteBuffer buff, int end, int byteWidth) {
Key(ReadBuf buff, int end, int byteWidth) {
super(buff, end, byteWidth);
}
@@ -760,7 +771,7 @@ public class FlexBuffers {
break;
}
}
return Utf8.getDefault().decodeUtf8(bb, end, size);
return bb.getString(end, size);
}
int compareTo(byte[] other) {
@@ -808,7 +819,7 @@ public class FlexBuffers {
public static class Map extends Vector {
private static final Map EMPTY_MAP = new Map(EMPTY_BB, 1, 1);
Map(ByteBuffer bb, int end, int byteWidth) {
Map(ReadBuf bb, int end, int byteWidth) {
super(bb, end, byteWidth);
}
@@ -913,7 +924,7 @@ public class FlexBuffers {
private static final Vector EMPTY_VECTOR = new Vector(EMPTY_BB, 1, 1);
Vector(ByteBuffer bb, int end, int byteWidth) {
Vector(ReadBuf bb, int end, int byteWidth) {
super(bb, end, byteWidth);
}
@@ -976,7 +987,7 @@ public class FlexBuffers {
private final int elemType;
TypedVector(ByteBuffer bb, int end, int byteWidth, int elemType) {
TypedVector(ReadBuf bb, int end, int byteWidth, int elemType) {
super(bb, end, byteWidth);
this.elemType = elemType;
}

View File

@@ -83,7 +83,7 @@ public class FlexBuffersBuilder {
private static final int WIDTH_16 = 1;
private static final int WIDTH_32 = 2;
private static final int WIDTH_64 = 3;
private final ByteBuffer bb;
private final ReadWriteBuf bb;
private final ArrayList<Value> stack = new ArrayList<>();
private final HashMap<String, Integer> keyPool = new HashMap<>();
private final HashMap<String, Integer> stringPool = new HashMap<>();
@@ -116,7 +116,7 @@ public class FlexBuffersBuilder {
* @param bufSize size of buffer in bytes.
*/
public FlexBuffersBuilder(int bufSize) {
this(ByteBuffer.allocate(bufSize), BUILDER_FLAG_SHARE_KEYS);
this(new ArrayReadWriteBuf(bufSize), BUILDER_FLAG_SHARE_KEYS);
}
/**
@@ -132,11 +132,14 @@ public class FlexBuffersBuilder {
* @param bb `ByteBuffer` that will hold the message
* @param flags Share flags
*/
@Deprecated
public FlexBuffersBuilder(ByteBuffer bb, int flags) {
this(new ArrayReadWriteBuf(bb.array()), flags);
}
public FlexBuffersBuilder(ReadWriteBuf bb, int flags) {
this.bb = bb;
this.flags = flags;
bb.order(ByteOrder.LITTLE_ENDIAN);
bb.position(0);
}
/**
@@ -154,7 +157,7 @@ public class FlexBuffersBuilder {
*
* @return `ByteBuffer` with finished message
*/
public ByteBuffer getBuffer() {
public ReadWriteBuf getBuffer() {
assert (finished);
return bb;
}
@@ -180,17 +183,20 @@ public class FlexBuffersBuilder {
if (key == null) {
return -1;
}
int pos = bb.position();
int pos = bb.writePosition();
if ((flags & BUILDER_FLAG_SHARE_KEYS) != 0) {
if (keyPool.get(key) == null) {
bb.put(key.getBytes(StandardCharsets.UTF_8));
Integer keyFromPool = keyPool.get(key);
if (keyFromPool == null) {
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
bb.put(keyBytes, 0, keyBytes.length);
bb.put((byte) 0);
keyPool.put(key, pos);
} else {
pos = keyPool.get(key);
pos = keyFromPool;
}
} else {
bb.put(key.getBytes(StandardCharsets.UTF_8));
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
bb.put(keyBytes, 0, keyBytes.length);
bb.put((byte) 0);
keyPool.put(key, pos);
}
@@ -373,8 +379,8 @@ public class FlexBuffersBuilder {
int bitWidth = widthUInBits(blob.length);
int byteWidth = align(bitWidth);
writeInt(blob.length, byteWidth);
int sloc = bb.position();
bb.put(blob);
int sloc = bb.writePosition();
bb.put(blob, 0, blob.length);
if (trailing) {
bb.put((byte) 0);
}
@@ -384,7 +390,7 @@ public class FlexBuffersBuilder {
// Align to prepare for writing a scalar with a certain size.
private int align(int alignment) {
int byteWidth = 1 << alignment;
int padBytes = Value.paddingBytes(bb.position(), byteWidth);
int padBytes = Value.paddingBytes(bb.writePosition(), byteWidth);
while (padBytes-- != 0) {
bb.put((byte) 0);
}
@@ -463,15 +469,14 @@ public class FlexBuffersBuilder {
// some other object.
assert (stack.size() == 1);
// Write root value.
int byteWidth = align(stack.get(0).elemWidth(bb.position(), 0));
int byteWidth = align(stack.get(0).elemWidth(bb.writePosition(), 0));
writeAny(stack.get(0), byteWidth);
// Write root type.
bb.put(stack.get(0).storedPackedType());
// Write root size. Normally determined by parent, but root has no parent :)
bb.put((byte) byteWidth);
bb.limit(bb.position());
this.finished = true;
return bb;
return ByteBuffer.wrap(bb.data(), 0, bb.writePosition());
}
/*
@@ -493,13 +498,13 @@ public class FlexBuffersBuilder {
if (keys != null) {
// If this vector is part of a map, we will pre-fix an offset to the keys
// to this vector.
bitWidth = Math.max(bitWidth, keys.elemWidth(bb.position(), 0));
bitWidth = Math.max(bitWidth, keys.elemWidth(bb.writePosition(), 0));
prefixElems += 2;
}
int vectorType = FBT_KEY;
// Check bit widths and types for all elements.
for (int i = start; i < stack.size(); i++) {
int elemWidth = stack.get(i).elemWidth(bb.position(), i + prefixElems);
int elemWidth = stack.get(i).elemWidth(bb.writePosition(), i + prefixElems);
bitWidth = Math.max(bitWidth, elemWidth);
if (typed) {
if (i == start) {
@@ -528,7 +533,7 @@ public class FlexBuffersBuilder {
writeInt(length, byteWidth);
}
// Then the actual data.
int vloc = bb.position();
int vloc = bb.writePosition();
for (int i = start; i < stack.size(); i++) {
writeAny(stack.get(i), byteWidth);
}
@@ -544,7 +549,7 @@ public class FlexBuffersBuilder {
}
private void writeOffset(long val, int byteWidth) {
int reloff = (int) (bb.position() - val);
int reloff = (int) (bb.writePosition() - val);
assert (byteWidth == 8 || reloff < 1L << (byteWidth * 8));
writeInt(reloff, byteWidth);
}
@@ -610,7 +615,7 @@ public class FlexBuffersBuilder {
int prefixElems = 1;
// Check bit widths and types for all elements.
for (int i = start; i < stack.size(); i++) {
int elemWidth = Value.elemWidth(FBT_KEY, WIDTH_8, stack.get(i).key, bb.position(), i + prefixElems);
int elemWidth = Value.elemWidth(FBT_KEY, WIDTH_8, stack.get(i).key, bb.writePosition(), i + prefixElems);
bitWidth = Math.max(bitWidth, elemWidth);
}
@@ -618,7 +623,7 @@ public class FlexBuffersBuilder {
// Write vector. First the keys width/offset if available, and size.
writeInt(length, byteWidth);
// Then the actual data.
int vloc = bb.position();
int vloc = bb.writePosition();
for (int i = start; i < stack.size(); i++) {
int pos = stack.get(i).key;
assert(pos != -1);

View File

@@ -0,0 +1,81 @@
package com.google.flatbuffers;
/**
* Represent a chunk of data, where FlexBuffers will read from.
*/
interface ReadBuf {
/**
* Read boolean from data. Booleans as stored as single byte
* @param index position of the element in ReadBuf
* @return boolean element
*/
boolean getBoolean(int index);
/**
* Read a byte from data.
* @param index position of the element in ReadBuf
* @return a byte
*/
byte get(int index);
/**
* Read a short from data.
* @param index position of the element in ReadBuf
* @return a short
*/
short getShort(int index);
/**
* Read a 32-bit int from data.
* @param index position of the element in ReadBuf
* @return an int
*/
int getInt(int index);
/**
* Read a 64-bit long from data.
* @param index position of the element in ReadBuf
* @return a long
*/
long getLong(int index);
/**
* Read a 32-bit float from data.
* @param index position of the element in ReadBuf
* @return a float
*/
float getFloat(int index);
/**
* Read a 64-bit float from data.
* @param index position of the element in ReadBuf
* @return a double
*/
double getDouble(int index);
/**
* Read an UTF-8 string from data.
* @param start initial element of the string
* @param size size of the string in bytes.
* @return a {@code String}
*/
String getString(int start, int size);
/**
* Expose ReadBuf as an array of bytes.
* This method is meant to be as efficient as possible, so for a array-backed ReadBuf, it should
* return its own internal data. In case access to internal data is not possible,
* a copy of the data into an array of bytes might occur.
* @return ReadBuf as an array of bytes
*/
byte[] data();
/**
* Defines the size of the message in the buffer. It also determines last position that buffer
* can be read. Last byte to be accessed is in position {@code limit() -1}.
* @return indicate last position
*/
int limit();
}

View File

@@ -0,0 +1,135 @@
package com.google.flatbuffers;
/**
* Interface to represent a read-write buffer. This interface will be used to access and write
* FlexBuffers message.
*/
interface ReadWriteBuf extends ReadBuf {
/**
* Put a boolean into the buffer at {@code writePosition()} . Booleans as stored as single
* byte. Write position will be incremented.
* @return boolean element
*/
void putBoolean(boolean value);
/**
* Put an array of bytes into the buffer at {@code writePosition()}. Write position will be
* incremented.
* @param value the data to be copied
* @param start initial position on value to be copied
* @param length amount of bytes to be copied
*/
void put (byte[] value, int start, int length);
/**
* Write a byte into the buffer at {@code writePosition()}. Write position will be
* incremented.
*/
void put(byte value);
/**
* Write a 16-bit into in the buffer at {@code writePosition()}. Write position will be
* incremented.
*/
void putShort(short value);
/**
* Write a 32-bit into in the buffer at {@code writePosition()}. Write position will be
* incremented.
*/
void putInt(int value);
/**
* Write a 64-bit into in the buffer at {@code writePosition()}. Write position will be
* incremented.
*/
void putLong(long value);
/**
* Write a 32-bit float into the buffer at {@code writePosition()}. Write position will be
* incremented.
*/
void putFloat(float value);
/**
* Write a 64-bit float into the buffer at {@code writePosition()}. Write position will be
* incremented.
*/
void putDouble(double value);
/**
* Write boolean into a given position on the buffer. Booleans as stored as single byte.
* @param index position of the element in buffer
*/
void setBoolean(int index, boolean value);
/**
* Read a byte from data.
* @param index position of the element in the buffer
* @return a byte
*/
void set(int index, byte value);
/**
* Write an array of bytes into the buffer.
* @param index initial position of the buffer to be written
* @param value the data to be copied
* @param start initial position on value to be copied
* @param length amount of bytes to be copied
*/
void set(int index, byte[] value, int start, int length);
/**
* Read a short from data.
* @param index position of the element in ReadBuf
* @return a short
*/
void setShort(int index, short value);
/**
* Read a 32-bit int from data.
* @param index position of the element in ReadBuf
* @return an int
*/
void setInt(int index, int value);
/**
* Read a 64-bit long from data.
* @param index position of the element in ReadBuf
* @return a long
*/
void setLong(int index, long value);
/**
* Read a 32-bit float from data.
* @param index position of the element in ReadBuf
* @return a float
*/
void setFloat(int index, float value);
/**
* Read a 64-bit float from data.
* @param index position of the element in ReadBuf
* @return a double
*/
void setDouble(int index, double value);
int writePosition();
/**
* Defines the size of the message in the buffer. It also determines last position that buffer
* can be read or write. Last byte to be accessed is in position {@code limit() -1}.
* @return indicate last position
*/
int limit();
/**
* Request capacity of the buffer. In case buffer is already larger
* than the requested, this method will just return true. Otherwise
* It might try to resize the buffer.
*
* @return true if buffer is able to offer
* the requested capacity
*/
boolean requestCapacity(int capacity);
}

View File

@@ -123,7 +123,7 @@ final public class Utf8Safe extends Utf8 {
return utf8Length;
}
private static String decodeUtf8Array(byte[] bytes, int index, int size) {
public static String decodeUtf8Array(byte[] bytes, int index, int size) {
// Bitwise OR combines the sign bits so any negative value fails the check.
if ((index | size | bytes.length - index - size) < 0) {
throw new ArrayIndexOutOfBoundsException(
@@ -197,7 +197,7 @@ final public class Utf8Safe extends Utf8 {
return new String(resultArr, 0, resultPos);
}
private static String decodeUtf8Buffer(ByteBuffer buffer, int offset,
public static String decodeUtf8Buffer(ByteBuffer buffer, int offset,
int length) {
// Bitwise OR combines the sign bits so any negative value fails the check.
if ((offset | length | buffer.limit() - offset - length) < 0) {