com.esotericsoftware.kryo.io.ByteBufferOutput Maven / Gradle / Ivy
/* Copyright (c) 2008, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
package com.esotericsoftware.kryo.io;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.util.UnsafeUtil;
import java.io.IOException;
import java.io.OutputStream;
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;
/** An OutputStream that buffers data in a byte array and optionally flushes to another OutputStream. Utility methods are provided
* for efficiently writing primitive types and strings.
*
* @author Roman Levenstein */
public class ByteBufferOutput extends Output {
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 Output. A buffer must be set before the Output is used.
* @see #setBuffer(ByteBuffer, int) */
public ByteBufferOutput () {
}
/** Creates a new Output for writing to a direct ByteBuffer.
* @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
public ByteBufferOutput (int bufferSize) {
this(bufferSize, bufferSize);
}
/** Creates a new Output for writing to a direct ByteBuffer.
* @param bufferSize The initial size of the buffer.
* @param maxBufferSize The buffer is doubled as needed until it exceeds maxBufferSize and an exception is thrown. */
public ByteBufferOutput (int bufferSize, int maxBufferSize) {
if (maxBufferSize < -1) throw new IllegalArgumentException("maxBufferSize cannot be < -1: " + maxBufferSize);
this.capacity = bufferSize;
this.maxCapacity = maxBufferSize == -1 ? Integer.MAX_VALUE : maxBufferSize;
niobuffer = ByteBuffer.allocateDirect(bufferSize);
niobuffer.order(byteOrder);
}
/** Creates a new Output for writing to an OutputStream. A buffer size of 4096 is used. */
public ByteBufferOutput (OutputStream outputStream) {
this(4096, 4096);
if (outputStream == null) throw new IllegalArgumentException("outputStream cannot be null.");
this.outputStream = outputStream;
}
/** Creates a new Output for writing to an OutputStream. */
public ByteBufferOutput (OutputStream outputStream, int bufferSize) {
this(bufferSize, bufferSize);
if (outputStream == null) throw new IllegalArgumentException("outputStream cannot be null.");
this.outputStream = outputStream;
}
/** Creates a new Output for writing to a ByteBuffer. */
public ByteBufferOutput (ByteBuffer buffer) {
setBuffer(buffer);
}
/** Creates a new Output for writing to a ByteBuffer.
* @param maxBufferSize The buffer is doubled as needed until it exceeds maxCapacity and an exception is thrown. */
public ByteBufferOutput (ByteBuffer buffer, int maxBufferSize) {
setBuffer(buffer, maxBufferSize);
}
/** Creates a direct ByteBuffer of a given size at a given address.
*
* Typical usage could look like this snippet:
*
*
* // Explicitly allocate memory
* long bufAddress = UnsafeUtil.unsafe().allocateMemory(4096);
* // Create a ByteBufferOutput using the allocated memory region
* ByteBufferOutput buffer = new ByteBufferOutput(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);
*
* @param address starting address of a memory region pre-allocated using Unsafe.allocateMemory()
* @param maxBufferSize */
public ByteBufferOutput (long address, int maxBufferSize) {
niobuffer = UnsafeUtil.getDirectBufferAt(address, maxBufferSize);
setBuffer(niobuffer, maxBufferSize);
}
/** Release a direct buffer. {@link #setBuffer(ByteBuffer, int)} should be called before next write operations can be called.
*
* NOTE: If Cleaner is not accessible due to SecurityManager restrictions, reflection could be used to obtain the "clean"
* method and then invoke it. */
public void release () {
clear();
UnsafeUtil.releaseBuffer(niobuffer);
niobuffer = null;
}
public ByteOrder order () {
return byteOrder;
}
public void order (ByteOrder byteOrder) {
this.byteOrder = byteOrder;
}
public OutputStream getOutputStream () {
return outputStream;
}
/** Sets a new OutputStream. The position and total are reset, discarding any buffered bytes.
* @param outputStream May be null. */
public void setOutputStream (OutputStream outputStream) {
this.outputStream = outputStream;
position = 0;
total = 0;
}
/** Sets the buffer that will be written to. maxCapacity is set to the specified buffer's capacity.
* @see #setBuffer(ByteBuffer, int) */
public void setBuffer (ByteBuffer buffer) {
setBuffer(buffer, buffer.capacity());
}
/** Sets the buffer that will be written to. The byte order, position and capacity are set to match the specified buffer. The
* total is set to 0. The {@link #setOutputStream(OutputStream) OutputStream} is set to null.
* @param maxBufferSize The buffer is doubled as needed until it exceeds maxCapacity and an exception is thrown. */
public void setBuffer (ByteBuffer buffer, int maxBufferSize) {
if (buffer == null) throw new IllegalArgumentException("buffer cannot be null.");
if (maxBufferSize < -1) throw new IllegalArgumentException("maxBufferSize cannot be < -1: " + maxBufferSize);
this.niobuffer = buffer;
this.maxCapacity = maxBufferSize == -1 ? Integer.MAX_VALUE : maxBufferSize;
byteOrder = buffer.order();
capacity = buffer.capacity();
position = buffer.position();
total = 0;
outputStream = null;
}
/** Returns the buffer. The bytes between zero and {@link #position()} are the data that has been written. */
public ByteBuffer getByteBuffer () {
niobuffer.position(position);
return niobuffer;
}
/** Returns a new byte array containing the bytes currently in the buffer between zero and {@link #position()}. */
public byte[] toBytes () {
byte[] newBuffer = new byte[position];
niobuffer.position(0);
niobuffer.get(newBuffer, 0, position);
return newBuffer;
}
/** Sets the current position in the buffer. */
public void setPosition (int position) {
this.position = position;
}
/** Sets the position and total to zero. */
public void clear () {
niobuffer.clear();
position = 0;
total = 0;
}
/** @return true if the buffer has been resized. */
protected boolean require (int required) throws KryoException {
if (capacity - position >= required) return false;
if (required > maxCapacity)
throw new KryoException("Buffer overflow. Max capacity: " + maxCapacity + ", required: " + required);
flush();
while (capacity - position < required) {
if (capacity == maxCapacity)
throw new KryoException("Buffer overflow. Available: " + (capacity - position) + ", required: " + required);
// Grow buffer.
if (capacity == 0) capacity = 1;
capacity = Math.min(capacity * 2, maxCapacity);
if (capacity < 0) capacity = maxCapacity;
ByteBuffer newBuffer = (niobuffer != null && !niobuffer.isDirect()) ? ByteBuffer.allocate(capacity) : ByteBuffer
.allocateDirect(capacity);
// Copy the whole buffer
niobuffer.position(0);
niobuffer.limit(position);
newBuffer.put(niobuffer);
newBuffer.order(niobuffer.order());
niobuffer = newBuffer;
}
return true;
}
// OutputStream
/** Writes the buffered bytes to the underlying OutputStream, if any. */
public void flush () throws KryoException {
if (outputStream == null) return;
try {
byte[] tmp = new byte[position];
niobuffer.position(0);
niobuffer.get(tmp);
niobuffer.position(0);
outputStream.write(tmp, 0, position);
} catch (IOException ex) {
throw new KryoException(ex);
}
total += position;
position = 0;
}
/** Flushes any buffered bytes and closes the underlying OutputStream, if any. */
public void close () throws KryoException {
flush();
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ignored) {
}
}
}
/** Writes a byte. */
public void write (int value) throws KryoException {
if (position == capacity) require(1);
niobuffer.put((byte)value);
position++;
}
/** Writes the bytes. Note the byte[] length is not written. */
public void write (byte[] bytes) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
writeBytes(bytes, 0, bytes.length);
}
/** Writes the bytes. Note the byte[] length is not written. */
public void write (byte[] bytes, int offset, int length) throws KryoException {
writeBytes(bytes, offset, length);
}
// byte
public void writeByte (byte value) throws KryoException {
if (position == capacity) require(1);
niobuffer.put(value);
position++;
}
public void writeByte (int value) throws KryoException {
if (position == capacity) require(1);
niobuffer.put((byte)value);
position++;
}
/** Writes the bytes. Note the byte[] length is not written. */
public void writeBytes (byte[] bytes) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
writeBytes(bytes, 0, bytes.length);
}
/** Writes the bytes. Note the byte[] length is not written. */
public void writeBytes (byte[] bytes, int offset, int count) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
int copyCount = Math.min(capacity - position, count);
while (true) {
niobuffer.put(bytes, offset, copyCount);
position += copyCount;
count -= copyCount;
if (count == 0) return;
offset += copyCount;
copyCount = Math.min(capacity, count);
require(copyCount);
}
}
// int
/** Writes a 4 byte int. */
public void writeInt (int value) throws KryoException {
require(4);
niobuffer.putInt(value);
position += 4;
}
public int writeInt (int value, boolean optimizePositive) throws KryoException {
if (!varIntsEnabled) {
writeInt(value);
return 4;
} else
return writeVarInt(value, optimizePositive);
}
public int writeVarInt (int val, boolean optimizePositive) throws KryoException {
niobuffer.position(position);
int value = val;
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
int varInt = 0;
varInt = (value & 0x7F);
value >>>= 7;
if (value == 0) {
writeByte(varInt);
return 1;
}
varInt |= 0x80;
varInt |= ((value & 0x7F) << 8);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeInt(varInt);
niobuffer.order(byteOrder);
position -= 2;
niobuffer.position(position);
return 2;
}
varInt |= (0x80 << 8);
varInt |= ((value & 0x7F) << 16);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeInt(varInt);
niobuffer.order(byteOrder);
position -= 1;
niobuffer.position(position);
return 3;
}
varInt |= (0x80 << 16);
varInt |= ((value & 0x7F) << 24);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeInt(varInt);
niobuffer.order(byteOrder);
position -= 0;
return 4;
}
varInt |= (0x80 << 24);
long varLong = (varInt & 0xFFFFFFFFL) | (((long)value) << 32);
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeLong(varLong);
niobuffer.order(byteOrder);
position -= 3;
niobuffer.position(position);
return 5;
}
// string
/** Writes the length and string, or null. Short strings are checked and if ASCII they are written more efficiently, else they
* are written as UTF8. If a string is known to be ASCII, {@link #writeAscii(String)} may be used. The string can be read using
* {@link Input#readString()} or {@link Input#readStringBuilder()}.
* @param value May be null. */
public void writeString (String value) throws KryoException {
niobuffer.position(position);
if (value == null) {
writeByte(0x80); // 0 means null, bit 8 means UTF8.
return;
}
int charCount = value.length();
if (charCount == 0) {
writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8.
return;
}
// Detect ASCII.
boolean ascii = false;
if (charCount > 1 && charCount < 64) {
ascii = true;
for (int i = 0; i < charCount; i++) {
int c = value.charAt(i);
if (c > 127) {
ascii = false;
break;
}
}
}
if (ascii) {
if (capacity - position < charCount)
writeAscii_slow(value, charCount);
else {
byte[] tmp = value.getBytes();
niobuffer.put(tmp, 0, tmp.length);
position += charCount;
}
niobuffer.put(position - 1, (byte)(niobuffer.get(position - 1) | 0x80));
} else {
writeUtf8Length(charCount + 1);
int charIndex = 0;
if (capacity - position >= charCount) {
// Try to write 8 bit chars.
int position = this.position;
for (; charIndex < charCount; charIndex++) {
int c = value.charAt(charIndex);
if (c > 127) break;
niobuffer.put(position++, (byte)c);
}
this.position = position;
niobuffer.position(position);
}
if (charIndex < charCount) writeString_slow(value, charCount, charIndex);
niobuffer.position(position);
}
}
/** Writes the length and CharSequence as UTF8, or null. The string can be read using {@link Input#readString()} or
* {@link Input#readStringBuilder()}.
* @param value May be null. */
public void writeString (CharSequence value) throws KryoException {
if (value == null) {
writeByte(0x80); // 0 means null, bit 8 means UTF8.
return;
}
int charCount = value.length();
if (charCount == 0) {
writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8.
return;
}
writeUtf8Length(charCount + 1);
int charIndex = 0;
if (capacity - position >= charCount) {
// Try to write 8 bit chars.
int position = this.position;
for (; charIndex < charCount; charIndex++) {
int c = value.charAt(charIndex);
if (c > 127) break;
niobuffer.put(position++, (byte)c);
}
this.position = position;
niobuffer.position(position);
}
if (charIndex < charCount) writeString_slow(value, charCount, charIndex);
niobuffer.position(position);
}
/** Writes a string that is known to contain only ASCII characters. Non-ASCII strings passed to this method will be corrupted.
* Each byte is a 7 bit character with the remaining byte denoting if another character is available. This is slightly more
* efficient than {@link #writeString(String)}. The string can be read using {@link Input#readString()} or
* {@link Input#readStringBuilder()}.
* @param value May be null. */
public void writeAscii (String value) throws KryoException {
if (value == null) {
writeByte(0x80); // 0 means null, bit 8 means UTF8.
return;
}
int charCount = value.length();
if (charCount == 0) {
writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8.
return;
}
if (capacity - position < charCount)
writeAscii_slow(value, charCount);
else {
byte[] tmp = value.getBytes();
niobuffer.put(tmp, 0, tmp.length);
position += charCount;
}
niobuffer.put(position - 1, (byte)(niobuffer.get(position - 1) | 0x80)); // Bit 8 means end of ASCII.
}
/** Writes the length of a string, which is a variable length encoded int except the first byte uses bit 8 to denote UTF8 and
* bit 7 to denote if another byte is present. */
private void writeUtf8Length (int value) {
if (value >>> 6 == 0) {
require(1);
niobuffer.put((byte)(value | 0x80)); // Set bit 8.
position += 1;
} else if (value >>> 13 == 0) {
require(2);
niobuffer.put((byte)(value | 0x40 | 0x80)); // Set bit 7 and 8.
niobuffer.put((byte)(value >>> 6));
position += 2;
} else if (value >>> 20 == 0) {
require(3);
niobuffer.put((byte)(value | 0x40 | 0x80)); // Set bit 7 and 8.
niobuffer.put((byte)((value >>> 6) | 0x80)); // Set bit 8.
niobuffer.put((byte)(value >>> 13));
position += 3;
} else if (value >>> 27 == 0) {
require(4);
niobuffer.put((byte)(value | 0x40 | 0x80)); // Set bit 7 and 8.
niobuffer.put((byte)((value >>> 6) | 0x80)); // Set bit 8.
niobuffer.put((byte)((value >>> 13) | 0x80)); // Set bit 8.
niobuffer.put((byte)(value >>> 20));
position += 4;
} else {
require(5);
niobuffer.put((byte)(value | 0x40 | 0x80)); // Set bit 7 and 8.
niobuffer.put((byte)((value >>> 6) | 0x80)); // Set bit 8.
niobuffer.put((byte)((value >>> 13) | 0x80)); // Set bit 8.
niobuffer.put((byte)((value >>> 20) | 0x80)); // Set bit 8.
niobuffer.put((byte)(value >>> 27));
position += 5;
}
}
private void writeString_slow (CharSequence value, int charCount, int charIndex) {
for (; charIndex < charCount; charIndex++) {
if (position == capacity) require(Math.min(capacity, charCount - charIndex));
int c = value.charAt(charIndex);
if (c <= 0x007F) {
niobuffer.put(position++, (byte)c);
} else if (c > 0x07FF) {
niobuffer.put(position++, (byte)(0xE0 | c >> 12 & 0x0F));
require(2);
niobuffer.put(position++, (byte)(0x80 | c >> 6 & 0x3F));
niobuffer.put(position++, (byte)(0x80 | c & 0x3F));
} else {
niobuffer.put(position++, (byte)(0xC0 | c >> 6 & 0x1F));
require(1);
niobuffer.put(position++, (byte)(0x80 | c & 0x3F));
}
}
}
private void writeAscii_slow (String value, int charCount) throws KryoException {
ByteBuffer buffer = this.niobuffer;
int charIndex = 0;
int charsToWrite = Math.min(charCount, capacity - position);
while (charIndex < charCount) {
byte[] tmp = new byte[charCount];
value.getBytes(charIndex, charIndex + charsToWrite, tmp, 0);
buffer.put(tmp, 0, charsToWrite);
// value.getBytes(charIndex, charIndex + charsToWrite, buffer, position);
charIndex += charsToWrite;
position += charsToWrite;
charsToWrite = Math.min(charCount - charIndex, capacity);
if (require(charsToWrite)) buffer = this.niobuffer;
}
}
// float
/** Writes a 4 byte float. */
public void writeFloat (float value) throws KryoException {
require(4);
niobuffer.putFloat(value);
position += 4;
}
/** Writes a 1-5 byte float with reduced precision.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (5 bytes). */
public int writeFloat (float value, float precision, boolean optimizePositive) throws KryoException {
return writeInt((int)(value * precision), optimizePositive);
}
// short
/** Writes a 2 byte short. */
public void writeShort (int value) throws KryoException {
require(2);
niobuffer.putShort((short)value);
position += 2;
}
// long
/** Writes an 8 byte long. */
public void writeLong (long value) throws KryoException {
require(8);
niobuffer.putLong(value);
position += 8;
}
public int writeLong (long value, boolean optimizePositive) throws KryoException {
if (!varIntsEnabled) {
writeLong(value);
return 8;
} else
return writeVarLong(value, optimizePositive);
}
public int writeVarLong (long value, boolean optimizePositive) throws KryoException {
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
int varInt = 0;
varInt = (int)(value & 0x7F);
value >>>= 7;
if (value == 0) {
writeByte(varInt);
return 1;
}
varInt |= 0x80;
varInt |= ((value & 0x7F) << 8);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeInt(varInt);
niobuffer.order(byteOrder);
position -= 2;
niobuffer.position(position);
return 2;
}
varInt |= (0x80 << 8);
varInt |= ((value & 0x7F) << 16);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeInt(varInt);
niobuffer.order(byteOrder);
position -= 1;
niobuffer.position(position);
return 3;
}
varInt |= (0x80 << 16);
varInt |= ((value & 0x7F) << 24);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeInt(varInt);
niobuffer.order(byteOrder);
position -= 0;
return 4;
}
varInt |= (0x80 << 24);
long varLong = (varInt & 0xFFFFFFFFL);
varLong |= (((long)(value & 0x7F)) << 32);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeLong(varLong);
niobuffer.order(byteOrder);
position -= 3;
niobuffer.position(position);
return 5;
}
varLong |= (0x80L << 32);
varLong |= (((long)(value & 0x7F)) << 40);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeLong(varLong);
niobuffer.order(byteOrder);
position -= 2;
niobuffer.position(position);
return 6;
}
varLong |= (0x80L << 40);
varLong |= (((long)(value & 0x7F)) << 48);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeLong(varLong);
niobuffer.order(byteOrder);
position -= 1;
niobuffer.position(position);
return 7;
}
varLong |= (0x80L << 48);
varLong |= (((long)(value & 0x7F)) << 56);
value >>>= 7;
if (value == 0) {
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeLong(varLong);
niobuffer.order(byteOrder);
return 8;
}
varLong |= (0x80L << 56);
niobuffer.order(ByteOrder.LITTLE_ENDIAN);
writeLong(varLong);
niobuffer.order(byteOrder);
write((byte)(value));
return 9;
}
/** Writes a 1-9 byte long.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes). */
public int writeLongS (long value, boolean optimizePositive) throws KryoException {
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
if (value >>> 7 == 0) {
require(1);
niobuffer.put((byte)value);
position += 1;
return 1;
}
if (value >>> 14 == 0) {
require(2);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7));
position += 2;
return 2;
}
if (value >>> 21 == 0) {
require(3);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14));
position += 3;
return 3;
}
if (value >>> 28 == 0) {
require(4);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14 | 0x80));
niobuffer.put((byte)(value >>> 21));
position += 4;
return 4;
}
if (value >>> 35 == 0) {
require(5);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14 | 0x80));
niobuffer.put((byte)(value >>> 21 | 0x80));
niobuffer.put((byte)(value >>> 28));
position += 5;
return 5;
}
if (value >>> 42 == 0) {
require(6);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14 | 0x80));
niobuffer.put((byte)(value >>> 21 | 0x80));
niobuffer.put((byte)(value >>> 28 | 0x80));
niobuffer.put((byte)(value >>> 35));
position += 6;
return 6;
}
if (value >>> 49 == 0) {
require(7);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14 | 0x80));
niobuffer.put((byte)(value >>> 21 | 0x80));
niobuffer.put((byte)(value >>> 28 | 0x80));
niobuffer.put((byte)(value >>> 35 | 0x80));
niobuffer.put((byte)(value >>> 42));
position += 7;
return 7;
}
if (value >>> 56 == 0) {
require(8);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14 | 0x80));
niobuffer.put((byte)(value >>> 21 | 0x80));
niobuffer.put((byte)(value >>> 28 | 0x80));
niobuffer.put((byte)(value >>> 35 | 0x80));
niobuffer.put((byte)(value >>> 42 | 0x80));
niobuffer.put((byte)(value >>> 49));
position += 8;
return 8;
}
require(9);
niobuffer.put((byte)((value & 0x7F) | 0x80));
niobuffer.put((byte)(value >>> 7 | 0x80));
niobuffer.put((byte)(value >>> 14 | 0x80));
niobuffer.put((byte)(value >>> 21 | 0x80));
niobuffer.put((byte)(value >>> 28 | 0x80));
niobuffer.put((byte)(value >>> 35 | 0x80));
niobuffer.put((byte)(value >>> 42 | 0x80));
niobuffer.put((byte)(value >>> 49 | 0x80));
niobuffer.put((byte)(value >>> 56));
position += 9;
return 9;
}
// boolean
/** Writes a 1 byte boolean. */
public void writeBoolean (boolean value) throws KryoException {
require(1);
niobuffer.put((byte)(value ? 1 : 0));
position++;
}
// char
/** Writes a 2 byte char. */
public void writeChar (char value) throws KryoException {
require(2);
niobuffer.putChar(value);
position += 2;
}
// double
/** Writes an 8 byte double. */
public void writeDouble (double value) throws KryoException {
require(8);
niobuffer.putDouble(value);
position += 8;
}
/** Writes a 1-9 byte double with reduced precision.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes). */
public int writeDouble (double value, double precision, boolean optimizePositive) throws KryoException {
return writeLong((long)(value * precision), optimizePositive);
}
// Methods implementing bulk operations on arrays of primitive types
/** Bulk output of an int array. */
public void writeInts (int[] object) throws KryoException {
if (capacity - position >= object.length * 4 && isNativeOrder()) {
IntBuffer buf = niobuffer.asIntBuffer();
buf.put(object);
position += object.length * 4;
} else
super.writeInts(object);
}
/** Bulk output of an long array. */
public void writeLongs (long[] object) throws KryoException {
if (capacity - position >= object.length * 8 && isNativeOrder()) {
LongBuffer buf = niobuffer.asLongBuffer();
buf.put(object);
position += object.length * 8;
} else
super.writeLongs(object);
}
/** Bulk output of a float array. */
public void writeFloats (float[] object) throws KryoException {
if (capacity - position >= object.length * 4 && isNativeOrder()) {
FloatBuffer buf = niobuffer.asFloatBuffer();
buf.put(object);
position += object.length * 4;
} else
super.writeFloats(object);
}
/** Bulk output of a short array. */
public void writeShorts (short[] object) throws KryoException {
if (capacity - position >= object.length * 2 && isNativeOrder()) {
ShortBuffer buf = niobuffer.asShortBuffer();
buf.put(object);
position += object.length * 2;
} else
super.writeShorts(object);
}
/** Bulk output of a char array. */
public void writeChars (char[] object) throws KryoException {
if (capacity - position >= object.length * 2 && isNativeOrder()) {
CharBuffer buf = niobuffer.asCharBuffer();
buf.put(object);
position += object.length * 2;
} else
super.writeChars(object);
}
/** Bulk output of a double array. */
public void writeDoubles (double[] object) throws KryoException {
if (capacity - position >= object.length * 8 && isNativeOrder()) {
DoubleBuffer buf = niobuffer.asDoubleBuffer();
buf.put(object);
position += object.length * 8;
} else
super.writeDoubles(object);
}
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;
}
}