package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.util.UnsafeUtil;
/** An InputStream that reads data from a byte array and optionally fills the byte array from another InputStream as needed.
* Utility methods are provided for efficiently reading primitive types and strings.
*
* @author Roman Levenstein <romixlev@gmail.com> */
public class ByteBufferInput extends Input {
protected ByteBuffer niobuffer;
protected boolean varIntsEnabled = true;
/* Default byte order is BIG_ENDIAN to be compatible to the base class */
ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
protected final static ByteOrder nativeOrder = ByteOrder.nativeOrder();
/** Creates an uninitialized Input. {@link #setBuffer(byte[])} must be called before the Input is used. */
public ByteBufferInput () {
}
/** Creates a new Input for reading from a byte array.
* @param bufferSize The size of the buffer. An exception is thrown if more bytes than this are read. */
public ByteBufferInput (int bufferSize) {
this.capacity = bufferSize;
niobuffer = ByteBuffer.allocateDirect(bufferSize);
niobuffer.order(byteOrder);
}
/** Creates a new Input for reading from a byte array.
* @param buffer An exception is thrown if more bytes than this are read. */
public ByteBufferInput (ByteBuffer buffer) {
this(buffer, 0, buffer.position());
}
public ByteBufferInput (byte[] buffer) {
setBuffer(buffer);
}
/** Creates a new Input for reading from a byte array.
* @param buffer An exception is thrown if more bytes than this are read. */
public ByteBufferInput (ByteBuffer buffer, int offset, int count) {
ByteBuffer newBuffer = buffer.duplicate();
newBuffer.order(byteOrder);
newBuffer.limit(count);
newBuffer.rewind();
setBuffer(newBuffer, offset, count);
}
/** Creates a new Input for reading from an InputStream with a buffer size of 4096. */
public ByteBufferInput (InputStream inputStream) {
this(4096);
if (inputStream == null) throw new IllegalArgumentException("inputStream cannot be null.");
this.inputStream = inputStream;
}
/** Creates a new Input for reading from an InputStream. */
public ByteBufferInput (InputStream inputStream, int bufferSize) {
this(bufferSize);
if (inputStream == null) throw new IllegalArgumentException("inputStream cannot be null.");
this.inputStream = inputStream;
}
public ByteOrder order () {
return byteOrder;
}
public void order (ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
/** Sets a new buffer. The position and total are reset, discarding any buffered bytes. */
public void setBuffer (byte[] bytes) {
ByteBuffer directBuffer = ByteBuffer.allocateDirect(bytes.length);
directBuffer.put(bytes);
directBuffer.position(0);
directBuffer.order(byteOrder);
setBuffer(directBuffer, 0, bytes.length);
}
/** Sets a new buffer. The position and total are reset, discarding any buffered bytes. */
public void setBuffer (ByteBuffer bytes, int offset, int count) {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
niobuffer = bytes;
position = offset;
limit = offset + count;
capacity = bytes.capacity();
total = 0;
inputStream = null;
niobuffer.position(position);
}
/*** Release a direct buffer. {@link #setBuffer(ByteBuffer, int, int)} should be called before next write operations can be
* called. */
public void release () {
close();
UnsafeUtil.releaseBuffer(niobuffer);
niobuffer = null;
}
/*** This constructor allows for creation of a direct ByteBuffer of a given size at a given address.
*
* <p>
* Typical usage could look like this snippet:
*
* <pre>
* // Explicitly allocate memory
* long bufAddress = UnsafeUtil.unsafe().allocateMemory(4096);
* // Create a ByteBufferInput using the allocated memory region
* ByteBufferInput buffer = new ByteBufferInput(bufAddress, 4096);
*
* // Do some operations on this buffer here
*
* // Say that ByteBuffer won't be used anymore
* buffer.release();
* // Release the allocated region
* UnsafeUtil.unsafe().freeMemory(bufAddress);
* </pre>
*
* @param address starting address of a memory region pre-allocated using Unsafe.allocateMemory()
* @param maxBufferSize */
public ByteBufferInput (long address, int maxBufferSize) {
niobuffer = UnsafeUtil.getDirectBufferAt(address, maxBufferSize);
setBuffer(niobuffer, 0, maxBufferSize);
}
public ByteBuffer getByteBuffer () {
return niobuffer;
}
public InputStream getInputStream () {
return inputStream;
}
/** Sets a new InputStream. The position and total are reset, discarding any buffered bytes.
* @param inputStream May be null. */
public void setInputStream (InputStream inputStream) {
this.inputStream = inputStream;
limit = 0;
rewind();
}
public void rewind () {
super.rewind();
niobuffer.position(0);
}
/** Fills the buffer with more bytes. Can be overridden to fill the bytes from a source other than the InputStream. */
protected int fill (ByteBuffer buffer, int offset, int count) throws KryoException {
if (inputStream == null) return -1;
try {
byte[] tmp = new byte[count];
int result = inputStream.read(tmp, 0, count);
buffer.position(offset);
if (result >= 0) {
buffer.put(tmp, 0, result);
buffer.position(offset);
}
return result;
} catch (IOException ex) {
throw new KryoException(ex);
}
}
/** @param required Must be > 0. The buffer is filled until it has at least this many bytes.
* @return the number of bytes remaining.
* @throws KryoException if EOS is reached before required bytes are read (buffer underflow). */
final protected int require (int required) throws KryoException {
int remaining = limit - position;
if (remaining >= required) return remaining;
if (required > capacity) throw new KryoException("Buffer too small: capacity: " + capacity + ", required: " + required);
int count;
// Try to fill the buffer.
if (remaining > 0) {
count = fill(niobuffer, limit, capacity - limit);
if (count == -1) throw new KryoException("Buffer underflow.");
remaining += count;
if (remaining >= required) {
limit += count;
return remaining;
}
}
// Compact. Position after compaction can be non-zero
niobuffer.position(position);
niobuffer.compact();
total += position;
position = 0;
while (true) {
count = fill(niobuffer, remaining, capacity - remaining);
if (count == -1) {
if (remaining >= required) break;
throw new KryoException("Buffer underflow.");
}
remaining += count;
if (remaining >= required) break; // Enough has been read.
}
limit = remaining;
niobuffer.position(0);
return remaining;
}
/** @param optional Try to fill the buffer with this many bytes.
* @return the number of bytes remaining, but not more than optional, or -1 if the EOS was reached and the buffer is empty. */
private int optional (int optional) throws KryoException {
int remaining = limit - position;
if (remaining >= optional) return optional;
optional = Math.min(optional, capacity);
// Try to fill the buffer.
int count = fill(niobuffer, limit, capacity - limit);
if (count == -1) return remaining == 0 ? -1 : Math.min(remaining, optional);
remaining += count;
if (remaining >= optional) {
limit += count;
return optional;
}
// Compact.
niobuffer.compact();
total += position;
position = 0;
while (true) {
count = fill(niobuffer, remaining, capacity - remaining);
if (count == -1) break;
remaining += count;
if (remaining >= optional) break; // Enough has been read.
}
limit = remaining;
niobuffer.position(position);
return remaining == 0 ? -1 : Math.min(remaining, optional);
}
// InputStream
/** Reads a single byte as an int from 0 to 255, or -1 if there are no more bytes are available. */
public int read () throws KryoException {
if (optional(1) <= 0) return -1;
niobuffer.position(position);
position++;
return niobuffer.get() & 0xFF;
}
/** Reads bytes.length bytes or less and writes them to the specified byte[], starting at 0, and returns the number of bytes
* read. */
public int read (byte[] bytes) throws KryoException {
niobuffer.position(position);
return read(bytes, 0, bytes.length);
}
/** Reads count bytes or less and writes them to the specified byte[], starting at offset, and returns the number of bytes read
* or -1 if no more bytes are available. */
public int read (byte[] bytes, int offset, int count) throws KryoException {
niobuffer.position(position);
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
int startingCount = count;
int copyCount = Math.min(limit - position, count);
while (true) {
niobuffer.get(bytes, offset, copyCount);
position += copyCount;
count -= copyCount;
if (count == 0) break;
offset += copyCount;
copyCount = optional(count);
if (copyCount == -1) {
// End of data.
if (startingCount == count) return -1;
break;
}
if (position == limit) break;
}
return startingCount - count;
}
/** Discards the specified number of bytes. */
public long skip (long count) throws KryoException {
long remaining = count;
while (remaining > 0) {
int skip = Math.min(Integer.MAX_VALUE, (int)remaining);
skip(skip);
remaining -= skip;
}
return count;
}
/** Closes the underlying InputStream, if any. */
public void close () throws KryoException {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ignored) {
}
}
}
// byte
/** Reads a single byte. */
public byte readByte () throws KryoException {
niobuffer.position(position);
require(1);
position++;
return niobuffer.get();
}
/** Reads a byte as an int from 0 to 255. */
public int readByteUnsigned () throws KryoException {
// buffer.position(position);
require(1);
position++;
return niobuffer.get() & 0xFF;
}
/** Reads the specified number of bytes into a new byte[]. */
public byte[] readBytes (int length) throws KryoException {
byte[] bytes = new byte[length];
readBytes(bytes, 0, length);
return bytes;
}
/** Reads bytes.length bytes and writes them to the specified byte[], starting at index 0. */
public void readBytes (byte[] bytes) throws KryoException {
readBytes(bytes, 0, bytes.length);
}
/** Reads count bytes and writes them to the specified byte[], starting at offset. */
public void readBytes (byte[] bytes, int offset, int count) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
int copyCount = Math.min(limit - position, count);
while (true) {
niobuffer.get(bytes, offset, copyCount);
position += copyCount;
count -= copyCount;
if (count == 0) break;
offset += copyCount;
copyCount = Math.min(count, capacity);
require(copyCount);
}
}
public int readInt () throws KryoException {
require(4);
position += 4;
return niobuffer.getInt();
}
public int readInt (boolean optimizePositive) throws KryoException {
if (varIntsEnabled)
return readVarInt(optimizePositive);
else
return readInt();
}
public int readVarInt (boolean optimizePositive) throws KryoException {
niobuffer.position(position);
if (require(1) < 5) return readInt_slow(optimizePositive);
position++;
int b = niobuffer.get();
int result = b & 0x7F;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
}
private int readInt_slow (boolean optimizePositive) {
// The buffer is guaranteed to have at least 1 byte.
position++;
int b = niobuffer.get();
int result = b & 0x7F;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
}
/** Returns true if enough bytes are available to read an int with {@link #readInt(boolean)}. */
public boolean canReadInt () throws KryoException {
if (limit - position >= 5) return true;
if (optional(5) <= 0) return false;
int p = position;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
return true;
}
/** Returns true if enough bytes are available to read a long with {@link #readLong(boolean)}. */
public boolean canReadLong () throws KryoException {
if (limit - position >= 9) return true;
if (optional(5) <= 0) return false;
int p = position;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
if ((niobuffer.get(p++) & 0x80) == 0) return true;
if (p == limit) return false;
return true;
}
/** Reads the length and string of UTF8 characters, or null. This can read strings written by {@link Output#writeString(String)}
* , {@link Output#writeString(CharSequence)}, and {@link Output#writeAscii(String)}.
* @return May be null. */
public String readString () {
niobuffer.position(position);
int available = require(1);
position++;
int b = niobuffer.get();
if ((b & 0x80) == 0) return readAscii(); // ASCII.
// Null, empty, or UTF8.
int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b);
switch (charCount) {
case 0:
return null;
case 1:
return "";
}
charCount--;
if (chars.length < charCount) chars = new char[charCount];
readUtf8(charCount);
return new String(chars, 0, charCount);
}
private int readUtf8Length (int b) {
int result = b & 0x3F; // Mask all but first 6 bits.
if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 6;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 13;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 20;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 27;
}
}
}
}
return result;
}
private int readUtf8Length_slow (int b) {
int result = b & 0x3F; // Mask all but first 6 bits.
if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 6;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 13;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 20;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 27;
}
}
}
}
return result;
}
private void readUtf8 (int charCount) {
char[] chars = this.chars;
// Try to read 7 bit ASCII chars.
int charIndex = 0;
int count = Math.min(require(1), charCount);
int position = this.position;
int b;
while (charIndex < count) {
position++;
b = niobuffer.get();
if (b < 0) {
position--;
break;
}
chars[charIndex++] = (char)b;
}
this.position = position;
// If buffer didn't hold all chars or any were not ASCII, use slow path for remainder.
if (charIndex < charCount) {
niobuffer.position(position);
readUtf8_slow(charCount, charIndex);
}
}
private void readUtf8_slow (int charCount, int charIndex) {
char[] chars = this.chars;
while (charIndex < charCount) {
if (position == limit) require(1);
position++;
int b = niobuffer.get() & 0xFF;
switch (b >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
chars[charIndex] = (char)b;
break;
case 12:
case 13:
if (position == limit) require(1);
position++;
chars[charIndex] = (char)((b & 0x1F) << 6 | niobuffer.get() & 0x3F);
break;
case 14:
require(2);
position += 2;
int b2 = niobuffer.get();
int b3 = niobuffer.get();
chars[charIndex] = (char)((b & 0x0F) << 12 | (b2 & 0x3F) << 6 | b3 & 0x3F);
break;
}
charIndex++;
}
}
private String readAscii () {
int end = position;
int start = end - 1;
int limit = this.limit;
int b;
do {
if (end == limit) return readAscii_slow();
end++;
b = niobuffer.get();
} while ((b & 0x80) == 0);
niobuffer.put(end - 1, (byte)(niobuffer.get(end - 1) & 0x7F)); // Mask end of ascii bit.
byte[] tmp = new byte[end - start];
niobuffer.position(start);
niobuffer.get(tmp);
String value = new String(tmp, 0, 0, end - start);
niobuffer.put(end - 1, (byte)(niobuffer.get(end - 1) | 0x80));
position = end;
niobuffer.position(position);
return value;
}
private String readAscii_slow () {
position--; // Re-read the first byte.
// Copy chars currently in buffer.
int charCount = limit - position;
if (charCount > chars.length) chars = new char[charCount * 2];
char[] chars = this.chars;
for (int i = position, ii = 0, n = limit; i < n; i++, ii++)
chars[ii] = (char)niobuffer.get(i);
position = limit;
// Copy additional chars one by one.
while (true) {
require(1);
position++;
int b = niobuffer.get();
if (charCount == chars.length) {
char[] newChars = new char[charCount * 2];
System.arraycopy(chars, 0, newChars, 0, charCount);
chars = newChars;
this.chars = newChars;
}
if ((b & 0x80) == 0x80) {
chars[charCount++] = (char)(b & 0x7F);
break;
}
chars[charCount++] = (char)b;
}
return new String(chars, 0, charCount);
}
/** Reads the length and string of UTF8 characters, or null. This can read strings written by {@link Output#writeString(String)}
* , {@link Output#writeString(CharSequence)}, and {@link Output#writeAscii(String)}.
* @return May be null. */
public StringBuilder readStringBuilder () {
niobuffer.position(position);
int available = require(1);
position++;
int b = niobuffer.get();
if ((b & 0x80) == 0) return new StringBuilder(readAscii()); // ASCII.
// Null, empty, or UTF8.
int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b);
switch (charCount) {
case 0:
return null;
case 1:
return new StringBuilder("");
}
charCount--;
if (chars.length < charCount) chars = new char[charCount];
readUtf8(charCount);
StringBuilder builder = new StringBuilder(charCount);
builder.append(chars, 0, charCount);
return builder;
}
/** Reads a 4 byte float. */
public float readFloat () throws KryoException {
require(4);
position += 4;
return niobuffer.getFloat();
}
/** Reads a 1-5 byte float with reduced precision. */
public float readFloat (float precision, boolean optimizePositive) throws KryoException {
return readInt(optimizePositive) / (float)precision;
}
/** Reads a 2 byte short. */
public short readShort () throws KryoException {
require(2);
position += 2;
return niobuffer.getShort();
}
/** Reads a 2 byte short as an int from 0 to 65535. */
public int readShortUnsigned () throws KryoException {
require(2);
position += 2;
return niobuffer.getShort();
}
/** Reads an 8 byte long. */
public long readLong () throws KryoException {
require(8);
position += 8;
return niobuffer.getLong();
}
/** {@inheritDoc} */
public long readLong (boolean optimizePositive) throws KryoException {
if (varIntsEnabled)
return readVarLong(optimizePositive);
else
return readLong();
}
/** {@inheritDoc} */
public long readVarLong (boolean optimizePositive) throws KryoException {
niobuffer.position(position);
if (require(1) < 9) return readLong_slow(optimizePositive);
position++;
int b = niobuffer.get();
long result = b & 0x7F;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
position++;
b = niobuffer.get();
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) result = (result >>> 1) ^ -(result & 1);
return result;
}
private long readLong_slow (boolean optimizePositive) {
// The buffer is guaranteed to have at least 1 byte.
position++;
int b = niobuffer.get();
long result = b & 0x7F;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
require(1);
position++;
b = niobuffer.get();
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) result = (result >>> 1) ^ -(result & 1);
return result;
}
/** Reads a 1 byte boolean. */
public boolean readBoolean () throws KryoException {
require(1);
position++;
return niobuffer.get() == 1 ? true : false;
}
/** Reads a 2 byte char. */
public char readChar () throws KryoException {
require(2);
position += 2;
return niobuffer.getChar();
}
/** Reads an 8 bytes double. */
public double readDouble () throws KryoException {
require(8);
position += 8;
return niobuffer.getDouble();
}
/** Reads a 1-9 byte double with reduced precision. */
public double readDouble (double precision, boolean optimizePositive) throws KryoException {
return readLong(optimizePositive) / (double)precision;
}
// Methods implementing bulk operations on arrays of primitive types
/** Bulk input of an int array. */
public int[] readInts (int length) throws KryoException {
if (capacity - position >= length * 4 && isNativeOrder()) {
int[] array = new int[length];
IntBuffer buf = niobuffer.asIntBuffer();
buf.get(array);
position += length * 4;
niobuffer.position(position);
return array;
} else
return super.readInts(length);
}
/** Bulk input of a long array. */
public long[] readLongs (int length) throws KryoException {
if (capacity - position >= length * 8 && isNativeOrder()) {
long[] array = new long[length];
LongBuffer buf = niobuffer.asLongBuffer();
buf.get(array);
position += length * 8;
niobuffer.position(position);
return array;
} else
return super.readLongs(length);
}
/** Bulk input of a float array. */
public float[] readFloats (int length) throws KryoException {
if (capacity - position >= length * 4 && isNativeOrder()) {
float[] array = new float[length];
FloatBuffer buf = niobuffer.asFloatBuffer();
buf.get(array);
position += length * 4;
niobuffer.position(position);
return array;
} else
return super.readFloats(length);
}
/** Bulk input of a short array. */
public short[] readShorts (int length) throws KryoException {
if (capacity - position >= length * 2 && isNativeOrder()) {
short[] array = new short[length];
ShortBuffer buf = niobuffer.asShortBuffer();
buf.get(array);
position += length * 2;
niobuffer.position(position);
return array;
} else
return super.readShorts(length);
}
/** Bulk input of a char array. */
public char[] readChars (int length) throws KryoException {
if (capacity - position >= length * 2 && isNativeOrder()) {
char[] array = new char[length];
CharBuffer buf = niobuffer.asCharBuffer();
buf.get(array);
position += length * 2;
niobuffer.position(position);
return array;
} else
return super.readChars(length);
}
/** Bulk input of a double array. */
public double[] readDoubles (int length) throws KryoException {
if (capacity - position >= length * 8 && isNativeOrder()) {
double[] array = new double[length];
DoubleBuffer buf = niobuffer.asDoubleBuffer();
buf.get(array);
position += length * 8;
niobuffer.position(position);
return array;
} else
return super.readDoubles(length);
}
private boolean isNativeOrder () {
return byteOrder == nativeOrder;
}
/*** Return current setting for variable length encoding of integers
* @return current setting for variable length encoding of integers */
public boolean getVarIntsEnabled () {
return varIntsEnabled;
}
/*** Controls if a variable length encoding for integer types should be used when serializers suggest it.
*
* @param varIntsEnabled */
public void setVarIntsEnabled (boolean varIntsEnabled) {
this.varIntsEnabled = varIntsEnabled;
}
}