├── src ├── test │ ├── resources │ │ ├── file-to-find.txt │ │ └── btmtt-invalid │ │ │ └── prim-output.txt │ └── java │ │ └── net │ │ └── openhft │ │ └── chronicle │ │ └── bytes │ │ ├── perf │ │ ├── ContentEqual20JLBH.java │ │ ├── ContentEqual2JLBH.java │ │ ├── ContentEqual128JLBH.java │ │ ├── ContentEqual8192JLBH.java │ │ ├── NativeBytesReadWriteJLBH.java │ │ ├── OnHeapBytesReadWriteJLBH.java │ │ ├── ChunkedMappedBytesReadWriteJLBH.java │ │ └── SingleMappedBytesReadWriteJLBH.java │ │ ├── CommonMarshallableTest.java │ │ ├── IBytesMethod.java │ │ ├── StopCharsTesterTest.java │ │ ├── CipherPerfMain.java │ │ ├── readme │ │ ├── README.adoc │ │ └── CASTest.java │ │ ├── util │ │ ├── CompressionTest.java │ │ ├── DecoratedBufferOverflowExceptionTest.java │ │ ├── Bit8StringInternerTest.java │ │ ├── StringInternerBytesTest.java │ │ ├── CompressionsTest.java │ │ ├── EscapingStopCharsTesterTest.java │ │ └── EscapingStopCharTesterTest.java │ │ ├── VanillaBytesEnsureCapacityTest.java │ │ ├── internal │ │ ├── BytesInternalSubBytesErrorsTest.java │ │ ├── ResourceUtilTest.java │ │ ├── HeapBytesStoreOpsTest.java │ │ ├── NativeBytesStoreOpsTest.java │ │ ├── Parse8bitVariantsTest.java │ │ ├── CanonicalPathUtilTest.java │ │ ├── ReferenceCountedUtilTest.java │ │ ├── BytesInternalContentEqualTest.java │ │ ├── ByteStringReaderWriterTest.java │ │ └── BytesInternalUtf8Test.java │ │ ├── StopBitLengthTest.java │ │ ├── UnicodeToStringTest.java │ │ ├── UncheckedBytesBehaviourTest.java │ │ ├── BytesUtilEqualityTest.java │ │ ├── ReleasedBytesStoreTest.java │ │ ├── PrewriteTest.java │ │ ├── MyBytes.java │ │ ├── BytesDebugAndUtf8Test.java │ │ ├── BytesCopyOfTest.java │ │ ├── RandomDataInputUtf8LimitedMoreTest.java │ │ ├── VanillaBytesOpsTest.java │ │ ├── MyNested.java │ │ ├── ZeroCostAssertionStatusTest.java │ │ ├── RingBufferReaderTest.java │ │ ├── StopCharTesterTest.java │ │ ├── HexDumpBytesAdvancedTest.java │ │ ├── MethodReaderBuilderTest.java │ │ ├── ReferenceTracingLeakTest.java │ │ ├── ByteCheckSumTest.java │ │ ├── VanillaBytesTest.java │ │ ├── UTF8BytesTest.java │ │ ├── VanillaBytesCapacityAndZeroOutTest.java │ │ ├── pool │ │ └── BytesPoolTest.java │ │ ├── CopyToTest.java │ │ ├── BytesContextTest.java │ │ ├── Issue225Test.java │ │ ├── ConnectionDroppedExceptionTest.java │ │ ├── HeapByteStoreTest.java │ │ ├── PrintVdsoMain.java │ │ ├── TempDirectoryIntegrationTest.java │ │ ├── StopBitDecimalTest.java │ │ ├── MyByteable.java │ │ ├── ref │ │ ├── TextLongArrayReferenceTest.java │ │ ├── BinaryIntReferenceTest.java │ │ ├── UncheckedLongReferenceTest.java │ │ ├── TextIntReferenceTest.java │ │ ├── TextLongReferenceTest.java │ │ ├── BinaryTwoLongReferenceTest.java │ │ └── BooleanReferenceTest.java │ │ ├── MyScalars.java │ │ ├── Issue281Test.java │ │ ├── BytesWrite8bitRoundTripTest.java │ │ ├── BytesBoundsAndLimitsTest.java │ │ ├── BytesRingBufferTest.java │ │ ├── BytesMethodReaderBuilderTest.java │ │ ├── SyncModeTest.java │ │ ├── StreamingInputStreamTest.java │ │ ├── issue │ │ ├── Issue462Test.java │ │ └── Issue464BytesStoreEmptyTest.java │ │ ├── Issue128Test.java │ │ ├── ReadLenientTest.java │ │ ├── ByteableTest.java │ │ ├── MappedBytesWrite8bitBoundaryTest.java │ │ ├── HexDumpBytesTest.java │ │ ├── algo │ │ └── XxHashTest.java │ │ ├── VanillaBytesUsageTest.java │ │ ├── BytesCopyMatrixTest.java │ │ ├── MappedBytesStoreFactoryTest.java │ │ ├── NativeBytesOverflowTest.java │ │ └── BytesWriteSkipBehaviourTest.java └── main │ ├── java │ └── net │ │ └── openhft │ │ └── chronicle │ │ └── bytes │ │ ├── package-info.java │ │ ├── algo │ │ └── package-info.java │ │ ├── pool │ │ └── package-info.java │ │ ├── ref │ │ ├── package-info.java │ │ ├── TwoLongReference.java │ │ ├── LongReference.java │ │ ├── ByteableIntArrayValues.java │ │ └── ByteableLongArrayValues.java │ │ ├── util │ │ ├── package-info.java │ │ ├── DecoratedBufferOverflowException.java │ │ ├── DecoratedBufferUnderflowException.java │ │ ├── EscapingStopCharTester.java │ │ └── EscapingStopCharsTester.java │ │ ├── render │ │ ├── package-info.java │ │ ├── Decimaliser.java │ │ ├── StandardDecimaliser.java │ │ └── DecimalAppender.java │ │ ├── domestic │ │ └── package-info.java │ │ ├── internal │ │ ├── package-info.java │ │ ├── HasUncheckedRandomDataInput.java │ │ ├── migration │ │ │ └── HashCodeEqualsUtil.java │ │ ├── Chars.java │ │ ├── CanonicalPathUtil.java │ │ ├── Unmapper.java │ │ └── ReferenceCountedUtil.java │ │ ├── DynamicallySized.java │ │ ├── OffsetFormat.java │ │ ├── BytesParselet.java │ │ ├── NewChunkListener.java │ │ ├── CommonMarshallable.java │ │ ├── FieldGroup.java │ │ ├── DistributedUniqueTimeDeduplicator.java │ │ ├── BytesMethodWriterInvocationHandler.java │ │ ├── BytesConsumer.java │ │ ├── BytesContext.java │ │ ├── MultiReaderBytesRingBuffer.java │ │ ├── MethodId.java │ │ ├── SyncMode.java │ │ ├── MethodReaderInterceptorReturns.java │ │ ├── HexDumpBytesDescription.java │ │ ├── MethodWriterInterceptorReturns.java │ │ ├── StreamingCommon.java │ │ ├── Invocation.java │ │ ├── UpdateInterceptor.java │ │ ├── MappedBytesStoreFactory.java │ │ ├── RingBufferReaderStats.java │ │ ├── StopCharTester.java │ │ ├── WriteBytesMarshallable.java │ │ ├── UTFDataFormatRuntimeException.java │ │ ├── BytesRingBufferStats.java │ │ ├── MethodWriterInvocationHandler.java │ │ ├── StopCharsTester.java │ │ ├── ConnectionDroppedException.java │ │ └── BytesMarshallable.java │ └── docs │ ├── decimal-rendering.adoc │ └── pool-overview.adoc ├── docs ├── images │ ├── bytes2.jpg │ ├── Figure1.png │ ├── customize-data-views.png │ ├── customize-data-views-menu.jpg │ └── customize-data-views-menu.tiff └── systemProperties.adoc ├── images └── Bytes_line.png ├── microbenchmarks ├── system.properties ├── README.adoc └── src │ └── main │ └── java │ └── net │ └── openhft │ └── chronicle │ └── bytes │ └── microbenchmarks │ ├── jmh │ └── ElasticBenchmarkRunner.java │ ├── AppendLongCoolerMain.java │ ├── BytesCoolerMain.java │ └── DistributedUniqueTimeProviderBenchmark.java ├── system.properties └── .gitignore /src/test/resources/file-to-find.txt: -------------------------------------------------------------------------------- 1 | empty 2 | -------------------------------------------------------------------------------- /docs/images/bytes2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Bytes/HEAD/docs/images/bytes2.jpg -------------------------------------------------------------------------------- /images/Bytes_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Bytes/HEAD/images/Bytes_line.png -------------------------------------------------------------------------------- /docs/images/Figure1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Bytes/HEAD/docs/images/Figure1.png -------------------------------------------------------------------------------- /docs/images/customize-data-views.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Bytes/HEAD/docs/images/customize-data-views.png -------------------------------------------------------------------------------- /docs/images/customize-data-views-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Bytes/HEAD/docs/images/customize-data-views-menu.jpg -------------------------------------------------------------------------------- /docs/images/customize-data-views-menu.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenHFT/Chronicle-Bytes/HEAD/docs/images/customize-data-views-menu.tiff -------------------------------------------------------------------------------- /microbenchmarks/system.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | # 4 | 5 | jvm.resource.tracing=false 6 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/algo/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.algo; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/pool/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.pool; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/ref/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/util/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/render/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.render; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/domestic/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.domestic; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/DynamicallySized.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | /** 7 | * Marker for {@link Byteable} objects whose encoded length may vary with their state. 8 | */ 9 | public interface DynamicallySized { 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/ContentEqual20JLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | public class ContentEqual20JLBH { 7 | public static void main(String[] args) { 8 | ContentEqualJLBH.runWith(() -> ContentEqualJLBH.bytesFor(20)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/ContentEqual2JLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | public class ContentEqual2JLBH { 7 | public static void main(String[] args) { 8 | ContentEqualJLBH.runWith(() -> ContentEqualJLBH.bytesFor(2)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/ContentEqual128JLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | public class ContentEqual128JLBH { 7 | public static void main(String[] args) { 8 | ContentEqualJLBH.runWith(() -> ContentEqualJLBH.bytesFor(128)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/ContentEqual8192JLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | public class ContentEqual8192JLBH { 7 | public static void main(String[] args) { 8 | ContentEqualJLBH.runWith(() -> ContentEqualJLBH.bytesFor(8192)); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/NativeBytesReadWriteJLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | 8 | public class NativeBytesReadWriteJLBH { 9 | 10 | public static void main(String[] args) { 11 | BytesReadWriteJLBH.runForBytes(Bytes.allocateElasticDirect(1024 * 1024)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/OnHeapBytesReadWriteJLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | 8 | public class OnHeapBytesReadWriteJLBH { 9 | 10 | public static void main(String[] args) { 11 | BytesReadWriteJLBH.runForBytes(Bytes.allocateElasticOnHeap(1024 * 1024)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /system.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | # 4 | 5 | # Tracing if resources are closed/released correctly. 6 | jvm.resource.tracing=true 7 | disable.resource.warning=true 8 | disable.discard.warning=false 9 | # for profiling 10 | jvm.safepoint.enabled=false 11 | # temporary option 12 | warnAndCloseIfNotClosed=true 13 | # reduce logging of the announcer 14 | chronicle.announcer.disable=true 15 | # to ease migration of other repos 16 | bytes.append.0=false 17 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/CommonMarshallableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class CommonMarshallableTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void usesSelfDescribingMessage() { 14 | assertTrue(new CommonMarshallable() { 15 | }.usesSelfDescribingMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/IBytesMethod.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.InvalidMarshallableException; 7 | 8 | interface IBytesMethod { 9 | @MethodId(0x81L) 10 | void myByteable(MyByteable byteable) throws InvalidMarshallableException; 11 | 12 | @MethodId(0x82L) 13 | void myScalars(MyScalars scalars); 14 | 15 | @MethodId(0x83L) 16 | void myNested(MyNested nested); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/OffsetFormat.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.NonNegative; 7 | /** 8 | * Strategy for formatting offsets when dumping bytes. 9 | */ 10 | @FunctionalInterface 11 | public interface OffsetFormat { 12 | 13 | /** 14 | * Formats {@code offset} and appends it to {@code bytes}. 15 | */ 16 | void append(@NonNegative long offset, Bytes bytes); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/BytesParselet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | /** 7 | * Parses messages read from a {@link BytesIn} when no specific method handler 8 | * is available. 9 | */ 10 | @FunctionalInterface 11 | public interface BytesParselet { 12 | /** 13 | * Handles a message of the supplied {@code messageType} using bytes from 14 | * {@code in}. 15 | */ 16 | void accept(long messageType, BytesIn in); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/NewChunkListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.NonNegative; 7 | 8 | /** 9 | * Listener notified when a new chunk is allocated by a {@link MappedFile}. 10 | */ 11 | @FunctionalInterface 12 | public interface NewChunkListener { 13 | 14 | /** 15 | * Invoked after mapping a new chunk. 16 | */ 17 | void onNewChunk(String filename, @NonNegative int chunk, @NonNegative long delayMicros); 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/StopCharsTesterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | public class StopCharsTesterTest { 10 | 11 | @Test 12 | public void testCustomStopCharsTester() { 13 | StopCharsTester tester = (ch, peekNextCh) -> ch == ',' || ch == ';'; 14 | 15 | Assert.assertTrue(tester.isStopChar(',', 0)); 16 | Assert.assertTrue(tester.isStopChar(';', 0)); 17 | Assert.assertFalse(tester.isStopChar('a', 0)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/ChunkedMappedBytesReadWriteJLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | import net.openhft.chronicle.bytes.MappedBytes; 7 | 8 | import java.io.FileNotFoundException; 9 | 10 | public class ChunkedMappedBytesReadWriteJLBH { 11 | 12 | public static void main(String[] args) throws FileNotFoundException { 13 | try (final MappedBytes bytes = MappedBytes.mappedBytes("/dev/shm/ChunkedMappedBytesArrayReadWriteJLBH", 1024 * 1024)) { 14 | BytesReadWriteJLBH.runForBytes(bytes); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/perf/SingleMappedBytesReadWriteJLBH.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.perf; 5 | 6 | import net.openhft.chronicle.bytes.MappedBytes; 7 | 8 | import java.io.FileNotFoundException; 9 | 10 | public class SingleMappedBytesReadWriteJLBH { 11 | 12 | public static void main(String[] args) throws FileNotFoundException { 13 | try (final MappedBytes bytes = MappedBytes.singleMappedBytes("/dev/shm/SingleMappedBytesArrayReadWriteJLBH", 1024 * 1024)) { 14 | BytesReadWriteJLBH.runForBytes(bytes); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/CipherPerfMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.security.Provider; 7 | import java.security.Security; 8 | import java.util.Map; 9 | 10 | public class CipherPerfMain { 11 | public static void main(String[] args) { 12 | for (Provider providers : Security.getProviders()) { 13 | for (Map.Entry entry : providers.entrySet()) { 14 | if (entry.getKey().toString().startsWith("Cipher.")) 15 | System.out.println(entry); 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/HasUncheckedRandomDataInput.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Provides a means to obtain an {@link UncheckedRandomDataInput} view for fast 10 | * reads where bounds checks have already been performed by the caller. 11 | */ 12 | @FunctionalInterface 13 | public interface HasUncheckedRandomDataInput { 14 | 15 | /** 16 | * @return a view for random reads with minimal bounds checking 17 | */ 18 | @NotNull 19 | UncheckedRandomDataInput acquireUncheckedInput(); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /microbenchmarks/README.adoc: -------------------------------------------------------------------------------- 1 | = Chronicle Bytes Microbenchmarks 2 | :lang: en-GB 3 | 4 | This module contains JMH benchmarks that measure the throughput of common 5 | operations such as primitive writes, string parsing and CAS updates. 6 | 7 | == Purpose 8 | The benchmarks help detect performance regressions and guide optimisation work. 9 | 10 | == How to Run 11 | From this directory execute: 12 | 13 | [source,bash] 14 | ---- 15 | mvn -q clean verify 16 | ---- 17 | 18 | Results are printed on the console after the JMH harness completes. 19 | 20 | == Adding Benchmarks 21 | Create a new class under `src/main/java` and follow the existing patterns. 22 | Each benchmark should document what it measures and keep setup code minimal. 23 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/readme/README.adoc: -------------------------------------------------------------------------------- 1 | = README examples for Chronicle Bytes 2 | :lang: en-GB 3 | 4 | This package contains small JUnit tests that double as usage examples. 5 | They are referenced from the main documentation and can be executed like any other unit test. 6 | 7 | == Files 8 | 9 | * `CASTest.java` 10 | * `PrimitiveTest.java` 11 | * `StopBitTest.java` 12 | * `StringsTest.java` 13 | 14 | == Running the Examples 15 | 16 | Run the tests from your IDE or via Maven: 17 | 18 | [source,bash] 19 | ---- 20 | mvn -q test -Dtest=net.openhft.chronicle.bytes.readme.* 21 | ---- 22 | 23 | The tests show basic read and write operations. 24 | They are designed to be short so the code snippets are easy to copy. 25 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/CompressionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import org.junit.Test; 8 | import static org.mockito.Mockito.*; 9 | 10 | public class CompressionTest { 11 | 12 | @Test 13 | public void testCompressWithUnsupportedAlgorithm() throws IllegalArgumentException { 14 | Bytes uncompressed = mock(Bytes.class); 15 | Bytes compressed = mock(Bytes.class); 16 | 17 | Compression.compress("unsupported_algo", uncompressed, compressed); 18 | verify(compressed, never()).write(any(Bytes.class)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/DecoratedBufferOverflowExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class DecoratedBufferOverflowExceptionTest { 11 | 12 | @Test 13 | public void testMessage() { 14 | String expectedMessage = "Custom message describing the overflow"; 15 | DecoratedBufferOverflowException exception = new DecoratedBufferOverflowException(expectedMessage); 16 | 17 | // Assert that the message is correctly set and retrieved 18 | assertEquals(expectedMessage, exception.getMessage()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/VanillaBytesEnsureCapacityTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class VanillaBytesEnsureCapacityTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void elasticEnsureCapacityGrows() { 14 | Bytes b = Bytes.allocateElasticOnHeap(8); 15 | try { 16 | long rc = b.realCapacity(); 17 | byte[] chunk = new byte[1024]; 18 | b.write(chunk); 19 | assertTrue(b.realCapacity() > rc); 20 | } finally { 21 | b.releaseLast(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/ref/TwoLongReference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Byteable; 7 | import net.openhft.chronicle.core.values.TwoLongValue; 8 | 9 | /** 10 | * Reference to two contiguous 64-bit values. 11 | * 12 | *

The interface itself does not prescribe thread-safety; the 13 | * implementation decides.

14 | * 15 | * @see BinaryTwoLongReference 16 | */ 17 | @SuppressWarnings("rawtypes") 18 | public interface TwoLongReference extends TwoLongValue, Byteable { 19 | // This interface combines TwoLongValue and Byteable 20 | // Specific method declarations are not necessary here as they are inherited 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/Bit8StringInternerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | public class Bit8StringInternerTest { 12 | 13 | @Test 14 | public void testGetValue() { 15 | Bytes bytesStore = Bytes.from("Hello World"); 16 | int length = (int) bytesStore.readRemaining(); 17 | 18 | Bit8StringInterner interner = new Bit8StringInterner(16); 19 | 20 | String internedString = interner.getValue(bytesStore, length); 21 | 22 | assertEquals("Hello World", internedString); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/CommonMarshallable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.DontChain; 7 | 8 | /** 9 | * Marker for objects that can be serialised to bytes. Implementations may choose to embed 10 | * type or structural metadata so that the resulting message is self describing. 11 | */ 12 | @DontChain 13 | public interface CommonMarshallable { 14 | 15 | /** 16 | * Indicates whether the serialised form should contain enough metadata for a generic parser to 17 | * understand it without prior knowledge of the concrete type. 18 | * 19 | * @return {@code true} by default 20 | */ 21 | default boolean usesSelfDescribingMessage() { 22 | return true; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/BytesInternalSubBytesErrorsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.junit.Test; 9 | 10 | import java.nio.BufferUnderflowException; 11 | 12 | public class BytesInternalSubBytesErrorsTest extends BytesTestCommon { 13 | 14 | @Test(expected = BufferUnderflowException.class) 15 | public void subBytesThrowsWhenLengthTooLarge() { 16 | Bytes src = Bytes.from("abc"); 17 | try { 18 | // request a sub view longer than remaining 19 | BytesInternal.subBytes(src, 0, 10); 20 | } finally { 21 | src.releaseLast(); 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /microbenchmarks/src/main/java/net/openhft/chronicle/bytes/microbenchmarks/jmh/ElasticBenchmarkRunner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.microbenchmarks.jmh; 5 | 6 | import org.openjdk.jmh.runner.Runner; 7 | import org.openjdk.jmh.runner.RunnerException; 8 | import org.openjdk.jmh.runner.options.Options; 9 | import org.openjdk.jmh.runner.options.OptionsBuilder; 10 | 11 | public class ElasticBenchmarkRunner { 12 | 13 | public static void main(String[] args) throws RunnerException { 14 | Options opt = new OptionsBuilder() 15 | .include(ElasticByteBufferJmh.class.getSimpleName()) 16 | .include(ElasticDirectJmh.class.getSimpleName()) 17 | .forks(1) 18 | .build(); 19 | 20 | new Runner(opt).run(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/FieldGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.lang.annotation.ElementType; 7 | import java.lang.annotation.Retention; 8 | import java.lang.annotation.RetentionPolicy; 9 | import java.lang.annotation.Target; 10 | /** 11 | * Groups related fields so a contiguous {@link Bytes} view can be created via utilities such as 12 | * {@link Bytes#forFieldGroup(Object, String)}. 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target(ElementType.FIELD) 16 | public @interface FieldGroup { 17 | 18 | /** 19 | * Defines the name of the field group. Multiple fields with the same {@code value} are considered 20 | * part of the same logical group. 21 | * 22 | * @return the name of the group 23 | */ 24 | String value(); 25 | } 26 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/StringInternerBytesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | public class StringInternerBytesTest extends BytesTestCommon { 14 | 15 | @Test 16 | public void testIntern() { 17 | @NotNull StringInternerBytes si = new StringInternerBytes(128); 18 | for (int i = 0; i < 100; i++) { 19 | Bytes b = Bytes.from("key" + i); 20 | si.intern(b, (int) b.readRemaining()); 21 | b.releaseLast(); 22 | } 23 | assertEquals(89, si.valueCount()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### How to update 2 | # This is copied from OpenHFT/.gitignore 3 | # update the original and run OpenHFT/update_gitignore.sh 4 | 5 | ### Compiled class file 6 | *.class 7 | 8 | ### Package Files 9 | *.jar 10 | *.war 11 | *.ear 12 | 13 | ### Log file 14 | *.log 15 | 16 | ### IntelliJ 17 | *.iml 18 | *.ipr 19 | *.iws 20 | .idea 21 | compat_reports 22 | .attach_pid* 23 | 24 | ### Virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | hs_err_pid* 26 | 27 | ### Maven template 28 | target/ 29 | pom.xml.tag 30 | pom.xml.releaseBackup 31 | pom.xml.versionsBackup 32 | pom.xml.next 33 | release.properties 34 | 35 | ### Eclipse template 36 | *.pydevproject 37 | .metadata 38 | .gradle 39 | bin/ 40 | tmp/ 41 | *.tmp 42 | *.bak 43 | *.swp 44 | *~.nib 45 | local.properties 46 | .classpath 47 | .project 48 | .settings/ 49 | .loadpath 50 | 51 | ### Queue files 52 | *.cq4t 53 | *.cq4 54 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/DistributedUniqueTimeDeduplicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | /** 7 | * Detects and optionally retains the newest timestamp for each host id so duplicates can be filtered. 8 | */ 9 | public interface DistributedUniqueTimeDeduplicator { 10 | 11 | /** 12 | * Compares {@code timestampHostId} with the last timestamp held for its host id. 13 | * 14 | * @param timestampHostId value embedding time and host id 15 | * @return -1 if older, 0 if equal or no previous value, +1 if newer 16 | */ 17 | int compareByHostId(long timestampHostId); 18 | 19 | /** 20 | * As {@link #compareByHostId(long)} but also retains {@code timestampHostId} if it is newer. 21 | */ 22 | int compareAndRetainNewer(long timestampHostId); 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/StopBitLengthTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | import static org.junit.Assert.assertTrue; 10 | 11 | public class StopBitLengthTest extends BytesTestCommon { 12 | 13 | @Test 14 | public void boundaries() { 15 | assertEquals(1, BytesUtil.stopBitLength(0)); 16 | assertEquals(1, BytesUtil.stopBitLength(0x7F)); 17 | assertEquals(2, BytesUtil.stopBitLength(0x80)); 18 | assertEquals(2, BytesUtil.stopBitLength(0x3FFF)); 19 | assertTrue(BytesUtil.stopBitLength(0x4000) >= 3); 20 | assertTrue(BytesUtil.stopBitLength(Integer.MAX_VALUE) >= 3); 21 | assertTrue(BytesUtil.stopBitLength(Long.MAX_VALUE) >= 9); 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/BytesMethodWriterInvocationHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.Closeable; 7 | 8 | import java.lang.reflect.InvocationHandler; 9 | 10 | /** 11 | * An {@link java.lang.reflect.InvocationHandler} for method writers operating 12 | * on {@link BytesOut}. It extends the standard handler contract by exposing a 13 | * hook for resource cleanup via {@link #onClose(Closeable)}. 14 | */ 15 | public interface BytesMethodWriterInvocationHandler extends InvocationHandler { 16 | 17 | /** 18 | * Register a {@link Closeable} resource that should be closed when the 19 | * associated writer is closed. 20 | * 21 | * @param closeable resource to close with the writer 22 | */ 23 | void onClose(Closeable closeable); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/BytesConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.nio.BufferOverflowException; 7 | 8 | /** 9 | * Consumes bytes from a source and writes them to a {@link BytesOut} instance. 10 | * Implementations typically pull data from a queue or ring buffer. 11 | */ 12 | @FunctionalInterface 13 | public interface BytesConsumer { 14 | 15 | /** 16 | * Attempts to pull data from the source into {@code bytes}. 17 | * 18 | * @param bytes destination for the consumed data, positioned for writing 19 | * @return {@code true} if bytes were written, {@code false} if no data was available 20 | * @throws BufferOverflowException if {@code bytes} lacks capacity for the read data 21 | */ 22 | boolean read(BytesOut bytes) throws BufferOverflowException; 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/UnicodeToStringTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assume.assumeFalse; 11 | 12 | public class UnicodeToStringTest { 13 | 14 | @Test 15 | public void testUtfStringInAndOut() { 16 | assumeFalse(Jvm.maxDirectMemory() == 0); 17 | 18 | Bytes bytes = Bytes.elasticByteBuffer(); 19 | bytes.appendUtf8("óaóó"); 20 | assertEquals("óaóó", bytes.toUtf8String()); 21 | } 22 | 23 | @Test 24 | public void testUtfStringInAndOutOnHeap() { 25 | Bytes bytes = Bytes.allocateElasticOnHeap(); 26 | bytes.appendUtf8("óaóó"); 27 | assertEquals("óaóó", bytes.toUtf8String()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/UncheckedBytesBehaviourTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class UncheckedBytesBehaviourTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void uncheckedOnDirectAndNoopWhenFalse() { 14 | Bytes d = Bytes.allocateDirect(16); 15 | Bytes u = d.unchecked(true); 16 | try { 17 | u.append("zz"); 18 | assertEquals("zz", u.toString()); 19 | } finally { 20 | u.releaseLast(); 21 | } 22 | 23 | Bytes h = Bytes.allocateElasticOnHeap(8); 24 | try { 25 | Bytes same = h.unchecked(false); 26 | assertSame(h, same); 27 | } finally { 28 | h.releaseLast(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesUtilEqualityTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class BytesUtilEqualityTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void bytesEqualCoversLongIntShortBytePaths() { 14 | // length 15 => 8 (long) + 4 (int) + 2 (short) + 1 (byte) 15 | Bytes a = Bytes.from("ABCDEFGHIJKLMNO"); 16 | Bytes b = Bytes.from("ABCDEFGHIJKLMNO"); 17 | Bytes c = Bytes.from("ABCDEFGH1JKLMNO"); 18 | try { 19 | assertTrue(BytesUtil.bytesEqual(a, 0, b, 0, 15)); 20 | assertFalse(BytesUtil.bytesEqual(a, 0, c, 0, 15)); 21 | } finally { 22 | a.releaseLast(); 23 | b.releaseLast(); 24 | c.releaseLast(); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ReleasedBytesStoreTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.bytes.internal.NativeBytesStore; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | public class ReleasedBytesStoreTest extends BytesTestCommon { 12 | 13 | @Test 14 | public void release() { 15 | Bytes bytes = Bytes.allocateElasticDirect(); 16 | assertNull(bytes.bytesStore().underlyingObject()); 17 | bytes.writeLong(0, 0); 18 | assertEquals(NativeBytesStore.class, bytes.bytesStore().getClass()); 19 | bytes.releaseLast(); 20 | assertEquals(0, bytes.bytesStore().refCount()); 21 | try { 22 | bytes.writeLong(0, 0); 23 | fail(); 24 | } catch (NullPointerException e) { 25 | // expected. 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/PrewriteTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class PrewriteTest extends BytesTestCommon { 11 | @Test 12 | public void test() { 13 | Bytes bytes = Bytes.allocateDirect(64); 14 | bytes.clearAndPad(64); 15 | bytes.prepend(1234); 16 | bytes.prewrite(",hi,".getBytes()); 17 | Bytes words = Bytes.from("words"); 18 | bytes.prewrite(words); 19 | bytes.prewriteByte((byte) ','); 20 | bytes.prewriteInt(0x34333231); 21 | bytes.prewriteLong(0x3837363534333231L); 22 | bytes.prewriteShort((short) 0x3130); 23 | assertEquals("01123456781234,words,hi,1234", bytes.toString()); 24 | 25 | bytes.releaseLast(); 26 | words.releaseLast(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MyBytes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.io.Closeable; 7 | import java.io.IOException; 8 | 9 | class MyBytes implements BytesMarshallable, Closeable { 10 | private Bytes bytes1; 11 | private Bytes bytes2; 12 | 13 | public MyBytes() { 14 | } 15 | 16 | public MyBytes(Bytes bytes1, Bytes bytes2) { 17 | this.bytes1 = bytes1; 18 | this.bytes2 = bytes2; 19 | } 20 | 21 | @Override 22 | public void close() 23 | throws IOException { 24 | if (bytes1 != null) bytes1.releaseLast(); 25 | if (bytes2 != null) bytes2.releaseLast(); 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return "MyBytes{" + 31 | "bytes1=" + bytes1 + 32 | ", bytes2=" + bytes2 + 33 | '}'; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/ResourceUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 12 | import static org.junit.jupiter.api.Assertions.assertThrows; 13 | 14 | class ResourceUtilTest extends BytesTestCommon { 15 | 16 | @Test 17 | void throwExceptionIfReleased() { 18 | final Bytes bytes = Bytes.from("A"); 19 | assertDoesNotThrow(() -> ReferenceCountedUtil.throwExceptionIfReleased(bytes)); 20 | bytes.releaseLast(); 21 | assertThrows(ClosedIllegalStateException.class, () -> ReferenceCountedUtil.throwExceptionIfReleased(bytes)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesDebugAndUtf8Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class BytesDebugAndUtf8Test extends BytesTestCommon { 11 | 12 | @Test 13 | public void appendAndParseUtf8AndDebugString() { 14 | Bytes b = Bytes.allocateElasticOnHeap(64); 15 | try { 16 | BytesUtil.appendUtf8(b, "hello"); 17 | long rp = b.readPosition(); 18 | StringBuilder sb = new StringBuilder(); 19 | BytesUtil.parseUtf8(b, sb, 5); 20 | assertEquals("hello", sb.toString()); 21 | 22 | // debug string contains representation 23 | String dbg = BytesUtil.toDebugString(b, rp, 5); 24 | assertFalse(dbg.isEmpty()); 25 | } finally { 26 | b.releaseLast(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/migration/HashCodeEqualsUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal.migration; 5 | 6 | import net.openhft.chronicle.bytes.BytesStore; 7 | import net.openhft.chronicle.bytes.algo.BytesStoreHash; 8 | import net.openhft.chronicle.core.io.ReferenceOwner; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public final class HashCodeEqualsUtil { 12 | 13 | private HashCodeEqualsUtil() { 14 | } 15 | 16 | public static int hashCode(final @NotNull BytesStore bytes) { 17 | // Reserving prevents illegal access to this Bytes object if released by another thread 18 | final ReferenceOwner owner = ReferenceOwner.temporary("hashCode"); 19 | bytes.reserve(owner); 20 | try { 21 | return BytesStoreHash.hash32(bytes); 22 | } finally { 23 | bytes.release(owner); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesCopyOfTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class BytesCopyOfTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void copyOfReturnsDirectBytesWithSameReadableContent() { 14 | Bytes src = Bytes.allocateElasticOnHeap(32); 15 | try { 16 | src.append("lorem-ipsum"); 17 | src.readSkip(6); // point to "ipsum" 18 | Bytes copy = BytesUtil.copyOf(src); 19 | try { 20 | assertEquals("ipsum", copy.toString()); 21 | // copy is direct; avoid growing it to keep within fixed capacity 22 | } finally { 23 | copy.releaseLast(); 24 | } 25 | } finally { 26 | src.releaseLast(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/RandomDataInputUtf8LimitedMoreTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import java.nio.BufferUnderflowException; 9 | 10 | import static org.junit.Assert.assertThrows; 11 | 12 | public class RandomDataInputUtf8LimitedMoreTest extends BytesTestCommon { 13 | 14 | @Test 15 | public void bufferUnderflowWhenDeclaredLengthExceedsRemaining() { 16 | Bytes b = Bytes.allocateElasticOnHeap(16); 17 | try { 18 | // Write stop-bit length larger than the following data 19 | b.writeStopBit(10); 20 | b.append("abc"); 21 | StringBuilder sb = new StringBuilder(); 22 | assertThrows(BufferUnderflowException.class, 23 | () -> b.readUtf8Limited(0, sb, 20)); 24 | } finally { 25 | b.releaseLast(); 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/VanillaBytesOpsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class VanillaBytesOpsTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void writeReadPrimitivesAndZeroOut() { 14 | Bytes b = Bytes.allocateElasticOnHeap(64); 15 | try { 16 | b.writeInt(0x11223344); 17 | b.writeLong(0x0102030405060708L); 18 | 19 | b.readPosition(0); 20 | assertEquals(0x11223344, b.readInt()); 21 | assertEquals(0x0102030405060708L, b.readLong()); 22 | 23 | // zero out the int we wrote and check 24 | b.zeroOut(0, 4); 25 | assertEquals(0, b.peekUnsignedByte(0)); 26 | assertEquals(0, b.peekUnsignedByte(1)); 27 | } finally { 28 | b.releaseLast(); 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MyNested.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.InvalidMarshallableException; 7 | import net.openhft.chronicle.core.io.Validatable; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | class MyNested implements BytesMarshallable, Validatable { 11 | private MyByteable byteable; 12 | private MyScalars scalars; 13 | 14 | public MyNested() { 15 | } 16 | 17 | public MyNested(MyByteable byteable, MyScalars scalars) { 18 | this.byteable = byteable; 19 | this.scalars = scalars; 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String toString() { 25 | return "MyNested{" + 26 | "byteable=" + byteable + 27 | ", scalars=" + scalars + 28 | '}'; 29 | } 30 | 31 | @Override 32 | public void validate() throws InvalidMarshallableException { 33 | byteable.validate(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ZeroCostAssertionStatusTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.assertions.AssertUtil; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import static org.junit.Assert.assertTrue; 10 | 11 | class ZeroCostAssertionStatusTest extends BytesTestCommon { 12 | 13 | @Test 14 | void show() { 15 | boolean ae = false; 16 | try { 17 | assert 0 != 0; 18 | } catch (AssertionError assertionError) { 19 | ae = true; 20 | } 21 | 22 | boolean zcae = false; 23 | try { 24 | assert AssertUtil.SKIP_ASSERTIONS || 0 != 0; 25 | } catch (AssertionError assertionError) { 26 | zcae = true; 27 | } 28 | 29 | System.out.println("Normal assertions are " + (ae ? "ON" : "OFF")); 30 | System.out.println("Zero-cost assertions are " + (zcae ? "ON" : "OFF")); 31 | assertTrue(true); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/RingBufferReaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import static org.mockito.Mockito.*; 9 | 10 | public class RingBufferReaderTest { 11 | 12 | private RingBufferReader reader; 13 | 14 | @Before 15 | public void setUp() { 16 | reader = mock(RingBufferReader.class); 17 | } 18 | 19 | @Test 20 | public void testIsEmpty() { 21 | when(reader.isEmpty()).thenReturn(true); 22 | 23 | assert(reader.isEmpty()); 24 | 25 | verify(reader, times(1)).isEmpty(); 26 | } 27 | 28 | @Test 29 | public void testIsStopped() { 30 | when(reader.isStopped()).thenReturn(false); 31 | 32 | assert(!reader.isStopped()); 33 | 34 | verify(reader, times(1)).isStopped(); 35 | } 36 | 37 | @Test 38 | public void testStop() { 39 | reader.stop(); 40 | 41 | verify(reader, times(1)).stop(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/HeapBytesStoreOpsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesStore; 8 | import net.openhft.chronicle.bytes.BytesTestCommon; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | public class HeapBytesStoreOpsTest extends BytesTestCommon { 14 | 15 | @Test 16 | public void heapStorePrimitiveOps() { 17 | Bytes heap = Bytes.allocateElasticOnHeap(32); 18 | try { 19 | BytesStore store = heap.bytesStore(); 20 | long off = heap.start(); 21 | store.writeInt(off, 0x11223344); 22 | assertEquals(0x11223344, store.readInt(off)); 23 | store.writeOrderedInt(off, 0x55667788); 24 | assertEquals(0x55667788, store.readInt(off)); 25 | } finally { 26 | heap.releaseLast(); 27 | } 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/StopCharTesterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | import static org.junit.Assert.*; 8 | 9 | public class StopCharTesterTest { 10 | 11 | @Test 12 | public void testIsStopChar() { 13 | StopCharTester tester = ch -> ch == ';' || ch == ','; 14 | 15 | assertTrue("Semicolon should be a stop char", tester.isStopChar(';')); 16 | assertTrue("Comma should be a stop char", tester.isStopChar(',')); 17 | assertFalse("Letter should not be a stop char", tester.isStopChar('A')); 18 | } 19 | 20 | @Test 21 | public void testEscaping() { 22 | StopCharTester baseTester = ch -> ch == ';'; 23 | StopCharTester escapingTester = baseTester.escaping(); 24 | 25 | assertTrue("Semicolon should be a stop char without escaping", baseTester.isStopChar(';')); 26 | assertFalse("Escaped semicolon should not be a stop char", escapingTester.isStopChar('\\')); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/HexDumpBytesAdvancedTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class HexDumpBytesAdvancedTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void numberWrapAndIndentation() { 14 | HexDumpBytes hdb = new HexDumpBytes(); 15 | try { 16 | hdb.numberWrap(16).offsetFormat((o, b) -> b.appendBase16(o, 2)); 17 | hdb.writeHexDumpDescription("hdr"); 18 | hdb.write("1234567890abcdefghij".getBytes()); 19 | hdb.adjustHexDumpIndentation(2); 20 | hdb.writeHexDumpDescription("nest"); 21 | hdb.write("zz".getBytes()); 22 | 23 | final String s = hdb.toHexString(); 24 | assertTrue(s.contains("hdr")); 25 | assertTrue(s.contains("nest")); 26 | assertTrue(s.contains("00")); 27 | } finally { 28 | hdb.releaseLast(); 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MethodReaderBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.mockito.Mockito; 10 | import java.util.function.Predicate; 11 | 12 | import static org.junit.Assume.assumeFalse; 13 | import static org.mockito.Mockito.*; 14 | 15 | public class MethodReaderBuilderTest { 16 | 17 | @Before 18 | public void setup() { 19 | assumeFalse(Jvm.isJava21Plus()); 20 | } 21 | 22 | @Test 23 | public void testWarnMissing() { 24 | MethodReaderBuilder builder = mock(MethodReaderBuilder.class, Mockito.CALLS_REAL_METHODS); 25 | 26 | when(builder.exceptionHandlerOnUnknownMethod(any())).thenReturn(builder); 27 | 28 | builder.warnMissing(true); 29 | 30 | verify(builder).exceptionHandlerOnUnknownMethod(Jvm.warn()); 31 | 32 | builder.warnMissing(false); 33 | verify(builder).exceptionHandlerOnUnknownMethod(Jvm.debug()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ReferenceTracingLeakTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.AbstractReferenceCounted; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | 11 | public class ReferenceTracingLeakTest extends BytesTestCommon { 12 | 13 | @Test 14 | public void leakDetectionReportsCreatedHere() throws Exception { 15 | final NativeBytes leaked = Bytes.allocateElasticDirect(64); 16 | try { 17 | assertNotNull("createdHere should be recorded for traced resources", 18 | ((AbstractReferenceCounted) leaked).createdHere()); 19 | 20 | final AssertionError leak = assertThrows(AssertionError.class, AbstractReferenceCounted::assertReferencesReleased); 21 | assertTrue("Expect suppressed entries describing the leak", leak.getSuppressed().length > 0); 22 | } finally { 23 | leaked.releaseLast(); 24 | } 25 | AbstractReferenceCounted.assertReferencesReleased(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ByteCheckSumTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class ByteCheckSumTest extends BytesTestCommon { 11 | @Test 12 | public void test() { 13 | Bytes bytes = Bytes.allocateDirect(32); 14 | doTest(bytes); 15 | bytes.releaseLast(); 16 | } 17 | 18 | @Test 19 | public void testHeap() { 20 | Bytes bytes = Bytes.allocateElasticOnHeap(32); 21 | doTest(bytes); 22 | bytes.releaseLast(); 23 | } 24 | 25 | private void doTest(Bytes bytes) { 26 | bytes.append("abcdef"); 27 | assertEquals(('a' + 'b' + 'c' + 'd' + 'e' + 'f') & 0xff, bytes.byteCheckSum()); 28 | assertEquals(('b' + 'c' + 'd' + 'e' + 'f') & 0xff, bytes.byteCheckSum(1, 6)); 29 | assertEquals(('b' + 'c' + 'd') & 0xff, bytes.byteCheckSum(1, 4)); 30 | assertEquals(('c' + 'd') & 0xff, bytes.byteCheckSum(2, 4)); 31 | assertEquals(('c') & 0xff, bytes.byteCheckSum(2, 3)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/VanillaBytesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import static org.junit.jupiter.api.Assertions.assertEquals; 10 | 11 | final class VanillaBytesTest extends BytesTestCommon { 12 | 13 | @Test 14 | void testBytesForRead() { 15 | byte[] byteArr = new byte[128]; 16 | for (int i = 0; i < byteArr.length; i++) 17 | byteArr[i] = (byte) i; 18 | Bytes bytes = Bytes.wrapForRead(byteArr); 19 | bytes.readSkip(8); 20 | @NotNull Bytes bytes2 = bytes.bytesForRead(); 21 | assertEquals(128 - 8, bytes2.readRemaining()); 22 | assertEquals(8, bytes2.readPosition()); 23 | assertEquals(8, bytes2.readByte(bytes2.start())); 24 | assertEquals(9, bytes2.readByte(bytes2.start() + 1)); 25 | assertEquals(9, bytes.readByte(9)); 26 | bytes2.writeByte(bytes2.start() + 1, 99); 27 | assertEquals(99, bytes.readByte(99)); 28 | 29 | bytes.releaseLast(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/BytesContext.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.Closeable; 7 | 8 | /** 9 | * Holds a {@link Bytes} buffer and optional key for a unit of work. Implementations 10 | * may support rollback of writes when the context is closed. 11 | */ 12 | public interface BytesContext extends Closeable { 13 | 14 | /** 15 | * Returns the buffer associated with this context. 16 | */ 17 | Bytes bytes(); 18 | 19 | /** 20 | * Provides a context-dependent key, such as a message type. 21 | */ 22 | int key(); 23 | 24 | /** 25 | * Indicates whether this context has been closed. The default implementation 26 | * throws {@link UnsupportedOperationException} and should be overridden. 27 | */ 28 | @Override 29 | default boolean isClosed() { 30 | throw new UnsupportedOperationException("todo"); 31 | } 32 | 33 | /** 34 | * Marks this context to roll back any writes when {@link #close()} is called. 35 | */ 36 | default void rollbackOnClose() { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/UTF8BytesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import org.junit.Test; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.nio.file.Files; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assume.assumeFalse; 15 | 16 | public class UTF8BytesTest extends BytesTestCommon { 17 | 18 | private static final String MESSAGE = "awésome-message-1"; 19 | 20 | @Test 21 | public void testUtfEncoding() throws IOException { 22 | assumeFalse(Jvm.maxDirectMemory() == 0); 23 | 24 | File f = Files.createTempFile("testUtfEncoding", "data").toFile(); 25 | f.deleteOnExit(); 26 | final MappedBytes bytes = MappedBytes.mappedBytes(f, 256, 0); 27 | int len = (int) AppendableUtil.findUtf8Length(MESSAGE); 28 | bytes.appendUtf8(MESSAGE); 29 | 30 | StringBuilder sb = new StringBuilder(); 31 | bytes.parseUtf8(sb, true, len); 32 | assertEquals(MESSAGE, sb.toString()); 33 | bytes.releaseLast(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/MultiReaderBytesRingBuffer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Extension of the BytesRingBuffer interface that supports multiple readers. 10 | * Each reader in a MultiReaderBytesRingBuffer has a separate read position, 11 | * allowing independent progression through the buffer. 12 | */ 13 | public interface MultiReaderBytesRingBuffer extends BytesRingBuffer { 14 | 15 | /** 16 | * Creates a RingBufferReader with a default ID of 0. 17 | * 18 | * @return a new RingBufferReader 19 | */ 20 | @NotNull 21 | default RingBufferReader createReader() { 22 | return createReader(0); 23 | } 24 | 25 | /** 26 | * Creates a RingBufferReader with a specified reader ID. 27 | * Each reader has a separate read position, which allows independent progression through the buffer. 28 | * 29 | * @param id the identifier for the new reader 30 | * @return a new RingBufferReader with the given ID 31 | */ 32 | @NotNull 33 | RingBufferReader createReader(int id); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/ref/LongReference.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Byteable; 7 | import net.openhft.chronicle.core.values.LongValue; 8 | 9 | /** 10 | * Represents a reference to a 64-bit long value, which is both {@link Byteable} and {@link LongValue}. 11 | * 12 | *

The {@code LongReference} interface provides a contract for classes that need to represent 13 | * a reference to a long value which can be read from or written to a {@link net.openhft.chronicle.bytes.BytesStore}. 14 | * This interface is particularly useful for memory-mapped values, where changes to the value are reflected in memory. 15 | * 16 | *

Classes implementing this interface are expected to provide efficient, low-level access 17 | * to the underlying bytes of the referenced long value. 18 | * 19 | * @see Byteable 20 | * @see LongValue 21 | */ 22 | @SuppressWarnings("rawtypes") 23 | public interface LongReference extends LongValue, Byteable { 24 | // This interface combines LongValue and Byteable 25 | // Specific method declarations are not necessary here as they are inherited 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/CompressionsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import org.junit.jupiter.api.Test; 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | import static org.junit.jupiter.api.Assertions.assertEquals; 12 | import static org.junit.jupiter.api.Assertions.assertNotNull; 13 | 14 | class CompressionsTest { 15 | 16 | @Test 17 | void testBinaryCompression() { 18 | byte[] original = "test data".getBytes(); 19 | 20 | byte[] compressed = Compressions.Binary.compress(original); 21 | byte[] decompressed = Compressions.Binary.uncompress(compressed); 22 | assertEquals(new String(original), new String(decompressed)); 23 | 24 | InputStream decompressingStream = Compressions.Binary.decompressingStream(new ByteArrayInputStream(compressed)); 25 | OutputStream compressingStream = Compressions.Binary.compressingStream(new ByteArrayOutputStream()); 26 | assertNotNull(decompressingStream); 27 | assertNotNull(compressingStream); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/MethodId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * Annotation that denotes a method as having a numeric identifier for efficient encoding. 10 | * 11 | *

12 | * Applying this annotation to a method allows it to be associated with a numeric value, 13 | * which can be leveraged during the encoding process to enhance efficiency. Numeric values 14 | * are more efficient to encode and decode than string representations, especially in 15 | * high-performance or resource-constrained environments. 16 | *

17 | * The numeric identifier is user-defined and should be unique to ensure correct mapping. 18 | * For simpler decoding, a character can be used as the numeric identifier, leveraging 19 | * its underlying ASCII or Unicode numeric value. 20 | */ 21 | @Retention(RetentionPolicy.RUNTIME) 22 | @Target(ElementType.METHOD) 23 | @Inherited 24 | public @interface MethodId { 25 | /** 26 | * The unique numeric identifier associated with the method. 27 | * 28 | * @return The unique numeric identifier associated with the method. 29 | */ 30 | long value(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/SyncMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.posix.MSyncFlag; 7 | 8 | /** 9 | * Synchronisation options for memory mapped file updates, mirroring the 10 | * behaviour of {@code msync(2)}. 11 | */ 12 | public enum SyncMode { 13 | /** 14 | * No synchronisation is requested. 15 | */ 16 | NONE(null), 17 | /** 18 | * Synchronous update using {@link MSyncFlag#MS_SYNC}. The call blocks until 19 | * all modified pages are written to disk. 20 | */ 21 | SYNC(MSyncFlag.MS_SYNC), 22 | /** 23 | * Asynchronous update using {@link MSyncFlag#MS_ASYNC}. Dirty pages are 24 | * scheduled for write out but the call returns immediately. 25 | */ 26 | ASYNC(MSyncFlag.MS_ASYNC); 27 | 28 | private final MSyncFlag mSyncFlag; 29 | 30 | SyncMode(MSyncFlag mSyncFlag) { 31 | this.mSyncFlag = mSyncFlag; 32 | } 33 | 34 | /** 35 | * Returns the {@link MSyncFlag} associated with this sync mode. 36 | * 37 | * @return the MSyncFlag value, may be null for {@code NONE} 38 | */ 39 | public MSyncFlag mSyncFlag() { 40 | return mSyncFlag; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/NativeBytesStoreOpsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.BytesStore; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.junit.Test; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | 12 | public class NativeBytesStoreOpsTest extends BytesTestCommon { 13 | 14 | @Test 15 | public void readWriteAndVolatileOrderedOps() { 16 | BytesStore store = BytesStore.nativeStore(32); 17 | try { 18 | long off = 0; 19 | store.writeLong(off, 0x0102030405060708L); 20 | assertEquals(0x0102030405060708L, store.readLong(off)); 21 | store.writeInt(off + 8, 0x11223344); 22 | assertEquals(0x11223344, store.readInt(off + 8)); 23 | 24 | store.writeVolatileLong(off, 9L); 25 | assertEquals(9L, store.readVolatileLong(off)); 26 | store.writeOrderedLong(off, 10L); 27 | assertEquals(10L, store.readLong(off)); 28 | assertEquals(15L, store.addAndGetLong(off, 5L)); 29 | } finally { 30 | store.releaseLast(); 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/Parse8bitVariantsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import net.openhft.chronicle.bytes.StopCharTesters; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | public class Parse8bitVariantsTest extends BytesTestCommon { 14 | 15 | @Test 16 | public void parse8bitIntoStringBuilderAndBytes() { 17 | Bytes alpha = Bytes.from("alpha"); 18 | Bytes beta = Bytes.from("beta"); 19 | try { 20 | StringBuilder sb = new StringBuilder(); 21 | BytesInternal.parse8bit(alpha, sb, StopCharTesters.NON_ALPHA_DIGIT); 22 | assertEquals("alpha", sb.toString()); 23 | Bytes out = Bytes.allocateElasticOnHeap(8); 24 | try { 25 | BytesInternal.parse8bit(beta, out, StopCharTesters.NON_ALPHA_DIGIT); 26 | assertEquals("beta", out.toString()); 27 | } finally { 28 | out.releaseLast(); 29 | } 30 | } finally { 31 | alpha.releaseLast(); 32 | beta.releaseLast(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/VanillaBytesCapacityAndZeroOutTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class VanillaBytesCapacityAndZeroOutTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void ensureCapacityGrowsAndZeroOutsRange() { 14 | Bytes b = Bytes.allocateElasticOnHeap(8); 15 | try { 16 | // Grow in small steps 17 | for (int i = 0; i < 10; i++) { 18 | b.append('X'); 19 | } 20 | long capAfter = b.capacity(); 21 | assertTrue("Expected capacity to grow beyond initial", capAfter >= 10); 22 | 23 | // zeroOut a large range including unwritten tail 24 | long start = 2; 25 | long end = Math.min(b.writePosition() + 16, b.capacity()); 26 | b.zeroOut(start, end); 27 | 28 | // Verify visible zeroing only on written region 29 | b.readPosition(0); 30 | byte first = b.readByte(); 31 | assertEquals('X', first); 32 | byte third = b.readByte(2); 33 | assertEquals(0, third); 34 | } finally { 35 | b.releaseLast(); 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/pool/BytesPoolTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.pool; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.core.scoped.ScopedResource; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import static org.junit.jupiter.api.Assertions.assertEquals; 11 | import static org.junit.jupiter.api.Assertions.assertNotNull; 12 | 13 | class BytesPoolTest { 14 | 15 | @Test 16 | void testAcquireBytes() { 17 | try (ScopedResource> resource = BytesPool.createThreadLocal().get()) { 18 | Bytes bytes = resource.get(); 19 | assertNotNull(bytes, "Acquired bytes should not be null."); 20 | 21 | assertEquals(0, bytes.readRemaining(), "Acquired bytes should be ready for use."); 22 | } 23 | } 24 | 25 | @Test 26 | void testBytesPoolUsage() { 27 | try (ScopedResource> resource = BytesPool.createThreadLocal().get()) { 28 | Bytes bytes = resource.get(); 29 | 30 | bytes.writeUtf8("Hello, World!"); 31 | assertEquals("Hello, World!", bytes.readUtf8()); 32 | 33 | bytes.clear(); 34 | 35 | assertEquals(0, bytes.readRemaining()); 36 | 37 | bytes.releaseLast(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/MethodReaderInterceptorReturns.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * Functional interface representing an interceptor for methods invoked through a MethodReader. 11 | *

12 | * The intercept method is called whenever a method is invoked on the MethodReader. It provides 13 | * an opportunity to modify, inspect, or take action based on the method invocation. 14 | */ 15 | @FunctionalInterface 16 | public interface MethodReaderInterceptorReturns { 17 | /** 18 | * Intercepts a method invocation. 19 | * 20 | * @param m the method that is being invoked 21 | * @param o the object the underlying method is invoked from 22 | * @param args the arguments used for the method call 23 | * @param invocation a functional interface representing the invocation of the method 24 | * @return the result of the method invocation, which can be the original result or a modified one 25 | * @throws InvocationTargetException if the invoked method throws an exception 26 | */ 27 | Object intercept(Method m, Object o, Object[] args, Invocation invocation) 28 | throws InvocationTargetException; 29 | } 30 | -------------------------------------------------------------------------------- /docs/systemProperties.adoc: -------------------------------------------------------------------------------- 1 | 2 | == System Properties 3 | Below, a number of relevant System Properties are listed. 4 | 5 | NOTE: All boolean properties below are read using link:https://javadoc.io/static/net.openhft/chronicle-core/2.23ea13/net/openhft/chronicle/core/Jvm.html#getBoolean-java.lang.String-[net.openhft.chronicle.core.Jvm.getBoolean(java.lang.String)], and so are enabled if either `-Dflag` or `-Dflag=true` or `-Dflag=yes` 6 | 7 | .System properties 8 | [cols=4*, options="header"] 9 | |=== 10 | | Property Key | Default | Description | Java Variable Name (Type) 11 | | bytes.guarded | `false` | If enabled, @param guarded turn on | _BYTES_GUARDED_ (boolean) 12 | | bytes.bounds.unchecked | `false` | If enabled, determines if bytes boundaries data alignment | _BYTES_BOUNDS_UNCHECKED_ (boolean) 13 | | trace.mapped.bytes | `false` | If enabled, returns information such as mappedFile and refCount | _TRACE_ (boolean) 14 | | mappedFile.retain | `false` | See NOTE to enable system property | _RETAIN_ (boolean) 15 | | user.name | unknown | The default user name, unless otherwise specified | _USER_NAME_ (String) 16 | | timestamp.dir | OS.TMP | Returns directory of file as timestamp | _TIME_STAMP_DIR_ (String) 17 | | timestamp.path | unknown | Returns file path of timestamp.dir file | _TIME_STAMP_PATH_(String) 18 | | bytes.max-array-len | 16777216 | Maximum array length accepted when reading | _MAX_ARRAY_LEN_ (int) 19 | |=== 20 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/CopyToTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import org.junit.Test; 8 | 9 | import java.nio.ByteBuffer; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assume.assumeFalse; 13 | 14 | public class CopyToTest { 15 | 16 | @Test 17 | public void testCopyFromDirectBytesIntoByteBuffer() { 18 | assumeFalse(Jvm.maxDirectMemory() == 0); 19 | 20 | Bytes bytesToTest = Bytes.fromDirect("THIS IS A TEST STRING"); 21 | ByteBuffer copyToDestination = ByteBuffer.allocateDirect(128); 22 | copyToDestination.limit((int) bytesToTest.readLimit()); 23 | bytesToTest.copyTo(copyToDestination); 24 | assertEquals("THIS IS A TEST STRING", Bytes.wrapForRead(copyToDestination).toUtf8String()); 25 | } 26 | 27 | @Test 28 | public void testCopyFromHeapBytesIntoByteBuffer() { 29 | Bytes bytesToTest = Bytes.from("THIS IS A TEST STRING"); 30 | ByteBuffer copyToDestination = ByteBuffer.allocate(128); 31 | copyToDestination.limit((int) bytesToTest.readLimit()); 32 | bytesToTest.copyTo(copyToDestination); 33 | assertEquals("THIS IS A TEST STRING", Bytes.wrapForRead(copyToDestination).toUtf8String()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/CanonicalPathUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.BytesTestCommon; 7 | import net.openhft.chronicle.core.OS; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.io.FileWriter; 12 | import java.io.IOException; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | public class CanonicalPathUtilTest extends BytesTestCommon { 17 | 18 | @Test 19 | public void returnsInternedCanonicalPath() throws IOException { 20 | File dir = new File(OS.getTarget(), "canon-test"); 21 | assertTrue(dir.mkdirs() || dir.isDirectory()); 22 | File f1 = new File(dir, "a/.././file.txt"); 23 | File f2 = new File(dir, "./file.txt"); 24 | 25 | // ensure file exists 26 | File parent = f2.getParentFile(); 27 | assertTrue(parent.mkdirs() || parent.isDirectory()); 28 | try (FileWriter fw = new FileWriter(f2)) { 29 | fw.write("x"); 30 | } 31 | 32 | String p1 = CanonicalPathUtil.of(f1); 33 | String p2 = CanonicalPathUtil.of(f2); 34 | 35 | assertEquals(p1, p2); 36 | assertSame("String must be interned", p1, p1.intern()); 37 | assertSame("Same canonical path must be same instance", p1, p2); 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/HexDumpBytesDescription.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 7 | import net.openhft.chronicle.core.io.ThreadingIllegalStateException; 8 | 9 | import static net.openhft.chronicle.core.Jvm.uncheckedCast; 10 | 11 | /** 12 | * Provides hooks for adding comments and controlling indentation when generating hex dumps. 13 | */ 14 | public interface HexDumpBytesDescription> { 15 | /** 16 | * @return {@code true} if comments are retained for later inclusion in the hex dump 17 | */ 18 | default boolean retainedHexDumpDescription() { 19 | return false; 20 | } 21 | 22 | /** 23 | * Adds {@code comment} to the output, either as a full line (if starting with {@code '#'}) or 24 | * appended to the current line. 25 | */ 26 | default B writeHexDumpDescription(CharSequence comment) 27 | throws ClosedIllegalStateException, ThreadingIllegalStateException { 28 | return uncheckedCast(this); 29 | } 30 | 31 | /** 32 | * Adjusts the indentation level for subsequent dump lines. 33 | */ 34 | default B adjustHexDumpIndentation(int n) 35 | throws IllegalStateException { 36 | return uncheckedCast(this); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/Chars.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Lookup utilities for rendering bytes as characters, used in hex dumps and 10 | * similar operations. 11 | */ 12 | public final class Chars { 13 | private Chars() { } 14 | /** lookup table for byte value to String */ 15 | public static final String[] charToString = createCharToString(); 16 | 17 | /** 18 | * Populates {@link #charToString} with printable representations for all 19 | * byte values. Control characters are encoded as escape sequences. 20 | */ 21 | @NotNull 22 | public static String[] createCharToString() { 23 | @NotNull String[] charToString = new String[256]; 24 | charToString[0] = "\u0660"; 25 | for (int i = 1; i < 21; i++) 26 | charToString[i] = Character.toString((char) (i + 0x2487)); 27 | for (int i = ' '; i < 256; i++) 28 | charToString[i] = Character.toString((char) i); 29 | for (int i = 21; i < ' '; i++) 30 | charToString[i] = "\\u00" + Integer.toHexString(i).toUpperCase(); 31 | for (int i = 0x80; i < 0xA0; i++) 32 | charToString[i] = "\\u00" + Integer.toHexString(i).toUpperCase(); 33 | return charToString; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/MethodWriterInterceptorReturns.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.lang.reflect.Method; 7 | import java.util.function.BiFunction; 8 | 9 | /** 10 | * Functional interface representing an interceptor for methods invoked through a MethodWriter. 11 | *

12 | * The interceptor provides a means to manipulate or monitor the invocation of methods. It allows for actions 13 | * to be taken before or after a method invocation, or to bypass the method invocation entirely. 14 | *

15 | * This can be particularly useful for scenarios such as logging method invocations, modifying method parameters, 16 | * changing return values, or implementing pre- and post-method invocation actions. 17 | */ 18 | @FunctionalInterface 19 | public interface MethodWriterInterceptorReturns { 20 | 21 | /** 22 | * Intercepts a method invocation. 23 | * 24 | * @param method the method that is being invoked 25 | * @param args the arguments used for the method call 26 | * @param invoker a functional interface representing the invocation of the method 27 | * @return the next object to use if there is any chaining, either this, null if no chaining, or another object. 28 | */ 29 | Object intercept(Method method, Object[] args, BiFunction invoker); 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesContextTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.*; 10 | import static org.mockito.Mockito.*; 11 | 12 | public class BytesContextTest { 13 | 14 | private BytesContext context; 15 | 16 | @Before 17 | public void setUp() { 18 | // Mock the BytesContext interface 19 | context = mock(BytesContext.class); 20 | doThrow(UnsupportedOperationException.class).when(context).isClosed(); 21 | } 22 | 23 | @Test 24 | public void testKey() { 25 | // Setup a specific key to return 26 | final int expectedKey = 42; 27 | when(context.key()).thenReturn(expectedKey); 28 | 29 | int actualKey = context.key(); 30 | assertEquals("Key should match the expected value", expectedKey, actualKey); 31 | } 32 | 33 | @Test(expected = UnsupportedOperationException.class) 34 | public void testIsClosedThrowsUnsupportedOperationException() { 35 | context.isClosed(); 36 | } 37 | 38 | @Test 39 | public void testRollbackOnClose() { 40 | try { 41 | context.rollbackOnClose(); 42 | } catch (Exception e) { 43 | fail("rollbackOnClose should not throw any exception"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/Issue225Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class Issue225Test extends BytesTestCommon { 11 | @Test 12 | public void testTrailingZeros() { 13 | for (int i = 1000; i < 10_000; i++) { 14 | double value = i / 1000.0; 15 | final String valueStr; 16 | if ((long) value == value) 17 | valueStr = "" + (long) value; 18 | else 19 | valueStr = "" + value; 20 | Bytes bytes = Bytes.allocateElastic(32); 21 | byte[] rbytes = new byte[24]; 22 | bytes.append(value); 23 | assertEquals(value, bytes.parseDouble(), 0.0); 24 | if ((long) value == value) 25 | assertEquals(0, bytes.lastDecimalPlaces()); 26 | else 27 | assertEquals(valueStr.length() - 2, bytes.lastDecimalPlaces()); 28 | bytes.readPosition(0); 29 | int length = bytes.read(rbytes); 30 | assertEquals(valueStr.length(), length); 31 | final String substring = new String(rbytes).substring(0, (int) bytes.writePosition()); 32 | assertEquals(valueStr, substring); 33 | bytes.releaseLast(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/StreamingCommon.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 7 | import net.openhft.chronicle.core.io.ThreadingIllegalStateException; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * A common base interface for streaming data access. It manages fundamental 12 | * buffer properties such as positions and limits and supports random access 13 | * semantics. Implementations are mainly used by higher level streaming 14 | * interfaces like {@link StreamingDataInput} and {@link StreamingDataOutput}. 15 | * 16 | * @param type of the implementing class 17 | */ 18 | public interface StreamingCommon> extends RandomCommon { 19 | 20 | /** 21 | * Resets the read and write positions to {@link #start()} and sets the 22 | * effective limits to {@link #capacity()}. The underlying data is left 23 | * unchanged but the buffer behaves as if newly allocated. 24 | * 25 | * @return this instance for chaining 26 | * @throws ClosedIllegalStateException if the resource has been released or closed 27 | * @throws ThreadingIllegalStateException if accessed by multiple threads in an unsafe way 28 | */ 29 | @NotNull 30 | S clear() throws ClosedIllegalStateException, ThreadingIllegalStateException; 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ConnectionDroppedExceptionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | public class ConnectionDroppedExceptionTest { 10 | 11 | @Test 12 | public void testMessageConstructor() { 13 | String expectedMessage = "Connection dropped unexpectedly."; 14 | ConnectionDroppedException exception = new ConnectionDroppedException(expectedMessage); 15 | 16 | Assert.assertEquals(expectedMessage, exception.getMessage()); 17 | } 18 | 19 | @Test 20 | public void testCauseConstructor() { 21 | Throwable expectedCause = new RuntimeException("Underlying cause"); 22 | ConnectionDroppedException exception = new ConnectionDroppedException(expectedCause); 23 | 24 | Assert.assertEquals(expectedCause, exception.getCause()); 25 | } 26 | 27 | @Test 28 | public void testMessageAndCauseConstructor() { 29 | String expectedMessage = "Connection dropped with details."; 30 | Throwable expectedCause = new RuntimeException("Specific cause"); 31 | ConnectionDroppedException exception = new ConnectionDroppedException(expectedMessage, expectedCause); 32 | 33 | Assert.assertEquals(expectedMessage, exception.getMessage()); 34 | Assert.assertEquals(expectedCause, exception.getCause()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/Invocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * A functional interface representing the act of invoking a method. 11 | *

12 | * It is primarily used as a callback within interceptor patterns such as 13 | * {@link net.openhft.chronicle.bytes.MethodReaderInterceptorReturns} to 14 | * allow the interceptor to control or augment the actual method execution. 15 | */ 16 | @FunctionalInterface 17 | public interface Invocation { 18 | /** 19 | * Invokes the supplied method. 20 | * 21 | * @param m the {@link Method} to invoke, must not be {@code null} 22 | * @param o the instance on which the method should be invoked, {@code null} for static methods 23 | * @param args the arguments to be passed to the method, may be {@code null} 24 | * @return the result of the invocation or {@code null} if the method returns void 25 | * @throws InvocationTargetException if the underlying method throws an exception 26 | * @throws IllegalArgumentException if the arguments do not match the method signature 27 | * @throws NullPointerException if {@code m} is {@code null} 28 | */ 29 | Object invoke(Method m, Object o, Object[] args) 30 | throws InvocationTargetException; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/CanonicalPathUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.core.io.IORuntimeException; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | /** 13 | * Utility for obtaining and internalising canonical file paths. This allows the 14 | * same physical file to be referenced by a unique {@link String} token even when 15 | * different {@link File} objects are used. 16 | */ 17 | public final class CanonicalPathUtil { 18 | 19 | private CanonicalPathUtil() {} 20 | 21 | /** 22 | * Returns the canonical path of {@code file} as an interned {@link String}. 23 | * This provides a unique monitor object for synchronising across different 24 | * {@code File} instances that reference the same path. 25 | * 26 | * @param file the file for which to obtain the canonical path 27 | * @return interned canonical path 28 | * @throws IORuntimeException if the canonical path cannot be resolved 29 | */ 30 | public static String of(@NotNull final File file) { 31 | try { 32 | return file.getCanonicalPath().intern(); 33 | } catch (IOException ioe) { 34 | throw new IORuntimeException("Unable to obtain the canonical path for " + file.getAbsolutePath(), ioe); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/resources/btmtt-invalid/prim-output.txt: -------------------------------------------------------------------------------- 1 | 81 01 # myByteable 2 | 4e # flag 3 | 02 # b 4 | 02 00 # s 5 | 33 # c 6 | 04 00 00 00 # i 7 | 00 00 b0 40 # f 8 | 06 00 00 00 00 00 00 00 # l 9 | cd cc cc cc cc cc 1e 40 # d 10 | ### End Of Block 11 | ### End Of Block 12 | # myByteable 13 | ### End Of Block 14 | 82 01 # myScalars 15 | 05 48 65 6c 6c 6f # s 16 | 01 31 # bi 17 | 02 31 30 # bd 18 | 0a 32 30 31 37 2d 31 31 2d 30 36 # date 19 | 0c 31 32 3a 33 35 3a 35 36 2e 37 37 35 # time 20 | 17 32 30 31 37 2d 31 31 2d 30 36 54 31 32 3a 33 # dateTime 21 | 35 3a 35 36 2e 37 37 35 27 32 30 31 37 2d 31 31 # zonedDateTime 22 | 2d 30 36 54 31 32 3a 33 35 3a 35 36 2e 37 37 35 23 | 5a 5b 45 75 72 6f 70 65 2f 4c 6f 6e 64 6f 6e 5d # uuid 24 | 24 30 30 30 30 30 30 30 31 2d 32 33 34 35 2d 36 25 | 37 38 39 2d 30 30 30 30 2d 30 30 30 30 30 30 61 26 | 62 63 64 65 66 27 | ### End Of Block 28 | ### End Of Block 29 | ### End Of Test 30 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/UpdateInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | /** 7 | * Represents an operation that intercepts a method call, possibly modifies the input argument, 8 | * and determines whether to proceed with the original operation. 9 | * 10 | *

This interface can be used to implement custom behaviors before an operation is carried out, 11 | * such as validation, transformation, or cancellation of the operation based on the method 12 | * parameters or other conditions. 13 | */ 14 | @FunctionalInterface 15 | public interface UpdateInterceptor { 16 | 17 | /** 18 | * Potentially modifies the provided argument and determines whether to proceed with 19 | * the operation that was intercepted. 20 | * 21 | * @param methodName the name of the method that was intercepted 22 | * @param t the input argument to the method - for a method call with multiple arguments, 23 | * only the last one is passed. This object may be modified by this method. 24 | * @return a boolean value indicating whether to proceed with the operation. If false, 25 | * the operation that was intercepted will not be carried out. 26 | * @throws IllegalArgumentException if {@code t} is an instance of Validatable and its validation fails 27 | */ 28 | boolean update(String methodName, Object t) throws IllegalArgumentException; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/render/Decimaliser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.render; 5 | 6 | /** 7 | * Strategy interface that decomposes a floating point number into sign, 8 | * mantissa and exponent suitable for textual serialisation. 9 | * Implementations may trade performance against precision. 10 | * 11 | *

NaN, infinity and negative zero values are not converted and should cause 12 | * the method to return {@code false}. 13 | * 14 | * @see DecimalAppender 15 | */ 16 | public interface Decimaliser { 17 | 18 | /** 19 | * Convert {@code value} to a decimal representation and append it. 20 | * 21 | * @param value the double value to serialise; must be finite and not negative zero 22 | * @param decimalAppender the target receiving sign, mantissa and exponent 23 | * @return {@code true} if the value could be represented and appended 24 | */ 25 | boolean toDecimal(double value, DecimalAppender decimalAppender); 26 | 27 | /** 28 | * Convert {@code value} to a decimal representation and append it. 29 | * 30 | * @param value the float value to serialise; must be finite and not negative zero 31 | * @param decimalAppender the target receiving sign, mantissa and exponent 32 | * @return {@code true} if the value could be represented and appended 33 | */ 34 | boolean toDecimal(float value, DecimalAppender decimalAppender); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/Unmapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import net.openhft.chronicle.core.OS; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * Runnable that unmaps a memory region when executed, typically via a cleaner 14 | * service. 15 | */ 16 | public final class Unmapper implements Runnable { 17 | private final long size; 18 | 19 | private final int pageSize; 20 | 21 | private volatile long address; 22 | 23 | /** 24 | * @param address start of the region 25 | * @param size size of the region 26 | * @param pageSize operating system page size 27 | */ 28 | public Unmapper(long address, long size, int pageSize) throws IllegalStateException { 29 | 30 | assert (address != 0); 31 | this.address = address; 32 | this.size = size; 33 | this.pageSize = pageSize; 34 | } 35 | 36 | /** 37 | * Performs the unmap. If already unmapped the call is ignored. 38 | */ 39 | @Override 40 | public void run() { 41 | if (address == 0) 42 | return; 43 | 44 | try { 45 | OS.unmap(address, size, pageSize); 46 | address = 0; 47 | 48 | } catch (@NotNull IOException e) { 49 | Jvm.warn().on(OS.class, "Error on unmap and release", e); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/ReferenceCountedUtilTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 9 | import net.openhft.chronicle.core.io.ReferenceCounted; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import java.util.function.Consumer; 13 | 14 | import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 15 | import static org.junit.jupiter.api.Assertions.assertThrows; 16 | 17 | class ReferenceCountedUtilTest extends BytesTestCommon { 18 | 19 | @Test 20 | void throwExceptionIfReleased() { 21 | test(o -> ReferenceCountedUtil.throwExceptionIfReleased((ReferenceCounted) o)); 22 | } 23 | 24 | @Test 25 | void testThrowExceptionIfReleased() { 26 | test(ReferenceCountedUtil::throwExceptionIfReleased); 27 | assertDoesNotThrow(() -> ReferenceCountedUtil.throwExceptionIfReleased("Foo")); 28 | assertThrows(NullPointerException.class, () -> ReferenceCountedUtil.throwExceptionIfReleased(null)); 29 | } 30 | 31 | private void test(Consumer method) { 32 | final Bytes bytes = Bytes.from("A"); 33 | assertDoesNotThrow(() -> method.accept(bytes)); 34 | bytes.releaseLast(); 35 | assertThrows(ClosedIllegalStateException.class, () -> method.accept(bytes)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/HeapByteStoreTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.bytes.internal.HeapBytesStore; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.junit.Test; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | public class HeapByteStoreTest extends BytesTestCommon { 13 | @SuppressWarnings("rawtypes") 14 | @Test 15 | public void testEquals() { 16 | @NotNull HeapBytesStore hbs = HeapBytesStore.wrap("Hello".getBytes()); 17 | @NotNull HeapBytesStore hbs2 = HeapBytesStore.wrap("Hello".getBytes()); 18 | @NotNull HeapBytesStore hbs3 = HeapBytesStore.wrap("He!!o".getBytes()); 19 | @NotNull HeapBytesStore hbs4 = HeapBytesStore.wrap("Hi".getBytes()); 20 | assertEquals(hbs, hbs2); 21 | assertEquals(hbs2, hbs); 22 | assertNotEquals(hbs, hbs3); 23 | assertNotEquals(hbs3, hbs); 24 | assertNotEquals(hbs, hbs4); 25 | assertNotEquals(hbs4, hbs); 26 | } 27 | 28 | @Test 29 | public void testElasticBytesEnsuringCapacity() { 30 | Bytes bytes = Bytes.elasticHeapByteBuffer(); 31 | long initialCapacity = bytes.realCapacity(); 32 | bytes.clearAndPad(bytes.realCapacity() + 128); 33 | // ensure this succeeds even though we are above the real capacity - this should trigger resize 34 | bytes.prewriteInt(1); 35 | assertTrue(bytes.realCapacity()> initialCapacity); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/PrintVdsoMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.io.*; 9 | 10 | public class PrintVdsoMain { 11 | public static void main(String[] args) 12 | throws IOException, IllegalStateException { 13 | long start = 0; 14 | long end = 0; 15 | @NotNull String maps = "/proc/self/maps"; 16 | if (!new File(maps).exists()) return; 17 | try (@NotNull BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(maps)))) { 18 | for (String line; (line = br.readLine()) != null; ) { 19 | if (line.endsWith("[vdso]")) { 20 | @NotNull String[] parts = line.split("[- ]"); 21 | start = Long.parseLong(parts[0], 16); 22 | end = Long.parseLong(parts[1], 16); 23 | } 24 | 25 | // System.out.println(line); 26 | } 27 | } catch (IOException ioe) { 28 | throw ioe; 29 | } 30 | System.out.printf("vdso %x to %x %n", start, end); 31 | @NotNull PointerBytesStore nb = new PointerBytesStore(); 32 | nb.set(start, end - start); 33 | @NotNull FileOutputStream fos = new FileOutputStream("vdso.elf"); 34 | for (Bytes b = nb.bytesForRead(); b.readRemaining() > 0; ) 35 | fos.write(b.readByte()); 36 | fos.close(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/TempDirectoryIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.OS; 7 | import net.openhft.chronicle.core.io.IOTools; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | 14 | import static org.junit.Assert.assertFalse; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | public class TempDirectoryIntegrationTest extends BytesTestCommon { 18 | 19 | @Test 20 | public void createTempDirectoryUnderTargetAndCleanup() throws Exception { 21 | final Path tempDir = IOTools.createTempDirectory("bytes-temp"); 22 | final Path targetRoot = new File(OS.getTarget()).getAbsoluteFile().toPath().normalize(); 23 | assertTrue("Temp directory should live under OS target", 24 | tempDir.toAbsolutePath().normalize().startsWith(targetRoot)); 25 | 26 | Files.createDirectories(tempDir); 27 | assertTrue("Temp directory should exist", Files.isDirectory(tempDir)); 28 | final Path marker = tempDir.resolve("marker.bin"); 29 | Files.write(marker, new byte[]{1, 2, 3}); 30 | assertTrue("Marker file should exist inside temp dir", Files.exists(marker)); 31 | 32 | assertTrue("Temp directory deletion should succeed", IOTools.deleteDirWithFiles(tempDir.toFile())); 33 | assertFalse("Temp directory should be removed", Files.exists(tempDir)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/StopBitDecimalTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Maths; 7 | import org.junit.Test; 8 | 9 | import java.math.BigDecimal; 10 | import java.math.BigInteger; 11 | import java.nio.ByteBuffer; 12 | import java.util.Random; 13 | 14 | import static junit.framework.TestCase.assertEquals; 15 | import static org.junit.Assume.assumeFalse; 16 | 17 | public class StopBitDecimalTest extends BytesTestCommon { 18 | @Test 19 | public void testDecimals() { 20 | assumeFalse(NativeBytes.areNewGuarded()); 21 | 22 | Bytes bytes = Bytes.elasticHeapByteBuffer(16); 23 | Random rand = new Random(); 24 | for (int i = 0; i < 10_000; i++) { 25 | rand.setSeed(i); 26 | bytes.clear(); 27 | int scale = rand.nextInt(10); 28 | double d = (rand.nextLong() % 1e14) / Maths.tens(scale); 29 | bytes.writeStopBitDecimal(d); 30 | BigDecimal bd = BigDecimal.valueOf(d); 31 | long v = bytes.readStopBit(); 32 | BigDecimal ebd = new BigDecimal(BigInteger.valueOf(v / 10), (int) (Math.abs(v) % 10)); 33 | assertEquals("i: " + i + ", d: " + d + ", v: " + v, ebd.doubleValue(), bd.doubleValue(), 0.0); 34 | bytes.readPosition(0); 35 | double d2 = bytes.readStopBitDecimal(); 36 | assertEquals("i: " + i + ", d: " + d + ", v: " + v, d, d2, 0.0); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /microbenchmarks/src/main/java/net/openhft/chronicle/bytes/microbenchmarks/AppendLongCoolerMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.microbenchmarks; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.core.cooler.CoolerTester; 8 | import net.openhft.chronicle.core.cooler.CpuCoolers; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class AppendLongCoolerMain { 12 | 13 | static int i = 0; 14 | static long[] longs = {Integer.MIN_VALUE, -128, 0, 1, 11, 111, Integer.MAX_VALUE, Long.MAX_VALUE}; 15 | 16 | public static void main(String[] args) { 17 | Bytes bytes = Bytes.allocateElasticDirect(32); 18 | 19 | new CoolerTester( 20 | CpuCoolers.PAUSE1, 21 | CpuCoolers.BUSY100, 22 | CpuCoolers.ALL 23 | ).add("write", () -> doWrite(bytes)) 24 | .run(); 25 | } 26 | 27 | @NotNull 28 | public static Object doWrite(Bytes bytes) { 29 | bytes.clear(); 30 | bytes.append(longs[i++ % longs.length]); 31 | return bytes; 32 | } 33 | 34 | @NotNull 35 | public static Object doRead(Bytes bytes) { 36 | bytes.readPosition(0); 37 | double v = bytes.parseDouble(); 38 | if (v < 0) throw new AssertionError(); 39 | return bytes; 40 | } 41 | 42 | @NotNull 43 | public static Object doTest(Bytes bytes) { 44 | doWrite(bytes); 45 | doRead(bytes); 46 | return bytes; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MyByteable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.InvalidMarshallableException; 7 | import net.openhft.chronicle.core.io.Validatable; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | class MyByteable implements BytesMarshallable, Validatable { 11 | private boolean flag; 12 | byte b; 13 | short s; 14 | private char c; 15 | private int i; 16 | private float f; 17 | private long l; 18 | private double d; 19 | 20 | public MyByteable() { 21 | } 22 | 23 | public MyByteable(boolean flag, byte b, short s, char c, int i, float f, long l, double d) { 24 | this.flag = flag; 25 | this.b = b; 26 | this.s = s; 27 | this.c = c; 28 | this.i = i; 29 | this.f = f; 30 | this.l = l; 31 | this.d = d; 32 | } 33 | 34 | @Override 35 | public void validate() throws InvalidMarshallableException { 36 | if (b == 0) 37 | throw new InvalidMarshallableException("b must not be 0"); 38 | } 39 | 40 | @NotNull 41 | @Override 42 | public String toString() { 43 | return "MyByteable{" + 44 | "flag=" + flag + 45 | ", b=" + b + 46 | ", s=" + s + 47 | ", c=" + c + 48 | ", i=" + i + 49 | ", f=" + f + 50 | ", l=" + l + 51 | ", d=" + d + 52 | '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/TextLongArrayReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | public class TextLongArrayReferenceTest extends BytesTestCommon { 14 | @Test 15 | public void getSetValues() { 16 | int length = 5 * 22 + 90; 17 | Bytes bytes = Bytes.allocateElastic(length); 18 | TextLongArrayReference.write(bytes, 5); 19 | 20 | try (@NotNull TextLongArrayReference array = new TextLongArrayReference()) { 21 | array.bytesStore(bytes, 0, length); 22 | 23 | assertEquals(5, array.getCapacity()); 24 | for (int i = 0; i < 5; i++) 25 | array.setValueAt(i, i + 1); 26 | 27 | for (int i = 0; i < 5; i++) 28 | assertEquals(i + 1, array.getValueAt(i)); 29 | 30 | @NotNull final String expected = "{ locked: false, capacity: 5 , used: 00000000000000000000, " + 31 | "values: [ 00000000000000000001, 00000000000000000002, 00000000000000000003, 00000000000000000004, 00000000000000000005 ] }\n"; 32 | // System.out.println(expected.length()); 33 | assertEquals(expected, 34 | bytes.toString()); 35 | bytes.releaseLast(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/docs/decimal-rendering.adoc: -------------------------------------------------------------------------------- 1 | = Decimal Rendering Strategies 2 | :doctype: book 3 | :toc: 4 | :toclevels: 2 5 | :lang: en-GB 6 | 7 | This page summarises the options in the `net.openhft.chronicle.bytes.render` package. 8 | It accompanies the Javadoc and shows how to render floating point values into 9 | textual form suitable for Chronicle's wire formats. 10 | 11 | == Choosing a Decimaliser 12 | 13 | * `SimpleDecimaliser` is extremely fast but gives up for values that need more 14 | than `18` decimal places or exceed `1e15` while scaling. 15 | * `MaximumPrecision` allows a fixed number of decimal places, rounding with 16 | `Math.round` as required. 17 | * `UsesBigDecimal` handles the widest range of values using 18 | `BigDecimal` and therefore allocates objects and may be slower. 19 | * `GeneralDecimaliser` tries the simple approach first and falls back to 20 | `UsesBigDecimal` when necessary. 21 | * `StandardDecimaliser` is the default for most use cases. It attempts a 22 | precision of `18` decimal places and then falls back to `UsesBigDecimal`. 23 | 24 | == Example Usage 25 | 26 | The following snippet converts a value to text using a `Bytes` buffer: 27 | 28 | [source,java] 29 | ---- 30 | Bytes bytes = Bytes.allocateElasticOnHeap(); 31 | Decimaliser d = StandardDecimaliser.STANDARD; 32 | boolean ok = d.toDecimal(1.2345, (neg, m, e) -> bytes.append(neg ? '-' : '') 33 | .append(m) 34 | .append('e') 35 | .append(-e)); 36 | System.out.println(bytes.toString()); 37 | ---- 38 | 39 | See the <> guide for details on using 40 | these renderers within wire formats. 41 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/MappedBytesStoreFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.NonNegative; 7 | import net.openhft.chronicle.core.annotation.Positive; 8 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 9 | import net.openhft.chronicle.core.io.ReferenceOwner; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | /** 13 | * Factory for creating {@link MappedBytesStore} instances. 14 | */ 15 | @FunctionalInterface 16 | public interface MappedBytesStoreFactory { 17 | 18 | /** 19 | * Creates a {@link MappedBytesStore} for the given mapping parameters. 20 | * 21 | * @param owner reference owner for the created store 22 | * @param mappedFile parent mapped file 23 | * @param start logical start offset within the file 24 | * @param address native memory address of the mapping 25 | * @param capacity total size of the mapped region 26 | * @param safeCapacity portion of the region accessible without remapping 27 | * @param pageSize page size for alignment checks 28 | * @return the created store 29 | * @throws ClosedIllegalStateException if the mapped file has been closed 30 | */ 31 | @NotNull 32 | MappedBytesStore create(ReferenceOwner owner, MappedFile mappedFile, @NonNegative long start, @NonNegative long address, @NonNegative long capacity, @NonNegative long safeCapacity, @Positive int pageSize) 33 | throws ClosedIllegalStateException; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /microbenchmarks/src/main/java/net/openhft/chronicle/bytes/microbenchmarks/BytesCoolerMain.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.microbenchmarks; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.core.cooler.CoolerTester; 8 | import net.openhft.chronicle.core.cooler.CpuCoolers; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class BytesCoolerMain { 12 | 13 | public static void main(String[] args) { 14 | Bytes small = Bytes.allocateDirect(23); 15 | Bytes big = Bytes.allocateDirect(400); 16 | 17 | System.out.println("WITH COOLERS ACROSS MEMORY"); 18 | new CoolerTester( 19 | CpuCoolers.BUSY100, 20 | CpuCoolers.PAUSE1, 21 | CpuCoolers.ALL 22 | ) 23 | .add("direct", () -> doWrite(big, 21)) 24 | .add("small", () -> doWrite(small, 3)) 25 | .run(); 26 | } 27 | 28 | @NotNull 29 | public static Object doWrite(Bytes bytes, int digits) { 30 | bytes.clear(); 31 | bytes.append(123.456, digits); 32 | return bytes; 33 | } 34 | 35 | @NotNull 36 | public static Object doRead(Bytes bytes) { 37 | bytes.readPosition(0); 38 | double v = bytes.parseDouble(); 39 | if (v < 0) throw new AssertionError(); 40 | return bytes; 41 | } 42 | 43 | @NotNull 44 | public static Object doTest(Bytes bytes) { 45 | doWrite(bytes, 3); 46 | doRead(bytes); 47 | return bytes; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/EscapingStopCharsTesterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.StopCharsTester; 7 | import org.junit.Test; 8 | import org.junit.Before; 9 | import static org.mockito.Mockito.*; 10 | import static org.junit.Assert.*; 11 | 12 | public class EscapingStopCharsTesterTest { 13 | 14 | private StopCharsTester baseTester; 15 | private EscapingStopCharsTester tester; 16 | @Before 17 | public void setUp() { 18 | // Setup the base tester with specific behavior for demonstration 19 | baseTester = (ch, peekNextCh) -> ch == 'x'; // Let's say 'x' is a stop character 20 | tester = new EscapingStopCharsTester(baseTester); 21 | } 22 | 23 | @Test 24 | public void testIsStopCharWithEscape() { 25 | // First call with escape character 26 | assertFalse("Escaped character should not be stop char", tester.isStopChar('\\', 'x')); 27 | // Next call with the character that would normally be a stop character 28 | assertFalse("Character following an escape should not be treated as stop char", tester.isStopChar('x', ' ')); 29 | // Subsequent call with a stop character not preceded by an escape 30 | assertTrue("Non-escaped stop char should be recognized as stop char", tester.isStopChar('x', ' ')); 31 | } 32 | 33 | @Test 34 | public void testIsStopCharWithoutEscape() { 35 | assertFalse("Non-stop char should not be recognized as stop char", tester.isStopChar('y', ' ')); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/RingBufferReaderStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.NonNegative; 7 | 8 | /** 9 | * An interface to provide statistics about a {@link RingBufferReader}'s reading operations. 10 | * This includes the number of successful reads, missed reads and how far behind the reader is. 11 | */ 12 | public interface RingBufferReaderStats { 13 | 14 | /** 15 | * Retrieves and resets the count of successful read operations performed by the RingBufferReader. 16 | * Calling this method resets the number. 17 | * 18 | * @return The number of successful read operations since the last call to this method. 19 | */ 20 | @NonNegative 21 | long getAndClearReadCount(); 22 | 23 | /** 24 | * Retrieves and resets the count of missed read operations performed by the RingBufferReader. 25 | * Missed reads occur if there was no new data to be read. 26 | * Calling this method resets the number. 27 | * 28 | * @return The number of missed read operations since the last call to this method. 29 | */ 30 | @NonNegative 31 | long getAndClearMissedReadCount(); 32 | 33 | /** 34 | * Calculates how far behind the RingBufferReader is relative to the write position in the Ring Buffer. 35 | * This provides an indication of how much unread data remains in the buffer for this reader. 36 | * 37 | * @return The number of bytes yet to be read by the RingBufferReader. 38 | */ 39 | @NonNegative 40 | long behind(); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/util/DecoratedBufferOverflowException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import java.nio.BufferOverflowException; 7 | 8 | /** 9 | * Customized {@link BufferOverflowException} with a descriptive message. 10 | * This exception is thrown to indicate that there is an attempt to write 11 | * data into a buffer beyond its capacity. 12 | */ 13 | public final class DecoratedBufferOverflowException extends BufferOverflowException { 14 | private static final long serialVersionUID = 0L; 15 | 16 | /** 17 | * The custom message describing this exception. 18 | */ 19 | private final String message; 20 | 21 | /** 22 | * Constructs a new exception with the specified detail message. 23 | * 24 | * @param message the detail message 25 | */ 26 | public DecoratedBufferOverflowException(final String message) { 27 | this.message = message; 28 | } 29 | 30 | /** 31 | * Constructs a new exception with the specified detail message and cause. 32 | * 33 | * @param message the detail message 34 | * @param cause the cause 35 | */ 36 | public DecoratedBufferOverflowException(final String message, final Throwable cause) { 37 | this.message = message; 38 | initCause(cause); 39 | } 40 | 41 | /** 42 | * Returns the detail message of this exception. 43 | * 44 | * @return the detail message string of this exception 45 | */ 46 | @Override 47 | public String getMessage() { 48 | return message; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/util/DecoratedBufferUnderflowException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import java.nio.BufferUnderflowException; 7 | 8 | /** 9 | * Customized {@link BufferUnderflowException} with a descriptive message. 10 | * This exception is thrown to indicate that there is an attempt to read 11 | * data from a buffer beyond its limit. 12 | */ 13 | public final class DecoratedBufferUnderflowException extends BufferUnderflowException { 14 | 15 | private static final long serialVersionUID = 0L; 16 | /** 17 | * The custom message describing this exception. 18 | */ 19 | private final String message; 20 | 21 | /** 22 | * Constructs a new exception with the specified detail message. 23 | * 24 | * @param message the detail message 25 | */ 26 | public DecoratedBufferUnderflowException(final String message) { 27 | this.message = message; 28 | } 29 | 30 | /** 31 | * Constructs a new exception with the specified detail message and cause. 32 | * 33 | * @param message the detail message 34 | * @param cause the cause 35 | */ 36 | public DecoratedBufferUnderflowException(final String message, final Throwable cause) { 37 | this.message = message; 38 | initCause(cause); 39 | } 40 | 41 | /** 42 | * Returns the detail message of this exception. 43 | * 44 | * @return the detail message string of this exception 45 | */ 46 | @Override 47 | public String getMessage() { 48 | return message; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/StopCharTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.bytes.util.EscapingStopCharTester; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * A functional interface for defining a strategy to identify stop characters during string parsing. 11 | * It allows customization of the end condition for the parsing operation. 12 | */ 13 | @FunctionalInterface 14 | public interface StopCharTester { 15 | 16 | /** 17 | * Tests if the provided character should be regarded as a stop character during a string parsing operation. 18 | * The specific logic for this determination can be defined per use case. 19 | * 20 | *

21 | * Note: For safety reasons, a character of value 0 should either return true (i.e., be considered a stop character) 22 | * or throw an IllegalStateException. This is to prevent issues with null-terminated strings. 23 | * 24 | * @param ch the character to be tested. If ch is 0, the method should return true or throw an exception. 25 | * @return true if the provided character is a stop character, false otherwise. 26 | */ 27 | boolean isStopChar(int ch); 28 | 29 | /** 30 | * Returns a new instance that respects escape characters. 31 | * This allows for parsing scenarios where certain stop characters should be ignored if they are escaped. 32 | * 33 | * @return a new that takes escape characters into account. 34 | */ 35 | @NotNull 36 | default StopCharTester escaping() { 37 | return new EscapingStopCharTester(this); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/WriteBytesMarshallable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.DontChain; 7 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 8 | import net.openhft.chronicle.core.io.InvalidMarshallableException; 9 | import net.openhft.chronicle.core.io.ThreadingIllegalStateException; 10 | 11 | import java.nio.BufferOverflowException; 12 | 13 | /** 14 | * Functional interface for objects that can serialise their state directly to a 15 | * {@link BytesOut} stream. Implementations typically call 16 | * {@link net.openhft.chronicle.core.io.Validatable#validate()} before writing. 17 | */ 18 | @FunctionalInterface 19 | @DontChain 20 | public interface WriteBytesMarshallable extends CommonMarshallable { 21 | 22 | /** 23 | * Writes this object's state to {@code bytes} using a custom binary format. 24 | * Implementations may validate their state prior to writing and throw 25 | * {@link InvalidMarshallableException} if invalid. 26 | * 27 | * @param bytes the target stream 28 | * @throws BufferOverflowException if there is insufficient space in the buffer 29 | * @throws InvalidMarshallableException if the object is not in a valid state for serialisation 30 | * @throws ClosedIllegalStateException if the resource has been released or closed 31 | * @throws ThreadingIllegalStateException if accessed by multiple threads in an unsafe way 32 | */ 33 | void writeMarshallable(BytesOut bytes) 34 | throws IllegalStateException, BufferOverflowException, InvalidMarshallableException; 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/BinaryIntReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.BytesStore; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class BinaryIntReferenceTest extends BytesTestCommon { 14 | @Test 15 | public void test() { 16 | BytesStore nbs = BytesStore.nativeStoreWithFixedCapacity(32); 17 | try (@NotNull BinaryIntReference ref = new BinaryIntReference()) { 18 | ref.bytesStore(nbs, 16, 4); 19 | assertEquals(0, ref.getValue()); 20 | ref.addAtomicValue(1); 21 | assertEquals(1, ref.getVolatileValue()); 22 | ref.addValue(-2); 23 | assertEquals("value: -1", ref.toString()); 24 | assertFalse(ref.compareAndSwapValue(0, 1)); 25 | assertTrue(ref.compareAndSwapValue(-1, 2)); 26 | assertEquals(4, ref.maxSize()); 27 | assertEquals(16, ref.offset()); 28 | assertEquals(nbs, ref.bytesStore()); 29 | assertEquals(0L, nbs.readLong(0)); 30 | assertEquals(0L, nbs.readLong(8)); 31 | assertEquals(2, nbs.readInt(16)); 32 | assertEquals(0L, nbs.readLong(20)); 33 | 34 | ref.setValue(10); 35 | assertEquals(10L, nbs.readInt(16)); 36 | ref.setOrderedValue(20); 37 | Thread.yield(); 38 | assertEquals(20L, nbs.readVolatileInt(16)); 39 | } 40 | nbs.releaseLast(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/render/StandardDecimaliser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.render; 5 | 6 | /** 7 | * Default decimaliser that attempts {@link MaximumPrecision} with precision 18 8 | * and falls back to {@link UsesBigDecimal} for large numbers. 9 | */ 10 | public class StandardDecimaliser implements Decimaliser { 11 | 12 | /** 13 | * Singleton instance of StandardDecimaliser. 14 | */ 15 | public static final StandardDecimaliser STANDARD = new StandardDecimaliser(); 16 | 17 | /** 18 | * Initial strategy rounding to eighteen decimal places. 19 | */ 20 | static final MaximumPrecision PRECISION_18 = new MaximumPrecision(18); 21 | 22 | /** 23 | * Convert {@code value} using {@link #PRECISION_18} then {@link UsesBigDecimal}. 24 | */ 25 | @Override 26 | public boolean toDecimal(double value, DecimalAppender decimalAppender) { 27 | // Tries to convert using MaximumPrecision first, then falls back to UsesBigDecimal. 28 | return PRECISION_18.toDecimal(value, decimalAppender) 29 | || UsesBigDecimal.USES_BIG_DECIMAL.toDecimal(value, decimalAppender); 30 | } 31 | 32 | /** 33 | * Convert {@code value} using {@link #PRECISION_18} then {@link UsesBigDecimal}. 34 | */ 35 | @Override 36 | public boolean toDecimal(float value, DecimalAppender decimalAppender) { 37 | // Tries to convert using MaximumPrecision first, then falls back to UsesBigDecimal. 38 | return PRECISION_18.toDecimal(value, decimalAppender) 39 | || UsesBigDecimal.USES_BIG_DECIMAL.toDecimal(value, decimalAppender); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MyScalars.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.math.BigDecimal; 9 | import java.math.BigInteger; 10 | import java.time.LocalDate; 11 | import java.time.LocalDateTime; 12 | import java.time.LocalTime; 13 | import java.time.ZonedDateTime; 14 | import java.util.UUID; 15 | 16 | class MyScalars implements BytesMarshallable { 17 | private String s; 18 | private BigInteger bi; 19 | private BigDecimal bd; 20 | private LocalDate date; 21 | private LocalTime time; 22 | private LocalDateTime dateTime; 23 | private ZonedDateTime zonedDateTime; 24 | private UUID uuid; 25 | 26 | public MyScalars() { 27 | } 28 | 29 | public MyScalars(String s, BigInteger bi, BigDecimal bd, LocalDate date, LocalTime time, LocalDateTime dateTime, ZonedDateTime zonedDateTime, UUID uuid) { 30 | this.s = s; 31 | this.bi = bi; 32 | this.bd = bd; 33 | this.date = date; 34 | this.time = time; 35 | this.dateTime = dateTime; 36 | this.zonedDateTime = zonedDateTime; 37 | this.uuid = uuid; 38 | } 39 | 40 | @NotNull 41 | @Override 42 | public String toString() { 43 | return "MyScalars{" + 44 | "s='" + s + '\'' + 45 | ", bi=" + bi + 46 | ", bd=" + bd + 47 | ", date=" + date + 48 | ", time=" + time + 49 | ", dateTime=" + dateTime + 50 | ", zonedDateTime=" + zonedDateTime + 51 | ", uuid=" + uuid + 52 | '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/Issue281Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import org.junit.Test; 8 | 9 | import java.nio.ByteBuffer; 10 | import java.nio.ByteOrder; 11 | import java.nio.charset.StandardCharsets; 12 | 13 | import static org.junit.Assert.assertTrue; 14 | import static org.junit.Assume.assumeFalse; 15 | 16 | public class Issue281Test extends BytesTestCommon { 17 | private static void bufferToBytes(Bytes bytes, ByteBuffer dataBuffer, int index) { 18 | int length = dataBuffer.get(index); // length prefix (offset) 19 | bytes.write(0, dataBuffer, index + 1, length); 20 | bytes.writeSkip(length); 21 | } 22 | 23 | @Test 24 | public void testByteBufferToBytes() { 25 | assumeFalse(Jvm.maxDirectMemory() == 0); 26 | 27 | final Bytes data = Bytes.allocateElasticDirect().append("1234567890ABCD"); 28 | final Bytes retVal = Bytes.allocateElasticDirect(); 29 | ByteBuffer buffer = ByteBuffer.allocateDirect(16); 30 | String test = "1234567890ABCD"; 31 | buffer.put((byte) test.length()); 32 | for (byte b : test.getBytes(StandardCharsets.UTF_8)) { 33 | buffer.put(b); 34 | } 35 | buffer.order(ByteOrder.LITTLE_ENDIAN); 36 | bufferToBytes(retVal, buffer, 0); // this calls bufferToBytes below 37 | assertTrue(data.contentEquals(retVal)); 38 | 39 | retVal.clear(); 40 | buffer.order(ByteOrder.BIG_ENDIAN); 41 | bufferToBytes(retVal, buffer, 0); // this calls bufferToBytes below 42 | assertTrue(data.contentEquals(retVal)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesWrite8bitRoundTripTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class BytesWrite8bitRoundTripTest extends BytesTestCommon { 11 | 12 | @Test 13 | public void roundTripOnHeap() { 14 | roundTrip(Bytes.allocateElasticOnHeap()); 15 | } 16 | 17 | @Test 18 | public void roundTripDirect() { 19 | roundTrip(Bytes.allocateElasticDirect()); 20 | } 21 | 22 | private void roundTrip(Bytes bytes) { 23 | try { 24 | String[] names = { 25 | "", // empty 26 | "a", 27 | "helloWorld", 28 | // ISO-8859-1 content 29 | "price£", 30 | // near 255 boundary 31 | repeat('x', 250) 32 | }; 33 | 34 | for (String s : names) { 35 | long pos0 = bytes.writePosition(); 36 | bytes.write8bit(s); 37 | long pos1 = bytes.writePosition(); 38 | bytes.readPosition(pos0); 39 | String got = bytes.read8bit(); 40 | assertEquals(s, got); 41 | // read position should catch up to write 42 | assertEquals(pos1, bytes.readPosition()); 43 | } 44 | } finally { 45 | bytes.releaseLast(); 46 | } 47 | } 48 | 49 | private static String repeat(char c, int n) { 50 | StringBuilder sb = new StringBuilder(n); 51 | for (int i = 0; i < n; i++) sb.append(c); 52 | return sb.toString(); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/UncheckedLongReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.BytesTestCommon; 7 | import net.openhft.chronicle.bytes.internal.NativeBytesStore; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class UncheckedLongReferenceTest extends BytesTestCommon { 14 | @Test 15 | public void test() { 16 | @NotNull NativeBytesStore nbs = NativeBytesStore.nativeStoreWithFixedCapacity(32); 17 | try (@NotNull UncheckedLongReference ref = new UncheckedLongReference()) { 18 | ref.bytesStore(nbs, 16, 8); 19 | assertEquals(0, ref.getValue()); 20 | ref.addAtomicValue(1); 21 | assertEquals(1, ref.getVolatileValue()); 22 | ref.addValue(-2); 23 | assertEquals("value: -1", ref.toString()); 24 | assertFalse(ref.compareAndSwapValue(0, 1)); 25 | assertTrue(ref.compareAndSwapValue(-1, 2)); 26 | assertEquals(8, ref.maxSize()); 27 | assertEquals(nbs.addressForRead(16), ref.offset()); 28 | assertEquals(nbs, ref.bytesStore()); 29 | assertEquals(0L, nbs.readLong(0)); 30 | assertEquals(0L, nbs.readLong(8)); 31 | assertEquals(2L, nbs.readLong(16)); 32 | assertEquals(0L, nbs.readLong(24)); 33 | 34 | ref.setValue(10); 35 | assertEquals(10L, nbs.readLong(16)); 36 | ref.setOrderedValue(20); 37 | Thread.yield(); 38 | assertEquals(20L, nbs.readLong(16)); 39 | } 40 | nbs.releaseLast(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/UTFDataFormatRuntimeException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.IORuntimeException; 7 | 8 | /** 9 | * Thrown to indicate a failure when encoding or decoding UTF-8 data. Extends 10 | * {@link IORuntimeException} so callers need not catch it. 11 | */ 12 | public class UTFDataFormatRuntimeException extends IORuntimeException { 13 | private static final long serialVersionUID = 0L; 14 | /** 15 | * Constructs a new UTFDataFormatRuntimeException with the specified detail message. 16 | * The cause is not initialized, and may subsequently be initialized by a call to {@link #initCause}. 17 | * 18 | * @param message the detail message. The detail message is saved for later retrieval by the {@link #getMessage()} method. 19 | */ 20 | public UTFDataFormatRuntimeException(String message) { 21 | super(message); 22 | } 23 | 24 | /** 25 | * Constructs a new UTFDataFormatRuntimeException with the specified detail message and cause. 26 | *

27 | * Note that the detail message associated with {@code cause} is not automatically incorporated in 28 | * this runtime exception's detail message. 29 | * 30 | * @param message the detail message (which is saved for later retrieval by the {@link #getMessage()} method). 31 | * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). 32 | * (A null value is permitted, and indicates that the cause is nonexistent or unknown.) 33 | */ 34 | public UTFDataFormatRuntimeException(String message, Exception cause) { 35 | super(message, cause); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/BytesRingBufferStats.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.NonNegative; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * This interface provides statistics about a {@link BytesRingBuffer}. 12 | */ 13 | public interface BytesRingBufferStats { 14 | /** 15 | * Minimum free space observed for the writer since the last call. Reset on 16 | * each invocation. Returns {@link Long#MAX_VALUE} if no reads occurred in 17 | * that period. 18 | */ 19 | @NonNegative 20 | long minNumberOfWriteBytesRemaining(); 21 | 22 | /** 23 | * @return the total capacity of the ring buffer in bytes. 24 | */ 25 | @NonNegative 26 | long capacity(); 27 | 28 | /** 29 | * Calling this method resets the number. 30 | * 31 | * @return the number of write operations performed since the last call to this method. 32 | */ 33 | @NonNegative 34 | long getAndClearWriteCount(); 35 | 36 | /** 37 | * Calling this method resets the number. 38 | * 39 | * @return the number of missed write operations since the last call to this method. 40 | */ 41 | @NonNegative 42 | long getAndClearMissedWriteCount(); 43 | 44 | /** 45 | * Calling this method resets the number. 46 | * 47 | * @return the number of contentions since the last call to this method. 48 | */ 49 | @NonNegative 50 | long getAndClearContentionCount(); 51 | 52 | /** 53 | * @return a list of {@link RingBufferReaderStats} objects, each representing the statistics 54 | * for a reader of the ring buffer. 55 | */ 56 | List readers(); 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesBoundsAndLimitsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import java.nio.BufferOverflowException; 9 | import java.nio.BufferUnderflowException; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class BytesBoundsAndLimitsTest extends BytesTestCommon { 14 | 15 | @Test(expected = BufferOverflowException.class) 16 | public void writeBeyondWriteLimitThrows() { 17 | Bytes b = Bytes.allocateElasticOnHeap(8); 18 | try { 19 | b.writeLimit(4); 20 | b.writeLong(1L); // 8 bytes > writeLimit 21 | } finally { 22 | b.releaseLast(); 23 | } 24 | } 25 | 26 | @Test(expected = BufferUnderflowException.class) 27 | public void readBeyondReadLimitThrows() { 28 | Bytes b = Bytes.allocateElasticOnHeap(8); 29 | try { 30 | b.writeInt(123); 31 | b.readPosition(0); 32 | b.readLong(); // 8 bytes > available 4 33 | } finally { 34 | b.releaseLast(); 35 | } 36 | } 37 | 38 | @Test 39 | public void clearIsClearAndZeroOut() { 40 | Bytes b = Bytes.allocateElasticOnHeap(16); 41 | try { 42 | assertTrue(b.isClear()); 43 | b.writeLimit(b.capacity() - 1); 44 | assertFalse(b.isClear()); 45 | b.clear(); 46 | assertTrue(b.isClear()); 47 | 48 | b.append("abcdef"); 49 | b.zeroOut(0, 6); 50 | for (int i = 0; i < 6; i++) { 51 | assertEquals(0, b.peekUnsignedByte(i)); 52 | } 53 | } finally { 54 | b.releaseLast(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/TextIntReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import net.openhft.chronicle.bytes.StopCharTesters; 9 | import net.openhft.chronicle.bytes.internal.NativeBytesStore; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.junit.Test; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | public class TextIntReferenceTest extends BytesTestCommon { 16 | @Test 17 | public void test() { 18 | @NotNull NativeBytesStore nbs = NativeBytesStore.nativeStoreWithFixedCapacity(64); 19 | nbs.zeroOut(0, 64); 20 | try (@NotNull TextIntReference ref = new TextIntReference()) { 21 | ref.bytesStore(nbs, 16, ref.maxSize()); 22 | assertEquals(0, ref.getValue()); 23 | ref.addAtomicValue(1); 24 | assertEquals(1, ref.getVolatileValue()); 25 | ref.addValue(-2); 26 | assertEquals("value: -1", ref.toString()); 27 | assertFalse(ref.compareAndSwapValue(0, 1)); 28 | assertTrue(ref.compareAndSwapValue(-1, 2)); 29 | assertEquals(46, ref.maxSize()); 30 | assertEquals(16, ref.offset()); 31 | assertEquals(nbs, ref.bytesStore()); 32 | assertEquals(0L, nbs.readLong(0)); 33 | assertEquals(0L, nbs.readLong(8)); 34 | Bytes bytes = nbs.bytesForRead(); 35 | bytes.readPosition(16); 36 | assertEquals("!!atomic { locked: false, value: 0000000002 }", bytes.parseUtf8(StopCharTesters.CONTROL_STOP)); 37 | bytes.releaseLast(); 38 | } 39 | nbs.releaseLast(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesRingBufferTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.mockito.Mock; 9 | import org.mockito.MockitoAnnotations; 10 | 11 | import static org.junit.Assert.*; 12 | import static org.mockito.Mockito.*; 13 | 14 | public class BytesRingBufferTest { 15 | 16 | @Mock 17 | private BytesRingBuffer bytesRingBuffer; 18 | 19 | @Mock 20 | private BytesStore mockBytesStore; 21 | 22 | @Before 23 | public void setUp() { 24 | MockitoAnnotations.openMocks(this); 25 | } 26 | 27 | @Test 28 | public void testClear() { 29 | doNothing().when(bytesRingBuffer).clear(); 30 | bytesRingBuffer.clear(); 31 | verify(bytesRingBuffer).clear(); 32 | } 33 | 34 | @Test 35 | public void testOffer() { 36 | when(bytesRingBuffer.offer(any())).thenReturn(true); 37 | assertTrue(bytesRingBuffer.offer(mockBytesStore)); 38 | } 39 | 40 | @Test 41 | public void testRead() { 42 | when(bytesRingBuffer.read(any())).thenReturn(true); 43 | assertTrue(bytesRingBuffer.read(mock(BytesOut.class))); 44 | } 45 | 46 | @Test 47 | public void testReadRemaining() { 48 | when(bytesRingBuffer.readRemaining()).thenReturn(10L); 49 | assertEquals(10L, bytesRingBuffer.readRemaining()); 50 | } 51 | 52 | @Test 53 | public void testIsEmpty() { 54 | when(bytesRingBuffer.isEmpty()).thenReturn(true); 55 | assertTrue(bytesRingBuffer.isEmpty()); 56 | } 57 | 58 | @Test(expected = ClassNotFoundException.class) 59 | public void testNewInstanceThrowsException() { 60 | BytesRingBuffer.newInstance(mockBytesStore); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/TextLongReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import net.openhft.chronicle.bytes.StopCharTesters; 9 | import net.openhft.chronicle.bytes.internal.NativeBytesStore; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.junit.Assert; 12 | import org.junit.Test; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | public class TextLongReferenceTest extends BytesTestCommon { 17 | 18 | @Test 19 | public void testSetValue() { 20 | @NotNull NativeBytesStore bytesStore = NativeBytesStore.nativeStoreWithFixedCapacity(64); 21 | bytesStore.zeroOut(0, 64); 22 | try (@NotNull final TextLongReference value = new TextLongReference()) { 23 | value.bytesStore(bytesStore, 0, value.maxSize()); 24 | bytesStore.writeByte(value.maxSize(), 0); 25 | int expected = 10; 26 | value.setValue(expected); 27 | 28 | long l = bytesStore.parseLong(TextLongReference.VALUE); 29 | 30 | Assert.assertEquals(expected, value.getValue()); 31 | Assert.assertEquals(expected, l); 32 | 33 | assertFalse(value.compareAndSwapValue(0, 1)); 34 | assertTrue(value.compareAndSwapValue(10, 2)); 35 | assertEquals(56, value.maxSize()); 36 | assertEquals(0, value.offset()); 37 | 38 | Bytes bytes = bytesStore.bytesForRead(); 39 | bytes.readPosition(0); 40 | assertEquals("!!atomic { locked: false, value: 00000000000000000002 }", bytes.parseUtf8(StopCharTesters.CONTROL_STOP)); 41 | bytes.releaseLast(); 42 | } 43 | bytesStore.releaseLast(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/MethodWriterInvocationHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.Closeable; 7 | 8 | import java.lang.reflect.InvocationHandler; 9 | /** 10 | * Interface for handling invocations in a MethodWriter. 11 | * This provides advanced configurations for MethodWriters, including 12 | * history recording, resource cleanup, generic event specification, 13 | * and the option to use method IDs. 14 | */ 15 | public interface MethodWriterInvocationHandler extends InvocationHandler { 16 | 17 | /** 18 | * Enable or disable the recording of method invocation history. 19 | * 20 | * @param recordHistory boolean flag to indicate if history should be recorded 21 | */ 22 | void recordHistory(boolean recordHistory); 23 | 24 | /** 25 | * Attach a Closeable resource that will be closed when this handler is closed. 26 | * This is useful for handling resource cleanup after the handler is done. 27 | * 28 | * @param closeable the Closeable resource to be managed 29 | */ 30 | void onClose(Closeable closeable); 31 | 32 | /** 33 | * Specify the identifier for generic events. 34 | * A generic event uses the first argument as the method name, providing a flexible way to write arbitrary methods at runtime. 35 | * 36 | * @param genericEvent the identifier used for generic events 37 | */ 38 | void genericEvent(String genericEvent); 39 | 40 | /** 41 | * Enable or disable the use of method IDs. 42 | * When enabled, methods can be encoded with a numeric ID instead of a string for efficiency. 43 | * 44 | * @param useMethodIds boolean flag to indicate if method IDs should be used 45 | */ 46 | void useMethodIds(boolean useMethodIds); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/StopCharsTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.bytes.util.EscapingStopCharsTester; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * A functional interface that defines a strategy for identifying stop characters during a string parsing operation. 11 | * This allows customization of how and where string parsing should terminate. 12 | */ 13 | @FunctionalInterface 14 | public interface StopCharsTester { 15 | /** 16 | * Determines whether the provided character should cause the string parsing operation to stop. 17 | * The logic for deciding this can be custom defined for different scenarios. 18 | * 19 | *

20 | * For safety reasons, it is advised that a byte of value 0 should either be defined as a stop character 21 | * or should throw an IllegalStateException to prevent issues with null-terminated strings. 22 | * 23 | * @param ch the character to test. If this is 0, it should return true or throw an exception. 24 | * @param peekNextCh the next character that would be parsed after 'ch'. It can be used for context aware stopping, like identifying escape sequences. 25 | * @return true if the provided character is a stop character, false otherwise. 26 | */ 27 | boolean isStopChar(int ch, int peekNextCh); 28 | 29 | /** 30 | * Creates a new that respects escape characters in the string parsing operation. 31 | * This allows for more complex string parsing scenarios where certain stop characters may need to be ignored 32 | * if they are escaped. 33 | * 34 | * @return A new that respects escape characters. 35 | */ 36 | @NotNull 37 | default StopCharsTester escaping() { 38 | return new EscapingStopCharsTester(this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesMethodReaderBuilderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.onoes.ExceptionHandler; 7 | import org.junit.jupiter.api.BeforeEach; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import static org.junit.jupiter.api.Assertions.*; 11 | import static org.mockito.Mockito.*; 12 | 13 | class BytesMethodReaderBuilderTest { 14 | 15 | private BytesIn mockBytesIn; 16 | 17 | @BeforeEach 18 | void setUp() { 19 | mockBytesIn = mock(BytesIn.class); 20 | } 21 | 22 | @Test 23 | void constructorWithBytesInShouldNotThrow() { 24 | assertDoesNotThrow(() -> new BytesMethodReaderBuilder(mockBytesIn)); 25 | } 26 | 27 | @Test 28 | void settingExceptionHandlerOnUnknownMethod() { 29 | BytesMethodReaderBuilder builder = new BytesMethodReaderBuilder(mockBytesIn); 30 | ExceptionHandler mockHandler = mock(ExceptionHandler.class); 31 | assertDoesNotThrow(() -> builder.exceptionHandlerOnUnknownMethod(mockHandler)); 32 | } 33 | 34 | @Test 35 | void settingMethodEncoderLookup() { 36 | BytesMethodReaderBuilder builder = new BytesMethodReaderBuilder(mockBytesIn); 37 | MethodEncoderLookup lookup = MethodEncoderLookup.BY_ANNOTATION; 38 | assertEquals(builder, builder.methodEncoderLookup(lookup), "Builder should support method chaining for methodEncoderLookup setting."); 39 | } 40 | 41 | @Test 42 | void settingAndInitializingDefaultParselet() { 43 | BytesMethodReaderBuilder builder = new BytesMethodReaderBuilder(mockBytesIn); 44 | BytesParselet mockParselet = mock(BytesParselet.class); 45 | builder.defaultParselet(mockParselet); 46 | assertEquals(mockParselet, builder.defaultParselet(), "The set defaultParselet should be returned."); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/SyncModeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import net.openhft.chronicle.core.io.IOTools; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.Parameterized; 11 | 12 | import java.io.File; 13 | import java.io.FileNotFoundException; 14 | import java.util.stream.Stream; 15 | 16 | import static net.openhft.chronicle.core.Jvm.uncheckedCast; 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assume.assumeFalse; 19 | 20 | @RunWith(Parameterized.class) 21 | public class SyncModeTest extends BytesTestCommon { 22 | private final SyncMode syncMode; 23 | 24 | public SyncModeTest(SyncMode syncMode) { 25 | this.syncMode = syncMode; 26 | } 27 | 28 | @Parameterized.Parameters(name = "{0}") 29 | public static Object[][] parameters() { 30 | return Stream.of(SyncMode.values()).map(s -> new Object[]{s}).toArray(Object[][]::new); 31 | } 32 | 33 | @Test 34 | public void largeFile() throws FileNotFoundException { 35 | assumeFalse(Jvm.maxDirectMemory() == 0); 36 | 37 | File tmpfile = IOTools.createTempFile("sync.dat"); 38 | try (MappedFile mappedFile = MappedFile.mappedFile(tmpfile, 64 << 20); 39 | MappedBytes bytes = MappedBytes.mappedBytes(mappedFile)) { 40 | mappedFile.syncMode(syncMode); 41 | bytes.readLong(0); 42 | MappedBytesStore mbs = uncheckedCast(bytes.bytesStore); 43 | assertEquals(syncMode, mbs.syncMode()); 44 | for (int i = 0; i < 64 << 20; i += 1 << 20) { 45 | mbs.syncUpTo(i); 46 | for (int j = 0; j < 1 << 20; j += 4 << 10) 47 | bytes.writeLong(i + j, j); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/StreamingInputStreamTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.jetbrains.annotations.NotNull; 7 | import org.junit.Test; 8 | 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | 13 | import static java.nio.charset.StandardCharsets.ISO_8859_1; 14 | import static org.junit.Assert.assertArrayEquals; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | public class StreamingInputStreamTest extends BytesTestCommon { 18 | 19 | // https://github.com/OpenHFT/Chronicle-Bytes/issues/48 20 | @Test 21 | public void readOfZeroShouldReturnZero() 22 | throws IOException { 23 | @NotNull Bytes b = Bytes.allocateElasticDirect(); 24 | prepareBytes(b); 25 | 26 | @NotNull InputStream is = b.inputStream(); 27 | assertEquals(0, is.read(new byte[5], 0, 0)); 28 | b.releaseLast(); 29 | } 30 | 31 | @Test(timeout = 1000) 32 | public void testReadBlock() 33 | throws IOException { 34 | 35 | @NotNull Bytes b = Bytes.allocateElasticDirect(); 36 | @NotNull byte[] test = prepareBytes(b); 37 | 38 | @NotNull InputStream is = b.inputStream(); 39 | try (@NotNull ByteArrayOutputStream os = new ByteArrayOutputStream()) { 40 | @NotNull byte[] buffer = new byte[8]; 41 | for (int len; (len = is.read(buffer)) != -1; ) 42 | os.write(buffer, 0, len); 43 | os.flush(); 44 | assertArrayEquals(test, os.toByteArray()); 45 | } 46 | 47 | b.releaseLast(); 48 | } 49 | 50 | private byte[] prepareBytes(final Bytes b) { 51 | @NotNull byte[] test = "Hello World, Have a great day!".getBytes(ISO_8859_1); 52 | b.write(test); 53 | return test; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /microbenchmarks/src/main/java/net/openhft/chronicle/bytes/microbenchmarks/DistributedUniqueTimeProviderBenchmark.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.microbenchmarks; 5 | 6 | import net.openhft.chronicle.bytes.DistributedUniqueTimeProvider; 7 | import org.openjdk.jmh.annotations.*; 8 | import org.openjdk.jmh.runner.Runner; 9 | import org.openjdk.jmh.runner.RunnerException; 10 | import org.openjdk.jmh.runner.options.Options; 11 | import org.openjdk.jmh.runner.options.OptionsBuilder; 12 | import org.openjdk.jmh.runner.options.TimeValue; 13 | 14 | import java.util.UUID; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | @State(Scope.Benchmark) 18 | public class DistributedUniqueTimeProviderBenchmark { 19 | private DistributedUniqueTimeProvider timeProvider; 20 | 21 | public static void main(String[] args) throws RunnerException { 22 | Options opt = new OptionsBuilder() 23 | .include(DistributedUniqueTimeProviderBenchmark.class.getSimpleName()) 24 | .warmupIterations(3) 25 | .measurementIterations(5) 26 | .measurementTime(TimeValue.seconds(5)) 27 | .forks(5) 28 | .build(); 29 | 30 | new Runner(opt).run(); 31 | } 32 | 33 | @Setup 34 | public void setUp() { 35 | timeProvider = DistributedUniqueTimeProvider.forHostId(1); 36 | } 37 | 38 | @TearDown 39 | public void tearDown() { 40 | timeProvider.close(); 41 | } 42 | 43 | /* 44 | @Benchmark 45 | @BenchmarkMode(Mode.AverageTime) 46 | @OutputTimeUnit(TimeUnit.NANOSECONDS) 47 | public long currentTimeNanos() { 48 | return timeProvider.currentTimeNanos(); 49 | } 50 | */ 51 | 52 | @Benchmark 53 | @BenchmarkMode(Mode.AverageTime) 54 | @OutputTimeUnit(TimeUnit.NANOSECONDS) 55 | public UUID randomUUID() { 56 | return UUID.randomUUID(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/issue/Issue462Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.issue; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.core.Jvm; 8 | import org.junit.jupiter.params.ParameterizedTest; 9 | import org.junit.jupiter.params.provider.MethodSource; 10 | 11 | import java.nio.ByteBuffer; 12 | import java.nio.ByteOrder; 13 | import java.util.stream.Stream; 14 | 15 | import static org.junit.jupiter.api.Assertions.assertEquals; 16 | 17 | class Issue462Test { 18 | 19 | private static Stream> bytesToTest() { 20 | if (Jvm.maxDirectMemory() == 0) { 21 | return Stream.of( 22 | Bytes.elasticHeapByteBuffer(), 23 | Bytes.elasticHeapByteBuffer(128)); 24 | } 25 | return Stream.of( 26 | Bytes.elasticByteBuffer(), 27 | Bytes.elasticByteBuffer(128), 28 | Bytes.elasticByteBuffer(128, 256), 29 | Bytes.elasticHeapByteBuffer(), 30 | Bytes.elasticHeapByteBuffer(128)); 31 | } 32 | 33 | @ParameterizedTest 34 | @MethodSource("bytesToTest") 35 | void testByteBufferByteOrder(Bytes bytes) { 36 | final long value = 0x0102030405060708L; 37 | bytes.writeLong(value); 38 | final ByteBuffer byteBuffer = bytes.underlyingObject(); 39 | assertEquals(ByteOrder.nativeOrder(), byteBuffer.order()); 40 | final long aLong = byteBuffer.getLong(); 41 | assertEquals(Long.toHexString(value), Long.toHexString(aLong)); 42 | assertEquals(value, aLong); 43 | byteBuffer.putDouble(0, 0.1); 44 | final double actual = bytes.readDouble(); 45 | assertEquals(Long.toHexString(Double.doubleToLongBits(0.1)), Long.toHexString(Double.doubleToLongBits(actual))); 46 | assertEquals(0.1, actual, 0.0); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/BytesInternalContentEqualTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.junit.Test; 9 | 10 | import static org.junit.Assert.assertFalse; 11 | import static org.junit.Assert.assertTrue; 12 | 13 | public class BytesInternalContentEqualTest extends BytesTestCommon { 14 | 15 | @Test 16 | public void heapVsDirectEqualContent() { 17 | Bytes heap = Bytes.from("abcdef"); 18 | Bytes direct = Bytes.allocateDirect(6); 19 | try { 20 | direct.append("abcdef"); 21 | // ensure comparisons start from position 0 22 | heap.readPosition(0); 23 | direct.readPosition(0); 24 | 25 | assertTrue("Expected equal content across heap and direct stores", 26 | BytesInternal.contentEqual(heap.bytesStore(), direct.bytesStore())); 27 | } finally { 28 | heap.releaseLast(); 29 | direct.releaseLast(); 30 | } 31 | } 32 | 33 | @Test 34 | public void differentLengthsAreNotEqual() { 35 | Bytes left = Bytes.from("abc"); 36 | Bytes right = Bytes.from("abcd"); 37 | try { 38 | assertFalse(BytesInternal.contentEqual(left.bytesStore(), right.bytesStore())); 39 | } finally { 40 | left.releaseLast(); 41 | right.releaseLast(); 42 | } 43 | } 44 | 45 | @Test 46 | public void singleByteMismatchDetected() { 47 | Bytes left = Bytes.from("abcde"); 48 | Bytes right = Bytes.from("abXde"); 49 | try { 50 | assertFalse(BytesInternal.contentEqual(left.bytesStore(), right.bytesStore())); 51 | } finally { 52 | left.releaseLast(); 53 | right.releaseLast(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/Issue128Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import java.text.DecimalFormat; 9 | 10 | import static net.openhft.chronicle.bytes.UnsafeTextBytesTest.testAppendDouble; 11 | import static org.junit.Assert.assertEquals; 12 | 13 | public class Issue128Test extends BytesTestCommon { 14 | private static final DecimalFormat DF; 15 | 16 | static { 17 | DecimalFormat df = new DecimalFormat(); 18 | df.setMinimumFractionDigits(1); 19 | df.setMaximumFractionDigits(30); 20 | DF = df; 21 | } 22 | 23 | @Test 24 | public void testCorrect() { 25 | Bytes bytes = Bytes.allocateDirect(32); 26 | try { 27 | // odd ones are trouble. 28 | for (int i = 1; i < 1_000_000; i += 2) { 29 | double v6 = (double) i / 1_000_000; 30 | doTest(bytes, v6); 31 | doTest(bytes, 999 + v6); 32 | double v7 = (double) i / 10_000_000; 33 | doTest(bytes, v7); 34 | double v8 = (double) i / 100_000_000; 35 | doTest(bytes, v8); 36 | double v9 = (double) i / 1_000_000_000; 37 | doTest(bytes, v9); 38 | } 39 | } finally { 40 | bytes.releaseLast(); 41 | } 42 | } 43 | 44 | private void doTest(Bytes bytes, double v) { 45 | String format = DF.format(v); 46 | String output = testAppendDouble(bytes, v); 47 | if (Double.parseDouble(output) != v || format.length() != output.length()) { 48 | // Don't compare strings if we've added an exponent 49 | if (!output.contains("E")) { 50 | assertEquals(DF.format(v), output); 51 | } else { 52 | assertEquals(v, Double.parseDouble(output), 0.0); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ReadLenientTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import java.math.BigDecimal; 9 | import java.math.BigInteger; 10 | import java.nio.BufferUnderflowException; 11 | import java.nio.ByteBuffer; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assert.assertFalse; 15 | import static org.junit.Assume.assumeFalse; 16 | 17 | public class ReadLenientTest extends BytesTestCommon { 18 | @Test 19 | public void testLenient() { 20 | assumeFalse(NativeBytes.areNewGuarded()); 21 | doTest(Bytes.allocateDirect(64)); 22 | doTest(Bytes.allocateElasticOnHeap(64)); 23 | doTest(Bytes.from("")); 24 | } 25 | 26 | private void doTest(Bytes bytes) 27 | throws BufferUnderflowException, ArithmeticException, IllegalArgumentException { 28 | bytes.lenient(true); 29 | ByteBuffer bb = ByteBuffer.allocateDirect(32); 30 | bytes.read(bb); 31 | assertEquals(0, bb.position()); 32 | 33 | assertEquals(BigDecimal.ZERO, bytes.readBigDecimal()); 34 | assertEquals(BigInteger.ZERO, bytes.readBigInteger()); 35 | assertFalse(bytes.readBoolean()); 36 | assertEquals("", bytes.read8bit()); 37 | assertEquals("", bytes.readUtf8()); 38 | assertEquals(0, bytes.readByte()); 39 | assertEquals(-1, bytes.readUnsignedByte()); // note this behaviour is need to find the end of a stream. 40 | assertEquals(0, bytes.readShort()); 41 | assertEquals(0, bytes.readUnsignedShort()); 42 | assertEquals(0, bytes.readInt()); 43 | assertEquals(0, bytes.readUnsignedInt()); 44 | assertEquals(0.0, bytes.readFloat(), 0.0); 45 | assertEquals(0.0, bytes.readDouble(), 0.0); 46 | bytes.readSkip(8); 47 | assertEquals(0, bytes.readPosition()); 48 | 49 | bytes.releaseLast(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/BinaryTwoLongReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.BytesStore; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class BinaryTwoLongReferenceTest extends BytesTestCommon { 14 | @Test 15 | public void test() { 16 | BytesStore nbs = BytesStore.nativeStoreWithFixedCapacity(32); 17 | try (@NotNull BinaryTwoLongReference ref = new BinaryTwoLongReference()) { 18 | ref.bytesStore(nbs, 16, 16); 19 | assertEquals(0, ref.getValue()); 20 | assertEquals(0, ref.getValue2()); 21 | ref.addAtomicValue(1); 22 | assertEquals(1, ref.getVolatileValue()); 23 | assertEquals(0, ref.getVolatileValue2()); 24 | ref.addAtomicValue2(-1); 25 | assertEquals(1, ref.getVolatileValue()); 26 | assertEquals(-1, ref.getVolatileValue2()); 27 | 28 | ref.addValue(-2); 29 | assertEquals("value: -1, value2: -1", ref.toString()); 30 | assertFalse(ref.compareAndSwapValue(0, 1)); 31 | assertTrue(ref.compareAndSwapValue(-1, 2)); 32 | assertEquals(16, ref.maxSize()); 33 | assertEquals(16, ref.offset()); 34 | assertEquals(nbs, ref.bytesStore()); 35 | assertEquals(0L, nbs.readLong(0)); 36 | assertEquals(0L, nbs.readLong(8)); 37 | assertEquals(2L, nbs.readLong(16)); 38 | assertEquals(-1L, nbs.readLong(24)); 39 | 40 | ref.setValue(10); 41 | assertEquals(10L, nbs.readLong(16)); 42 | ref.setOrderedValue(20); 43 | Thread.yield(); 44 | assertEquals(20L, nbs.readVolatileLong(16)); 45 | } 46 | nbs.releaseLast(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/issue/Issue464BytesStoreEmptyTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.issue; 5 | 6 | import net.openhft.chronicle.bytes.BytesStore; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.junit.Test; 9 | 10 | import java.util.function.Supplier; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | public class Issue464BytesStoreEmptyTest extends BytesTestCommon { 15 | @Test 16 | public void emptyShouldNotAllocate() { 17 | doTest(BytesStore::empty); 18 | } 19 | 20 | @Test 21 | public void nullByteArrayShouldNotAllocate() { 22 | assertThrows(NullPointerException.class, () -> BytesStore.wrap((byte[]) null)); 23 | } 24 | 25 | @Test 26 | public void allocateEmptyStringShouldNotAllocate() { 27 | doTest(() -> BytesStore.from("")); 28 | } 29 | 30 | @Test 31 | public void emptyBytesStoreShouldNotAllocate() { 32 | doTest(() -> BytesStore.from(BytesStore.empty())); 33 | } 34 | 35 | @Test 36 | public void emptyStringBuilderShouldNotAllocate() { 37 | doTest(() -> BytesStore.from(new StringBuilder())); 38 | } 39 | 40 | @Test(expected = NullPointerException.class) 41 | public void nullNativeStoreFromShouldNotAllocate() { 42 | doTest(() -> BytesStore.nativeStoreFrom(null)); 43 | } 44 | 45 | @Test 46 | public void emptyCopyFromShouldNotAllocate() { 47 | doTest(() -> BytesStore.empty().copy()); 48 | } 49 | 50 | @Test 51 | public void emptyByteArrayShouldHaveDifferentUnderlying() { 52 | BytesStore a = BytesStore.wrap(new byte[0]); 53 | BytesStore b = BytesStore.wrap(new byte[0]); 54 | assertNotSame(a, b); 55 | assertNotSame(a.underlyingObject(), b.underlyingObject()); 56 | } 57 | 58 | private void doTest(Supplier> supplier) { 59 | assertSame(supplier.get(), supplier.get()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ByteableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import java.io.IOException; 10 | import static org.junit.Assert.*; 11 | import static org.mockito.Mockito.*; 12 | 13 | public class ByteableTest { 14 | 15 | private Byteable byteable; 16 | private BytesStore bytesStore; 17 | 18 | @SuppressWarnings("unchecked") 19 | @Before 20 | public void setUp() throws IOException { 21 | byteable = mock(Byteable.class); 22 | bytesStore = mock(BytesStore.class); 23 | doThrow(UnsupportedOperationException.class).when(byteable).address(); 24 | doThrow(UnsupportedOperationException.class).when(byteable).lock(true); 25 | doThrow(UnsupportedOperationException.class).when(byteable).tryLock(true); 26 | } 27 | 28 | @Test 29 | public void testOffset() { 30 | long expectedOffset = 5L; 31 | when(byteable.offset()).thenReturn(expectedOffset); 32 | 33 | assertEquals(expectedOffset, byteable.offset()); 34 | } 35 | 36 | @Test(expected = UnsupportedOperationException.class) 37 | public void testAddressThrowsUnsupportedOperationException() { 38 | when(byteable.address()).thenCallRealMethod(); 39 | byteable.address(); 40 | } 41 | 42 | @Test 43 | public void testMaxSize() { 44 | long expectedSize = 1024L; 45 | when(byteable.maxSize()).thenReturn(expectedSize); 46 | 47 | assertEquals(expectedSize, byteable.maxSize()); 48 | } 49 | 50 | @Test(expected = UnsupportedOperationException.class) 51 | public void testLockThrowsUnsupportedOperationException() throws IOException { 52 | byteable.lock(true); 53 | } 54 | 55 | @Test(expected = UnsupportedOperationException.class) 56 | public void testTryLockThrowsUnsupportedOperationException() throws IOException { 57 | byteable.tryLock(true); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/util/EscapingStopCharTesterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.StopCharTester; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertFalse; 10 | import static org.junit.Assert.assertTrue; 11 | 12 | public class EscapingStopCharTesterTest { 13 | 14 | @Test 15 | public void testIsStopCharWithAndWithoutEscape() { 16 | // Setup a StopCharTester that considers 'x' as a stop character 17 | StopCharTester baseTester = ch -> ch == 'x'; 18 | 19 | EscapingStopCharTester escapingTester = new EscapingStopCharTester(baseTester); 20 | 21 | // Verify that 'x' is normally considered a stop character 22 | assertTrue("Expected 'x' to be a stop character", escapingTester.isStopChar('x')); 23 | 24 | // Simulate escaping by passing the escape character before 'x' 25 | assertFalse("Escape character should not be considered a stop character", escapingTester.isStopChar('\\')); 26 | assertFalse("Escaped 'x' should not be considered a stop character", escapingTester.isStopChar('x')); 27 | 28 | // Ensure 'x' is considered a stop character again after escaping 29 | assertTrue("Expected 'x' to be recognized as a stop character when not escaped", escapingTester.isStopChar('x')); 30 | } 31 | 32 | @Test 33 | public void testEscapingStopCharTester() { 34 | StopCharTester baseTester = ch -> ch == 'x'; // Let's say 'x' is a stop character 35 | EscapingStopCharTester tester = new EscapingStopCharTester(baseTester); 36 | 37 | assertFalse("First escape character should not be stop char", tester.isStopChar('\\')); 38 | assertFalse("Second escape character should not be stop char", tester.isStopChar('\\')); 39 | assertTrue("Non-escaped character following escapes should be considered stop char if it matches baseTester", tester.isStopChar('x')); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MappedBytesWrite8bitBoundaryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import net.openhft.chronicle.core.OS; 8 | import net.openhft.chronicle.core.io.BackgroundResourceReleaser; 9 | import org.junit.Test; 10 | 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.nio.charset.StandardCharsets; 14 | import java.nio.file.FileSystemException; 15 | import java.nio.file.Files; 16 | 17 | import static org.junit.Assert.assertEquals; 18 | import static org.junit.Assume.assumeFalse; 19 | 20 | public class MappedBytesWrite8bitBoundaryTest extends BytesTestCommon { 21 | 22 | @Test 23 | public void write8bitAcrossChunkBoundary() throws IOException { 24 | assumeFalse(Jvm.maxDirectMemory() == 0); 25 | // Use page size as chunk to make boundary deterministic 26 | final int chunk = OS.pageSize(); 27 | File file = new File(OS.getTarget(), "mapped-write8bit-boundary-" + System.nanoTime() + ".dat"); 28 | Files.createDirectories(file.getParentFile().toPath()); 29 | String msg = repeat('A', 32); 30 | try { 31 | try (MappedBytes mb = MappedBytes.mappedBytes(file, chunk)) { 32 | // position at end of first chunk minus a few bytes so the encoded length + data cross 33 | mb.writePosition(chunk - 2); 34 | mb.write8bit(msg); 35 | mb.readPosition(chunk - 2); 36 | String got = mb.read8bit(); 37 | assertEquals(msg, got); 38 | } 39 | } finally { 40 | BackgroundResourceReleaser.releasePendingResources(); 41 | Files.deleteIfExists(file.toPath()); 42 | } 43 | } 44 | 45 | private static String repeat(char c, int n) { 46 | byte[] b = new byte[n]; 47 | for (int i = 0; i < n; i++) b[i] = (byte) c; 48 | return new String(b, StandardCharsets.ISO_8859_1); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/HexDumpBytesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import net.openhft.chronicle.core.OS; 8 | import org.junit.Test; 9 | 10 | import java.io.File; 11 | import java.io.FileNotFoundException; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | import static org.junit.Assume.assumeFalse; 15 | 16 | public class HexDumpBytesTest extends BytesTestCommon { 17 | 18 | @Test 19 | public void offsetFormat() { 20 | doTest(new HexDumpBytes()); 21 | } 22 | 23 | private static void doTest(HexDumpBytes bytes) { 24 | bytes.numberWrap(8) 25 | .offsetFormat((o, b) -> b.appendBase16(o, 4)); 26 | bytes.writeHexDumpDescription("hi").write(new byte[18]); 27 | bytes.adjustHexDumpIndentation(1); 28 | bytes.writeHexDumpDescription("nest").write(new byte[18]); 29 | assertEquals("" + 30 | "0000 00 00 00 00 00 00 00 00 # hi\n" + 31 | "0008 00 00 00 00 00 00 00 00\n" + 32 | "0010 00 00\n" + 33 | "0012 00 00 00 00 00 00 00 00 # nest\n" + 34 | "001a 00 00 00 00 00 00 00 00\n" + 35 | "0022 00 00\n", bytes.toHexString()); 36 | bytes.releaseLast(); 37 | } 38 | 39 | @Test 40 | public void memoryMapped() throws FileNotFoundException { 41 | assumeFalse(Jvm.maxDirectMemory() == 0); 42 | 43 | File file = new File(OS.getTarget(), "HexDumpBytesTest-" + System.nanoTime() + ".dat"); 44 | File parent = file.getParentFile(); 45 | if (parent != null && !parent.exists()) { 46 | parent.mkdirs(); 47 | } 48 | try (MappedBytes mappedBytes = MappedBytes.mappedBytes(file, 64 * 1024)) { 49 | doTest(new HexDumpBytes(mappedBytes)); 50 | } finally { 51 | if (!file.delete()) { 52 | file.deleteOnExit(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/ConnectionDroppedException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.IORuntimeException; 7 | 8 | /** 9 | * {@link IORuntimeException} signalling an unexpected loss of connection, typically used by 10 | * networking components. 11 | */ 12 | public class ConnectionDroppedException extends IORuntimeException { 13 | private static final long serialVersionUID = 0L; 14 | 15 | /** 16 | * Constructs a {@code ConnectionDroppedException} with the specified detail message. 17 | * 18 | * @param message the detail message saved for later retrieval by the {@link #getMessage()} method. 19 | */ 20 | public ConnectionDroppedException(String message) { 21 | super(message); 22 | } 23 | 24 | /** 25 | * Constructs a {@code ConnectionDroppedException} with the specified cause. 26 | * 27 | * @param e the cause (which is saved for later retrieval by the {@link #getCause()} method). 28 | * (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) 29 | */ 30 | public ConnectionDroppedException(Throwable e) { 31 | super(e); 32 | } 33 | 34 | /** 35 | * Constructs a {@code ConnectionDroppedException} with the specified detail message and cause. 36 | *

37 | * Note that the detail message associated with {@code cause} is not automatically incorporated in 38 | * this runtime exception's detail message. 39 | * 40 | * @param message the detail message saved for later retrieval by the {@link #getMessage()} method. 41 | * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). 42 | * (A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.) 43 | */ 44 | public ConnectionDroppedException(String message, Throwable cause) { 45 | super(message, cause); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/algo/XxHashTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.algo; 5 | 6 | import net.openhft.chronicle.bytes.BytesStore; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.nio.BufferUnderflowException; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | public class XxHashTest { 15 | 16 | @Test 17 | public void testHashEmptyBytesStore() { 18 | BytesStore emptyBytesStore = BytesStore.empty(); 19 | long hash = XxHash.INSTANCE.applyAsLong(emptyBytesStore); 20 | // Assert not throwing an exception and returns a deterministic value 21 | Assert.assertNotNull(hash); 22 | } 23 | 24 | @Test 25 | public void testHashConsistency() { 26 | byte[] data = "test data".getBytes(); 27 | BytesStore bytesStore1 = BytesStore.wrap(data); 28 | BytesStore bytesStore2 = BytesStore.wrap(data.clone()); 29 | 30 | long hash1 = XxHash.INSTANCE.applyAsLong(bytesStore1); 31 | long hash2 = XxHash.INSTANCE.applyAsLong(bytesStore2); 32 | 33 | // Assert that hashes for identical data are equal 34 | assertEquals(hash1, hash2); 35 | } 36 | 37 | @Test 38 | public void testHashWithDifferentLengths() { 39 | BytesStore bytesStore = BytesStore.from("some test data"); 40 | long fullHash = XxHash.INSTANCE.applyAsLong(bytesStore, bytesStore.readRemaining()); 41 | long partialHash = XxHash.INSTANCE.applyAsLong(bytesStore, bytesStore.readRemaining() - 1); 42 | 43 | // Assert that changing the length results in different hashes 44 | Assert.assertNotEquals(fullHash, partialHash); 45 | } 46 | 47 | @Test(expected = BufferUnderflowException.class) 48 | public void testHashBeyondLengthThrowsException() { 49 | BytesStore bytesStore = BytesStore.from("short"); 50 | // Attempt to hash beyond the available length 51 | XxHash.INSTANCE.applyAsLong(bytesStore, bytesStore.readRemaining() + 1); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/ref/ByteableIntArrayValues.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Byteable; 7 | import net.openhft.chronicle.bytes.DynamicallySized; 8 | import net.openhft.chronicle.core.annotation.NonNegative; 9 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 10 | import net.openhft.chronicle.core.io.ThreadingIllegalStateException; 11 | import net.openhft.chronicle.core.values.IntArrayValues; 12 | 13 | /** 14 | * Off-heap, contiguous array of signed 32-bit values. 15 | *

16 | * Values must be stored contiguously following 17 | * {@link BinaryIntArrayReference#SHIFT} in little-endian order. 18 | * 19 | * @see IntArrayValues 20 | * @see Byteable 21 | * @see DynamicallySized 22 | * @see BinaryIntArrayReference 23 | */ 24 | @SuppressWarnings("rawtypes") 25 | public interface ByteableIntArrayValues extends IntArrayValues, Byteable, DynamicallySized { 26 | 27 | /** 28 | * Calculates the byte size required to hold the provided element capacity. 29 | * 30 | * @param capacity the number of elements 31 | * @return total bytes needed for this capacity 32 | * @throws ClosedIllegalStateException If the resource has been released or closed. 33 | * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way 34 | */ 35 | @Override 36 | long sizeInBytes(@NonNegative long capacity) 37 | throws IllegalStateException; 38 | 39 | /** 40 | * Sets the capacity of the array as a count of elements, not bytes. 41 | * 42 | * @param arrayLength the desired element count 43 | * @return this instance for chaining 44 | * @throws ClosedIllegalStateException If the resource has been released or closed. 45 | * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way 46 | */ 47 | ByteableIntArrayValues capacity(@NonNegative long arrayLength) 48 | throws IllegalStateException; 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/render/DecimalAppender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.render; 5 | 6 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 7 | import net.openhft.chronicle.core.io.ThreadingIllegalStateException; 8 | 9 | /** 10 | * Handler for decimal numbers extracted by a {@link Decimaliser}. 11 | * Implementations must document their threading guarantees. In Chronicle Bytes 12 | * a typical implementation appends directly to a byte buffer without 13 | * allocation. 14 | *

15 | * A decimal number is represented as: {@code decimal = sign * mantissa * 10 ^ (-exponent)}, 16 | * where: 17 | *

    18 | *
  • {@code sign} is -1 if the number is negative, +1 otherwise.
  • 19 | *
  • {@code mantissa} holds the significant digits of the decimal number.
  • 20 | *
  • {@code exponent} denotes the power of 10 by which the mantissa is scaled.
  • 21 | *
22 | * Implementations of this interface should provide strategies to handle these individual components. 23 | */ 24 | @FunctionalInterface 25 | public interface DecimalAppender { 26 | 27 | /** 28 | * Append a decimal number, represented by its sign, mantissa and exponent, to a target. 29 | * The target is often a {@link net.openhft.chronicle.bytes.BytesOut} buffer. 30 | * 31 | * @param isNegative Whether the number is negative. {@code true} indicates a negative number, 32 | * {@code false} indicates a positive number. 33 | * @param mantissa The significant digits of the decimal number, represented as a long integer. 34 | * @param exponent The power of ten by which the mantissa is scaled, typically in the range 0-18. 35 | * @throws ClosedIllegalStateException If the resource has been released or closed. 36 | * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way 37 | */ 38 | void append(boolean isNegative, long mantissa, int exponent) 39 | throws ClosedIllegalStateException, ThreadingIllegalStateException; 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/VanillaBytesUsageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.bytes.internal.NativeBytesStore; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | public class VanillaBytesUsageTest extends BytesTestCommon { 12 | 13 | @Test 14 | public void wrapNativeStoreMaintainsOffsets() { 15 | NativeBytesStore store = NativeBytesStore.nativeStoreWithFixedCapacity(64); 16 | try { 17 | store.writeLong(0, 0x1122334455667788L); 18 | 19 | VanillaBytes bytes = VanillaBytes.wrap(store); 20 | try { 21 | bytes.readLimit(store.capacity()); 22 | bytes.readPosition(0); 23 | assertEquals(0x1122334455667788L, bytes.readLong()); 24 | } finally { 25 | bytes.releaseLast(); 26 | } 27 | } finally { 28 | store.releaseLast(); 29 | } 30 | } 31 | 32 | @Test 33 | public void vanillaBytesCanSwapUnderlyingStore() { 34 | NativeBytesStore storeA = NativeBytesStore.nativeStoreWithFixedCapacity(32); 35 | NativeBytesStore storeB = NativeBytesStore.nativeStoreWithFixedCapacity(32); 36 | try { 37 | storeA.writeUtf8(0, "alpha"); 38 | storeB.writeUtf8(0, "beta"); 39 | 40 | VanillaBytes reusable = VanillaBytes.vanillaBytes(); 41 | try { 42 | reusable.bytesStore(storeA, 0, storeA.capacity()); 43 | reusable.readPosition(0); 44 | assertEquals("alpha", reusable.readUtf8()); 45 | 46 | reusable.bytesStore(storeB, 0, storeB.capacity()); 47 | reusable.readPosition(0); 48 | assertEquals("beta", reusable.readUtf8()); 49 | } finally { 50 | reusable.releaseLast(); 51 | } 52 | } finally { 53 | storeA.releaseLast(); 54 | storeB.releaseLast(); 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesCopyMatrixTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.nio.charset.StandardCharsets; 11 | 12 | import static org.junit.Assert.assertArrayEquals; 13 | import static org.junit.Assert.assertEquals; 14 | 15 | public class BytesCopyMatrixTest extends BytesTestCommon { 16 | 17 | @Test 18 | public void heapToNativeStoreCopiesReadablePortion() { 19 | Bytes source = Bytes.allocateElasticOnHeap(); 20 | source.append("alpha-beta"); 21 | source.readPosition(6); // start at beta 22 | BytesStore target = BytesStore.nativeStoreWithFixedCapacity((int) source.readRemaining()); 23 | try { 24 | long copied = source.copyTo(target); 25 | assertEquals(source.readRemaining(), copied); 26 | assertEquals(6, source.readPosition()); 27 | 28 | Bytes view = target.bytesForRead(); 29 | try { 30 | byte[] data = new byte[(int) copied]; 31 | view.read(data); 32 | assertArrayEquals("beta".getBytes(StandardCharsets.ISO_8859_1), data); 33 | } finally { 34 | view.releaseLast(); 35 | } 36 | } finally { 37 | target.releaseLast(); 38 | source.releaseLast(); 39 | } 40 | } 41 | 42 | @Test 43 | public void directBytesCopyToOutputStream() throws IOException { 44 | Bytes source = Bytes.allocateDirect(32); 45 | try { 46 | source.append("payload"); 47 | source.readPosition(0); 48 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 49 | source.copyTo(baos); 50 | assertEquals("payload", baos.toString(StandardCharsets.ISO_8859_1.name())); 51 | assertEquals("copyTo(OutputStream) must not move readPosition", 0, source.readPosition()); 52 | } finally { 53 | source.releaseLast(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/ref/BooleanReferenceTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.BinaryWireCode; 7 | import net.openhft.chronicle.bytes.BytesStore; 8 | import net.openhft.chronicle.bytes.BytesTestCommon; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.junit.Test; 11 | 12 | import java.nio.charset.StandardCharsets; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | public class BooleanReferenceTest extends BytesTestCommon { 17 | @Test 18 | public void testBinary() { 19 | BytesStore nbs = BytesStore.nativeStoreWithFixedCapacity(2); 20 | try (@NotNull BinaryBooleanReference ref = new BinaryBooleanReference()) { 21 | // First value 22 | byte val1 = (byte) BinaryWireCode.FALSE; 23 | nbs.writeByte(0, val1); 24 | 25 | ref.bytesStore(nbs, 0, 1); 26 | 27 | assertFalse(ref.getValue()); 28 | ref.setValue(true); 29 | 30 | // Second value 31 | byte val2 = (byte) BinaryWireCode.TRUE; // true 32 | nbs.writeByte(1, val2); 33 | 34 | ref.bytesStore(nbs, 1, 1); 35 | assertTrue(ref.getValue()); 36 | assertEquals(1, ref.maxSize()); 37 | 38 | } 39 | nbs.releaseLast(); 40 | } 41 | 42 | @Test 43 | public void testText() { 44 | BytesStore nbs = BytesStore.nativeStoreWithFixedCapacity(5); 45 | try (@NotNull TextBooleanReference ref = new TextBooleanReference()) { 46 | 47 | // First value 48 | nbs.write(0, "false".getBytes(StandardCharsets.ISO_8859_1)); 49 | 50 | ref.bytesStore(nbs, 0, 5); 51 | 52 | assertFalse(ref.getValue()); 53 | ref.setValue(true); 54 | 55 | // Second value 56 | nbs.write(5, " true".getBytes(StandardCharsets.ISO_8859_1)); 57 | 58 | ref.bytesStore(nbs, 5, 5); 59 | assertTrue(ref.getValue()); 60 | assertEquals(5, ref.maxSize()); 61 | 62 | } 63 | nbs.releaseLast(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/ref/ByteableLongArrayValues.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.ref; 5 | 6 | import net.openhft.chronicle.bytes.Byteable; 7 | import net.openhft.chronicle.bytes.DynamicallySized; 8 | import net.openhft.chronicle.core.annotation.NonNegative; 9 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 10 | import net.openhft.chronicle.core.io.ThreadingIllegalStateException; 11 | import net.openhft.chronicle.core.values.LongArrayValues; 12 | 13 | /** 14 | * Off-heap, contiguous array of signed 64-bit values. 15 | *

16 | * Implementations must store each value contiguously according to 17 | * {@link BinaryLongArrayReference#SHIFT} and are expected to use 18 | * little-endian aligned storage. 19 | * 20 | * @see LongArrayValues 21 | * @see Byteable 22 | * @see DynamicallySized 23 | * @see BinaryLongArrayReference 24 | */ 25 | @SuppressWarnings("rawtypes") 26 | public interface ByteableLongArrayValues extends LongArrayValues, Byteable, DynamicallySized { 27 | 28 | /** 29 | * Calculates the byte size required to hold the provided element capacity. 30 | * 31 | * @param capacity the number of elements 32 | * @return total bytes needed for this capacity 33 | * @throws ClosedIllegalStateException If the resource has been released or closed. 34 | * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way 35 | */ 36 | @Override 37 | long sizeInBytes(@NonNegative long capacity) 38 | throws IllegalStateException; 39 | 40 | /** 41 | * Sets the capacity of the array as a count of elements, not bytes. 42 | * 43 | * @param arrayLength the desired element count 44 | * @return this instance for chaining 45 | * @throws ClosedIllegalStateException If the resource has been released or closed. 46 | * @throws ThreadingIllegalStateException If this resource was accessed by multiple threads in an unsafe way 47 | */ 48 | 49 | ByteableLongArrayValues capacity(@NonNegative long arrayLength) 50 | throws IllegalStateException; 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/MappedBytesStoreFactoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 7 | import net.openhft.chronicle.core.io.ReferenceOwner; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.mockito.Mock; 11 | import org.mockito.MockitoAnnotations; 12 | 13 | import java.io.File; 14 | 15 | import static org.junit.Assert.assertNotNull; 16 | import static org.mockito.Mockito.*; 17 | 18 | public class MappedBytesStoreFactoryTest { 19 | 20 | @Mock 21 | private MappedBytesStoreFactory factory; 22 | 23 | @Mock 24 | private ReferenceOwner owner; 25 | 26 | @Mock 27 | private MappedFile mappedFile; 28 | 29 | @Before 30 | public void setUp() { 31 | MockitoAnnotations.openMocks(this); 32 | when(mappedFile.file()).thenReturn(new File("test")); 33 | when(factory.create(eq(owner), eq(mappedFile), anyLong(), anyLong(), anyLong(), anyLong(), anyInt())) 34 | .thenReturn(mock(MappedBytesStore.class)); 35 | } 36 | 37 | @Test 38 | public void createMappedBytesStoreWithValidParameters() throws ClosedIllegalStateException { 39 | long start = 0L; 40 | long address = 1024L; 41 | long capacity = 4096L; 42 | long safeCapacity = 2048L; 43 | int pageSize = 4096; 44 | 45 | MappedBytesStore store = factory.create(owner, mappedFile, start, address, capacity, safeCapacity, pageSize); 46 | assertNotNull(store); 47 | verify(factory, times(1)).create(owner, mappedFile, start, address, capacity, safeCapacity, pageSize); 48 | } 49 | 50 | @Test(expected = ClosedIllegalStateException.class) 51 | public void createMappedBytesStoreWhenFileClosed() throws ClosedIllegalStateException { 52 | when(factory.create(any(), any(), anyLong(), anyLong(), anyLong(), anyLong(), anyInt())) 53 | .thenThrow(new ClosedIllegalStateException("MappedFile has been released")); 54 | 55 | factory.create(owner, mappedFile, 0, 0, 0, 0, PageUtil.getPageSize("test")); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/internal/ReferenceCountedUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.core.io.ClosedIllegalStateException; 7 | import net.openhft.chronicle.core.io.ReferenceCounted; 8 | 9 | import static net.openhft.chronicle.core.util.ObjectUtils.requireNonNull; 10 | 11 | /** 12 | * Helpers for checking the state of {@link ReferenceCounted} objects. The class 13 | * is not instantiable. 14 | */ 15 | public final class ReferenceCountedUtil { 16 | 17 | // Private constructor to prevent instantiation 18 | private ReferenceCountedUtil() { 19 | } 20 | 21 | /** 22 | * Verifies that {@code referenceCounted} still has a positive reference 23 | * count. If not, {@link ReferenceCounted#releaseLast()} is invoked which 24 | * will throw a {@link ClosedIllegalStateException} with additional context. 25 | * 26 | * @param referenceCounted the resource to test 27 | * @throws ClosedIllegalStateException if already released 28 | * @throws NullPointerException if {@code referenceCounted} is null 29 | */ 30 | public static void throwExceptionIfReleased(final ReferenceCounted referenceCounted) throws ClosedIllegalStateException { 31 | if (referenceCounted.refCount() <= 0) { 32 | // Rather than throwing a new ClosedIllegalStateException, we invoke releaseLast() that 33 | // will provide much more tracing information. 34 | // Once the ref count reaches zero, this is guaranteed to throw an exception 35 | referenceCounted.releaseLast(); 36 | } 37 | } 38 | 39 | /** 40 | * As {@link #throwExceptionIfReleased(ReferenceCounted)} but only if 41 | * {@code object} implements {@link ReferenceCounted}. Otherwise a simple 42 | * null check is performed. 43 | */ 44 | public static void throwExceptionIfReleased(final Object object) throws ClosedIllegalStateException { 45 | if (object instanceof ReferenceCounted) { 46 | throwExceptionIfReleased((ReferenceCounted) object); 47 | } else { 48 | requireNonNull(object); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/NativeBytesOverflowTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.Jvm; 7 | import org.junit.Test; 8 | 9 | import java.nio.BufferOverflowException; 10 | import java.nio.ByteBuffer; 11 | 12 | import static net.openhft.chronicle.bytes.BytesStore.wrap; 13 | import static org.junit.Assert.assertTrue; 14 | import static org.junit.Assume.assumeFalse; 15 | 16 | public class NativeBytesOverflowTest extends BytesTestCommon { 17 | 18 | @Test(expected = BufferOverflowException.class) 19 | public void testExceedWriteLimitNativeWriteBytes() { 20 | BytesStore store = wrap(ByteBuffer.allocate(128)); 21 | Bytes nb = new NativeBytes<>(store); 22 | try { 23 | nb.writeLimit(2).writePosition(0); 24 | nb.writeLong(10L); 25 | } finally { 26 | nb.releaseLast(); 27 | } 28 | } 29 | 30 | @Test(expected = BufferOverflowException.class) 31 | public void testExceedWriteLimitGuardedBytes() { 32 | Bytes guardedNativeBytes = new GuardedNativeBytes<>(wrap(ByteBuffer.allocate(128)), 128); 33 | try { 34 | guardedNativeBytes.writeLimit(2).writePosition(0); 35 | guardedNativeBytes.writeLong(10L); 36 | } finally { 37 | guardedNativeBytes.releaseLast(); 38 | } 39 | } 40 | 41 | @Test(expected = BufferOverflowException.class) 42 | public void testElastic() { 43 | assumeFalse(Jvm.maxDirectMemory() == 0); 44 | 45 | Bytes bytes = Bytes.elasticByteBuffer(); 46 | try { 47 | bytes.writeLimit(2).writePosition(0); 48 | bytes.writeLong(10L); 49 | } finally { 50 | bytes.releaseLast(); 51 | } 52 | } 53 | 54 | @Test 55 | public void testNativeWriteBytes2() { 56 | Bytes nb = new NativeBytes<>(wrap(ByteBuffer.allocate(128))).unchecked(true); 57 | 58 | nb.writeLimit(2).writePosition(0); 59 | nb.writeLong(10L); 60 | 61 | // this is OK as we are unchecked ! 62 | assertTrue(nb.writePosition() > nb.writeLimit()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/docs/pool-overview.adoc: -------------------------------------------------------------------------------- 1 | = Chronicle Bytes Pooling 2 | :doctype: book 3 | :toc: 4 | :toclevels: 2 5 | :lang: en-GB 6 | 7 | Chronicle Bytes provides a pooling mechanism to reuse `Bytes` objects, primarily to minimise allocation overhead and reduce Garbage Collector (GC) pressure in very low-latency scenarios. 8 | This is particularly beneficial when temporary `Bytes` instances are frequently needed. 9 | 10 | The `BytesPool` class offers static factory methods (e.g., `BytesPool.createThreadLocal()`) to create a thread-local pool of reusable `Bytes` instances, typically `Bytes.allocateElasticDirect()` instances. 11 | Each thread maintains its own small cache of these `Bytes` objects. 12 | When a `Bytes` instance is acquired from the pool, an available one from the cache is provided. 13 | Upon release, the instance is `clear()`-ed and returned to the thread's cache for future reuse. 14 | 15 | The number of `Bytes` instances retained per thread can be configured using the system property `chronicle.bytesPool.instancesPerThread` (defaulting to 4). 16 | 17 | == Acquiring and Releasing Pooled Bytes 18 | 19 | The recommended way to use the pool is with a try-with-resources statement on a `ScopedResource`, which ensures the `Bytes` instance is automatically returned to the pool. 20 | 21 | [source,java] 22 | ---- 23 | import net.openhft.chronicle.bytes.Bytes; 24 | import net.openhft.chronicle.bytes.pool.BytesPool; 25 | import net.openhft.chronicle.core.scoped.ScopedResource; 26 | import net.openhft.chronicle.core.scoped.ScopedResourcePool; 27 | 28 | // Create a pool (can be a static field or managed elsewhere) 29 | ScopedResourcePool> bytesPool = BytesPool.createThreadLocal(); 30 | 31 | // Acquire a Bytes instance from the pool 32 | try (ScopedResource> sb = bytesPool.get()) { 33 | Bytes b = sb.get(); 34 | // Use b for operations 35 | b.writeUtf8("Hello, pooled Bytes!"); 36 | // b is automatically cleared and returned to the pool at the end of this block 37 | } 38 | ---- 39 | 40 | This approach helps in managing the lifecycle of pooled `Bytes` objects efficiently and safely. 41 | 42 | For further details on native memory management and considerations, refer to `memory-management.adoc` and `project-requirements.adoc` (specifically requirement `CB-FN-014`). -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/util/EscapingStopCharTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.StopCharTester; 7 | 8 | /** 9 | * Implementation of {@link StopCharTester} where a backslash ('\\') escapes the 10 | * following character. The tester delegates to another {@code StopCharTester} 11 | * for actual stop character detection of non escaped characters. 12 | *

13 | * The escape state persists for a single subsequent call to 14 | * {@link #isStopChar(int)} on the same instance. Instances are therefore not 15 | * thread safe. See also {@link EscapingStopCharsTester} for the two-argument 16 | * variant. 17 | */ 18 | public class EscapingStopCharTester implements StopCharTester { 19 | 20 | // The decorated StopCharTester 21 | private final StopCharTester sct; 22 | // A flag to track whether the last character was an escape character 23 | private boolean escaped = false; 24 | 25 | /** 26 | * @param sct the underlying {@link StopCharTester} used when the character 27 | * is not escaped 28 | */ 29 | public EscapingStopCharTester(StopCharTester sct) { 30 | this.sct = sct; 31 | } 32 | 33 | /** 34 | * Tests whether the given character should be considered as a stop character. 35 | * A character immediately after an escape character ('\\') is never considered a stop character. 36 | * 37 | * @param ch the character to test 38 | * @return {@code true} if the character is a stop character, {@code false} otherwise 39 | */ 40 | @Override 41 | public boolean isStopChar(int ch) { 42 | // If the previous character was an escape character, do not treat 'ch' as a stop character 43 | if (escaped) { 44 | escaped = false; 45 | return false; 46 | } 47 | 48 | // If the current character is an escape character, set the flag and do not treat it as a stop character 49 | if (ch == '\\') { 50 | escaped = true; 51 | return false; 52 | } 53 | 54 | // Delegate to the decorated StopCharTester 55 | return sct.isStopChar(ch); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/ByteStringReaderWriterTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | import java.io.Reader; 12 | import java.io.Writer; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | public class ByteStringReaderWriterTest extends BytesTestCommon { 18 | 19 | @Test 20 | public void readerReadsAllAndSkipHonoured() throws IOException { 21 | final Bytes bytes = Bytes.allocateElasticOnHeap(64); 22 | try { 23 | bytes.append("abc123XYZ"); 24 | 25 | final Reader reader = new ByteStringReader(bytes); 26 | 27 | // skip a few, then read remaining 28 | long skipped = reader.skip(3); 29 | assertEquals(3L, skipped); 30 | 31 | char[] buf = new char[16]; 32 | int n = reader.read(buf, 0, buf.length); 33 | String s = new String(buf, 0, n); 34 | assertEquals("123XYZ", s); 35 | 36 | // EOF returns -1 37 | assertEquals(-1, reader.read()); 38 | 39 | } finally { 40 | bytes.releaseLast(); 41 | } 42 | } 43 | 44 | @Test 45 | public void writerAppendsVariousOverloads() throws IOException { 46 | final Bytes bytes = Bytes.allocateElasticOnHeap(64); 47 | try { 48 | final ByteStringWriter writer = new ByteStringWriter(bytes); 49 | 50 | writer.write('A'); 51 | writer.write("BC"); 52 | writer.write("012345", 1, 3); // writes "123" 53 | Writer w = writer.append('X') 54 | .append("YZ") 55 | .append("-HELLO-", 1, 6); // "HELLO" 56 | w.flush(); 57 | 58 | final String out = bytes.toString(); 59 | assertTrue(out, out.contains("ABC123XYZHELLO")); 60 | assertEquals("ABC123XYZHELLO", out); 61 | 62 | } finally { 63 | bytes.releaseLast(); 64 | } 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/internal/BytesInternalUtf8Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.internal; 5 | 6 | import net.openhft.chronicle.bytes.Bytes; 7 | import net.openhft.chronicle.bytes.BytesTestCommon; 8 | import net.openhft.chronicle.bytes.StopCharTesters; 9 | import net.openhft.chronicle.bytes.StreamingDataOutput; 10 | import org.junit.Test; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | public class BytesInternalUtf8Test extends BytesTestCommon { 15 | 16 | @Test 17 | public void appendUtf8CharSequenceVariants() { 18 | Bytes out = Bytes.allocateElasticOnHeap(32); 19 | try { 20 | CharSequence cs = "hello-world"; 21 | BytesInternal.appendUtf8((StreamingDataOutput) out, cs, 0, cs.length()); 22 | assertEquals("hello-world", out.toString()); 23 | 24 | out.clear(); 25 | char[] chars = "abcdef".toCharArray(); 26 | // use end index exclusive one less to avoid inclusive access 27 | BytesInternal.appendUtf8(out, (CharSequence) new String(chars), 1, chars.length - 1); 28 | assertEquals("bcdef", out.toString()); 29 | 30 | // long string across internal buffers 31 | out.clear(); 32 | String longStr = new String(new char[1024]).replace('\0', 'x'); 33 | BytesInternal.appendUtf8(out, longStr, 0, longStr.length()); 34 | assertEquals(longStr.length(), out.length()); 35 | } finally { 36 | out.releaseLast(); 37 | } 38 | } 39 | 40 | @Test 41 | public void parseUtf8And8bitWithStopTesters() { 42 | Bytes a = Bytes.from("alpha"); 43 | Bytes b = Bytes.from("beta"); 44 | try { 45 | StringBuilder sb = new StringBuilder(); 46 | BytesInternal.parseUtf8(a, sb, StopCharTesters.NON_ALPHA_DIGIT); 47 | assertEquals("alpha", sb.toString()); 48 | 49 | sb.setLength(0); 50 | BytesInternal.parseUtf8(b, sb, StopCharTesters.NON_ALPHA_DIGIT); 51 | assertEquals("beta", sb.toString()); 52 | } finally { 53 | a.releaseLast(); 54 | b.releaseLast(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/readme/CASTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.readme; 5 | 6 | import net.openhft.chronicle.bytes.BytesTestCommon; 7 | import net.openhft.chronicle.bytes.HexDumpBytes; 8 | import net.openhft.chronicle.bytes.NativeBytes; 9 | import org.junit.Test; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertTrue; 13 | import static org.junit.Assume.assumeFalse; 14 | 15 | public class CASTest extends BytesTestCommon { 16 | @Test 17 | public void testCAS() { 18 | assumeFalse(NativeBytes.areNewGuarded()); 19 | 20 | final HexDumpBytes bytes = new HexDumpBytes() 21 | .offsetFormat((o, b) -> b.appendBase16(o, 4)); 22 | try { 23 | 24 | bytes.writeHexDumpDescription("s32").writeUtf8("s32"); 25 | bytes.writeSkip((-bytes.writePosition()) & (4 - 1)); 26 | long s32 = bytes.writePosition(); 27 | bytes.writeInt(0); 28 | 29 | bytes.writeHexDumpDescription("s64").writeUtf8("s64"); 30 | bytes.writeSkip((-bytes.writePosition()) & (8 - 1)); 31 | long s64 = bytes.writePosition(); 32 | bytes.writeLong(0); 33 | 34 | final String expected1 = "0000 03 73 33 32 00 00 00 00 # s32\n" + 35 | "0008 03 73 36 34 00 00 00 00 00 00 00 00 00 00 00 00 # s64\n"; 36 | 37 | final String actual1 = bytes.toHexString(); 38 | 39 | assertEquals(expected1, actual1); 40 | 41 | //System.out.println(bytes.toHexString()); 42 | 43 | assertTrue(bytes.compareAndSwapInt(s32, 0, Integer.MAX_VALUE)); 44 | assertTrue(bytes.compareAndSwapLong(s64, 0, Long.MAX_VALUE)); 45 | 46 | // System.out.println(bytes.toHexString()); 47 | 48 | final String expected2 = "0000 03 73 33 32 ff ff ff 7f # s32\n" + 49 | "0008 03 73 36 34 00 00 00 00 ff ff ff ff ff ff ff 7f # s64\n"; 50 | final String actual2 = bytes.toHexString(); 51 | 52 | assertEquals(expected2, actual2); 53 | 54 | } finally { 55 | bytes.releaseLast(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/test/java/net/openhft/chronicle/bytes/BytesWriteSkipBehaviourTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import org.junit.Test; 7 | 8 | import java.nio.BufferOverflowException; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | public class BytesWriteSkipBehaviourTest extends BytesTestCommon { 13 | 14 | @Test 15 | public void reserveThenFillHeader() { 16 | Bytes bytes = Bytes.allocateElasticOnHeap(64); 17 | try { 18 | long start = bytes.writePosition(); 19 | bytes.writeSkip(4); // reserve header 20 | bytes.writeInt(0x11223344); 21 | bytes.writeShort((short) 0x55AA); 22 | long end = bytes.writePosition(); 23 | // backfill header with payload length 24 | long payloadLen = end - start - 4; 25 | bytes.writeInt(start, (int) payloadLen); 26 | 27 | bytes.readPosition(start); 28 | assertEquals(payloadLen, bytes.readInt()); 29 | assertEquals(0x11223344, bytes.readInt()); 30 | assertEquals((short) 0x55AA, bytes.readShort()); 31 | } finally { 32 | bytes.releaseLast(); 33 | } 34 | } 35 | 36 | @Test 37 | public void backtrackOneRemovesTrailingSeparator() { 38 | Bytes bytes = Bytes.allocateElasticOnHeap(32); 39 | try { 40 | // Use length-prefixed UTF-8 so readUtf8() is valid 41 | bytes.writeUtf8("abc,"); 42 | // Overwrite the last payload byte (comma) with 'd' 43 | bytes.writeSkip(-1); // drop comma 44 | bytes.writeByte((byte) 'd'); 45 | bytes.readPosition(0); 46 | assertEquals("abcd", bytes.readUtf8()); 47 | } finally { 48 | bytes.releaseLast(); 49 | } 50 | } 51 | 52 | @Test(expected = BufferOverflowException.class) 53 | public void excessiveNegativeSkipThrows() { 54 | Bytes bytes = Bytes.allocateElasticOnHeap(16); 55 | try { 56 | bytes.append("xx"); 57 | // attempt to backtrack beyond start 58 | bytes.writeSkip(- (bytes.writePosition() + 2)); 59 | } finally { 60 | bytes.releaseLast(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/BytesMarshallable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes; 5 | 6 | import net.openhft.chronicle.core.annotation.DontChain; 7 | import net.openhft.chronicle.core.io.*; 8 | 9 | import java.nio.BufferOverflowException; 10 | import java.nio.BufferUnderflowException; 11 | 12 | /** 13 | * Serialisable object that reads and writes its state directly to a 14 | * {@link Bytes} stream. Default implementations delegate to 15 | * {@link BytesUtil} utilities. The interface is marked with 16 | * {@link DontChain} to discourage chaining of implementations. 17 | */ 18 | @DontChain 19 | public interface BytesMarshallable extends ReadBytesMarshallable, WriteBytesMarshallable { 20 | 21 | /** 22 | * {@inheritDoc} 23 | */ 24 | @Override 25 | default boolean usesSelfDescribingMessage() { 26 | return false; 27 | } 28 | 29 | /** 30 | * {@inheritDoc} 31 | */ 32 | @Override 33 | default void readMarshallable(BytesIn bytes) 34 | throws IORuntimeException, BufferUnderflowException, IllegalStateException, InvalidMarshallableException { 35 | BytesUtil.readMarshallable(this, bytes); 36 | ValidatableUtil.validate(this); 37 | } 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | @Override 43 | default void writeMarshallable(BytesOut bytes) 44 | throws IllegalStateException, BufferOverflowException, BufferUnderflowException, ArithmeticException, InvalidMarshallableException { 45 | ValidatableUtil.validate(this); 46 | BytesUtil.writeMarshallable(this, bytes); 47 | } 48 | 49 | /** 50 | * Dumps the binary form of this object as a hex string for debugging. 51 | */ 52 | default String $toString() { 53 | ValidatableUtil.startValidateDisabled(); 54 | try { 55 | HexDumpBytes bytes = new HexDumpBytes(); 56 | writeMarshallable(bytes); 57 | String s = "# " + getClass().getName() + "\n" + bytes.toHexString(); 58 | bytes.releaseLast(); 59 | return s; 60 | } catch (Throwable e) { 61 | return e.toString(); 62 | } finally { 63 | ValidatableUtil.endValidateDisabled(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/net/openhft/chronicle/bytes/util/EscapingStopCharsTester.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 3 | */ 4 | package net.openhft.chronicle.bytes.util; 5 | 6 | import net.openhft.chronicle.bytes.StopCharsTester; 7 | 8 | /** 9 | * Implementation of {@link StopCharsTester} that treats a backslash ('\\') as an 10 | * escape character. The tester delegates to another {@code StopCharsTester} when 11 | * a character is not escaped. 12 | *

13 | * The escape state is held per instance: after seeing a backslash the next call 14 | * to {@link #isStopChar(int, int)} ignores the character passed and clears the 15 | * escaped state. Instances are therefore not thread safe. See also 16 | * {@link EscapingStopCharTester} for the single-character variant. 17 | */ 18 | public class EscapingStopCharsTester implements StopCharsTester { 19 | 20 | private final StopCharsTester sct; 21 | // A flag to track whether the last character was an escape character 22 | private boolean escaped = false; 23 | 24 | /** 25 | * @param sct the underlying {@link StopCharsTester} to which non escaped 26 | * characters will be delegated 27 | */ 28 | public EscapingStopCharsTester(StopCharsTester sct) { 29 | this.sct = sct; 30 | } 31 | 32 | /** 33 | * Tests whether the given character should be considered as a stop character. 34 | * A character immediately after an escape character ('\\') is never considered a stop character. 35 | * 36 | * @param ch the character to test 37 | * @param peekNextCh the next character (peeked ahead) 38 | * @return {@code true} if the character is a stop character, {@code false} otherwise 39 | */ 40 | @Override 41 | public boolean isStopChar(int ch, int peekNextCh) { 42 | // If the previous character was an escape character, do not treat 'ch' as a stop character 43 | if (escaped) { 44 | escaped = false; 45 | return false; 46 | } 47 | 48 | // If the current character is an escape character, set the flag and do not treat it as a stop character 49 | if (ch == '\\') { 50 | escaped = true; 51 | return false; 52 | } 53 | 54 | // Delegate to the decorated StopCharsTester 55 | return sct.isStopChar(ch, peekNextCh); 56 | } 57 | } 58 | --------------------------------------------------------------------------------