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

net.openhft.chronicle.bytes.BytesStore Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2016-2022 chronicle.software
 *
 *     https://chronicle.software
 *
 * 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 net.openhft.chronicle.bytes;

import net.openhft.chronicle.bytes.algo.OptimisedBytesStoreHash;
import net.openhft.chronicle.bytes.algo.VanillaBytesStoreHash;
import net.openhft.chronicle.bytes.internal.*;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.annotation.NonNegative;
import net.openhft.chronicle.core.io.ClosedIllegalStateException;
import net.openhft.chronicle.core.io.IORuntimeException;
import net.openhft.chronicle.core.io.ReferenceCounted;
import net.openhft.chronicle.core.io.ThreadingIllegalStateException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.crypto.Cipher;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

import static java.lang.Math.min;
import static net.openhft.chronicle.bytes.internal.ReferenceCountedUtil.throwExceptionIfReleased;
import static net.openhft.chronicle.core.util.ObjectUtils.requireNonNull;

/**
 * This interface represents an immutable reference to a segment of bytes with a fixed range.
 * It can be safely shared across threads given that the data it references is accessed in a thread-safe manner.
 * Direct access is only possible within the allocated capacity of the BytesStore.
 *
 * @param  The BytesStore type
 * @param  The underlying data type the BytesStore manages
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public interface BytesStore, U>
        extends RandomDataInput, RandomDataOutput, ReferenceCounted, CharSequence {

    /**
     * Converts a CharSequence into a BytesStore. The characters are encoded using ISO_8859_1.
     *
     * @param cs the CharSequence to be converted
     * @return a BytesStore which contains the bytes from the CharSequence
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    static BytesStore from(@NotNull CharSequence cs) throws ClosedIllegalStateException, ThreadingIllegalStateException {
        if (cs.length() == 0)
            return empty();
        if (cs instanceof BytesStore)
            return from((BytesStore) cs);
        return from(cs.toString());
    }

    /**
     * Returns a BytesStore using the bytes in another specified BytesStore.
     *
     * @param cs the source BytesStore
     * @return a new BytesStore that is a copy of the source
     * @throws ClosedIllegalStateException    If the resource has been released or closed.
     * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way.
     */
    static ,B> BytesStore from(@NotNull BytesStore cs)
            throws ClosedIllegalStateException {
        return cs.copy();
    }

    /**
     * Converts a String into a BytesStore. The characters in the String are encoded using ISO_8859_1.
     *
     * @param cs the String to be converted
     * @return a BytesStore which contains the bytes from the String
     */
    static BytesStore from(@NotNull String cs) {
        return cs.length() == 0 ? empty() : BytesStore.wrap(cs.getBytes(StandardCharsets.ISO_8859_1));
    }

    /**
     * Provides a BytesStore that allows access to a group of fields in a given object.
     *
     * @param o         the object that contains the fields
     * @param groupName the group name of the fields
     * @param padding   the padding to be used
     * @return a BytesStore which points to the fields
     */
    static  BytesStore forFields(Object o, String groupName, int padding) {
        return HeapBytesStore.forFields(o, groupName, padding);
    }

    /**
     * Wraps a byte array into a BytesStore. There will be only one copy in memory.
     *
     * @param bytes the byte array to be wrapped
     * @return a BytesStore that contains the bytes from the array
     */
    static BytesStore wrap(byte[] bytes) {
        return HeapBytesStore.wrap(bytes);
    }

    /**
     * Wraps a ByteBuffer into a BytesStore. The ByteBuffer can be either on heap or off heap.
     * When the resulting BytesStore is closed, the direct ByteBuffer will be deallocated and should not be used anymore.
     *
     * @param bb the ByteBuffer to be wrapped
     * @return a BytesStore that contains the bytes from the ByteBuffer
     * @see #follow(ByteBuffer)
     */
    @NotNull
    static BytesStore wrap(@NotNull ByteBuffer bb) {
        return bb.isDirect()
                ? NativeBytesStore.wrap(bb)
                : HeapBytesStore.wrap(bb);
    }

    /**
     * Wraps a ByteBuffer which can be either on heap or off heap without taking ownership of that buffer.
     * 

* When resulting BytesStore instance is closed, direct {@code byteBuffer} will not be deallocated so its * life cycle should be tracked elsewhere. * * @param bb the ByteBuffer to follow * @return a BytesStore that directly interfaces with the given ByteBuffer * @see #wrap(ByteBuffer) */ @NotNull static BytesStore follow(@NotNull ByteBuffer bb) { return bb.isDirect() ? NativeBytesStore.follow(bb) : HeapBytesStore.wrap(bb); } /** * This is an elastic native store. * Creates a flexible BytesStore instance that resides in native memory. * * @param capacity the initial capacity of the buffer * @return a BytesStore with the provided capacity in native memory */ static BytesStore nativeStore(@NonNegative long capacity) { return NativeBytesStore.nativeStore(capacity); } /** * Creates a BytesStore instance with a fixed capacity that resides in native memory. * * @param capacity the fixed capacity of the buffer * @return a BytesStore with the provided fixed capacity in native memory */ static BytesStore nativeStoreWithFixedCapacity(@NonNegative long capacity) { return NativeBytesStore.nativeStoreWithFixedCapacity(capacity); } /** * Creates a lazily initialized BytesStore instance with a fixed capacity that resides in native memory. * * @param capacity the fixed capacity of the buffer * @return a BytesStore with the provided fixed capacity in native memory, initialized on demand */ static BytesStore lazyNativeBytesStoreWithFixedCapacity(@NonNegative long capacity) { return NativeBytesStore.lazyNativeBytesStoreWithFixedCapacity(capacity); } /** * Creates a flexible ByteBuffer instance that resides in native memory. * * @param size the initial size of the ByteBuffer * @param maxSize the maximum allowable size of the ByteBuffer * @return a ByteBuffer with the provided initial size and maximum size in native memory */ static BytesStore elasticByteBuffer(@NonNegative int size, @NonNegative long maxSize) { return NativeBytesStore.elasticByteBuffer(size, maxSize); } /** * Creates and returns a new BytesStore that resides in native memory whereby the contents and * size of the native memory is determined by the provided {@code bytes} array. * * @param bytes the content to initialize the new ByteStore * @return a new BytesStore that resides in native memory whereby the contents and * size of the native memory is determined by the provided {@code bytes} array */ static BytesStore nativeStoreFrom(byte[] bytes) { Objects.requireNonNull(bytes); return NativeBytesStore.from(bytes); } /** * Creates a new PointerBytesStore that can be set to any address in memory. * * @return a new, uninitialized PointerBytesStore */ @NotNull static PointerBytesStore nativePointer() { return new PointerBytesStore(); } /** * Creates a PointerBytesStore that wraps bytes starting from a specific address in memory. * * @param address the starting memory address for the PointerBytesStore * @param length the length of the memory segment to be wrapped by the PointerBytesStore * @return a PointerBytesStore that wraps the specified memory segment */ @NotNull static PointerBytesStore wrap(long address, @NonNegative long length) { @NotNull PointerBytesStore pbs = nativePointer(); pbs.set(address, length); return pbs; } /** * Provides an empty, fixed-sized and immutable BytesStore. * * @return an instance of an empty BytesStore */ @SuppressWarnings("unchecked") static , T> BytesStore empty() { return (BytesStore) NoBytesStore.NO_BYTES_STORE; } /** * Performs a compare-and-swap operation on the specified float value at the given offset. * If the current float value at the offset equals the expected value, it's replaced with the provided new value. * * @param offset the position where the float value is stored * @param expected the expected current value * @param value the new value to be set if the current value equals the expected value * @return true if the compare-and-swap was successful, false otherwise * @throws BufferOverflowException If the offset is out of bounds * @throws ClosedIllegalStateException If the resource has been released or closed. */ @Override default boolean compareAndSwapFloat(@NonNegative long offset, float expected, float value) throws BufferOverflowException, ClosedIllegalStateException { return compareAndSwapInt(offset, Float.floatToRawIntBits(expected), Float.floatToRawIntBits(value)); } /** * Similar to {@link #compareAndSwapFloat(long, float, float)} but operates on a double value. */ @Override default boolean compareAndSwapDouble(@NonNegative long offset, double expected, double value) throws BufferOverflowException, ClosedIllegalStateException { return compareAndSwapLong(offset, Double.doubleToRawLongBits(expected), Double.doubleToRawLongBits(value)); } /** * Adds an integer to the current integer value at the specified offset and returns the result. * * @param offset the position where the integer is stored * @param adding the integer to add * @return the result of the addition * @throws BufferUnderflowException If the offset is out of bounds * @throws ClosedIllegalStateException If the resource has been released or closed. */ @SuppressWarnings("deprecation") default int addAndGetInt(@NonNegative long offset, int adding) throws BufferUnderflowException, ClosedIllegalStateException { return BytesInternal.addAndGetInt(this, offset, adding); } /** * Similar to {@link #addAndGetInt(long, int)} but operates on a long value. */ @SuppressWarnings("deprecation") default long addAndGetLong(@NonNegative long offset, long adding) throws BufferUnderflowException, ClosedIllegalStateException { return BytesInternal.addAndGetLong(this, offset, adding); } /** * Similar to {@link #addAndGetInt(long, int)} but operates on a float value. */ @SuppressWarnings("deprecation") default float addAndGetFloat(@NonNegative long offset, float adding) throws BufferUnderflowException, ClosedIllegalStateException { return BytesInternal.addAndGetFloat(this, offset, adding); } /** * Similar to {@link #addAndGetInt(long, int)} but operates on a double value. */ @SuppressWarnings("deprecation") default double addAndGetDouble(@NonNegative long offset, double adding) throws BufferUnderflowException, ClosedIllegalStateException { return BytesInternal.addAndGetDouble(this, offset, adding); } /** * Checks if this BytesStore uses direct memory. * * @return true if it uses direct memory, false otherwise */ @Override boolean isDirectMemory(); /** * Creates and returns a copy of this BytesStore. * * @return a new instance of BytesStore that is a copy of this BytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ BytesStore copy() throws ClosedIllegalStateException, ThreadingIllegalStateException; /** * Returns a Bytes that wraps this ByteStore from the {@code start} to the {@code realCapacity}. *

* The returned Bytes is not elastic and can be both read and written using cursors. * * @return a Bytes that wraps this ByteStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @Override @NotNull default Bytes bytesForRead() throws ClosedIllegalStateException, ThreadingIllegalStateException { try { Bytes ret = bytesForWrite(); ret.readLimit(writeLimit()); ret.writeLimit(realCapacity()); ret.readPosition(start()); return ret; } catch (BufferUnderflowException | BufferOverflowException e) { throw new IllegalStateException(e); } } /** * Returns a Bytes that wraps this ByteStore from the {@code start} to the {@code realCapacity}. *

* The returned Bytes is not elastic and can be both read and written using cursors. * * @return a Bytes that wraps this BytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @Override @NotNull default Bytes bytesForWrite() throws ClosedIllegalStateException { try { return new VanillaBytes<>(this, writePosition(), writeLimit()); } catch (IllegalArgumentException e) { throw new IllegalStateException(e); } } /** * Returns if the {@code readPosition} is at the {@code start} and * the {@code writeLimit} is at the {@code end}. *

* I.e {@code start() == readPosition() && writeLimit() == capacity()} * * @return if the {@code readPosition} is at the {@code start} and * the {@code writeLimit} is at the {@code end} */ default boolean isClear() { return true; } /** * Returns the actual capacity of the ByteStore before any resizing occurs. * * @return the current capacity of the ByteStore */ @Override default @NonNegative long realCapacity() { return capacity(); } /** * Provides the maximum limit that can be set for the ByteStore. * * @return the maximum capacity of the ByteStore */ @Override @NonNegative long capacity(); /** * @return the underlying object being wrapped, if there is one, or null if not. */ @Nullable U underlyingObject(); /** * Returns if a specified offset is inside this BytesStore limits. *

* Use this test to determine if an offset is considered safe for reading from. Note that it checks we are * inside the BytesStore limits *without* including the overlap * * @param offset the specified offset to check * @return {@code true} if offset is safe */ default boolean inside(@NonNegative long offset) { return start() <= offset && offset < safeLimit(); } /** * Returns if a number of bytes starting from an offset are inside this ByteStore limits. * * @param offset the starting index to check * @param bufferSize the number of bytes to be read/written * @return {@code true} if the bytes between the offset and offset+buffer are inside the BytesStore */ default boolean inside(@NonNegative long offset, @NonNegative long bufferSize) { return start() <= offset && offset + bufferSize <= safeLimit(); } /** * @return how many bytes can be safely read, i.e. what is the real capacity of the underlying data. */ default long safeLimit() { return capacity(); } /** * Returns the number of bytes that were copied from this BytesStore to a destination BytesStore. *

* Copies the data to another BytesStore as long as space is available in the destination BytesStore. * * @param store the BytesStore to copy to * @return how many bytes were copied * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default long copyTo(@NotNull BytesStore store) throws ClosedIllegalStateException, ThreadingIllegalStateException { requireNonNull(store); throwExceptionIfReleased(this); throwExceptionIfReleased(store); long readPos = readPosition(); long writePos = store.writePosition(); long copy = min(readRemaining(), store.writeRemaining()); long i = 0; try { for (; i < copy - 7; i += 8) store.writeLong(writePos + i, readLong(readPos + i)); for (; i < copy; i++) store.writeByte(writePos + i, readByte(readPos + i)); } catch (BufferOverflowException | BufferUnderflowException e) { throw new IllegalStateException(e); } return copy; } /** * Copies the bytes in the BytesStore to an OutputStream object. * * @param out the specified OutputStream that this BytesStore is copied to * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. * @see java.io.OutputStream */ default void copyTo(@NotNull OutputStream out) throws IOException, ClosedIllegalStateException, ThreadingIllegalStateException { BytesInternal.copy(this, out); } /** * Fills the BytesStore with zeros. * * @param start first byte inclusive * @param end last byte exclusive * @return this * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @Override @NotNull default B zeroOut(@NonNegative long start, @NonNegative long end) throws ClosedIllegalStateException, ThreadingIllegalStateException { if (end <= start) return (B) this; if (start < start()) start = start(); if (end > capacity()) end = capacity(); long i = start; try { for (; i < end - 7; i += 8L) writeLong(i, 0L); for (; i < end; i++) writeByte(i, 0); } catch (BufferOverflowException | IllegalArgumentException | ArithmeticException e) { throw new IllegalStateException(e); } return (B) this; } /** * This method is inherited from CharSequence so result should be the length of the contained * chars sequence although it actually returns the number of underlying bytes. These 2 numbers are only the same * if the encoding we are using is single char for single byte. * * @return length in bytes to read or Integer.MAX_VALUE if longer. */ @Override @NonNegative default int length() { return (int) Math.min(Integer.MAX_VALUE, readRemaining()); } /** * Assume ISO-8859-1 encoding, subclasses can override this. * * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @Override default char charAt(@NonNegative int index) throws IndexOutOfBoundsException { try { return (char) readUnsignedByte(readPosition() + index); } catch (BufferUnderflowException e) { throw new IndexOutOfBoundsException((readPosition() + index) + " >= " + readLimit()); } } /** * {@inheritDoc} * *
* This method constructs a new , memory storage type (heap or native) is preserved. */ @NotNull @Override default CharSequence subSequence(@NonNegative int start, @NonNegative int end) { if (start < 0 || end > length() || end < start) throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", length " + length()); try { return subBytes(readPosition() + start, (long) end - start); } catch (ClosedIllegalStateException e) { throw Jvm.rethrow(e); } } /** * By default, the maximum length of data shown is 256 characters. Use {@link #toDebugString(long)} if you want more. *

* This is assumed to be used to print the contents on a best effort basis. If an Error occurs it will be returned in the String. * * @return this BytesStore as a DebugString */ @NotNull default String toDebugString() { return toDebugString(512); } /** *

* This is assumed to be used to print the contents on a best effort basis. If an Error occurs it will be returned in the String. * @param maxLength the maximum length of the output * @return this BytesStore as a DebugString. */ @NotNull default String toDebugString(@NonNegative long maxLength) { try { return BytesInternal.toDebugString(this, maxLength); } catch (Exception e) { return e.toString(); } } /** * @return the underlying BytesStore */ @Nullable default BytesStore bytesStore() { return this; } /** * Returns if a portion of a specified BytesStore matches this BytesStore. * * @param bytesStore the BytesStore to match against * @param length the length to match * @return {@code true} if the bytes up to min(length, this.length(), bytesStore.length()) matched. * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way */ default boolean equalBytes(@NotNull BytesStore bytesStore, @NonNegative long length) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { return length == 8 && bytesStore.length() >= 8 ? readLong(readPosition()) == bytesStore.readLong(bytesStore.readPosition()) : BytesInternal.equalBytesAny(this, bytesStore, length); } /** * Returns the bytes sum of the readable bytes in this BytesStore. * * @return unsigned bytes sum * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way */ default int byteCheckSum() throws IORuntimeException, BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { return byteCheckSum(readPosition(), readLimit()); } catch (BufferUnderflowException e) { throw new IllegalStateException(e); } } /** * Returns the bytes sum between the specified indexes; start (inclusive) and end (exclusive). * * @param start the index of the first byte to sum * @param end the index of the last byte to sum * @return unsigned bytes sum * @throws BufferUnderflowException If the specified indexes are outside the limits of the BytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default int byteCheckSum(@NonNegative long start, @NonNegative long end) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { int sum = 0; for (long i = start; i < end; i++) { sum += readByte(i); } return sum & 0xFF; } /** * Returns if the BytesStore ends with a specified character. * * @param c the character to look for * @return {@code true} if the specified character is the same as the last character of this BytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default boolean endsWith(char c) throws ClosedIllegalStateException, ThreadingIllegalStateException { try { return readRemaining() > 0 && readUnsignedByte(readLimit() - 1) == c; } catch (BufferUnderflowException e) { throw new IllegalStateException(e); } } /** * Returns if the BytesStore starts with a specified character. * * @param c the character to look for * @return {@code true} if the specified character is the same as the first character of this BytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default boolean startsWith(char c) throws ClosedIllegalStateException, ThreadingIllegalStateException { try { return readRemaining() > 0 && readUnsignedByte(readPosition()) == c; } catch (BufferUnderflowException e) { throw new IllegalStateException(e); } } /** * Returns if the content of this BytesStore is the same as the content of a specified BytesStore. * * @param bytesStore the BytesStore to compare with * @return {@code true} if this BytesStore and the input BytesStore contain the same data * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default boolean contentEquals(@Nullable BytesStore bytesStore) throws ClosedIllegalStateException, ThreadingIllegalStateException { return BytesInternal.contentEqual(this, bytesStore); } /** * Returns if the content of this BytesStore starts with bytes equal to the content of a specified BytesStore. * * @param bytesStore the BytesStore to compare with * @return {@code true} if the content of this BytesStore starts with bytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default boolean startsWith(@Nullable BytesStore bytesStore) throws ClosedIllegalStateException, ThreadingIllegalStateException { return bytesStore != null && BytesInternal.startsWith(this, bytesStore); } /** * Returns the content of this BytesStore in 8bitString format. * * @return a String from the content of this BytesStore * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @NotNull default String to8bitString() throws ClosedIllegalStateException, ThreadingIllegalStateException { return BytesInternal.to8bitString(this); } /** * Perform a not atomic add and get operation for an unsigned byte value. This method * does not check for unsigned byte overflow. * * @param offset to add and get * @param adding value to add, can be 1 * @return the sum * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default int addAndGetUnsignedByteNotAtomic(@NonNegative long offset, int adding) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { int r = (readUnsignedByte(offset) + adding) & 0xFF; writeByte(offset, (byte) r); return r; } catch (BufferOverflowException e) { throw new IllegalStateException(e); } } /** * Perform a not atomic add and get operation for a short value. * * @param offset to add and get * @param adding value to add, can be 1 * @return the sum * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default short addAndGetShortNotAtomic(@NonNegative long offset, short adding) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { short r = (short) (readShort(offset) + adding); writeByte(offset, r); return r; } catch (BufferOverflowException | IllegalArgumentException | ArithmeticException e) { throw new IllegalStateException(e); } } /** * Perform a not atomic add and get operation for an int value. * * @param offset to add and get * @param adding value to add, can be 1 * @return the sum * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default int addAndGetIntNotAtomic(@NonNegative long offset, int adding) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { int r = readInt(offset) + adding; writeInt(offset, r); return r; } catch (BufferOverflowException e) { throw new IllegalStateException(e); } } /** * Perform a not atomic add and get operation for a float value. * * @param offset to add and get * @param adding value to add, can be 1 * @return the sum * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default double addAndGetDoubleNotAtomic(@NonNegative long offset, double adding) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { double r = readDouble(offset) + adding; writeDouble(offset, r); return r; } catch (BufferOverflowException e) { throw new IllegalStateException(e); } } /** * Perform a not atomic add and get operation for a float value. * * @param offset to add and get * @param adding value to add, can be 1 * @return the sum * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default float addAndGetFloatNotAtomic(@NonNegative long offset, float adding) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { float r = readFloat(offset) + adding; writeFloat(offset, r); return r; } catch (BufferOverflowException e) { throw new IllegalStateException(e); } } /** * Moves a sequence of bytes within this BytesStore from the source to destination index. * * @param from the index of the first byte to be moved * @param to the index where the first byte should be moved to * @param length the number of bytes to be moved * @throws BufferUnderflowException If there's not enough data to be moved * @throws ArithmeticException If the move would result in an index overflow * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ void move(@NonNegative long from, @NonNegative long to, @NonNegative long length) throws BufferUnderflowException, ArithmeticException, ClosedIllegalStateException, ThreadingIllegalStateException; /** * Writes a long value at a specified offset if the value is not smaller than the current value at that offset. * * @param offset the offset to write to * @param atLeast the long value that is to be written at offset if it is not less than the current value at offset * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way */ default void writeMaxLong(@NonNegative long offset, long atLeast) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { for (; ; ) { long v = readVolatileLong(offset); if (v >= atLeast) return; if (compareAndSwapLong(offset, v, atLeast)) return; Jvm.nanoPause(); } } catch (BufferOverflowException e) { throw new IllegalStateException(e); } } /** * Writes an int value at a specified offset if the value is not smaller than the current value at that offset. * * @param offset the offset to write to * @param atLeast the int value that is to be written at offset if it is not less than the current value at offset * @throws BufferUnderflowException If there's not enough data to be moved * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way */ default void writeMaxInt(@NonNegative long offset, int atLeast) throws BufferUnderflowException, ClosedIllegalStateException, ThreadingIllegalStateException { try { for (; ; ) { int v = readVolatileInt(offset); if (v >= atLeast) return; if (compareAndSwapInt(offset, v, atLeast)) return; Jvm.nanoPause(); } } catch (BufferOverflowException e) { throw new IllegalStateException(e); } } /** * @return {@code true} if the number of readable bytes of this BytesStore is zero. */ default boolean isEmpty() { return readRemaining() == 0; } /** * Encrypts or decrypts this BytesStore using the provided Cipher and writes the result to the outBytes. * It ensures that outBytes has sufficient capacity for the result and restores the original read position of outBytes after operation. * * @param cipher the Cipher to use for encryption or decryption * @param outBytes the Bytes object where the result will be written * @param using1 a ByteBuffer to use as temporary buffer during the operation * @param using2 another ByteBuffer to use as temporary buffer during the operation * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way */ default void cipher(@NotNull Cipher cipher, @NotNull Bytes outBytes, @NotNull ByteBuffer using1, @NotNull ByteBuffer using2) throws ClosedIllegalStateException, ThreadingIllegalStateException { final long readPos = outBytes.readPosition(); try { long writePos = outBytes.writePosition(); BytesStore inBytes; long size = readRemaining(); if (this.isDirectMemory()) { inBytes = this; } else { inBytes = BytesStore.nativeStore(size); this.copyTo(inBytes); } BytesInternal.assignBytesStoreToByteBuffer(inBytes, using1); int outputSize = cipher.getOutputSize(Math.toIntExact(size)); outBytes.ensureCapacity(writePos + outputSize); outBytes.readPositionRemaining(writePos, outputSize); BytesInternal.assignBytesStoreToByteBuffer(outBytes, using2); int len = cipher.update(using1, using2); len += cipher.doFinal(using1, using2); assert len == using2.position(); outBytes.writePosition(writePos + using2.position()); } catch (IllegalStateException e) { throw e; } catch (@NotNull Exception e) { throw new IllegalStateException(e); } finally { // This would never fail as readPos is final and was valid from the beginning. outBytes.readPosition(readPos); } } /** * Convenience method to perform the cipher operation using thread local ByteBuffers for temporary buffers. * It encrypts or decrypts this BytesStore using the provided Cipher and writes the result to the outBytes. * * @param cipher the Cipher to use for encryption or decryption * @param outBytes the Bytes object where the result will be written * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way */ default void cipher(@NotNull Cipher cipher, @NotNull Bytes outBytes) throws ClosedIllegalStateException, ThreadingIllegalStateException { cipher(cipher, outBytes, BytesInternal.BYTE_BUFFER_TL.get(), BytesInternal.BYTE_BUFFER2_TL.get()); } /** * Returns if this ByteStore can be both read from and written to. *

* This is in contrast to a ByteStore than can only be read. * * @return if this ByteStore can be both read from and written to */ default boolean readWrite() { return true; } /** * Computes a hash code for this ByteStore's content up to the specified length. * * @param length the length up to which the hash code is to be computed * @return the computed hash code * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default long hash(long length) { return bytesStore() instanceof NativeBytesStore ? OptimisedBytesStoreHash.INSTANCE.applyAsLong(this, length) : VanillaBytesStoreHash.INSTANCE.applyAsLong(this, length); } /** * Returns if a specified portion of this BytesStore is equal to a specified String. * The portion is specified with its offset and length. * * @param start the portion offset * @param length the number of bytes from this BytesStore that should be compared to s * @param s the String to compare to * @return {@code true} if the specified portion of this BytesStore is equal to s * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ default boolean isEqual(@NonNegative long start, @NonNegative long length, String s) throws ClosedIllegalStateException, ThreadingIllegalStateException { if (s == null || s.length() != length) return false; int length2 = (int) length; for (int i = 0; i < length2; i++) if (s.charAt(i) != readUnsignedByte(start + i)) return false; return true; } }