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

net.openhft.chronicle.bytes.BytesUtil 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.internal.BytesFieldInfo;
import net.openhft.chronicle.bytes.internal.BytesInternal;
import net.openhft.chronicle.bytes.internal.ReferenceCountedUtil;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.Maths;
import net.openhft.chronicle.core.Memory;
import net.openhft.chronicle.core.OS;
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.InvalidMarshallableException;
import net.openhft.chronicle.core.io.ThreadingIllegalStateException;
import net.openhft.chronicle.core.util.ClassLocal;
import net.openhft.chronicle.core.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.List;

import static net.openhft.chronicle.core.UnsafeMemory.MEMORY;
import static net.openhft.chronicle.core.io.IOTools.*;

/**
 * Utility class for performing operations on Bytes and related data types.
 *
 * 

This class provides a collection of static methods to manipulate and * interact with Bytes objects. These methods include transformations, checks, * and complex calculations not provided in the Bytes class itself. * *

Some of the operations provided in this class include: *

    *
  • Converting Bytes objects to different representations, such as char arrays.
  • *
  • Reading and writing specific data formats from/to Bytes objects, such as stop bits.
  • *
  • Manipulating the content of Bytes objects, such as combining double newlines or reversing contents.
  • *
  • Performing complex mathematical calculations, like rounding up values based on byte alignment.
  • *
  • Providing utility methods for exceptions, booleans and byte manipulations.
  • *
* *

All methods in this class throw {@link java.lang.NullPointerException} if the objects provided to them are {@code null}. * * @see Bytes */ @SuppressWarnings("rawtypes") public enum BytesUtil { ; // none /** * An empty array of integers, for use in various methods. */ private static final int[] NO_INTS = {}; /** * Cache for results of {@link #isTriviallyCopyable0(Class)}. */ private static final ClassLocal TRIVIALLY_COPYABLE = ClassLocal.withInitial(BytesUtil::isTriviallyCopyable0); /** * The current user's name, retrieved from system properties, default is "unknown" if not set. */ private static final String USER_NAME = Jvm.getProperty("user.name", "unknown"); /** * The directory for timestamp, retrieved from system properties, defaults to OS temporary directory if not set. */ private static final String TIME_STAMP_DIR = Jvm.getProperty("timestamp.dir", OS.TMP); /** * The path for timestamp file, defaults to a file named .time-stamp.username.dat in timestamp directory. */ static final String TIME_STAMP_PATH = Jvm.getProperty("timestamp.path", new File(TIME_STAMP_DIR, ".time-stamp." + USER_NAME + ".dat").getAbsolutePath()); /** * Checks if the given class is trivially copyable. * * @param clazz Class to check. * @return true if the class is trivially copyable, false otherwise. */ public static boolean isTriviallyCopyable(@NotNull Class clazz) { final int[] ints = TRIVIALLY_COPYABLE.get(clazz); return ints[1] > 0; } /** * Helper method to determine if the given class is trivially copyable. * * @param clazz Class to check. * @return An array of integers representing certain properties of the class related to its copyability. * @throws UnsupportedOperationException If running on Azul Zing JVM. */ static int[] isTriviallyCopyable0(@NotNull Class clazz) { if (clazz.isArray()) { ClasscomponentType = clazz.getComponentType(); if (componentType.isPrimitive()) return new int[]{MEMORY.arrayBaseOffset(clazz)}; return NO_INTS; } List fields = BytesFieldInfo.fields(clazz); return calculateMinMax(fields); } /** * Calculates the minimum and maximum offset for the fields of a given class. * * @param fields The fields of the class. * @return An array of two integers, where the first element is the minimum offset, and the second element is the maximum offset. */ private static int[] calculateMinMax(final List fields) { int min = 0; int max = 0; for (Field field : fields) { final FieldGroup fieldGroup = Jvm.findAnnotation(field, FieldGroup.class); int start = (int) MEMORY.objectFieldOffset(field); int size = sizeOf(field.getType()); int end = start + size; boolean nonTrivial = !field.getType().isPrimitive(); if (nonTrivial) { if (max > 0) break; // otherwise skip them. } else { if (min == 0) min = start; max = end; } } return new int[]{min, max}; } /** * Checks if all the fields in the specified range of the given class are trivially copyable. * * @param clazz Class to check. * @param offset Start of the field area. * @param length Length of the field area. * @return true if all fields in the range are trivially copyable, false otherwise. */ public static boolean isTriviallyCopyable(Classclazz, @NonNegative int offset, @NonNegative int length) { int[] ints = TRIVIALLY_COPYABLE.get(clazz); if (ints.length == 0) return false; return offset >= ints[0] && (ints.length == 1 || offset + length <= ints[1]); } /** * Returns the range within which a class is trivially copyable. * * @param clazz Class to get the range for. * @return An array of integers representing the range in which the class is trivially copyable. */ public static int[] triviallyCopyableRange(Classclazz) { return TRIVIALLY_COPYABLE.get(clazz); } /** * Returns the offset of the first byte of the trivially copyable fields of a given class. * * @param clazz The class to examine. * @return The offset of the first byte that is trivially copyable. */ public static int triviallyCopyableStart(Classclazz) { return triviallyCopyableRange(clazz)[0]; } /** * Returns the length of the trivially copyable fields in a given class. * Note that references are ignored as they are not considered trivially copyable. * * @param clazz The class to examine. * @return The length of the trivially copyable data. */ public static int triviallyCopyableLength(Classclazz) { final int[] startEnd = triviallyCopyableRange(clazz); return startEnd[1] - startEnd[0]; } /** * Returns the size of a given type. * * @param type The type to calculate the size of. * @return The size of the type in bytes. */ private static int sizeOf(Class type) { return Memory.sizeOf(type); } /** * Finds the absolute path of a file specified by name. * Throws an exception if the file does not exist. * * @param name The name of the file to find. * @return The absolute path of the file. * @throws FileNotFoundException If the file does not exist. */ public static String findFile(@NotNull String name) throws FileNotFoundException { File file = new File(name); URL url = null; if (!file.exists()) { url = urlFor(Thread.currentThread().getContextClassLoader(), name); String file2 = url.getFile().replace("%20", " ") .replace("target/test-classes", "src/test/resources"); file = new File(file2); } if (!file.exists()) throw new FileNotFoundException(name); return file.getAbsolutePath(); } /** * Reads the content of a file specified by name into a Bytes object. * If the name starts with "=", the rest of the name string will be converted to Bytes directly. * * @param name The name of the file to read. * @return The content of the file as a Bytes object. * @throws IOException If an I/O error occurs. */ public static Bytes readFile(@NotNull String name) throws IOException { if (name.startsWith("=")) { return Bytes.from(name.substring(1)); } File file = new File(name); URL url = null; if (!file.exists()) { url = urlFor(Thread.currentThread().getContextClassLoader(), name); file = new File(url.getFile()); } return Bytes.wrapForRead(readAsBytes(url == null ? new FileInputStream(file) : open(url))); } /** * Writes the content of a Bytes object to a file specified by name. * * @param file The name of the file to write to. * @param bytes The Bytes object containing the data to write. * @throws IOException If an I/O error occurs. */ public static void writeFile(String file, Bytes bytes) throws IOException { try (OutputStream os = new FileOutputStream(file)) { os.write(bytes.underlyingObject()); } } /** * Compares bytes from two RandomDataInput objects to check if they are equal. * * @param a The first RandomDataInput object. * @param offset The starting position in the first object. * @param second The second RandomDataInput object. * @param secondOffset The starting position in the second object. * @param len The number of bytes to compare. * @return true if the bytes are equal, false otherwise. * @throws BufferUnderflowException If there is insufficient 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. */ public static boolean bytesEqual( @NotNull RandomDataInput a, @NonNegative long offset, @NotNull RandomDataInput second, long secondOffset, long len) throws BufferUnderflowException, IllegalStateException, ClosedIllegalStateException { long i = 0; while (len - i >= 8L) { if (a.readLong(offset + i) != second.readLong(secondOffset + i)) return false; i += 8L; } if (len - i >= 4L) { if (a.readInt(offset + i) != second.readInt(secondOffset + i)) return false; i += 4L; } if (len - i >= 2L) { if (a.readShort(offset + i) != second.readShort(secondOffset + i)) return false; i += 2L; } if (i < len) return a.readByte(offset + i) == second.readByte(secondOffset + i); return true; } /** * Compares a CharSequence with bytes from a RandomDataInput object to check if they are equal. * * @param cs The CharSequence to compare. * @param bs The RandomDataInput object. * @param offset The starting position in the RandomDataInput object. * @param length The number of bytes to compare. * @return true if the bytes are equal to the CharSequence, false otherwise. * @throws BufferUnderflowException If there is insufficient 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 */ public static boolean bytesEqual(@Nullable CharSequence cs, @NotNull RandomDataInput bs, @NonNegative long offset, @NonNegative int length) throws IllegalStateException, BufferUnderflowException { if (cs == null || cs.length() != length) return false; for (int i = 0; i < length; i++) { if (cs.charAt(i) != bs.readUnsignedByte(offset + i)) return false; } return true; } /** * Compares two objects for equality, with special handling for CharSequences. * * @param o1 The first object to compare. * @param o2 The second object to compare. * @return true if the objects are equal, false otherwise. */ public static boolean equals(Object o1, Object o2) { if (o1 == o2) return true; if (o1 instanceof CharSequence && o2 instanceof CharSequence) return StringUtils.isEqual((CharSequence) o1, (CharSequence) o2); return o1 != null && o1.equals(o2); } /** * Converts a string to an integer using ISO_8859_1 encoding. * * @param str The string to convert. * @return The integer value of the string. */ public static int asInt(@NotNull String str) { @NotNull ByteBuffer bb = ByteBuffer.wrap(str.getBytes(StandardCharsets.ISO_8859_1)).order(ByteOrder.nativeOrder()); return bb.getInt(); } /** * Calculates the number of bytes required to store a variable-length integer * using the stop bit encoding. * * @param n The integer to calculate the length for. * @return The number of bytes required to store the integer. */ public static int stopBitLength(long n) { if ((n & ~0x7F) == 0) { return 1; } if ((n & ~0x3FFF) == 0) { return 2; } return BytesInternal.stopBitLength0(n); } /** * Converts the bytes from a Bytes object into a character array. * * @param bytes The Bytes object to convert. * @return The character array converted from the bytes. * @throws ArithmeticException If there is an arithmetic error. * @throws BufferUnderflowException If there is insufficient 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 */ @NotNull public static char[] toCharArray(@NotNull Bytes bytes) throws ArithmeticException, IllegalStateException, BufferUnderflowException { @NotNull final char[] chars = new char[Maths.toUInt31(bytes.readRemaining())]; for (int i = 0; i < bytes.readRemaining(); i++) { chars[i] = (char) bytes.readUnsignedByte(i + bytes.readPosition()); } return chars; } /** * Converts a specific range of bytes from a Bytes object into a character array. * * @param bytes The Bytes object to convert. * @param position The starting position in the Bytes object. * @param length The number of bytes to convert. * @return The character array converted from the bytes. * @throws BufferUnderflowException If there is insufficient 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 */ @NotNull public static char[] toCharArray(@NotNull Bytes bytes, @NonNegative long position, @NonNegative int length) throws IllegalStateException, BufferUnderflowException { @NotNull final char[] chars = new char[length]; int j = 0; for (int i = 0; i < length; i++) { chars[j++] = (char) bytes.readUnsignedByte(position + i); } return chars; } /** * Reads a variable-length integer from a StreamingDataInput using the stop bit encoding. * * @param in The StreamingDataInput to read from. * @return The integer read. * @throws IORuntimeException If an IO error occurs. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static long readStopBit(@NotNull StreamingDataInput in) throws IORuntimeException, IllegalStateException, ClosedIllegalStateException { return BytesInternal.readStopBit(in); } /** * Writes a variable-length integer to a StreamingDataOutput using the stop bit encoding. * * @param out The StreamingDataOutput to write to. * @param n The integer to write. * @throws BufferOverflowException If there is insufficient space. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static void writeStopBit(@NotNull StreamingDataOutput out, long n) throws IllegalStateException, BufferOverflowException, ClosedIllegalStateException { BytesInternal.writeStopBit(out, n); } /** * Writes a variable-length integer to a specific position in a BytesStore using the stop bit encoding. * * @param bs The BytesStore to write to. * @param offset The position in the BytesStore to start writing. * @param n The integer to write. * @return The resulting offset after writing. * @throws BufferOverflowException If there is insufficient space. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static long writeStopBit(BytesStore bs, @NonNegative long offset, @NonNegative long n) throws IllegalStateException, BufferOverflowException, ClosedIllegalStateException { return BytesInternal.writeStopBit(bs, offset, n); } /** * Writes a variable-length integer to a specific memory address using the stop bit encoding. * * @param addr The memory address to write to. * @param n The integer to write. * @return The resulting memory address after writing. * @throws BufferOverflowException If there is insufficient space. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static long writeStopBit(long addr, long n) throws BufferOverflowException { return BytesInternal.writeStopBit(addr, n); } /** * Parses a UTF-8 string from a StreamingDataInput and appends it to an Appendable object. * * @param in The StreamingDataInput to read from. * @param appendable The Appendable to append to. * @param utflen The length of the UTF-8 string. * @throws UTFDataFormatRuntimeException If the UTF-8 format is invalid. * @throws BufferUnderflowException If there is insufficient 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. */ public static void parseUtf8( @NotNull StreamingDataInput in, Appendable appendable, @NonNegative int utflen) throws UTFDataFormatRuntimeException, IllegalStateException, BufferUnderflowException, ClosedIllegalStateException { BytesInternal.parseUtf8(in, appendable, true, utflen); } /** * Writes a CharSequence as a UTF-8 string to a StreamingDataOutput. * * @param out The StreamingDataOutput to write to. * @param cs The CharSequence to write. * @throws IndexOutOfBoundsException If the CharSequence length is out of bounds. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static void appendUtf8(@NotNull StreamingDataOutput out, @NotNull CharSequence cs) throws IndexOutOfBoundsException, ClosedIllegalStateException, ThreadingIllegalStateException { BytesInternal.appendUtf8(out, cs, 0, cs.length()); } /** * Reads a Marshallable object from a BytesIn object. * * @param marshallable The Marshallable object to read. * @param bytes The BytesIn object to read from. * @throws InvalidMarshallableException If the Marshallable object is invalid. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @SuppressWarnings("unchecked") public static void readMarshallable(@NotNull ReadBytesMarshallable marshallable, BytesIn bytes) throws InvalidMarshallableException { BytesMarshaller.BYTES_MARSHALLER_CL.get(marshallable.getClass()) .readMarshallable(marshallable, bytes); } /** * Writes a Marshallable object to a BytesOut object. * * @param marshallable The Marshallable object to write. * @param bytes The BytesOut object to write to. * @throws BufferOverflowException If there is insufficient space. * @throws ArithmeticException If an arithmetic error occurs. * @throws BufferUnderflowException If there is insufficient data. * @throws InvalidMarshallableException If the Marshallable object is invalid. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ @SuppressWarnings("unchecked") public static void writeMarshallable(@NotNull WriteBytesMarshallable marshallable, BytesOut bytes) throws IllegalStateException, BufferOverflowException, ArithmeticException, BufferUnderflowException, InvalidMarshallableException { BytesMarshaller.BYTES_MARSHALLER_CL.get(marshallable.getClass()) .writeMarshallable(marshallable, bytes); } /** * Returns a string representation of a throwable's stack trace prefixed with a given string. * * @param s The string to prefix the stack trace. * @param t The throwable to represent. * @return The string representation of the throwable's stack trace. */ static String asString(String s, Throwable t) { StringWriter sw = new StringWriter(); sw.append(s).append("\n"); t.printStackTrace(new PrintWriter(sw)); return sw.toString(); } /** * Converts a byte to a boolean. The byte is considered to represent the boolean value false * if it equals 0, 'N', or 'n'. Otherwise, it represents true. * * @param b The byte to convert. * @return The boolean value represented by the byte. */ public static boolean byteToBoolean(byte b) { return b != 0 && b != 'N' && b != 'n'; } /** * Rounds up a long value to the nearest multiple of 64. * * @param x The value to round up. * @return The rounded value. */ public static long roundUpTo64ByteAlign(long x) { return (x + 63L) & ~63L; } /** * Rounds up a long value to the nearest multiple of 8. * * @param x The value to round up. * @return The rounded value. */ public static long roundUpTo8ByteAlign(long x) { return (x + 7L) & ~7L; } /** * Reads padding bytes from a Bytes object to align the read position to the nearest 8-byte boundary. * * @param bytes The Bytes object. * @throws BufferUnderflowException If there is insufficient 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. */ public static void read8ByteAlignPadding(Bytes bytes) throws IllegalStateException, BufferUnderflowException { bytes.readPosition(roundUpTo8ByteAlign(bytes.readPosition())); } /** * Writes padding bytes to a Bytes object to align the write position to the nearest 8-byte boundary. * * @param bytes The Bytes object. * @throws BufferOverflowException If there is insufficient space. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static void write8ByteAlignPadding(Bytes bytes) throws BufferOverflowException, ClosedIllegalStateException { long start = bytes.writePosition(); long end = roundUpTo8ByteAlign(start); bytes.writePosition(end); bytes.zeroOut(start, end); } /** * Returns a debug string representation of a portion of a RandomDataInput object. * * @param bytes The RandomDataInput object. * @param start The starting position. * @param maxLength The maximum length. * @return The debug string. * @throws BufferUnderflowException If there is insufficient data. */ public static String toDebugString(@NotNull RandomDataInput bytes, @NonNegative long start, @NonNegative long maxLength) throws IllegalStateException, BufferUnderflowException { BytesStore bytes2 = bytes.subBytes(start, maxLength); return bytes2.toDebugString(maxLength); } /** * Copies 8-bit data from a BytesStore object to a specified address. * * @param bs The BytesStore object. * @param addressForWrite The address for writing. * @param length The length of data to copy. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static void copy8bit(BytesStore bs, long addressForWrite, @NonNegative long length) throws ClosedIllegalStateException { BytesInternal.copy8bit(bs, addressForWrite, length); } /** * Reverses the contents of a Bytes object from a specified starting position. * * @param text The Bytes object. * @param start The starting position. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static void reverse(Bytes text, @NonNegative int start) throws ClosedIllegalStateException { long rp = text.readPosition(); int end = text.length() - 1; int mid = (start + end + 1) / 2; for (int i = 0; i < mid - start; ++i) { char ch = text.charAt(start + i); text.writeUnsignedByte(rp + start + i, text.charAt(end - i)); text.writeUnsignedByte(rp + end - i, ch); } } /** * Pads an offset to align it to the nearest multiple of 4. * * @param from The original offset. * @return The padded offset. */ public static long padOffset(long from) { return (-from) & 0x3L; } /** * Checks the last two characters of the given Bytes object. If the last two characters are * both newlines, one of them is removed to ensure only a single newline remains. If the last * character is a space and the character before it is a space, newline or non-printable, * the last character is removed. * * @param bytes to check and trim as needed. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static void combineDoubleNewline(Bytes bytes) { long wp = bytes.writePosition(); long delta = wp - bytes.start(); final int ch1 = delta >= 1 ? bytes.peekUnsignedByte(wp - 1) : '\0'; switch (ch1) { case '\n': { final int ch2 = delta >= 2 ? bytes.peekUnsignedByte(wp - 2) : '\0'; switch (ch2) { case '\n': bytes.writePosition(wp - 1); return; case ' ': bytes.writePosition(wp - 2); bytes.append('\n'); return; default: return; } } case ' ': { final int ch2 = delta >= 2 ? bytes.peekUnsignedByte(wp - 2) : '\0'; if (ch2 == ' ') { final int ch3 = delta >= 3 ? bytes.peekUnsignedByte(wp - 3) : '\0'; if (ch3 > ' ') { bytes.writePosition(wp - 1); } } } } } /** * Checks if the given character is a control space character. A control space character * is defined as a character in the range from 0 to space (inclusive). * * @param ch The character to check. * @return True if the character is a control space character, false otherwise. */ static boolean isControlSpace(int ch) { return 0 <= ch && ch <= ' '; } /** * Returns a copy of the given Bytes object. The Bytes object must not have been released. * If the Bytes object is empty, an empty BytesStore is returned. * * @param bytes The Bytes object to copy. * @return A copy of the given Bytes object. * @throws ClosedIllegalStateException If the resource has been released or closed. * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way. */ public static Bytes copyOf(@NotNull final Bytes bytes) throws ClosedIllegalStateException, ThreadingIllegalStateException { ReferenceCountedUtil.throwExceptionIfReleased(bytes); final long remaining = bytes.readRemaining(); final long position = bytes.readPosition(); final Bytes bytes2 = Bytes.allocateDirect(Math.max(1, remaining)); bytes2.write(bytes, position, remaining); return bytes2; } /** * Issues a warning that elastic bytes are wrapped with unchecked() must call ensureCapacity() manually. */ static final class WarnUncheckedElasticBytes { static { Jvm.debug().on(WarnUncheckedElasticBytes.class, "Wrapping elastic bytes with unchecked() will require calling ensureCapacity() as needed!"); } private WarnUncheckedElasticBytes() { } @SuppressWarnings("EmptyMethod") static void warn() { // static block does the work. } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy