All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.esotericsoftware.kryo.io.UnsafeMemoryOutput 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 static com.esotericsoftware.kryo.util.UnsafeUtil.*;

import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.util.Util;

import sun.nio.ch.DirectBuffer;

/** An optimized OutputStream that writes data directly into the off-heap memory. Utility methods are provided for efficiently
 * writing primitive types, arrays of primitive types and strings. It uses @link{sun.misc.Unsafe} to achieve a very good
 * performance.
 * 
 * 

* Important notes:
*

  • This class increases performance, but may result in bigger size of serialized representation.
  • *
  • Bulk operations, e.g. on arrays of primitive types, are always using native byte order.
  • *
  • Fixed-size char, int, long, short, float and double elements are always written using native byte order.
  • *
  • Best performance is achieved if no variable length encoding for integers is used.
  • *
  • Output serialized using this class should always be deserilized using @link{UnsafeMemoryInput}
  • * *

    * @author Roman Levenstein */ public final class UnsafeMemoryOutput extends ByteBufferOutput { /** Start address of the memory buffer The memory buffer should be non-movable, which normally means that is is allocated * off-heap */ private long bufaddress; private final static boolean isLittleEndian = ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN); { varIntsEnabled = false; } /** Creates an uninitialized Output. {@link #setBuffer(byte[])} must be called before the Output is used. */ public UnsafeMemoryOutput () { } /** Creates a new Output for writing to a byte array. * * @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */ public UnsafeMemoryOutput (int bufferSize) { this(bufferSize, bufferSize); } /** Creates a new Output for writing to a byte array. * * @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 UnsafeMemoryOutput (int bufferSize, int maxBufferSize) { super(bufferSize, maxBufferSize); updateBufferAddress(); } /** Creates a new Output for writing to an OutputStream. A buffer size of 4096 is used. */ public UnsafeMemoryOutput (OutputStream outputStream) { super(outputStream); updateBufferAddress(); } /** Creates a new Output for writing to an OutputStream. */ public UnsafeMemoryOutput (OutputStream outputStream, int bufferSize) { super(outputStream, bufferSize); updateBufferAddress(); } public UnsafeMemoryOutput (long address, int maxBufferSize) { super(address, maxBufferSize); updateBufferAddress(); } public void setBuffer (ByteBuffer buffer, int maxBufferSize) { super.setBuffer(buffer, maxBufferSize); updateBufferAddress(); } private void updateBufferAddress () { bufaddress = ((DirectBuffer)super.niobuffer).address(); } /** Writes a 4 byte int. */ final public void writeInt (int value) throws KryoException { require(4); unsafe().putInt(bufaddress + position, value); position += 4; } /** Writes a 4 byte float. */ final public void writeFloat (float value) throws KryoException { require(4); unsafe().putFloat(bufaddress + position, value); position += 4; } /** Writes a 2 byte short. */ final public void writeShort (int value) throws KryoException { require(2); unsafe().putShort(bufaddress + position, (short)value); position += 2; } /** Writes an 8 byte long. */ final public void writeLong (long value) throws KryoException { require(8); unsafe().putLong(bufaddress + position, value); position += 8; } final public void writeByte (int value) throws KryoException { super.niobuffer.position(position); super.writeByte(value); } public void writeByte (byte value) throws KryoException { super.niobuffer.position(position); super.writeByte(value); } /** Writes a 1 byte boolean. */ final public void writeBoolean (boolean value) throws KryoException { super.niobuffer.position(position); super.writeBoolean(value); } /** Writes a 2 byte char. */ final public void writeChar (char value) throws KryoException { require(2); unsafe().putChar(bufaddress + position, value); position += 2; } /** Writes an 8 byte double. */ final public void writeDouble (double value) throws KryoException { require(8); unsafe().putDouble(bufaddress + position, value); position += 8; } final public int writeInt (int value, boolean optimizePositive) throws KryoException { if (!varIntsEnabled) { writeInt(value); return 4; } else return writeVarInt(value, optimizePositive); } final public int writeLong (long value, boolean optimizePositive) throws KryoException { if (!varIntsEnabled) { writeLong(value); return 8; } else return writeVarLong(value, optimizePositive); } final public int writeVarInt (int val, boolean optimizePositive) throws KryoException { long value = val; if (!optimizePositive) value = (value << 1) ^ (value >> 31); long varInt = 0; varInt = (value & 0x7F); value >>>= 7; if (value == 0) { writeByte((byte)varInt); return 1; } varInt |= 0x80; varInt |= ((value & 0x7F) << 8); value >>>= 7; if (value == 0) { writeLittleEndianInt((int)varInt); position -= 2; return 2; } varInt |= (0x80 << 8); varInt |= ((value & 0x7F) << 16); value >>>= 7; if (value == 0) { writeLittleEndianInt((int)varInt); position -= 1; return 3; } varInt |= (0x80 << 16); varInt |= ((value & 0x7F) << 24); value >>>= 7; if (value == 0) { writeLittleEndianInt((int)varInt); position -= 0; return 4; } varInt |= (0x80L << 24); varInt |= ((value & 0x7F) << 32); varInt &= 0xFFFFFFFFFL; writeLittleEndianLong(varInt); position -= 3; return 5; } final 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) { writeLittleEndianInt(varInt); position -= 2; return 2; } varInt |= (0x80 << 8); varInt |= ((value & 0x7F) << 16); value >>>= 7; if (value == 0) { writeLittleEndianInt(varInt); position -= 1; return 3; } varInt |= (0x80 << 16); varInt |= ((value & 0x7F) << 24); value >>>= 7; if (value == 0) { writeLittleEndianInt(varInt); position -= 0; return 4; } varInt |= (0x80L << 24); long varLong = (varInt & 0xFFFFFFFFL); varLong |= ((value & 0x7F) << 32); value >>>= 7; if (value == 0) { writeLittleEndianLong(varLong); position -= 3; return 5; } varLong |= (0x80L << 32); varLong |= ((value & 0x7F) << 40); value >>>= 7; if (value == 0) { writeLittleEndianLong(varLong); position -= 2; return 6; } varLong |= (0x80L << 40); varLong |= ((value & 0x7F) << 48); value >>>= 7; if (value == 0) { writeLittleEndianLong(varLong); position -= 1; return 7; } varLong |= (0x80L << 48); varLong |= ((value & 0x7F) << 56); value >>>= 7; if (value == 0) { writeLittleEndianLong(varLong); return 8; } varLong |= (0x80L << 56); writeLittleEndianLong(varLong); writeByte((int)(value & 0xFF)); return 9; } final private void writeLittleEndianInt (int val) { if (isLittleEndian) writeInt(val); else writeInt(Util.swapInt(val)); } final private void writeLittleEndianLong (long val) { if (isLittleEndian) writeLong(val); else writeLong(Util.swapLong(val)); } // Methods implementing bulk operations on arrays of primitive types final public void writeInts (int[] object, boolean optimizePositive) throws KryoException { if (!varIntsEnabled) { int bytesToCopy = object.length << 2; writeBytes(object, intArrayBaseOffset, 0, bytesToCopy); } else super.writeInts(object, optimizePositive); } final public void writeLongs (long[] object, boolean optimizePositive) throws KryoException { if (!varIntsEnabled) { int bytesToCopy = object.length << 3; writeBytes(object, longArrayBaseOffset, 0, bytesToCopy); } else super.writeLongs(object, optimizePositive); } final public void writeInts (int[] object) throws KryoException { int bytesToCopy = object.length << 2; writeBytes(object, intArrayBaseOffset, 0, bytesToCopy); } final public void writeLongs (long[] object) throws KryoException { int bytesToCopy = object.length << 3; writeBytes(object, longArrayBaseOffset, 0, bytesToCopy); } final public void writeFloats (float[] object) throws KryoException { int bytesToCopy = object.length << 2; writeBytes(object, floatArrayBaseOffset, 0, bytesToCopy); } final public void writeShorts (short[] object) throws KryoException { int bytesToCopy = object.length << 1; writeBytes(object, shortArrayBaseOffset, 0, bytesToCopy); } final public void writeChars (char[] object) throws KryoException { int bytesToCopy = object.length << 1; writeBytes(object, charArrayBaseOffset, 0, bytesToCopy); } final public void writeDoubles (double[] object) throws KryoException { int bytesToCopy = object.length << 3; writeBytes(object, doubleArrayBaseOffset, 0, bytesToCopy); } /** 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, (long)bytes.length); } /*** Output count bytes from a memory region starting at the given #{offset} inside the in-memory representation of obj object. * @param obj * @param offset * @param count */ final public void writeBytes (Object obj, long offset, long count) throws KryoException { writeBytes(obj, byteArrayBaseOffset, offset, count); } /*** Output count bytes from a memory region starting at the given #{offset} inside the in-memory representation of obj object. * The destination is defined by its address */ final private void writeBytes (Object srcArray, long srcArrayTypeOffset, long srcOffset, long count) throws KryoException { int copyCount = Math.min(capacity - position, (int)count); while (true) { unsafe().copyMemory(srcArray, srcArrayTypeOffset + srcOffset, null, bufaddress + position, copyCount); position += copyCount; count -= copyCount; if (count == 0) return; srcOffset += copyCount; copyCount = Math.min(capacity, (int)count); require(copyCount); } } }




    © 2015 - 2024 Weber Informatics LLC | Privacy Policy