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

com.fluxtion.agrona.concurrent.MappedResizeableBuffer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2024 Real Logic Limited.
 *
 * 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
 *
 * https://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 com.fluxtion.agrona.concurrent;

import com.fluxtion.agrona.BufferUtil;
import com.fluxtion.agrona.DirectBuffer;
import com.fluxtion.agrona.IoUtil;
import com.fluxtion.agrona.MutableDirectBuffer;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

import static java.nio.charset.StandardCharsets.UTF_8;
import static com.fluxtion.agrona.BitUtil.*;
import static com.fluxtion.agrona.BufferUtil.*;
import static com.fluxtion.agrona.UnsafeAccess.*;
import static com.fluxtion.agrona.concurrent.UnsafeBuffer.*;

/**
 * Supports regular, byte ordered, and atomic (memory ordered) access to an underlying buffer.
 * 

* This buffer is resizable and based upon an underlying FileChannel. * The channel is not closed when the buffer is closed. *

* Note: The resize method is not threadsafe. Concurrent access should only occur after a successful resize. */ @SuppressWarnings("removal") public class MappedResizeableBuffer implements AutoCloseable { private long addressOffset; private long capacity; private FileChannel fileChannel; private FileChannel.MapMode mapMode; /** * Attach a view to an off-heap memory region by address. Defaults to * {@link java.nio.channels.FileChannel.MapMode#READ_WRITE}. * * @param fileChannel the file to map * @param offset the offset of the file to start the mapping * @param initialLength of the buffer from the given address */ public MappedResizeableBuffer(final FileChannel fileChannel, final long offset, final long initialLength) { this.fileChannel = fileChannel; this.mapMode = FileChannel.MapMode.READ_WRITE; map(offset, initialLength); } /** * Attach a view to an off-heap memory region by address. * * @param fileChannel the file to map * @param mapMode for the mapping * @param offset the offset of the file to start the mapping * @param initialLength of the buffer from the given address */ public MappedResizeableBuffer( final FileChannel fileChannel, final FileChannel.MapMode mapMode, final long offset, final long initialLength) { this.fileChannel = fileChannel; this.mapMode = mapMode; map(offset, initialLength); } /** * {@inheritDoc} */ public void close() { unmap(); } /** * Resize the buffer. * * @param newLength in bytes. */ public void resize(final long newLength) { if (newLength <= 0) { throw new IllegalArgumentException("Length must be a positive long, but is: " + newLength); } unmap(); map(0, newLength); } /** * Remap the buffer using the existing file based on a new offset and length * * @param offset the offset of the file to start the mapping * @param length of the buffer from the given address */ public void wrap(final long offset, final long length) { if (offset == addressOffset && length == capacity) { return; } wrap(fileChannel, offset, length); } /** * Remap the buffer based on a new file, offset, and a length * * @param fileChannel the file to map * @param offset the offset of the file to start the mapping * @param length of the buffer from the given address */ public void wrap(final FileChannel fileChannel, final long offset, final long length) { unmap(); this.fileChannel = fileChannel; map(offset, length); } /** * Remap the buffer based on a new file, mapping mode, offset, and a length * * @param fileChannel the file to map * @param mapMode for the file when mapping. * @param offset the offset of the file to start the mapping * @param length of the buffer from the given address */ public void wrap( final FileChannel fileChannel, final FileChannel.MapMode mapMode, final long offset, final long length) { unmap(); this.fileChannel = fileChannel; this.mapMode = mapMode; map(offset, length); } /** * Address offset in memory at which the mapping begins. * * @return the address offset in memory at which the mapping begins. */ public long addressOffset() { return addressOffset; } /** * {@link FileChannel} that this buffer is mapping over. * * @return the {@link FileChannel} that this buffer is mapping over. */ public FileChannel fileChannel() { return fileChannel; } /** * The {@link java.nio.channels.FileChannel.MapMode} that will be used when mapping the file. * * @return {@link java.nio.channels.FileChannel.MapMode} that will be used when mapping the file. */ public FileChannel.MapMode mapMode() { return mapMode; } /** * Set a region of memory to a given byte value. * * @param index at which to start. * @param length of the run of bytes to set. * @param value the memory will be set to. */ public void setMemory(final long index, final int length, final byte value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); } final long offset = addressOffset + index; if (MEMSET_HACK_REQUIRED && length > MEMSET_HACK_THRESHOLD && 0 == (offset & 1)) { // This horrible filth is to encourage the JVM to call memset() when address is even. UNSAFE.putByte(null, offset, value); UNSAFE.setMemory(null, offset + 1, length - 1, value); } else { UNSAFE.setMemory(null, offset, length, value); } } /** * Capacity of the buffer in bytes. * * @return capacity of the buffer in bytes. */ public long capacity() { return capacity; } /** * Check if limit exceeds the capacity. * * @param limit to check. */ public void checkLimit(final long limit) { if (limit > capacity) { throw new IndexOutOfBoundsException("limit=" + limit + " is beyond capacity=" + capacity); } } /** * Verify that the underlying buffer is correctly aligned to prevent word tearing and other ordering issues. * * @throws IllegalStateException if the alignment is not correct. */ public void verifyAlignment() { if (0 != (addressOffset & (ALIGNMENT - 1))) { throw new IllegalStateException( "AtomicBuffer is not correctly aligned: addressOffset=" + addressOffset + " is not divisible by " + ALIGNMENT); } } /** * Get the value at a given index. * * @param index in bytes from which to get. * @param byteOrder of the value to be read. * @return the value for at a given index. */ public long getLong(final long index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } long bits = UNSAFE.getLong(null, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = Long.reverseBytes(bits); } return bits; } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. * @param byteOrder of the value when written. */ public void putLong(final long 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(null, addressOffset + index, bits); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public long getLong(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getLong(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putLong(final long index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } UNSAFE.putLong(null, addressOffset + index, value); } /** * Get the value at a given index with volatile semantics. * * @param index in bytes from which to get. * @return the value for at a given index. */ public long getLongVolatile(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getLongVolatile(null, addressOffset + index); } /** * Put a value to a given index with volatile semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putLongVolatile(final long index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } UNSAFE.putLongVolatile(null, addressOffset + index, value); } /** * Put a value to a given index with ordered store semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putLongOrdered(final long index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } UNSAFE.putOrderedLong(null, addressOffset + index, value); } /** * Add a value to a given index with ordered store semantics. Use a negative increment to decrement. * * @param index in bytes for where to put. * @param increment by which the value at the index will be adjusted. * @return the previous value at the index. */ public long addLongOrdered(final long index, final long increment) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } final long offset = addressOffset + index; final long value = UNSAFE.getLong(null, offset); UNSAFE.putOrderedLong(null, offset, value + increment); return value; } /** * Atomic compare and set of a long given an expected value. * * @param index in bytes for where to put. * @param expectedValue at to be compared. * @param updateValue to be exchanged. * @return set successful or not. */ public boolean compareAndSetLong(final long index, final long expectedValue, final long updateValue) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.compareAndSwapLong(null, addressOffset + index, expectedValue, updateValue); } /** * Atomically exchange a value at a location returning the previous contents. * * @param index in bytes for where to put. * @param value for at a given index. * @return previous value at the index. */ public long getAndSetLong(final long index, final long value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getAndSetLong(null, addressOffset + index, value); } /** * Atomically add a delta to a value at a location returning the previous contents. * To decrement a negative delta can be provided. * * @param index in bytes for where to put. * @param delta to be added to the value at the index. * @return previous value. */ public long getAndAddLong(final long index, final long delta) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_LONG); } return UNSAFE.getAndAddLong(null, addressOffset + index, delta); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @param byteOrder of the value to be read. * @return the value for at a given index. */ public int getInt(final long index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } int bits = UNSAFE.getInt(null, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = Integer.reverseBytes(bits); } return bits; } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. * @param byteOrder of the value when written. */ public void putInt(final long 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(null, addressOffset + index, bits); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public int getInt(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getInt(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putInt(final long index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } UNSAFE.putInt(null, addressOffset + index, value); } /** * Get the value at a given index with volatile semantics. * * @param index in bytes from which to get. * @return the value for at a given index. */ public int getIntVolatile(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getIntVolatile(null, addressOffset + index); } /** * Put a value to a given index with volatile semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putIntVolatile(final long index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } UNSAFE.putIntVolatile(null, addressOffset + index, value); } /** * Put a value to a given index with ordered store semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putIntOrdered(final long index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } UNSAFE.putOrderedInt(null, addressOffset + index, value); } /** * Add a value to a given index with ordered store semantics. Use a negative increment to decrement. * * @param index in bytes for where to put. * @param increment by which the value at the index will be adjusted. * @return the previous value at the index. */ public int addIntOrdered(final long index, final int increment) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } final long offset = addressOffset + index; final int value = UNSAFE.getInt(null, offset); UNSAFE.putOrderedInt(null, offset, value + increment); return value; } /** * Atomic compare and set of a long given an expected value. * * @param index in bytes for where to put. * @param expectedValue at to be compared. * @param updateValue to be exchanged. * @return set successful or not. */ public boolean compareAndSetInt(final long index, final int expectedValue, final int updateValue) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.compareAndSwapInt(null, addressOffset + index, expectedValue, updateValue); } /** * Atomically exchange a value at a location returning the previous contents. * * @param index in bytes for where to put. * @param value for at a given index. * @return previous value at the index. */ public int getAndSetInt(final long index, final int value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getAndSetInt(null, addressOffset + index, value); } /** * Atomically add a delta to a value at a location returning the previous contents. * To decrement a negative delta can be provided. * * @param index in bytes for where to put. * @param delta to be added to the value at the index. * @return previous value. */ public int getAndAddInt(final long index, final int delta) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_INT); } return UNSAFE.getAndAddInt(null, addressOffset + index, delta); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @param byteOrder of the value to be read. * @return the value for at a given index. */ public double getDouble(final long index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } if (NATIVE_BYTE_ORDER != byteOrder) { final long bits = UNSAFE.getLong(null, addressOffset + index); return Double.longBitsToDouble(Long.reverseBytes(bits)); } else { return UNSAFE.getDouble(null, addressOffset + index); } } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. * @param byteOrder of the value when written. */ public void putDouble(final long 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(null, addressOffset + index, bits); } else { UNSAFE.putDouble(null, addressOffset + index, value); } } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public double getDouble(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } return UNSAFE.getDouble(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putDouble(final long index, final double value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_DOUBLE); } UNSAFE.putDouble(null, addressOffset + index, value); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @param byteOrder of the value to be read. * @return the value for at a given index. */ public float getFloat(final long index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } if (NATIVE_BYTE_ORDER != byteOrder) { final int bits = UNSAFE.getInt(null, addressOffset + index); return Float.intBitsToFloat(Integer.reverseBytes(bits)); } else { return UNSAFE.getFloat(null, addressOffset + index); } } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. * @param byteOrder of the value when written. */ public void putFloat(final long 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(null, addressOffset + index, bits); } else { UNSAFE.putFloat(null, addressOffset + index, value); } } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public float getFloat(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } return UNSAFE.getFloat(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putFloat(final long index, final float value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_FLOAT); } UNSAFE.putFloat(null, addressOffset + index, value); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @param byteOrder of the value to be read. * @return the value for at a given index. */ public short getShort(final long index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } short bits = UNSAFE.getShort(null, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = Short.reverseBytes(bits); } return bits; } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. * @param byteOrder of the value when written. */ public void putShort(final long 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(null, addressOffset + index, bits); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public short getShort(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } return UNSAFE.getShort(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putShort(final long index, final short value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } UNSAFE.putShort(null, addressOffset + index, value); } /** * Get the value at a given index with volatile semantics. * * @param index in bytes from which to get. * @return the value for at a given index. */ public short getShortVolatile(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } return UNSAFE.getShortVolatile(null, addressOffset + index); } /** * Put a value to a given index with volatile semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putShortVolatile(final long index, final short value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_SHORT); } UNSAFE.putShortVolatile(null, addressOffset + index, value); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public byte getByte(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } return UNSAFE.getByte(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putByte(final long index, final byte value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } UNSAFE.putByte(null, addressOffset + index, value); } /** * Get the value at a given index with volatile semantics. * * @param index in bytes from which to get. * @return the value for at a given index. */ public byte getByteVolatile(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } return UNSAFE.getByteVolatile(null, addressOffset + index); } /** * Put a value to a given index with volatile semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putByteVolatile(final long index, final byte value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck(index); } UNSAFE.putByteVolatile(null, addressOffset + index, value); } /** * Get from the underlying buffer into a supplied byte array. * This method will try to fill the supplied byte array. * * @param index in the underlying buffer to start from. * @param dst into which the dst will be copied. */ public void getBytes(final long index, final byte[] dst) { getBytes(index, dst, 0, dst.length); } /** * Get bytes from the underlying buffer into a supplied byte array. * * @param index in the underlying buffer to start from. * @param dst into which the bytes will be copied. * @param offset in the supplied buffer to start the copy. * @param length of the supplied buffer to use. */ public void getBytes(final long index, final byte[] dst, final long offset, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(dst, offset, length); } UNSAFE.copyMemory(null, addressOffset + index, dst, ARRAY_BASE_OFFSET + offset, length); } /** * Get from the underlying buffer into a supplied {@link ByteBuffer} current {@link ByteBuffer#position()}. *

* The destination buffer will have its {@link ByteBuffer#position()} advanced as a result. * * @param index in the underlying buffer to start from. * @param dstBuffer into which the bytes will be copied. * @param length of the supplied buffer to use. */ public void getBytes(final long index, final ByteBuffer dstBuffer, final int length) { final int dstOffset = dstBuffer.position(); if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(dstBuffer, 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(null, addressOffset + index, dstByteArray, dstBaseOffset + dstOffset, length); dstBuffer.position(dstBuffer.position() + length); } /** * Put an array of src into the underlying buffer. * * @param index in the underlying buffer to start from. * @param src to be copied to the underlying buffer. */ public void putBytes(final long index, final byte[] src) { putBytes(index, src, 0, src.length); } /** * Put an array into the underlying buffer. * * @param index in the underlying buffer to start from. * @param src to be copied to the underlying buffer. * @param offset in the supplied buffer to begin the copy. * @param length of the supplied buffer to copy. */ public void putBytes(final long index, final byte[] src, final long offset, final int length) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(src, offset, length); } UNSAFE.copyMemory(src, ARRAY_BASE_OFFSET + offset, null, addressOffset + index, length); } /** * Put bytes into the underlying buffer for the view. Bytes will be copied from current * {@link ByteBuffer#position()} for a given length. *

* The source buffer will have its {@link ByteBuffer#position()} advanced as a result. * * @param index in the underlying buffer to start from. * @param srcBuffer to copy the bytes from. * @param length of the supplied buffer to copy. */ public void putBytes(final long index, final ByteBuffer srcBuffer, final int length) { final int srcIndex = srcBuffer.position(); if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, length); BufferUtil.boundsCheck(srcBuffer, srcIndex, length); } putBytes(index, srcBuffer, srcIndex, length); srcBuffer.position(srcIndex + length); } /** * Put bytes into the underlying buffer for the view. Bytes will be copied from the buffer index to * the buffer index + length. *

* The source buffer will not have its {@link ByteBuffer#position()} advanced as a result. * * @param index in the underlying buffer to start from. * @param srcBuffer to copy the bytes from (does not change position). * @param srcIndex in the source buffer from which the copy will begin. * @param length of the bytes to be copied. */ public void putBytes(final long index, final ByteBuffer srcBuffer, final long 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, null, addressOffset + index, length); } /** * Put bytes from a source {@link DirectBuffer} into this {@link MutableDirectBuffer} at given indices. * * @param index in this buffer to begin putting the bytes. * @param srcBuffer from which the bytes will be copied. * @param srcIndex in the source buffer from which the byte copy will begin. * @param length of the bytes to be copied. */ public void putBytes(final long 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, null, addressOffset + index, length); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @param byteOrder of the value to be read. * @return the value for at a given index. */ public char getChar(final long index, final ByteOrder byteOrder) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } char bits = UNSAFE.getChar(null, addressOffset + index); if (NATIVE_BYTE_ORDER != byteOrder) { bits = (char)Short.reverseBytes((short)bits); } return bits; } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. * @param byteOrder of the value when written. */ public void putChar(final long 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(null, addressOffset + index, bits); } /** * Get the value at a given index. * * @param index in bytes from which to get. * @return the value for at a given index. */ public char getChar(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } return UNSAFE.getChar(null, addressOffset + index); } /** * Put a value to a given index. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putChar(final long index, final char value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } UNSAFE.putChar(null, addressOffset + index, value); } /** * Get the value at a given index with volatile semantics. * * @param index in bytes from which to get. * @return the value for at a given index. */ public char getCharVolatile(final long index) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } return UNSAFE.getCharVolatile(null, addressOffset + index); } /** * Put a value to a given index with volatile semantics. * * @param index in bytes for where to put. * @param value for at a given index. */ public void putCharVolatile(final long index, final char value) { if (SHOULD_BOUNDS_CHECK) { boundsCheck0(index, SIZE_OF_CHAR); } UNSAFE.putCharVolatile(null, addressOffset + index, value); } /** * Get a String from bytes encoded in UTF-8 format that is length prefixed. * * @param offset at which the String begins. * @return the String as represented by the UTF-8 encoded bytes. */ public String getStringUtf8(final long offset) { final int length = getInt(offset); return getStringUtf8(offset, length); } /** * Get a String from bytes encoded in UTF-8 format that is length prefixed. * * @param offset at which the String begins. * @param byteOrder for the length at the beginning of the String. * @return the String as represented by the UTF-8 encoded bytes. */ public String getStringUtf8(final long offset, final ByteOrder byteOrder) { final int length = getInt(offset, byteOrder); return getStringUtf8(offset, length); } /** * Get part of String from bytes encoded in UTF-8 format that is length prefixed. * * @param offset at which the String begins. * @param length of the String in bytes to decode. * @return the String as represented by the UTF-8 encoded bytes. */ public String getStringUtf8(final long offset, final int length) { final byte[] stringInBytes = new byte[length]; getBytes(offset + STR_HEADER_LEN, stringInBytes); return new String(stringInBytes, UTF_8); } /** * Encode a String as UTF-8 bytes to the buffer with a length prefix. * * @param offset at which the String should be encoded. * @param value of the String to be encoded. * @return the number of bytes put to the buffer. */ public int putStringUtf8(final long offset, final String value) { return putStringUtf8(offset, value, Integer.MAX_VALUE); } /** * Encode a String as UTF-8 bytes to the buffer with a length prefix. * * @param offset at which the String should be encoded. * @param value of the String to be encoded. * @param byteOrder for the length prefix. * @return the number of bytes put to the buffer. */ public int putStringUtf8(final long offset, final String value, final ByteOrder byteOrder) { return putStringUtf8(offset, value, byteOrder, Integer.MAX_VALUE); } /** * Encode a String as UTF-8 bytes the buffer with a length prefix with a maximum encoded size check. * * @param offset at which the String should be encoded. * @param value of the String to be encoded. * @param maxEncodedSize to be checked before writing to the buffer. * @return the number of bytes put to the buffer. * @throws java.lang.IllegalArgumentException if the encoded bytes are greater than maxEncodedLength. */ public int putStringUtf8(final long offset, 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(offset, bytes.length); putBytes(offset + STR_HEADER_LEN, bytes); return STR_HEADER_LEN + bytes.length; } /** * Encode a String as UTF-8 bytes the buffer with a length prefix with a maximum encoded size check. * * @param offset at which the String should be encoded. * @param value of the String to be encoded. * @param byteOrder for the length prefix. * @param maxEncodedSize to be checked before writing to the buffer. * @return the number of bytes put to the buffer. * @throws java.lang.IllegalArgumentException if the encoded bytes are greater than maxEncodedLength. */ public int putStringUtf8(final long offset, 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(offset, bytes.length, byteOrder); putBytes(offset + STR_HEADER_LEN, bytes); return STR_HEADER_LEN + bytes.length; } /** * Get an encoded UTF-8 String from the buffer that does not have a length prefix. * * @param offset at which the String begins. * @param length of the String in bytes to decode. * @return the String as represented by the UTF-8 encoded bytes. */ public String getStringWithoutLengthUtf8(final long offset, final int length) { final byte[] stringInBytes = new byte[length]; getBytes(offset, stringInBytes); return new String(stringInBytes, UTF_8); } /** * Encode a String as UTF-8 bytes in the buffer without a length prefix. * * @param offset at which the String begins. * @param value of the String to be encoded. * @return the number of bytes encoded. */ public int putStringWithoutLengthUtf8(final long offset, final String value) { final byte[] bytes = value != null ? value.getBytes(UTF_8) : NULL_BYTES; putBytes(offset, bytes); return bytes.length; } /** * Check that a given length of bytes is within the bounds from a given index. * * @param index from which to check. * @param length in bytes of the range to check. * @throws java.lang.IndexOutOfBoundsException if the length goes outside the capacity range. */ public void boundsCheck(final long index, final int length) { boundsCheck0(index, length); } private void boundsCheck(final long index) { if (index < 0 || index >= capacity) { throw new IndexOutOfBoundsException("index=" + index + " capacity=" + capacity); } } private void boundsCheck0(final long index, final int length) { final long resultingPosition = index + (long)length; if (index < 0 || resultingPosition > capacity || resultingPosition < index) { throw new IndexOutOfBoundsException( "index=" + index + " length=" + length + " capacity=" + capacity); } } private void map(final long offset, final long length) { capacity = length; addressOffset = IoUtil.map(fileChannel, mapMode, offset, length); } private void unmap() { IoUtil.unmap(fileChannel, addressOffset, capacity); } /** * {@inheritDoc} */ public String toString() { return "MappedResizeableBuffer{" + "addressOffset=" + addressOffset + ", capacity=" + capacity + ", fileChannel=" + fileChannel + ", mapMode=" + mapMode + '}'; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy