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

org.agrona.concurrent.UnsafeBuffer Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
/*
 * Copyright 2014-2015 Real Logic Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.agrona.concurrent;

import org.agrona.BufferUtil;
import org.agrona.DirectBuffer;
import org.agrona.MutableDirectBuffer;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.agrona.BitUtil.*;
import static org.agrona.BufferUtil.*;
import static org.agrona.UnsafeAccess.UNSAFE;

/**
 * Supports regular, byte ordered, and atomic (memory ordered) access to an underlying buffer.
 * The buffer can be a byte[], one of the various {@link ByteBuffer} implementations, or an off Java heap memory address.
 * 

* {@link ByteOrder} of a wrapped buffer is not applied to the {@link UnsafeBuffer}; {@link UnsafeBuffer}s are * stateless and can be used concurrently. To control {@link ByteOrder} use the appropriate accessor method * with the {@link ByteOrder} overload. *

* Note: This class has a natural ordering that is inconsistent with equals. * Types my be different but equal on buffer contents. *

* Note: The wrap methods on this class are not thread safe. Concurrent access should only happen after a successful wrap. */ public class UnsafeBuffer implements AtomicBuffer { /** * Buffer alignment to ensure atomic word accesses. */ public static final int ALIGNMENT = SIZE_OF_LONG; public static final String DISABLE_BOUNDS_CHECKS_PROP_NAME = "agrona.disable.bounds.checks"; public static final boolean SHOULD_BOUNDS_CHECK = !Boolean.getBoolean(DISABLE_BOUNDS_CHECKS_PROP_NAME); private long addressOffset; private int capacity; private byte[] byteArray; private ByteBuffer byteBuffer; /** * Attach a view to a byte[] for providing direct access. * * @param buffer to which the view is attached. */ public UnsafeBuffer(final byte[] buffer) { wrap(buffer); } /** * Attach a view to a byte[] for providing direct access. * * @param buffer to which the view is attached. * @param offset within the buffer to begin. * @param length of the buffer to be included. */ public UnsafeBuffer(final byte[] buffer, final int offset, final int length) { wrap(buffer, offset, length); } /** * Attach a view to a {@link ByteBuffer} for providing direct access, the {@link ByteBuffer} can be * heap based or direct. * * @param buffer to which the view is attached. */ public UnsafeBuffer(final ByteBuffer buffer) { wrap(buffer); } /** * Attach a view to a {@link ByteBuffer} for providing direct access, the {@link ByteBuffer} can be * heap based or direct. * * @param buffer to which the view is attached. * @param offset within the buffer to begin. * @param length of the buffer to be included. */ public UnsafeBuffer(final ByteBuffer buffer, final int offset, final int length) { wrap(buffer, offset, length); } /** * Attach a view to an existing {@link DirectBuffer} * * @param buffer to which the view is attached. */ public UnsafeBuffer(final DirectBuffer buffer) { wrap(buffer); } /** * Attach a view to an existing {@link DirectBuffer} * * @param buffer to which the view is attached. * @param offset within the buffer to begin. * @param length of the buffer to be included. */ public UnsafeBuffer(final DirectBuffer buffer, final int offset, final int length) { wrap(buffer, offset, length); } /** * Attach a view to an off-heap memory region by address. This is useful for interacting with native libraries. * * @param address where the memory begins off-heap * @param length of the buffer from the given address */ public UnsafeBuffer(final long address, final int length) { wrap(address, length); } public void wrap(final byte[] buffer) { addressOffset = ARRAY_BASE_OFFSET; capacity = buffer.length; byteArray = buffer; byteBuffer = null; } public void wrap(final byte[] buffer, final int offset, final int length) { if (SHOULD_BOUNDS_CHECK) { final int bufferLength = buffer.length; if (offset != 0 && (offset < 0 || offset > bufferLength - 1)) { throw new IllegalArgumentException("offset=" + offset + " not valid for buffer.length=" + bufferLength); } if (length < 0 || length > bufferLength - offset) { throw new IllegalArgumentException( "offset=" + offset + " length=" + length + " not valid for buffer.length=" + bufferLength); } } addressOffset = ARRAY_BASE_OFFSET + offset; capacity = length; byteArray = buffer; byteBuffer = null; } public void wrap(final ByteBuffer buffer) { byteBuffer = buffer; if (buffer.isDirect()) { byteArray = null; addressOffset = address(buffer); } else { byteArray = array(byteBuffer); addressOffset = ARRAY_BASE_OFFSET + arrayOffset(byteBuffer); } capacity = buffer.capacity(); } public void wrap(final ByteBuffer buffer, final int offset, final int length) { if (SHOULD_BOUNDS_CHECK) { final int bufferCapacity = buffer.capacity(); if (offset != 0 && (offset < 0 || offset > bufferCapacity - 1)) { throw new IllegalArgumentException("offset=" + offset + " not valid for buffer.capacity()=" + bufferCapacity); } if (length < 0 || length > bufferCapacity - offset) { throw new IllegalArgumentException( "offset=" + offset + " length=" + length + " not valid for buffer.capacity()=" + bufferCapacity); } } byteBuffer = buffer; if (buffer.isDirect()) { byteArray = null; addressOffset = address(buffer) + offset; } else { byteArray = array(buffer); addressOffset = ARRAY_BASE_OFFSET + arrayOffset(buffer) + offset; } capacity = length; } public void wrap(final DirectBuffer buffer) { addressOffset = buffer.addressOffset(); capacity = buffer.capacity(); byteArray = buffer.byteArray(); byteBuffer = buffer.byteBuffer(); } public void wrap(final DirectBuffer buffer, final int offset, final int length) { if (SHOULD_BOUNDS_CHECK) { final int bufferCapacity = buffer.capacity(); if (offset != 0 && (offset < 0 || offset > bufferCapacity - 1)) { throw new IllegalArgumentException("offset=" + offset + " not valid for buffer.capacity()=" + bufferCapacity); } if (length < 0 || length > bufferCapacity - offset) { throw new IllegalArgumentException( "offset=" + offset + " length=" + length + " not valid for buffer.capacity()=" + bufferCapacity); } } addressOffset = buffer.addressOffset() + offset; capacity = length; byteArray = buffer.byteArray(); byteBuffer = buffer.byteBuffer(); } public void wrap(final long address, final int length) { addressOffset = address; capacity = length; byteArray = null; byteBuffer = null; } public long addressOffset() { return addressOffset; } public byte[] byteArray() { return byteArray; } public ByteBuffer byteBuffer() { return byteBuffer; } public void setMemory(final int index, final int length, final byte value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); } final long indexOffset = addressOffset + index; if (0 == (indexOffset & 1) && length > 64) { // This horrible filth is to encourage the JVM to call memset() when address is even. // TODO: check if this still applies when Java 9 is out!!! UNSAFE.putByte(byteArray, indexOffset, value); UNSAFE.setMemory(byteArray, indexOffset + 1, length - 1, value); } else { UNSAFE.setMemory(byteArray, indexOffset, length, value); } } public int capacity() { return capacity; } public void checkLimit(final int limit) { if (limit > capacity) { final String msg = String.format("limit=%d is beyond capacity=%d", limit, capacity); throw new IndexOutOfBoundsException(msg); } } public boolean isExpandable() { return false; } public void verifyAlignment() { if (0 != (addressOffset & (ALIGNMENT - 1))) { throw new IllegalStateException(String.format( "AtomicBuffer is not correctly aligned: addressOffset=%d in not divisible by %d", addressOffset, ALIGNMENT)); } } /////////////////////////////////////////////////////////////////////////// public long getLong(final int index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } long bits = UNSAFE.getLong(byteArray, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = Long.reverseBytes(bits); } return bits; } public void putLong(final int index, final long value, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } long bits = value; if (NATIVE_BYTE_ORDER != byteOrder) { bits = Long.reverseBytes(bits); } UNSAFE.putLong(byteArray, addressOffset + index, bits); } public long getLong(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getLong(byteArray, addressOffset + index); } public void putLong(final int index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } UNSAFE.putLong(byteArray, addressOffset + index, value); } public long getLongVolatile(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getLongVolatile(byteArray, addressOffset + index); } public void putLongVolatile(final int index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } UNSAFE.putLongVolatile(byteArray, addressOffset + index, value); } public void putLongOrdered(final int index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } UNSAFE.putOrderedLong(byteArray, addressOffset + index, value); } public long addLongOrdered(final int index, final long increment) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } final long offset = addressOffset + index; final byte[] byteArray = this.byteArray; final long value = UNSAFE.getLong(byteArray, offset); UNSAFE.putOrderedLong(byteArray, offset, value + increment); return value; } public boolean compareAndSetLong(final int index, final long expectedValue, final long updateValue) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.compareAndSwapLong(byteArray, addressOffset + index, expectedValue, updateValue); } public long getAndSetLong(final int index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getAndSetLong(byteArray, addressOffset + index, value); } public long getAndAddLong(final int index, final long delta) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getAndAddLong(byteArray, addressOffset + index, delta); } /////////////////////////////////////////////////////////////////////////// public int getInt(final int index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } int bits = UNSAFE.getInt(byteArray, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = Integer.reverseBytes(bits); } return bits; } public void putInt(final int index, final int value, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } int bits = value; if (NATIVE_BYTE_ORDER != byteOrder) { bits = Integer.reverseBytes(bits); } UNSAFE.putInt(byteArray, addressOffset + index, bits); } public int getInt(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getInt(byteArray, addressOffset + index); } public void putInt(final int index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } UNSAFE.putInt(byteArray, addressOffset + index, value); } public int getIntVolatile(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getIntVolatile(byteArray, addressOffset + index); } public void putIntVolatile(final int index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } UNSAFE.putIntVolatile(byteArray, addressOffset + index, value); } public void putIntOrdered(final int index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } UNSAFE.putOrderedInt(byteArray, addressOffset + index, value); } public int addIntOrdered(final int index, final int increment) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } final long offset = addressOffset + index; final byte[] byteArray = this.byteArray; final int value = UNSAFE.getInt(byteArray, offset); UNSAFE.putOrderedInt(byteArray, offset, value + increment); return value; } public boolean compareAndSetInt(final int index, final int expectedValue, final int updateValue) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.compareAndSwapInt(byteArray, addressOffset + index, expectedValue, updateValue); } public int getAndSetInt(final int index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getAndSetInt(byteArray, addressOffset + index, value); } public int getAndAddInt(final int index, final int delta) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getAndAddInt(byteArray, addressOffset + index, delta); } /////////////////////////////////////////////////////////////////////////// public double getDouble(final int index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } if (NATIVE_BYTE_ORDER != byteOrder) { final long bits = UNSAFE.getLong(byteArray, addressOffset + index); return Double.longBitsToDouble(Long.reverseBytes(bits)); } else { return UNSAFE.getDouble(byteArray, addressOffset + index); } } public void putDouble(final int index, final double value, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } if (NATIVE_BYTE_ORDER != byteOrder) { final long bits = Long.reverseBytes(Double.doubleToRawLongBits(value)); UNSAFE.putLong(byteArray, addressOffset + index, bits); } else { UNSAFE.putDouble(byteArray, addressOffset + index, value); } } public double getDouble(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } return UNSAFE.getDouble(byteArray, addressOffset + index); } public void putDouble(final int index, final double value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } UNSAFE.putDouble(byteArray, addressOffset + index, value); } /////////////////////////////////////////////////////////////////////////// public float getFloat(final int index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } if (NATIVE_BYTE_ORDER != byteOrder) { final int bits = UNSAFE.getInt(byteArray, addressOffset + index); return Float.intBitsToFloat(Integer.reverseBytes(bits)); } else { return UNSAFE.getFloat(byteArray, addressOffset + index); } } public void putFloat(final int index, final float value, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } if (NATIVE_BYTE_ORDER != byteOrder) { final int bits = Integer.reverseBytes(Float.floatToRawIntBits(value)); UNSAFE.putInt(byteArray, addressOffset + index, bits); } else { UNSAFE.putFloat(byteArray, addressOffset + index, value); } } public float getFloat(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } return UNSAFE.getFloat(byteArray, addressOffset + index); } public void putFloat(final int index, final float value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } UNSAFE.putFloat(byteArray, addressOffset + index, value); } /////////////////////////////////////////////////////////////////////////// public short getShort(final int index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } short bits = UNSAFE.getShort(byteArray, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = Short.reverseBytes(bits); } return bits; } public void putShort(final int index, final short value, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } short bits = value; if (NATIVE_BYTE_ORDER != byteOrder) { bits = Short.reverseBytes(bits); } UNSAFE.putShort(byteArray, addressOffset + index, bits); } public short getShort(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } return UNSAFE.getShort(byteArray, addressOffset + index); } public void putShort(final int index, final short value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } UNSAFE.putShort(byteArray, addressOffset + index, value); } public short getShortVolatile(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } return UNSAFE.getShortVolatile(byteArray, addressOffset + index); } public void putShortVolatile(final int index, final short value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } UNSAFE.putShortVolatile(byteArray, addressOffset + index, value); } /////////////////////////////////////////////////////////////////////////// public byte getByte(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } return UNSAFE.getByte(byteArray, addressOffset + index); } public void putByte(final int index, final byte value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } UNSAFE.putByte(byteArray, addressOffset + index, value); } public byte getByteVolatile(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } return UNSAFE.getByteVolatile(byteArray, addressOffset + index); } public void putByteVolatile(final int index, final byte value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } UNSAFE.putByteVolatile(byteArray, addressOffset + index, value); } public void getBytes(final int index, final byte[] dst) { getBytes(index, dst, 0, dst.length); } public void getBytes(final int index, final byte[] dst, final int offset, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(dst, offset, length); } UNSAFE.copyMemory(byteArray, addressOffset + index, dst, ARRAY_BASE_OFFSET + offset, length); } public void getBytes(final int index, final MutableDirectBuffer dstBuffer, final int dstIndex, final int length) { dstBuffer.putBytes(dstIndex, this, index, length); } public void getBytes(final int index, final ByteBuffer dstBuffer, final int length) { final int dstOffset = dstBuffer.position(); getBytes(index, dstBuffer, dstOffset, length); dstBuffer.position(dstOffset + length); } public void getBytes(final int index, final ByteBuffer dstBuffer, final int dstOffset, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(dstBuffer, (long)dstOffset, length); } final byte[] dstByteArray; final long dstBaseOffset; if (dstBuffer.isDirect()) { dstByteArray = null; dstBaseOffset = address(dstBuffer); } else { dstByteArray = array(dstBuffer); dstBaseOffset = ARRAY_BASE_OFFSET + arrayOffset(dstBuffer); } UNSAFE.copyMemory(byteArray, addressOffset + index, dstByteArray, dstBaseOffset + dstOffset, length); } public void putBytes(final int index, final byte[] src) { putBytes(index, src, 0, src.length); } public void putBytes(final int index, final byte[] src, final int offset, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(src, offset, length); } UNSAFE.copyMemory(src, ARRAY_BASE_OFFSET + offset, byteArray, addressOffset + index, length); } public void putBytes(final int index, final ByteBuffer srcBuffer, final int length) { final int srcIndex = srcBuffer.position(); putBytes(index, srcBuffer, srcIndex, length); srcBuffer.position(srcIndex + length); } public void putBytes(final int index, final ByteBuffer srcBuffer, final int srcIndex, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(srcBuffer, srcIndex, length); } final byte[] srcByteArray; final long srcBaseOffset; if (srcBuffer.isDirect()) { srcByteArray = null; srcBaseOffset = address(srcBuffer); } else { srcByteArray = array(srcBuffer); srcBaseOffset = ARRAY_BASE_OFFSET + arrayOffset(srcBuffer); } UNSAFE.copyMemory(srcByteArray, srcBaseOffset + srcIndex, byteArray, addressOffset + index, length); } public void putBytes(final int index, final DirectBuffer srcBuffer, final int srcIndex, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); srcBuffer.boundsCheck(srcIndex, length); } UNSAFE.copyMemory( srcBuffer.byteArray(), srcBuffer.addressOffset() + srcIndex, byteArray, addressOffset + index, length); } /////////////////////////////////////////////////////////////////////////// public char getChar(final int index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } char bits = UNSAFE.getChar(byteArray, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = (char)Short.reverseBytes((short)bits); } return bits; } public void putChar(final int index, final char value, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } char bits = value; if (NATIVE_BYTE_ORDER != byteOrder) { bits = (char)Short.reverseBytes((short)bits); } UNSAFE.putChar(byteArray, addressOffset + index, bits); } public char getChar(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } return UNSAFE.getChar(byteArray, addressOffset + index); } public void putChar(final int index, final char value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } UNSAFE.putChar(byteArray, addressOffset + index, value); } public char getCharVolatile(final int index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } return UNSAFE.getCharVolatile(byteArray, addressOffset + index); } public void putCharVolatile(final int index, final char value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } UNSAFE.putCharVolatile(byteArray, addressOffset + index, value); } /////////////////////////////////////////////////////////////////////////// public String getStringUtf8(final int index) { final int length = getInt(index); return getStringUtf8(index, length); } public String getStringUtf8(final int index, final ByteOrder byteOrder) { final int length = getInt(index, byteOrder); return getStringUtf8(index, length); } public String getStringUtf8(final int index, final int length) { final byte[] stringInBytes = new byte[length]; getBytes(index + SIZE_OF_INT, stringInBytes); return new String(stringInBytes, UTF_8); } public int putStringUtf8(final int index, final String value) { return putStringUtf8(index, value, Integer.MAX_VALUE); } public int putStringUtf8(final int index, final String value, final ByteOrder byteOrder) { return putStringUtf8(index, value, byteOrder, Integer.MAX_VALUE); } public int putStringUtf8(final int index, final String value, final int maxEncodedSize) { final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES; if (bytes.length > maxEncodedSize) { throw new IllegalArgumentException("Encoded string larger than maximum size: " + maxEncodedSize); } putInt(index, bytes.length); putBytes(index + SIZE_OF_INT, bytes); return SIZE_OF_INT + bytes.length; } public int putStringUtf8(final int index, final String value, final ByteOrder byteOrder, final int maxEncodedSize) { final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES; if (bytes.length > maxEncodedSize) { throw new IllegalArgumentException("Encoded string larger than maximum size: " + maxEncodedSize); } putInt(index, bytes.length, byteOrder); putBytes(index + SIZE_OF_INT, bytes); return SIZE_OF_INT + bytes.length; } public String getStringWithoutLengthUtf8(final int index, final int length) { final byte[] stringInBytes = new byte[length]; getBytes(index, stringInBytes); return new String(stringInBytes, UTF_8); } public int putStringWithoutLengthUtf8(final int index, final String value) { final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES; putBytes(index, bytes); return bytes.length; } /////////////////////////////////////////////////////////////////////////// private void boundsCheck(final int index) { if (index < 0 || index >= capacity) { throw new IndexOutOfBoundsException(String.format("index=%d, capacity=%d", index, capacity)); } } private void boundsCheck0(final int index, final int length) { final long resultingPosition = index + (long)length; if (index < 0 || resultingPosition > capacity) { throw new IndexOutOfBoundsException(String.format("index=%d, length=%d, capacity=%d", index, length, capacity)); } } public void boundsCheck(final int index, final int length) { boundsCheck0(index, length); } public int wrapAdjustment() { final long offset = (byteArray != null) ? ARRAY_BASE_OFFSET : BufferUtil.address(byteBuffer); return (int) (addressOffset - offset); } /////////////////////////////////////////////////////////////////////////// public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } final UnsafeBuffer that = (UnsafeBuffer)obj; if (capacity != that.capacity) { return false; } final byte[] thisByteArray = this.byteArray; final byte[] thatByteArray = that.byteArray; final long thisOffset = this.addressOffset; final long thatOffset = that.addressOffset; for (int i = 0, length = capacity; i < length; i++) { if (UNSAFE.getByte(thisByteArray, thisOffset + i) != UNSAFE.getByte(thatByteArray, thatOffset + i)) { return false; } } return true; } public int hashCode() { int hashCode = 1; final byte[] byteArray = this.byteArray; final long addressOffset = this.addressOffset; for (int i = 0, length = capacity; i < length; i++) { hashCode = 31 * hashCode + UNSAFE.getByte(byteArray, addressOffset + i); } return hashCode; } public int compareTo(final DirectBuffer that) { final int thisCapacity = this.capacity; final int thatCapacity = that.capacity(); final byte[] thisByteArray = this.byteArray; final byte[] thatByteArray = that.byteArray(); final long thisOffset = this.addressOffset; final long thatOffset = that.addressOffset(); for (int i = 0, length = Math.min(thisCapacity, thatCapacity); i < length; i++) { final int cmp = Byte.compare( UNSAFE.getByte(thisByteArray, thisOffset + i), UNSAFE.getByte(thatByteArray, thatOffset + i)); if (0 != cmp) { return cmp; } } if (thisCapacity != thatCapacity) { return thisCapacity - thatCapacity; } return 0; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy