| 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 void clear() { |
| this.writePos = 0; |
| } |
| |
| @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 (capacity < 0) { |
| throw new IllegalArgumentException("Capacity may not be negative (likely a previous int overflow)"); |
| } |
| if (buffer.length >= capacity) { |
| return true; |
| } |
| // implemented in the same growing fashion as ArrayList |
| int oldCapacity = buffer.length; |
| int newCapacity = oldCapacity + (oldCapacity >> 1); |
| if (newCapacity < capacity) { // Note: this also catches newCapacity int overflow |
| newCapacity = capacity; |
| } |
| buffer = Arrays.copyOf(buffer, newCapacity); |
| return true; |
| } |
| } |