mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-01 13:01:36 +00:00
[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:
241
java/com/google/flatbuffers/ArrayReadWriteBuf.java
Normal file
241
java/com/google/flatbuffers/ArrayReadWriteBuf.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
165
java/com/google/flatbuffers/ByteBufferReadWriteBuf.java
Normal file
165
java/com/google/flatbuffers/ByteBufferReadWriteBuf.java
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
* <p>
|
* <p>
|
||||||
* Example of usage:
|
* Example of usage:
|
||||||
* <pre>
|
* <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.Reference r = FlexBuffers.getRoot(bb); // Reads the root element
|
||||||
* FlexBuffers.Map map = r.asMap(); // We assumed root object is a map
|
* FlexBuffers.Map map = r.asMap(); // We assumed root object is a map
|
||||||
* System.out.println(map.get("name").asString()); // prints element with key "name"
|
* 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 */
|
/** 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
|
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
|
* 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
|
// return position of the element that the offset is pointing to
|
||||||
private static int indirect(ByteBuffer bb, int offset, int byteWidth) {
|
private static int indirect(ReadBuf bb, int offset, int byteWidth) {
|
||||||
// we assume all offset fits on a int, since ByteBuffer operates with that assumption
|
// we assume all offset fits on a int, since ReadBuf operates with that assumption
|
||||||
return (int) (offset - readUInt(bb, offset, byteWidth));
|
return (int) (offset - readUInt(bb, offset, byteWidth));
|
||||||
}
|
}
|
||||||
|
|
||||||
// read unsigned int with size byteWidth and return as a 64-bit integer
|
// 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) {
|
switch (byteWidth) {
|
||||||
case 1: return byteToUnsignedInt(buff.get(end));
|
case 1: return byteToUnsignedInt(buff.get(end));
|
||||||
case 2: return shortToUnsignedInt(buff.getShort(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
|
// 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);
|
return (int) readLong(buff, end, byteWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read signed int of size byteWidth and return as 64-bit int
|
// 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) {
|
switch (byteWidth) {
|
||||||
case 1: return buff.get(end);
|
case 1: return buff.get(end);
|
||||||
case 2: return buff.getShort(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) {
|
switch (byteWidth) {
|
||||||
case 4: return buff.getFloat(end);
|
case 4: return buff.getFloat(end);
|
||||||
case 8: return buff.getDouble(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.
|
* the root element.
|
||||||
* @param buffer ByteBuffer containing FlexBuffer message
|
* @param buffer ReadBuf containing FlexBuffer message
|
||||||
* @return {@link Reference} to the root object
|
* @return {@link Reference} to the root object
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Reference getRoot(ByteBuffer buffer) {
|
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.
|
// See Finish() below for the serialization counterpart of this.
|
||||||
// The root ends at the end of the buffer, so we parse backwards from there.
|
// The root ends at the end of the buffer, so we parse backwards from there.
|
||||||
int end = buffer.limit();
|
int end = buffer.limit();
|
||||||
@@ -213,17 +224,17 @@ public class FlexBuffers {
|
|||||||
public static class Reference {
|
public static class Reference {
|
||||||
|
|
||||||
private static final Reference NULL_REFERENCE = new Reference(EMPTY_BB, 0, 1, 0);
|
private static final Reference NULL_REFERENCE = new Reference(EMPTY_BB, 0, 1, 0);
|
||||||
private ByteBuffer bb;
|
private ReadBuf bb;
|
||||||
private int end;
|
private int end;
|
||||||
private int parentWidth;
|
private int parentWidth;
|
||||||
private int byteWidth;
|
private int byteWidth;
|
||||||
private int type;
|
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);
|
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.bb = bb;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
this.parentWidth = parentWidth;
|
this.parentWidth = parentWidth;
|
||||||
@@ -484,13 +495,13 @@ public class FlexBuffers {
|
|||||||
if (isString()) {
|
if (isString()) {
|
||||||
int start = indirect(bb, end, parentWidth);
|
int start = indirect(bb, end, parentWidth);
|
||||||
int size = (int) readUInt(bb, start - byteWidth, byteWidth);
|
int size = (int) readUInt(bb, start - byteWidth, byteWidth);
|
||||||
return Utf8.getDefault().decodeUtf8(bb, start, size);
|
return bb.getString(start, size);
|
||||||
}
|
}
|
||||||
else if (isKey()){
|
else if (isKey()){
|
||||||
int start = indirect(bb, end, byteWidth);
|
int start = indirect(bb, end, byteWidth);
|
||||||
for (int i = start; ; i++) {
|
for (int i = start; ; i++) {
|
||||||
if (bb.get(i) == 0) {
|
if (bb.get(i) == 0) {
|
||||||
return Utf8.getDefault().decodeUtf8(bb, start, i - start);
|
return bb.getString(start, i - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -619,11 +630,11 @@ public class FlexBuffers {
|
|||||||
* Points into the data buffer and allows access to one type.
|
* Points into the data buffer and allows access to one type.
|
||||||
*/
|
*/
|
||||||
private static abstract class Object {
|
private static abstract class Object {
|
||||||
ByteBuffer bb;
|
ReadBuf bb;
|
||||||
int end;
|
int end;
|
||||||
int byteWidth;
|
int byteWidth;
|
||||||
|
|
||||||
Object(ByteBuffer buff, int end, int byteWidth) {
|
Object(ReadBuf buff, int end, int byteWidth) {
|
||||||
this.bb = buff;
|
this.bb = buff;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
this.byteWidth = byteWidth;
|
this.byteWidth = byteWidth;
|
||||||
@@ -640,9 +651,9 @@ public class FlexBuffers {
|
|||||||
// Stores size in `byte_width_` bytes before end position.
|
// Stores size in `byte_width_` bytes before end position.
|
||||||
private static abstract class Sized extends Object {
|
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);
|
super(buff, end, byteWidth);
|
||||||
size = readInt(bb, end - byteWidth, byteWidth);
|
size = readInt(bb, end - byteWidth, byteWidth);
|
||||||
}
|
}
|
||||||
@@ -655,14 +666,14 @@ public class FlexBuffers {
|
|||||||
/**
|
/**
|
||||||
* Represents a array of bytes element in the buffer
|
* 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
|
* copied into a byte[] using {@link getBytes()} or
|
||||||
* have individual bytes accessed individually using {@link get(int)}</p>
|
* have individual bytes accessed individually using {@link get(int)}</p>
|
||||||
*/
|
*/
|
||||||
public static class Blob extends Sized {
|
public static class Blob extends Sized {
|
||||||
static final Blob EMPTY = new Blob(EMPTY_BB, 1, 1);
|
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);
|
super(buff, end, byteWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,11 +683,11 @@ public class FlexBuffers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return {@link Blob} as `ByteBuffer`
|
* Return {@link Blob} as `ReadBuf`
|
||||||
* @return blob as `ByteBuffer`
|
* @return blob as `ReadBuf`
|
||||||
*/
|
*/
|
||||||
public ByteBuffer data() {
|
public ByteBuffer data() {
|
||||||
ByteBuffer dup = bb.duplicate();
|
ByteBuffer dup = ByteBuffer.wrap(bb.data());
|
||||||
dup.position(end);
|
dup.position(end);
|
||||||
dup.limit(end + size());
|
dup.limit(end + size());
|
||||||
return dup.asReadOnlyBuffer().slice();
|
return dup.asReadOnlyBuffer().slice();
|
||||||
@@ -709,7 +720,7 @@ public class FlexBuffers {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Utf8.getDefault().decodeUtf8(bb, end, size());
|
return bb.getString(end, size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -718,7 +729,7 @@ public class FlexBuffers {
|
|||||||
@Override
|
@Override
|
||||||
public StringBuilder toString(StringBuilder sb) {
|
public StringBuilder toString(StringBuilder sb) {
|
||||||
sb.append('"');
|
sb.append('"');
|
||||||
sb.append(Utf8.getDefault().decodeUtf8(bb, end, size()));
|
sb.append(bb.getString(end, size()));
|
||||||
return sb.append('"');
|
return sb.append('"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -731,7 +742,7 @@ public class FlexBuffers {
|
|||||||
|
|
||||||
private static final Key EMPTY = new Key(EMPTY_BB, 0, 0);
|
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);
|
super(buff, end, byteWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,7 +771,7 @@ public class FlexBuffers {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Utf8.getDefault().decodeUtf8(bb, end, size);
|
return bb.getString(end, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int compareTo(byte[] other) {
|
int compareTo(byte[] other) {
|
||||||
@@ -808,7 +819,7 @@ public class FlexBuffers {
|
|||||||
public static class Map extends Vector {
|
public static class Map extends Vector {
|
||||||
private static final Map EMPTY_MAP = new Map(EMPTY_BB, 1, 1);
|
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);
|
super(bb, end, byteWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,7 +924,7 @@ public class FlexBuffers {
|
|||||||
|
|
||||||
private static final Vector EMPTY_VECTOR = new Vector(EMPTY_BB, 1, 1);
|
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);
|
super(bb, end, byteWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -976,7 +987,7 @@ public class FlexBuffers {
|
|||||||
|
|
||||||
private final int elemType;
|
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);
|
super(bb, end, byteWidth);
|
||||||
this.elemType = elemType;
|
this.elemType = elemType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class FlexBuffersBuilder {
|
|||||||
private static final int WIDTH_16 = 1;
|
private static final int WIDTH_16 = 1;
|
||||||
private static final int WIDTH_32 = 2;
|
private static final int WIDTH_32 = 2;
|
||||||
private static final int WIDTH_64 = 3;
|
private static final int WIDTH_64 = 3;
|
||||||
private final ByteBuffer bb;
|
private final ReadWriteBuf bb;
|
||||||
private final ArrayList<Value> stack = new ArrayList<>();
|
private final ArrayList<Value> stack = new ArrayList<>();
|
||||||
private final HashMap<String, Integer> keyPool = new HashMap<>();
|
private final HashMap<String, Integer> keyPool = new HashMap<>();
|
||||||
private final HashMap<String, Integer> stringPool = new HashMap<>();
|
private final HashMap<String, Integer> stringPool = new HashMap<>();
|
||||||
@@ -116,7 +116,7 @@ public class FlexBuffersBuilder {
|
|||||||
* @param bufSize size of buffer in bytes.
|
* @param bufSize size of buffer in bytes.
|
||||||
*/
|
*/
|
||||||
public FlexBuffersBuilder(int bufSize) {
|
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 bb `ByteBuffer` that will hold the message
|
||||||
* @param flags Share flags
|
* @param flags Share flags
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public FlexBuffersBuilder(ByteBuffer bb, int flags) {
|
public FlexBuffersBuilder(ByteBuffer bb, int flags) {
|
||||||
|
this(new ArrayReadWriteBuf(bb.array()), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlexBuffersBuilder(ReadWriteBuf bb, int flags) {
|
||||||
this.bb = bb;
|
this.bb = bb;
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
bb.position(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +157,7 @@ public class FlexBuffersBuilder {
|
|||||||
*
|
*
|
||||||
* @return `ByteBuffer` with finished message
|
* @return `ByteBuffer` with finished message
|
||||||
*/
|
*/
|
||||||
public ByteBuffer getBuffer() {
|
public ReadWriteBuf getBuffer() {
|
||||||
assert (finished);
|
assert (finished);
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
@@ -180,17 +183,20 @@ public class FlexBuffersBuilder {
|
|||||||
if (key == null) {
|
if (key == null) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int pos = bb.position();
|
int pos = bb.writePosition();
|
||||||
if ((flags & BUILDER_FLAG_SHARE_KEYS) != 0) {
|
if ((flags & BUILDER_FLAG_SHARE_KEYS) != 0) {
|
||||||
if (keyPool.get(key) == null) {
|
Integer keyFromPool = keyPool.get(key);
|
||||||
bb.put(key.getBytes(StandardCharsets.UTF_8));
|
if (keyFromPool == null) {
|
||||||
|
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
|
||||||
|
bb.put(keyBytes, 0, keyBytes.length);
|
||||||
bb.put((byte) 0);
|
bb.put((byte) 0);
|
||||||
keyPool.put(key, pos);
|
keyPool.put(key, pos);
|
||||||
} else {
|
} else {
|
||||||
pos = keyPool.get(key);
|
pos = keyFromPool;
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
bb.put((byte) 0);
|
||||||
keyPool.put(key, pos);
|
keyPool.put(key, pos);
|
||||||
}
|
}
|
||||||
@@ -373,8 +379,8 @@ public class FlexBuffersBuilder {
|
|||||||
int bitWidth = widthUInBits(blob.length);
|
int bitWidth = widthUInBits(blob.length);
|
||||||
int byteWidth = align(bitWidth);
|
int byteWidth = align(bitWidth);
|
||||||
writeInt(blob.length, byteWidth);
|
writeInt(blob.length, byteWidth);
|
||||||
int sloc = bb.position();
|
int sloc = bb.writePosition();
|
||||||
bb.put(blob);
|
bb.put(blob, 0, blob.length);
|
||||||
if (trailing) {
|
if (trailing) {
|
||||||
bb.put((byte) 0);
|
bb.put((byte) 0);
|
||||||
}
|
}
|
||||||
@@ -384,7 +390,7 @@ public class FlexBuffersBuilder {
|
|||||||
// Align to prepare for writing a scalar with a certain size.
|
// Align to prepare for writing a scalar with a certain size.
|
||||||
private int align(int alignment) {
|
private int align(int alignment) {
|
||||||
int byteWidth = 1 << alignment;
|
int byteWidth = 1 << alignment;
|
||||||
int padBytes = Value.paddingBytes(bb.position(), byteWidth);
|
int padBytes = Value.paddingBytes(bb.writePosition(), byteWidth);
|
||||||
while (padBytes-- != 0) {
|
while (padBytes-- != 0) {
|
||||||
bb.put((byte) 0);
|
bb.put((byte) 0);
|
||||||
}
|
}
|
||||||
@@ -463,15 +469,14 @@ public class FlexBuffersBuilder {
|
|||||||
// some other object.
|
// some other object.
|
||||||
assert (stack.size() == 1);
|
assert (stack.size() == 1);
|
||||||
// Write root value.
|
// 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);
|
writeAny(stack.get(0), byteWidth);
|
||||||
// Write root type.
|
// Write root type.
|
||||||
bb.put(stack.get(0).storedPackedType());
|
bb.put(stack.get(0).storedPackedType());
|
||||||
// Write root size. Normally determined by parent, but root has no parent :)
|
// Write root size. Normally determined by parent, but root has no parent :)
|
||||||
bb.put((byte) byteWidth);
|
bb.put((byte) byteWidth);
|
||||||
bb.limit(bb.position());
|
|
||||||
this.finished = true;
|
this.finished = true;
|
||||||
return bb;
|
return ByteBuffer.wrap(bb.data(), 0, bb.writePosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -493,13 +498,13 @@ public class FlexBuffersBuilder {
|
|||||||
if (keys != null) {
|
if (keys != null) {
|
||||||
// If this vector is part of a map, we will pre-fix an offset to the keys
|
// If this vector is part of a map, we will pre-fix an offset to the keys
|
||||||
// to this vector.
|
// to this vector.
|
||||||
bitWidth = Math.max(bitWidth, keys.elemWidth(bb.position(), 0));
|
bitWidth = Math.max(bitWidth, keys.elemWidth(bb.writePosition(), 0));
|
||||||
prefixElems += 2;
|
prefixElems += 2;
|
||||||
}
|
}
|
||||||
int vectorType = FBT_KEY;
|
int vectorType = FBT_KEY;
|
||||||
// Check bit widths and types for all elements.
|
// Check bit widths and types for all elements.
|
||||||
for (int i = start; i < stack.size(); i++) {
|
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);
|
bitWidth = Math.max(bitWidth, elemWidth);
|
||||||
if (typed) {
|
if (typed) {
|
||||||
if (i == start) {
|
if (i == start) {
|
||||||
@@ -528,7 +533,7 @@ public class FlexBuffersBuilder {
|
|||||||
writeInt(length, byteWidth);
|
writeInt(length, byteWidth);
|
||||||
}
|
}
|
||||||
// Then the actual data.
|
// Then the actual data.
|
||||||
int vloc = bb.position();
|
int vloc = bb.writePosition();
|
||||||
for (int i = start; i < stack.size(); i++) {
|
for (int i = start; i < stack.size(); i++) {
|
||||||
writeAny(stack.get(i), byteWidth);
|
writeAny(stack.get(i), byteWidth);
|
||||||
}
|
}
|
||||||
@@ -544,7 +549,7 @@ public class FlexBuffersBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeOffset(long val, int byteWidth) {
|
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));
|
assert (byteWidth == 8 || reloff < 1L << (byteWidth * 8));
|
||||||
writeInt(reloff, byteWidth);
|
writeInt(reloff, byteWidth);
|
||||||
}
|
}
|
||||||
@@ -610,7 +615,7 @@ public class FlexBuffersBuilder {
|
|||||||
int prefixElems = 1;
|
int prefixElems = 1;
|
||||||
// Check bit widths and types for all elements.
|
// Check bit widths and types for all elements.
|
||||||
for (int i = start; i < stack.size(); i++) {
|
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);
|
bitWidth = Math.max(bitWidth, elemWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,7 +623,7 @@ public class FlexBuffersBuilder {
|
|||||||
// Write vector. First the keys width/offset if available, and size.
|
// Write vector. First the keys width/offset if available, and size.
|
||||||
writeInt(length, byteWidth);
|
writeInt(length, byteWidth);
|
||||||
// Then the actual data.
|
// Then the actual data.
|
||||||
int vloc = bb.position();
|
int vloc = bb.writePosition();
|
||||||
for (int i = start; i < stack.size(); i++) {
|
for (int i = start; i < stack.size(); i++) {
|
||||||
int pos = stack.get(i).key;
|
int pos = stack.get(i).key;
|
||||||
assert(pos != -1);
|
assert(pos != -1);
|
||||||
|
|||||||
81
java/com/google/flatbuffers/ReadBuf.java
Normal file
81
java/com/google/flatbuffers/ReadBuf.java
Normal 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();
|
||||||
|
|
||||||
|
}
|
||||||
135
java/com/google/flatbuffers/ReadWriteBuf.java
Normal file
135
java/com/google/flatbuffers/ReadWriteBuf.java
Normal 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);
|
||||||
|
}
|
||||||
@@ -123,7 +123,7 @@ final public class Utf8Safe extends Utf8 {
|
|||||||
return utf8Length;
|
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.
|
// Bitwise OR combines the sign bits so any negative value fails the check.
|
||||||
if ((index | size | bytes.length - index - size) < 0) {
|
if ((index | size | bytes.length - index - size) < 0) {
|
||||||
throw new ArrayIndexOutOfBoundsException(
|
throw new ArrayIndexOutOfBoundsException(
|
||||||
@@ -197,7 +197,7 @@ final public class Utf8Safe extends Utf8 {
|
|||||||
return new String(resultArr, 0, resultPos);
|
return new String(resultArr, 0, resultPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String decodeUtf8Buffer(ByteBuffer buffer, int offset,
|
public static String decodeUtf8Buffer(ByteBuffer buffer, int offset,
|
||||||
int length) {
|
int length) {
|
||||||
// Bitwise OR combines the sign bits so any negative value fails the check.
|
// Bitwise OR combines the sign bits so any negative value fails the check.
|
||||||
if ((offset | length | buffer.limit() - offset - length) < 0) {
|
if ((offset | length | buffer.limit() - offset - length) < 0) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import com.google.flatbuffers.UnionVector;
|
|||||||
import com.google.flatbuffers.FlexBuffers.FlexBufferException;
|
import com.google.flatbuffers.FlexBuffers.FlexBufferException;
|
||||||
import com.google.flatbuffers.FlexBuffers.Reference;
|
import com.google.flatbuffers.FlexBuffers.Reference;
|
||||||
import com.google.flatbuffers.FlexBuffers.Vector;
|
import com.google.flatbuffers.FlexBuffers.Vector;
|
||||||
|
import com.google.flatbuffers.ArrayReadWriteBuf;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@@ -1007,6 +1008,23 @@ class JavaTest {
|
|||||||
TestEq(source, result);
|
TestEq(source, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void testBuilderGrowth() {
|
||||||
|
FlexBuffersBuilder builder = new FlexBuffersBuilder();
|
||||||
|
builder.putString("This is a small string");
|
||||||
|
ByteBuffer b = builder.finish();
|
||||||
|
TestEq("This is a small string", FlexBuffers.getRoot(b).asString());
|
||||||
|
|
||||||
|
FlexBuffersBuilder failBuilder = new FlexBuffersBuilder(ByteBuffer.allocate(1));
|
||||||
|
try {
|
||||||
|
failBuilder.putString("This is a small string");
|
||||||
|
// This should never be reached, it should throw an exception
|
||||||
|
// since ByteBuffers do not grow
|
||||||
|
assert(false);
|
||||||
|
} catch (java.lang.ArrayIndexOutOfBoundsException exception) {
|
||||||
|
// It should throw exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void TestFlexBuffers() {
|
public static void TestFlexBuffers() {
|
||||||
testSingleElementByte();
|
testSingleElementByte();
|
||||||
testSingleElementShort();
|
testSingleElementShort();
|
||||||
@@ -1028,6 +1046,7 @@ class JavaTest {
|
|||||||
testFlexBuferEmpty();
|
testFlexBuferEmpty();
|
||||||
testFlexBufferVectorStrings();
|
testFlexBufferVectorStrings();
|
||||||
testDeprecatedTypedVectorString();
|
testDeprecatedTypedVectorString();
|
||||||
|
testBuilderGrowth();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TestVectorOfBytes() {
|
static void TestVectorOfBytes() {
|
||||||
|
|||||||
Reference in New Issue
Block a user