net.openhft.chronicle.bytes.Bytes Maven / Gradle / Ivy
/*
* Copyright 2016 higherfrequencytrading.com
*
* 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.core.OS;
import net.openhft.chronicle.core.io.IORuntimeException;
import net.openhft.chronicle.core.util.StringUtils;
import org.jetbrains.annotations.NotNull;
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;
/**
* Bytes is a pointer to a region of memory within a BytesStore. It can be for a fixed region of
* memory or an "elastic" buffer which can be resized, but not for a fixed region. This is a
* BytesStore which is mutable and not thread safe. It has a write position and read position which
* must follow these constraints start() <= readPosition() <= writePosition() <=
* writeLimit() <= capacity() Also readLimit() == writePosition() and readPosition()
* <= safeLimit();
*/
public interface Bytes extends
BytesStore, Underlying>,
BytesIn,
BytesOut {
long MAX_CAPACITY = Long.MAX_VALUE; // 8 EiB - 1
int DEFAULT_BYTE_BUFFER_CAPACITY = 256;
/**
* @return an elastic wrapper for a direct ByteBuffer which will be resized as required.
*/
static Bytes elasticByteBuffer() {
return elasticByteBuffer(DEFAULT_BYTE_BUFFER_CAPACITY);
}
static Bytes elasticByteBuffer(int initialCapacity, int maxSize) {
NativeBytesStore bs = NativeBytesStore.elasticByteBuffer(initialCapacity, maxSize);
try {
return bs.bytesForWrite();
} finally {
bs.release();
}
}
/**
* Returns an elastic wrapper for a direct ByteBuffer which will be resized as required, with
* the given initial capacity.
*/
static Bytes elasticByteBuffer(int initialCapacity) {
return elasticByteBuffer(initialCapacity, Integer.MAX_VALUE & ~(OS.pageSize() - 1));
}
/**
* @param byteBuffer to read
* @return a Bytes which wrap a ByteBuffer and is ready for reading.
*/
static Bytes wrapForRead(ByteBuffer byteBuffer) {
BytesStore, ByteBuffer> bs = BytesStore.wrap(byteBuffer);
try {
Bytes bbb = bs.bytesForRead();
bbb.readLimit(byteBuffer.limit());
bbb.readPosition(byteBuffer.position());
return bbb;
} finally {
bs.release();
}
}
/**
* @param byteBuffer to read
* @return a Bytes which wrap a ByteBuffer and is ready for writing.
*/
static Bytes wrapForWrite(ByteBuffer byteBuffer) {
BytesStore, ByteBuffer> bs = BytesStore.wrap(byteBuffer);
try {
Bytes bbb = bs.bytesForWrite();
bbb.writePosition(byteBuffer.position());
bbb.writeLimit(byteBuffer.limit());
return bbb;
} finally {
bs.release();
}
}
/**
* A Bytes suitable for writing to for testing purposes. It checks the writes made are the
* expected ones. An AssertionError is thrown if unexpected data is written, an
* UnsupportedOperationException is thrown if a read is attempted.
*
* @param text expected
* @return the expected buffer as Bytes
*/
@NotNull
static Bytes expect(@NotNull String text) {
return expect(wrapForRead(text.getBytes(StandardCharsets.ISO_8859_1)));
}
/**
* A Bytes suitable for writing to for testing purposes. It checks the writes made are the
* expected ones. An AssertionError is thrown if unexpected data is written, an
* UnsupportedOperationException is thrown if a read is attempted.
*
* @param bytesStore expected
* @return the expected buffer as Bytes
*/
@NotNull
static , Underlying> Bytes expect(BytesStore bytesStore) {
return new VanillaBytes<>(new ExpectedBytesStore<>(bytesStore));
}
/**
* Wrap the byte[] ready for reading
*
* @param byteArray to wrap
* @return the Bytes ready for reading.
*/
static Bytes wrapForRead(byte[] byteArray) {
HeapBytesStore bs = BytesStore.wrap(byteArray);
try {
return bs.bytesForRead();
} finally {
bs.release();
}
}
/**
* Wrap the byte[] ready for writing
*
* @param byteArray to wrap
* @return the Bytes ready for writing.
*/
static Bytes wrapForWrite(byte[] byteArray) {
BytesStore bs = (BytesStore) BytesStore.wrap(byteArray);
try {
return bs.bytesForWrite();
} finally {
bs.release();
}
}
/**
* Convert text to bytes using ISO-8859-1 encoding and return a Bytes ready for reading.
*
* @param text to convert
* @return Bytes ready for reading.
*/
static Bytes from(@NotNull CharSequence text) throws IllegalArgumentException, IllegalStateException {
if (text instanceof BytesStore)
return ((BytesStore) text).copy().bytesForRead();
return wrapForRead(text.toString().getBytes(StandardCharsets.ISO_8859_1));
}
@Deprecated
static Bytes wrapForRead(@NotNull CharSequence text) throws IllegalArgumentException, IllegalStateException {
return from(text);
}
/**
* Allocate a fixed size buffer read for writing.
*
* @param capacity minimum to allocate
* @return a new Bytes ready for writing.
*/
static VanillaBytes allocateDirect(long capacity) throws IllegalArgumentException {
NativeBytesStore bs = NativeBytesStore.nativeStoreWithFixedCapacity(capacity);
try {
return bs.bytesForWrite();
} finally {
bs.release();
}
}
/**
* Allocate an elastic buffer with initially no size.
*
* @return Bytes for writing.
*/
static NativeBytes allocateElasticDirect() {
return NativeBytes.nativeBytes();
}
/**
* Allocate an elastic buffer with initially no size.
*
* @return Bytes for writing.
*/
static NativeBytes allocateElasticDirect(long initialCapacity) throws IllegalArgumentException {
return NativeBytes.nativeBytes(initialCapacity);
}
/**
* Creates a string from the {@code position} to the {@code limit}, The buffer is not modified
* by this call
*
* @param buffer the buffer to use
* @return a string contain the text from the {@code position} to the {@code limit}
*/
static String toString(@NotNull final Bytes> buffer) throws BufferUnderflowException {
return toString(buffer, Integer.MAX_VALUE - 4);
}
/**
* Creates a string from the {@code position} to the {@code limit}, The buffer is not modified
* by this call
*
* @param buffer the buffer to use
* @param maxLen of the result returned
* @return a string contain the text from the {@code position} to the {@code limit}
*/
static String toString(@NotNull final Bytes> buffer, long maxLen) throws
BufferUnderflowException {
if (buffer.readRemaining() == 0)
return "";
final long length = Math.min(maxLen + 1, buffer.readRemaining());
return buffer.parseWithLength(length, b -> {
final StringBuilder builder = new StringBuilder();
try {
while (buffer.readRemaining() > 0) {
if (builder.length() >= maxLen) {
builder.append("...");
break;
}
builder.append((char) buffer.readByte());
}
} catch (IORuntimeException e) {
builder.append(' ').append(e);
}
// remove the last comma
return builder.toString();
});
}
/**
* The buffer is not modified by this call
*
* @param buffer the buffer to use
* @param position the position to create the string from
* @param len the number of characters to show in the string
* @return a string contain the text from offset {@code position}
*/
static String toString(@NotNull final Bytes buffer, long position, long len)
throws BufferUnderflowException, IORuntimeException {
final long pos = buffer.readPosition();
final long limit = buffer.readLimit();
buffer.readPositionRemaining(position, len);
try {
final StringBuilder builder = new StringBuilder();
while (buffer.readRemaining() > 0) {
builder.append((char) buffer.readByte());
}
// remove the last comma
return builder.toString();
} finally {
buffer.readLimit(limit);
buffer.readPosition(pos);
}
}
/**
* copies the contents of bytes into a direct byte buffer
*
* @param bytes the bytes to wrap
* @return a direct byte buffer contain the {@code bytes}
*/
static Bytes allocateDirect(@NotNull byte[] bytes) throws IllegalArgumentException {
Bytes result = allocateDirect(bytes.length);
try {
result.write(bytes);
} catch (BufferOverflowException | IORuntimeException e) {
throw new AssertionError(e);
}
return result;
}
static Bytes fromHexString(String s) {
return BytesInternal.fromHexString(s);
}
/**
* Return a Bytes which is optionally unchecked. This allows bounds checks to be turned off.
*
* @param unchecked if true, minimal bounds checks will be performed.
* @return Bytes without bounds checking.
* @throws IllegalStateException if the underlying BytesStore has been released
*/
default Bytes unchecked(boolean unchecked) throws IllegalStateException {
return unchecked ?
start() == 0 && bytesStore() instanceof NativeBytesStore ?
new UncheckedNativeBytes<>(this) :
new UncheckedBytes<>(this) :
this;
}
/**
* @return the size which can be safely read. If this isElastic() it can be lower than the
* point it can safely write.
*/
default long safeLimit() {
return bytesStore().safeLimit();
}
/**
* @return is the readPosition at the start and the writeLimit at the end.
*/
default boolean isClear() {
return start() == readPosition() && writeLimit() == capacity();
}
/**
* @return if isElastic, this can be much lower than the virtual capacity().
*/
default long realCapacity() {
return BytesStore.super.realCapacity();
}
/**
* @return a copy of this Bytes from position() to limit().
*/
BytesStore, Underlying> copy();
/**
* display the hex data of {@link Bytes} from the position() to the limit()
*
* @return hex representation of the buffer, from example [0D ,OA, FF]
*/
@NotNull
default String toHexString() throws IORuntimeException {
return toHexString(1024);
}
/**
* display the hex data of {@link Bytes} from the position() to the limit()
*
* @param maxLength limit the number of bytes to be dumped.
* @return hex representation of the buffer, from example [0D ,OA, FF]
*/
@NotNull
default String toHexString(long maxLength)
throws IORuntimeException {
return toHexString(readPosition(), maxLength);
}
/**
* display the hex data of {@link Bytes} from the position() to the limit()
*
* @param maxLength limit the number of bytes to be dumped.
* @return hex representation of the buffer, from example [0D ,OA, FF]
*/
@NotNull
default String toHexString(long offset, long maxLength)
throws IORuntimeException {
long maxLength2 = Math.min(maxLength, readLimit() - offset);
String ret = BytesInternal.toHexString(this, offset, maxLength2);
return maxLength2 < readLimit() - offset ? ret + "... truncated" : ret;
}
/**
* @return can the Bytes resize when more data is written than it's realCapacity()
*/
boolean isElastic();
/**
* grow the buffer if the buffer is elastic, if the buffer is not elastic and there is not
* enough capacity then this method will throws {@link java.nio.BufferOverflowException}
*
* @param size the capacity that you required
* @throws IllegalArgumentException if the buffer is not elastic and there is not enough space
* @throws IORuntimeException if an error occured trying to resize the underlying buffer.
*/
default void ensureCapacity(long size)
throws IllegalArgumentException, IORuntimeException {
if (size > capacity())
throw new IllegalArgumentException(isElastic() ? "todo" : "not elastic");
}
/**
* Creates a slice of the current Bytes based on its position() and limit(). As a sub-section
* of a Bytes it cannot be elastic.
*
* @return a slice of the existing Bytes where the start is moved to the position and the
* current limit determines the capacity.
* @throws IllegalStateException if the underlying BytesStore has been released
*/
@Override
default Bytes bytesForRead() throws IllegalStateException {
return isClear() ? BytesStore.super.bytesForRead() : new SubBytes<>(this, readPosition(), readLimit() + start());
}
/**
* @return the ByteStore this Bytes wraps.
*/
BytesStore bytesStore();
default boolean isEqual(String s) {
return StringUtils.isEqual(this, s);
}
default boolean isEmpty() {
return readRemaining() == 0;
}
/**
* Compact these Bytes by moving the readPosition to the start.
*
* @return this
*/
Bytes compact();
@Override
default long copyTo(@NotNull BytesStore store) {
return BytesStore.super.copyTo(store);
}
@Override
default void copyTo(OutputStream out) throws IOException {
BytesStore.super.copyTo(out);
}
@Override
default boolean sharedMemory() {
return bytesStore().sharedMemory();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy