summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Bourg <ebourg@apache.org>2016-08-03 10:17:09 +0200
committerEmmanuel Bourg <ebourg@apache.org>2016-08-03 10:17:09 +0200
commit3d9b009255ffd897a9bd84ca3977cd3f553da8ef (patch)
tree13a8296e2989ff8da3fc50d335fd48b2dd0c6064
parentb2ec1a2d459cfef3ff13133c1f7f5972e3740258 (diff)
Imported Upstream version 6.7.6
-rw-r--r--.gitignore113
-rw-r--r--LICENSE165
-rwxr-xr-x[-rw-r--r--]README.md14
-rwxr-xr-xlang-integration/pom.xml125
-rwxr-xr-xlang-osgi/pom.xml215
-rw-r--r--lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java89
-rw-r--r--lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java74
-rwxr-xr-xlang-sandbox/pom.xml96
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/WaitStrategy.java25
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/WaitStrategyBuilder.java190
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/Waiter.java22
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/Waiters.java46
-rwxr-xr-xlang-sandbox/src/main/java/net/openhft/lang/arena/Arena.java74
-rwxr-xr-xlang-sandbox/src/main/java/net/openhft/lang/arena/MappedArena.java134
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArenaStores.java225
-rwxr-xr-xlang-sandbox/src/main/java/net/openhft/lang/data-types.txt19
-rwxr-xr-xlang-sandbox/src/main/java/net/openhft/lang/io/OffHeapLock.java34
-rwxr-xr-xlang-sandbox/src/main/java/net/openhft/lang/io/OffHeapReadWriteLock.java191
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/RawCopier.java (renamed from lang/src/main/java/net/openhft/lang/io/serialization/RawCopier.java)21
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java50
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java (renamed from lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java)24
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java41
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java (renamed from lang/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java)6
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java (renamed from lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java)18
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java (renamed from lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java)48
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java (renamed from lang/src/main/java/net/openhft/lang/model/ClassModel.java)6
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java (renamed from lang/src/main/java/net/openhft/lang/model/DataValueMetaModel.java)14
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java (renamed from lang/src/main/java/net/openhft/lang/model/MethodFilter.java)8
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.java (renamed from lang/src/main/java/net/openhft/lang/model/MethodTemplate.java)6
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java (renamed from lang/src/main/java/net/openhft/lang/model/VanillaFilter.java)6
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/OffHeapReadWriteLockTest.java77
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java (renamed from lang/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java)10
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java (renamed from lang/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java)24
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java (renamed from lang/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java)18
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java (renamed from lang/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java)21
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java (renamed from lang/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java)54
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java (renamed from lang/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java)23
-rwxr-xr-xlang-test/pom.xml233
-rwxr-xr-x[-rw-r--r--]lang-test/src/main/java/net/openhft/lang/io/LockingViaMMapWithThreadIdMain.java (renamed from lang-integration/src/test/java/net/openhft/lang/io/LockingViaMMapWithThreadIdMain.java)34
-rwxr-xr-x[-rw-r--r--]lang-test/src/main/java/net/openhft/langosgi/model/JavaBeanInterface.java (renamed from lang-osgi/src/main/java/net/openhft/langosgi/model/JavaBeanInterface.java)20
-rw-r--r--lang-test/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java85
-rw-r--r--lang-test/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java73
-rw-r--r--lang-test/src/test/java/net/openhft/lang/osgi/OSGiTestBase.java54
-rwxr-xr-xlang/pom.xml257
-rw-r--r--lang/src/main/java/net/openhft/lang/Compare.java44
-rw-r--r--lang/src/main/java/net/openhft/lang/InterruptedRuntimeException.java23
-rwxr-xr-xlang/src/main/java/net/openhft/lang/Jvm.java184
-rw-r--r--lang/src/main/java/net/openhft/lang/LongHashable.java20
-rwxr-xr-xlang/src/main/java/net/openhft/lang/Maths.java70
-rw-r--r--lang/src/main/java/net/openhft/lang/MemoryUnit.java450
-rw-r--r--lang/src/main/java/net/openhft/lang/ReferenceCounted.java25
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/ATSDirectBitSet.java1160
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/DirectBitSet.java557
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/DirectBitSetBuilder.java58
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/HugeArray.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/HugeCollections.java35
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/HugeQueue.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/SingleThreadedDirectBitSet.java1337
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/impl/HugeArrayImpl.java45
-rw-r--r--lang/src/main/java/net/openhft/lang/collection/impl/HugeQueueImpl.java20
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/AbstractBytes.java1831
-rw-r--r--lang/src/main/java/net/openhft/lang/io/AbstractMappedStore.java269
-rw-r--r--lang/src/main/java/net/openhft/lang/io/BoundsCheckingDirectBytes.java43
-rw-r--r--lang/src/main/java/net/openhft/lang/io/BoundsCheckingNativeBytes.java53
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/ByteBufferBytes.java292
-rw-r--r--lang/src/main/java/net/openhft/lang/io/ByteBufferReuse.java159
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/ByteStringAppender.java24
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/ByteStringParser.java88
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/Bytes.java31
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/BytesCommon.java183
-rw-r--r--lang/src/main/java/net/openhft/lang/io/BytesHasher.java37
-rw-r--r--lang/src/main/java/net/openhft/lang/io/BytesStore.java61
-rw-r--r--lang/src/main/java/net/openhft/lang/io/CharBufferReuse.java122
-rw-r--r--lang/src/main/java/net/openhft/lang/io/CharBuffers.java28
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/CheckedBytes.java1313
-rw-r--r--lang/src/main/java/net/openhft/lang/io/ChronicleUnsafe.java231
-rw-r--r--lang/src/main/java/net/openhft/lang/io/DirectByteBufferBytes.java83
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/DirectBytes.java55
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/DirectStore.java148
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/EscapingStopCharTester.java46
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/FileLifecycleListener.java59
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/IByteBufferBytes.java29
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/IOTools.java43
-rwxr-xr-x[-rw-r--r--]lang/src/main/java/net/openhft/lang/io/MappedFile.java105
-rw-r--r--lang/src/main/java/net/openhft/lang/io/MappedMemory.java82
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/MappedNativeBytes.java730
-rw-r--r--lang/src/main/java/net/openhft/lang/io/MappedStore.java52
-rw-r--r--lang/src/main/java/net/openhft/lang/io/MultiStoreBytes.java61
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/MutableDecimal.java42
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/NativeBytes.java554
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/RandomDataInput.java297
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/RandomDataOutput.java270
-rw-r--r--lang/src/main/java/net/openhft/lang/io/RandomDataUpdate.java108
-rw-r--r--lang/src/main/java/net/openhft/lang/io/ResizeableMappedStore.java56
-rw-r--r--lang/src/main/java/net/openhft/lang/io/Reuses.java34
-rw-r--r--lang/src/main/java/net/openhft/lang/io/SettableAtt.java21
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/StopCharTester.java28
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/io/StopCharTesters.java30
-rw-r--r--lang/src/main/java/net/openhft/lang/io/StringBuilderUtils.java84
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/VanillaBytesHash.java89
-rw-r--r--lang/src/main/java/net/openhft/lang/io/VanillaBytesHasher.java46
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/VanillaMappedBlocks.java128
-rw-r--r--lang/src/main/java/net/openhft/lang/io/VanillaMappedBytes.java137
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/VanillaMappedCache.java141
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/VanillaMappedFile.java161
-rw-r--r--lang/src/main/java/net/openhft/lang/io/VanillaMappedMode.java85
-rw-r--r--lang/src/main/java/net/openhft/lang/io/VanillaMappedResource.java26
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/WrappedBytes.java1056
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java196
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java49
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java26
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java35
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java38
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java71
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java23
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java65
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java29
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java68
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java71
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java103
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java72
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java46
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java72
-rwxr-xr-x[-rw-r--r--]lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java43
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java46
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java65
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java49
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java29
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java57
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java75
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java62
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java27
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java37
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java40
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java55
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java208
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java33
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java46
-rwxr-xr-xlang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java121
-rw-r--r--lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java85
-rw-r--r--lang/src/main/java/net/openhft/lang/io/view/BytesInputStream.java119
-rw-r--r--lang/src/main/java/net/openhft/lang/io/view/BytesOutputStream.java109
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockState.java30
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockingStrategy.java35
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategies.java106
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategy.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/BytesAtomicAccess.java73
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/LockState.java30
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/LockingStrategy.java38
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/NativeAtomicAccess.java44
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteLockState.java35
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteLockingStrategy.java38
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockState.java35
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockingStrategy.java41
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockState.java26
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockingStrategy.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockState.java33
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockingStrategy.java33
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/TryAcquireOperation.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/TryAcquireOperations.java152
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/UnsafeAtomicAccess.java53
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteUpdateWithWaitsLockingStrategy.java381
-rw-r--r--lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteWithWaitsLockingStrategy.java232
-rw-r--r--lang/src/main/java/net/openhft/lang/model/Byteable.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/model/CodeGenerator.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/model/Copyable.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/model/DataValueClassCache.java50
-rw-r--r--lang/src/main/java/net/openhft/lang/model/DataValueClasses.java68
-rwxr-xr-x[-rw-r--r--]lang/src/main/java/net/openhft/lang/model/DataValueGenerator.java1118
-rw-r--r--lang/src/main/java/net/openhft/lang/model/DataValueModel.java20
-rwxr-xr-x[-rw-r--r--]lang/src/main/java/net/openhft/lang/model/DataValueModelImpl.java358
-rwxr-xr-x[-rw-r--r--]lang/src/main/java/net/openhft/lang/model/DataValueModels.java34
-rw-r--r--lang/src/main/java/net/openhft/lang/model/FieldModel.java47
-rw-r--r--lang/src/main/java/net/openhft/lang/model/HeapCodeGenerator.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/model/Out.java34
-rw-r--r--lang/src/main/java/net/openhft/lang/model/constraints/Digits.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/model/constraints/Group.java36
-rw-r--r--lang/src/main/java/net/openhft/lang/model/constraints/MaxSize.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/model/constraints/NotNull.java30
-rw-r--r--lang/src/main/java/net/openhft/lang/model/constraints/Nullable.java30
-rw-r--r--lang/src/main/java/net/openhft/lang/model/constraints/Range.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/pool/CharSequenceInterner.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/pool/EnumInterner.java70
-rw-r--r--[-rwxr-xr-x]lang/src/main/java/net/openhft/lang/pool/StringInterner.java52
-rw-r--r--lang/src/main/java/net/openhft/lang/testing/Differencer.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/testing/RunningMinimum.java22
-rw-r--r--lang/src/main/java/net/openhft/lang/testing/VanillaDifferencer.java20
-rwxr-xr-xlang/src/main/java/net/openhft/lang/thread/BusyPauser.java40
-rwxr-xr-xlang/src/main/java/net/openhft/lang/thread/LightPauser.java79
-rw-r--r--lang/src/main/java/net/openhft/lang/thread/NamedThreadFactory.java22
-rwxr-xr-xlang/src/main/java/net/openhft/lang/thread/Pauser.java30
-rw-r--r--lang/src/main/java/net/openhft/lang/threadlocal/Provider.java96
-rw-r--r--lang/src/main/java/net/openhft/lang/threadlocal/StatefulCopyable.java23
-rw-r--r--lang/src/main/java/net/openhft/lang/threadlocal/ThreadLocalCopies.java73
-rw-r--r--lang/src/main/java/net/openhft/lang/values/BooleanValue.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/ByteValue.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/CharValue.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/DoubleValue.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/values/FloatValue.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/values/Int24Value.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/Int48Value.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/IntValue.java27
-rw-r--r--lang/src/main/java/net/openhft/lang/values/LongValue.java24
-rw-r--r--lang/src/main/java/net/openhft/lang/values/ShortValue.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/StringValue.java32
-rw-r--r--lang/src/main/java/net/openhft/lang/values/UnsignedByteValue.java20
-rw-r--r--lang/src/main/java/net/openhft/lang/values/UnsignedIntValue.java21
-rw-r--r--lang/src/main/java/net/openhft/lang/values/UnsignedShortValue.java20
-rw-r--r--lang/src/test/java/DataValueGroupTest$BaseInterface$$Native.java112
-rw-r--r--lang/src/test/java/net/openhft/lang/GroupTest.java111
-rw-r--r--lang/src/test/java/net/openhft/lang/JvmTest.java20
-rw-r--r--lang/src/test/java/net/openhft/lang/MathsTest.java20
-rw-r--r--lang/src/test/java/net/openhft/lang/collection/DirectBitSetTest.java1060
-rw-r--r--lang/src/test/java/net/openhft/lang/collection/HugeArrayTest.java130
-rw-r--r--lang/src/test/java/net/openhft/lang/collection/HugePricesMain.java29
-rw-r--r--lang/src/test/java/net/openhft/lang/collection/HugeQueueTest.java21
-rw-r--r--lang/src/test/java/net/openhft/lang/example/CounterExampleMain.java48
-rwxr-xr-x[-rw-r--r--]lang/src/test/java/net/openhft/lang/io/AllocationRatesTest.java24
-rw-r--r--lang/src/test/java/net/openhft/lang/io/BigDecimalVsDoubleMain.java110
-rwxr-xr-x[-rw-r--r--]lang/src/test/java/net/openhft/lang/io/ByteBufferBytesTest.java241
-rwxr-xr-xlang/src/test/java/net/openhft/lang/io/BytesTest.java28
-rwxr-xr-x[-rw-r--r--]lang/src/test/java/net/openhft/lang/io/DirectByteBufferBytesTest.java252
-rw-r--r--[-rwxr-xr-x]lang/src/test/java/net/openhft/lang/io/DirectBytesTest.java107
-rw-r--r--lang/src/test/java/net/openhft/lang/io/IOToolsTest.java20
-rw-r--r--lang/src/test/java/net/openhft/lang/io/LockingViaFileLockMain.java26
-rw-r--r--lang/src/test/java/net/openhft/lang/io/LockingViaMMapMain.java31
-rw-r--r--lang/src/test/java/net/openhft/lang/io/MappedFileTest.java28
-rwxr-xr-xlang/src/test/java/net/openhft/lang/io/MappedStoreTest.java143
-rw-r--r--lang/src/test/java/net/openhft/lang/io/MutableDecimalTest.java26
-rwxr-xr-x[-rw-r--r--]lang/src/test/java/net/openhft/lang/io/NativeBytesTest.java259
-rwxr-xr-xlang/src/test/java/net/openhft/lang/io/OptimisedBytesHashTest.java220
-rwxr-xr-xlang/src/test/java/net/openhft/lang/io/PingPongMain.java95
-rw-r--r--lang/src/test/java/net/openhft/lang/io/ResizeableMappedStoreTest.java70
-rwxr-xr-xlang/src/test/java/net/openhft/lang/io/VanillaMappedFileTest.java376
-rwxr-xr-xlang/src/test/java/net/openhft/lang/io/examples/MappedStroreExampleMain.java44
-rwxr-xr-x[-rw-r--r--]lang/src/test/java/net/openhft/lang/io/examples/ParserExampleMain.java31
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/ByteMarshallableMarshallerTest.java29
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/ExternalizableMarshallerTest.java27
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/JDKZObjectSerializerTest.java58
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/JavaSerializationTest.java47
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/VanillaBytesMarshallerTest.java88
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshallerTest.java53
-rw-r--r--lang/src/test/java/net/openhft/lang/io/serialization/impl/StringZMapMarshallerTest.java59
-rw-r--r--lang/src/test/java/net/openhft/lang/locks/LockingStrategyTest.java537
-rwxr-xr-x[-rw-r--r--]lang/src/test/java/net/openhft/lang/model/DataValueGeneratorTest.java155
-rw-r--r--lang/src/test/java/net/openhft/lang/model/DataValueModelTest.java40
-rw-r--r--lang/src/test/java/net/openhft/lang/model/FirstPrimitiveFieldTest.java56
-rw-r--r--lang/src/test/java/net/openhft/lang/model/GetUsingStringInterface.java36
-rw-r--r--lang/src/test/java/net/openhft/lang/model/HasArraysInterface.java57
-rw-r--r--lang/src/test/java/net/openhft/lang/model/JavaBeanInterface.java41
-rw-r--r--lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetDate.java30
-rw-r--r--lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetMyEnum.java27
-rw-r--r--lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsing.java29
-rw-r--r--lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsingHeap.java29
-rw-r--r--lang/src/test/java/net/openhft/lang/model/MinimalInterface.java20
-rw-r--r--lang/src/test/java/net/openhft/lang/model/MyEnum.java34
-rw-r--r--lang/src/test/java/net/openhft/lang/model/NestedA.java21
-rw-r--r--lang/src/test/java/net/openhft/lang/model/NestedArrayInterface.java28
-rw-r--r--lang/src/test/java/net/openhft/lang/model/NestedB.java20
-rw-r--r--lang/src/test/java/net/openhft/lang/model/StringInterface.java20
-rw-r--r--lang/src/test/java/net/openhft/lang/model/VolatileTest.java128
-rw-r--r--lang/src/test/java/net/openhft/lang/testing/RunningMinimumTest.java22
-rwxr-xr-xlang/src/test/java/net/openhft/lang/thread/LightPauserTest.java48
-rwxr-xr-xlang/src/test/java/net/openhft/lang/values/BuySell.java5
-rwxr-xr-xlang/src/test/java/net/openhft/lang/values/BuySellValues.java12
-rw-r--r--lang/src/test/java/net/openhft/lang/values/CheckValuesBuildTest.java20
-rwxr-xr-xlang/src/test/java/net/openhft/lang/values/EnumValuesTest.java53
-rw-r--r--lang/src/test/java/net/openhft/lang/values/NestAll.java21
-rwxr-xr-xlang/src/test/java/net/openhft/lang/values/StringValueTest.java37
-rwxr-xr-xlang8/pom.xml200
-rwxr-xr-x[-rw-r--r--]pom.xml52
274 files changed, 25889 insertions, 3416 deletions
diff --git a/.gitignore b/.gitignore
index e7c1ea9..95de933 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,118 @@
*.class
+# Mobile Tools for Java (J2ME)
+#.mtj.tmp/
+/target
# Package Files #
*.jar
*.war
*.ear
+*.iml
+.idea*
+
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+
+
+### Eclipse template
+*.pydevproject
+.metadata
+.gradle
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# TeXlipse plugin
+.texlipse
+
+
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
-# IntelliJ
*.iml
-.idea
-# maven
-target
+## Directory-based project format:
+.idea/
+# if you remove the above rule, at least ignore the following:
+
+# User-specific stuff:
+# .idea/workspace.xml
+# .idea/tasks.xml
+# .idea/dictionaries
+
+# Sensitive or high-churn files:
+# .idea/dataSources.ids
+# .idea/dataSources.xml
+# .idea/sqlDataSources.xml
+# .idea/dynamic.xml
+# .idea/uiDesigner.xml
+
+# Gradle:
+# .idea/gradle.xml
+# .idea/libraries
+
+# Mongo Explorer plugin:
+# .idea/mongoSettings.xml
+
+## File-based project format:
+*.ipr
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+
+
+### Java template
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..02bbb60
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library. \ No newline at end of file
diff --git a/README.md b/README.md
index 3aa5918..2e77718 100644..100755
--- a/README.md
+++ b/README.md
@@ -6,11 +6,14 @@ This module is available on maven central as
<dependency>
<groupId>net.openhft</groupId>
<artifactId>lang</artifactId>
- <version>6.1.1</version>
+ <version><!--replace with the latest version--></version>
</dependency>
The version 6.x signifies that it is build for Java 6+. (It requires Java 6 update 18 or later to build)
+## JavaDoc
+Check out our documentation at [JavaDoc] (http://openhft.github.io/Java-Lang/apidocs/)
+
## Working with off heap objects.
Java-Lang 6.1 adds support for basic off heap data structures. More collections types and more complex data types will be added in future versions.
@@ -26,7 +29,7 @@ Java-Lang 6.1 adds support for basic off heap data structures. More collections
// set data on dt
array.recycle(dt); // recycle the reference (or discard it)
- // create a ring buffer
+ // create a ring writeBuffer
HugeQueue<DataType> queue = HugeCollections.newQueue(DataType.class, 10*1000*1000L);
// give me a reference to an object to populate
DataType dt2 = queue.offer();
@@ -51,11 +54,11 @@ Both classes provide functionality:
* addAndGetInt and getAndAddInt operations
####Example
- ByteBuffer byteBuffer = ByteBuffer.allocate(SIZE).order(ByteOrder.nativeOrder());
+ ByteBuffer byteBuffer = ByteBuffer.allocate(SIZE);
ByteBufferBytes bytes = new ByteBufferBytes(byteBuffer);
- for (long i = 0; i < bytes.capacity(); i++)
+ for (long i = 0; i < bytes.maximumLimit(); i++)
bytes.writeLong(i);
- for (long i = bytes.capacity()-8; i >= 0; i -= 8) {
+ for (long i = bytes.maximumLimit()-8; i >= 0; i -= 8) {
int j = bytes.readLong(i);
assert i == j;
}
@@ -72,3 +75,4 @@ Unzip master.zip, Java-Lang-master folder will be extracted from zip.
Now you have an eclipse project, import project into Eclipse
If your Eclipse configuration is not UTF-8, after importing the project you may see some errors and strange characters in some .java files. To get rid of this problem change character enconding to UTF-8: project->properties->resource->text file encoding->utf8
+
diff --git a/lang-integration/pom.xml b/lang-integration/pom.xml
deleted file mode 100755
index a56b1a4..0000000
--- a/lang-integration/pom.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright 2013 Peter Lawrey
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>net.openhft</groupId>
- <artifactId>lang-integration</artifactId>
- <version>6.1.3</version>
- <packaging>pom</packaging>
-
- <name>OpenHFT/Java-Lang/lang-osgi</name>
- <description>Java Lang library for High Frequency Trading (Java 6+)</description>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>net.openhft</groupId>
- <artifactId>lang</artifactId>
- <version>${project.version}</version>
- </dependency>
-
- <dependency>
- <groupId>net.openhft</groupId>
- <artifactId>affinity</artifactId>
- <version>2.0.1</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.11</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <testSourceDirectory>src/test/java</testSourceDirectory>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.1</version>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-source-plugin</artifactId>
- <version>2.2</version>
- <executions>
- <execution>
- <id>attach-sources</id>
- <phase>verify</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>2.9</version>
- <executions>
- <execution>
- <id>attach-javadocs</id>
- <phase>verify</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <show>public</show>
- <nohelp>true</nohelp>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <url>http://www.openhft.net</url>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
- <distribution>repo</distribution>
- <comments>A business-friendly OSS license</comments>
- </license>
- </licenses>
-
- <developers>
- <developer>
- <name>Peter Lawrey</name>
- <email>peter.lawrey@higherfrequencytrading.com</email>
- </developer>
- </developers>
-
- <scm>
- <url>scm:git:https://github.com/OpenHFT/Java-Lang.git</url>
- </scm>
-</project> \ No newline at end of file
diff --git a/lang-osgi/pom.xml b/lang-osgi/pom.xml
deleted file mode 100755
index fd8123f..0000000
--- a/lang-osgi/pom.xml
+++ /dev/null
@@ -1,215 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ Copyright 2013 Peter Lawrey
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>net.openhft</groupId>
- <artifactId>lang-osgi</artifactId>
- <version>6.1.3</version>
- <packaging>bundle</packaging>
-
- <name>OpenHFT/Java-Lang/lang-osgi</name>
- <description>Java Lang library for High Frequency Trading (Java 6+)</description>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <felix.version>3.2.2</felix.version>
- <pax.exam.version>3.3.0</pax.exam.version>
- <pax.url.version>1.6.0</pax.url.version>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.kohsuke.jetbrains</groupId>
- <artifactId>annotations</artifactId>
- <version>9.0</version>
- <scope>compile</scope>
- </dependency>
-
- <dependency>
- <groupId>net.openhft</groupId>
- <artifactId>lang</artifactId>
- <version>${project.version}</version>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.11</version>
- <scope>test</scope>
- </dependency>
-
-
- <!-- for OSGi testing -->
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-container-native</artifactId>
- <version>${pax.exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>${pax.exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-link-mvn</artifactId>
- <version>${pax.exam.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.url</groupId>
- <artifactId>pax-url-aether</artifactId>
- <version>${pax.url.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.framework</artifactId>
- <version>${felix.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-core</artifactId>
- <version>0.9.6</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>0.9.6</version>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
- <build>
- <testSourceDirectory>src/test/java</testSourceDirectory>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.1</version>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-source-plugin</artifactId>
- <version>2.2</version>
- <executions>
- <execution>
- <id>attach-sources</id>
- <phase>verify</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>2.9</version>
- <executions>
- <execution>
- <id>attach-javadocs</id>
- <phase>verify</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <show>public</show>
- <nohelp>true</nohelp>
- </configuration>
- </plugin>
- <!-- plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-gpg-plugin</artifactId>
- <version>1.4</version>
- <configuration>
- <passphrase>${gpg.passphrase}</passphrase>
- </configuration>
- <executions>
- <execution>
- <id>sign-artifacts</id>
- <phase>verify</phase>
- <goals>
- <goal>sign</goal>
- </goals>
- </execution>
- </executions>
- </plugin -->
-
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <version>2.3.7</version>
- <extensions>true</extensions>
- <configuration>
- <instructions>
- <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
- <Bundle-Name>${project.artifactId}</Bundle-Name>
- </instructions>
- </configuration>
- <executions>
- <!--
- This execution makes sure that the manifest is available
- when the tests are executed
- -->
- <execution>
- <goals>
- <goal>manifest</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
- <url>http://www.openhft.net</url>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
- <distribution>repo</distribution>
- <comments>A business-friendly OSS license</comments>
- </license>
- </licenses>
-
- <developers>
- <developer>
- <name>Peter Lawrey</name>
- <email>peter.lawrey@higherfrequencytrading.com</email>
- </developer>
- </developers>
-
- <scm>
- <url>scm:git:https://github.com/OpenHFT/Java-Lang.git</url>
- </scm>
-</project> \ No newline at end of file
diff --git a/lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java b/lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java
deleted file mode 100644
index d734312..0000000
--- a/lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2013 Peter Lawrey
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.openhft.lang.osgi;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.Logger;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import java.io.File;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.ops4j.pax.exam.CoreOptions.*;
-
-/**
- * @author lburgazzoli
- */
-@RunWith(PaxExam.class)
-public class OSGiBundleTest {
- @Inject
- BundleContext context;
-
- @Configuration
- public Option[] config() {
- Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
- root.setLevel(Level.INFO);
-
- return options(
- systemProperty("org.osgi.framework.storage.clean").value("true"),
- systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
- mavenBundle("net.openhft", "compiler", "2.1"),
- new File("Java-Lang/lang/target/classes").exists() ? bundle("reference:file:Java-Lang/lang/target/classes") : bundle("reference:file:../lang/target/classes"),
- new File("Java-Lang/lang-osgi/target/classes").exists() ? bundle("reference:file:Java-Lang/lang-osgi/target/classes") : bundle("reference:file:target/classes"),
- junitBundles(),
- systemPackage("sun.misc"),
- systemPackage("sun.nio.ch"),
- systemPackage("com.sun.tools.javac.api"),
- cleanCaches()
- );
- }
-
- @Test
- public void checkInject() {
- assertNotNull(context);
- }
-
- @Test
- public void checkHelloBundle() {
- Boolean bundleFound = false;
- Boolean bundleActive = false;
-
- Bundle[] bundles = context.getBundles();
- for (Bundle bundle : bundles) {
- if (bundle != null) {
- if (bundle.getSymbolicName().equals("net.openhft.lang")) {
- bundleFound = true;
- if (bundle.getState() == Bundle.ACTIVE) {
- bundleActive = true;
- }
- }
- }
- }
-
- assertTrue(bundleFound);
- assertTrue(bundleActive);
- }
-}
diff --git a/lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java b/lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java
deleted file mode 100644
index 6cae71a..0000000
--- a/lang-osgi/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2013 Peter Lawrey
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.openhft.lang.osgi;
-
-import ch.qos.logback.classic.Level;
-import ch.qos.logback.classic.Logger;
-import net.openhft.lang.collection.HugeArray;
-import net.openhft.lang.collection.HugeCollections;
-import net.openhft.langosgi.model.JavaBeanInterface;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.Option;
-import org.ops4j.pax.exam.junit.PaxExam;
-import org.osgi.framework.BundleContext;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import java.io.File;
-
-import static org.junit.Assert.assertNotNull;
-import static org.ops4j.pax.exam.CoreOptions.*;
-
-/**
- * @author lburgazzoli
- */
-@Ignore
-@RunWith(PaxExam.class)
-public class OSGiCollectionTest {
- @Inject
- BundleContext context;
-
- @Configuration
- public Option[] config() {
- Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
- root.setLevel(Level.INFO);
-
- return options(
- systemProperty("org.osgi.framework.storage.clean").value("true"),
- systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
- mavenBundle("net.openhft", "compiler", "2.1"),
- new File("Java-Lang/lang/target/classes").exists() ? bundle("reference:file:Java-Lang/lang/target/classes") : bundle("reference:file:../lang/target/classes"),
- new File("Java-Lang/lang-osgi/target/classes").exists() ? bundle("reference:file:Java-Lang/lang-osgi/target/classes") : bundle("reference:file:target/classes"),
- junitBundles(),
- systemPackage("sun.misc"),
- systemPackage("sun.nio.ch"),
- systemPackage("com.sun.tools.javac.api"),
- cleanCaches()
- );
- }
-
- @Test
- public void checkHugeArray() {
- int length = 10 * 1000 * 1000;
- HugeArray<JavaBeanInterface> array = HugeCollections.newArray(JavaBeanInterface.class, length);
-
- assertNotNull(array);
- }
-}
diff --git a/lang-sandbox/pom.xml b/lang-sandbox/pom.xml
new file mode 100755
index 0000000..a293f4d
--- /dev/null
+++ b/lang-sandbox/pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2015 higherfrequencytrading.com
+ ~
+ ~ This program is free software: you can redistribute it and/or modify
+ ~ it under the terms of the GNU Lesser General Public License as published by
+ ~ the Free Software Foundation, either version 3 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>net.openhft</groupId>
+ <artifactId>java-parent-pom</artifactId>
+ <version>1.1.1</version>
+ <relativePath/>
+ </parent>
+
+ <name>OpenHFT/Java-Lang/lang-sandbox</name>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>lang-sandbox</artifactId>
+ <version>6.7.1-SNAPSHOT</version>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>third-party-bom</artifactId>
+ <type>pom</type>
+ <version>3.4.20</version>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>lang</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>lang</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.java</groupId>
+ <artifactId>tools</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <compilerArgument>-Xlint:deprecation</compilerArgument>
+ <source>1.8</source>
+ <target>1.8</target>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/WaitStrategy.java b/lang-sandbox/src/main/java/net/openhft/lang/WaitStrategy.java
new file mode 100644
index 0000000..b53151c
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/WaitStrategy.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.openhft.lang;
+
+/*
+ * JLANGX-10 Wait strategy
+ */
+public interface WaitStrategy {
+ public void await(int counter);
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/WaitStrategyBuilder.java b/lang-sandbox/src/main/java/net/openhft/lang/WaitStrategyBuilder.java
new file mode 100644
index 0000000..d92e75a
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/WaitStrategyBuilder.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.openhft.lang;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class WaitStrategyBuilder {
+ private int lowerLimit;
+ private List<WaiterHelper> waiters;
+
+ public WaitStrategyBuilder() {
+ this.waiters = new LinkedList<WaiterHelper>();
+ this.lowerLimit = 0;
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ public WaitStrategyBuilder busyWaiter(int count) {
+ return waiter(Waiters.BUSY_WAITER,count);
+ }
+
+ public WaitStrategyBuilder yeldWaiter(int count) {
+ return waiter(Waiters.YELD_WAITER,count);
+ }
+
+ public WaitStrategyBuilder parkWaiter(int count) {
+ return waiter(Waiters.PARK_WAITER,count);
+ }
+
+ public WaitStrategyBuilder waiter(Waiter waiter,int count) {
+ this.waiters.add(new WaiterHelper(waiter,this.lowerLimit,count));
+ this.lowerLimit += count;
+ return this;
+ }
+
+ public WaitStrategy build() {
+ switch(this.waiters.size()) {
+ case 1:
+ return new WaitStrategy1(this.waiters);
+ case 2:
+ return new WaitStrategy2(this.waiters);
+ case 3:
+ return new WaitStrategy3(this.waiters);
+ }
+
+ return new WaitStrategyN(this.waiters);
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ private class WaiterHelper {
+ private final Waiter waiter;
+ private int min;
+ private int max;
+
+ public WaiterHelper(final Waiter waiter) {
+ this(waiter,-1,-1);
+ }
+
+ public WaiterHelper(final Waiter waiter,int start, int count) {
+ this.waiter = waiter;
+ this.min = start;
+ this.max = start + count;
+ }
+
+ public boolean contains(int value) {
+ return value >= this.min && value <= this.min;
+ }
+
+ public Waiter waiter() {
+ return this.waiter;
+ }
+
+ public int min() {
+ return this.min;
+ }
+
+ public int max() {
+ return this.max;
+ }
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ private class WaitStrategy1 implements WaitStrategy {
+ private final Waiter waiter;
+
+ public WaitStrategy1(final List<WaiterHelper> waiters) {
+ this.waiter = waiters.get(0).waiter;
+ }
+
+ @Override
+ public void await(int counter) {
+ this.waiter.await();
+ }
+ }
+
+ private class WaitStrategy2 implements WaitStrategy {
+ private final int limit;
+ private final Waiter waiter1;
+ private final Waiter waiter2;
+
+ public WaitStrategy2(final List<WaiterHelper> waiters) {
+ this.limit = waiters.get(0).max;
+ this.waiter1 = waiters.get(0).waiter;
+ this.waiter2 = waiters.get(1).waiter;
+ }
+
+ @Override
+ public void await(int counter) {
+ if(counter < this.limit) {
+ this.waiter1.await();
+
+ } else {
+ this.waiter2.await();
+ }
+ }
+ }
+
+ private class WaitStrategy3 implements WaitStrategy {
+ private final int limit1;
+ private final int limit2;
+ private final Waiter waiter1;
+ private final Waiter waiter2;
+ private final Waiter waiter3;
+
+ public WaitStrategy3(final List<WaiterHelper> waiters) {
+ this.limit1 = waiters.get(0).max;
+ this.limit2 = waiters.get(1).max;
+ this.waiter1 = waiters.get(0).waiter;
+ this.waiter2 = waiters.get(1).waiter;
+ this.waiter3 = waiters.get(2).waiter;
+ }
+
+ @Override
+ public void await(int counter) {
+ if(counter < this.limit1) {
+ this.waiter1.await();
+
+ } else if(counter < this.limit2) {
+ this.waiter2.await();
+
+ } else {
+ this.waiter3.await();
+ }
+ }
+ }
+
+ private class WaitStrategyN implements WaitStrategy {
+ final List<WaiterHelper> waiters;
+
+ public WaitStrategyN(final List<WaiterHelper> waiters) {
+ this.waiters = new LinkedList<WaiterHelper>(waiters);
+ }
+
+ @Override
+ public void await(int counter) {
+ WaiterHelper wh = null;
+ for(int i=0;i<this.waiters.size();i++) {
+ wh = this.waiters.get(i);
+ if(i == this.waiters.size() - 1 || wh.contains(counter)) {
+ wh.waiter().await();
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/Waiter.java b/lang-sandbox/src/main/java/net/openhft/lang/Waiter.java
new file mode 100644
index 0000000..0275376
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/Waiter.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.openhft.lang;
+
+public interface Waiter {
+ public void await();
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/Waiters.java b/lang-sandbox/src/main/java/net/openhft/lang/Waiters.java
new file mode 100644
index 0000000..4dd73e2
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/Waiters.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.openhft.lang;
+
+import java.util.concurrent.locks.LockSupport;
+
+public class Waiters {
+ public static final Waiter BUSY_WAITER = new BusyWaiter();
+ public static final Waiter YELD_WAITER = new YieldWaiter();
+ public static final Waiter PARK_WAITER = new ParkWaiter();
+
+ public static final class BusyWaiter implements Waiter {
+ @Override
+ public void await() {
+ }
+ }
+
+ public static final class YieldWaiter implements Waiter {
+ @Override
+ public void await() {
+ Thread.yield();
+ }
+ }
+
+ public static final class ParkWaiter implements Waiter {
+ @Override
+ public void await() {
+ LockSupport.parkNanos(1L);
+ }
+ }
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/arena/Arena.java b/lang-sandbox/src/main/java/net/openhft/lang/arena/Arena.java
new file mode 100755
index 0000000..9b76bc4
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/arena/Arena.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.arena;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.NativeBytes;
+import net.openhft.lang.io.OffHeapLock;
+
+/**
+ * Created by peter.lawrey on 20/06/14.
+ */
+public interface Arena {
+ enum Mode {
+ SINGLE_BLOCK, CONTINUOUS_BLOCKS, LINKED_BLOCKS
+ }
+
+ Mode getMode();
+
+ OffHeapLock readLock();
+
+ OffHeapLock writeLock();
+
+ // log2(allocation multiple)
+ int blockSizeBits();
+
+ // allocate a block of memory
+ int /* handle */ allocate(int hash, int sizeInBlocks);
+
+ // resize a block of memory
+ int /* new handle */ reallocate(int hash, int handle, int sizeInBlocks);
+
+ // free a block of memory
+ void free(int hash, int handle, int sizeInBlocks);
+
+ // read to data stored.
+ void copyTo(Bytes bytes, int handle);
+
+ // read from data stored
+ void copyFrom(int handle, Bytes bytes);
+
+ // map the data directly.
+ void setBytes(int handle, NativeBytes bytes) throws IllegalStateException;
+
+ // start a hash lookup
+ int firstHandleFor(int hash);
+
+ // next hash or 0
+ int nextHandle();
+
+ // metrics
+ int handlesUsed();
+
+ int handlesCapacity();
+
+ int entriesUsed();
+
+ int entriesCapacity();
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArena.java b/lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArena.java
new file mode 100755
index 0000000..cbd3223
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArena.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.arena;
+
+import net.openhft.lang.io.*;
+import net.openhft.lang.io.serialization.ObjectSerializer;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+/**
+ * Created by peter.lawrey on 22/06/14.
+ */
+public class MappedArena implements Arena {
+ static final byte[] MAGIC = "Arena001".getBytes();
+ static final int MAGIC_OFFSET = 0;
+ static final int LOCK_OFFSET = MAGIC_OFFSET + 8;
+ static final int ALLOCATE_SIZE_OFFSET = LOCK_OFFSET + 8;
+ static final int ALLOCATIONS_OFFSET = ALLOCATE_SIZE_OFFSET + 4;
+ static final int HEADER_ID_OFFSET0 = 32;
+ static final int HEADER_ID_SIZE = 4;
+ static final int HEADER_LENGTH = 64;
+
+ final MappedArenaStores stores;
+ private final Mode mode;
+ private final OffHeapLock readLock;
+ private final OffHeapLock writeLock;
+ private final DirectBytes header;
+
+ /**
+ * The lock consists of the reading/writing mode, writer count, writers waiting, reader count, readers waiting
+ */
+ public MappedArena(File file, long minSize, ObjectSerializer objectSerializer, Mode mode) throws IOException {
+ this.mode = mode;
+ stores = new MappedArenaStores(file, FileChannel.MapMode.READ_WRITE, minSize, objectSerializer);
+ header = stores.acquire(0, HEADER_LENGTH);
+ OffHeapReadWriteLock ohrwl = new OffHeapReadWriteLock(header, LOCK_OFFSET);
+ readLock = ohrwl.readLock();
+ writeLock = ohrwl.writeLock();
+ }
+
+ @Override
+ public Mode getMode() {
+ return mode;
+ }
+
+ @Override
+ public OffHeapLock readLock() {
+ return readLock;
+ }
+
+ @Override
+ public OffHeapLock writeLock() {
+ return writeLock;
+ }
+
+ @Override
+ public int blockSizeBits() {
+ return 0;
+ }
+
+ @Override
+ public int allocate(int hash, int sizeInBlocks) {
+ return 0;
+ }
+
+ @Override
+ public int reallocate(int hash, int handle, int sizeInBlocks) {
+ return 0;
+ }
+
+ @Override
+ public void free(int hash, int handle, int sizeInBlocks) {
+ }
+
+ @Override
+ public void copyTo(Bytes bytes, int handle) {
+ }
+
+ @Override
+ public void copyFrom(int handle, Bytes bytes) {
+ }
+
+ @Override
+ public void setBytes(int handle, NativeBytes bytes) throws IllegalStateException {
+ }
+
+ @Override
+ public int firstHandleFor(int hash) {
+ return 0;
+ }
+
+ @Override
+ public int nextHandle() {
+ return 0;
+ }
+
+ @Override
+ public int handlesUsed() {
+ return 0;
+ }
+
+ @Override
+ public int handlesCapacity() {
+ return 0;
+ }
+
+ @Override
+ public int entriesUsed() {
+ return 0;
+ }
+
+ @Override
+ public int entriesCapacity() {
+ return 0;
+ }
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArenaStores.java b/lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArenaStores.java
new file mode 100644
index 0000000..7918aa0
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/arena/MappedArenaStores.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.arena;
+
+import net.openhft.lang.io.BytesStore;
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.model.constraints.NotNull;
+import sun.misc.Cleaner;
+import sun.nio.ch.FileChannelImpl;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class MappedArenaStores implements Closeable {
+
+ private static final int MAP_RO = 0;
+ private static final int MAP_RW = 1;
+ private static final int MAP_PV = 2;
+
+ // retain to prevent GC.
+ private final File file;
+ private final RandomAccessFile randomAccessFile;
+ private final FileChannel fileChannel;
+ private final FileChannel.MapMode mode;
+ private final List<MappedArenaStore> storeList = new ArrayList<MappedArenaStore>();
+ private final ObjectSerializer objectSerializer;
+
+ public MappedArenaStores(File file, FileChannel.MapMode mode, long minSize, ObjectSerializer objectSerializer) throws IOException {
+ if (minSize < 0 || minSize > 128L << 40) {
+ throw new IllegalArgumentException("invalid minSize: " + minSize);
+ }
+
+ this.file = file;
+ this.objectSerializer = objectSerializer;
+
+ try {
+ randomAccessFile = new RandomAccessFile(file, accessModeFor(mode));
+ this.mode = mode;
+ this.fileChannel = randomAccessFile.getChannel();
+ storeList.add(new MappedArenaStore(0, minSize));
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+ }
+
+ public DirectBytes acquire(long offset, long size) throws IOException {
+ MappedArenaStore mas = acquireMAS(offset, size);
+ return mas.bytes(offset - mas.offset, size);
+ }
+
+ private MappedArenaStore acquireMAS(long offset, long size) throws IOException {
+ long end = offset + size;
+ for (MappedArenaStore store : storeList) {
+ if (store.offset >= offset && store.end <= end)
+ return store;
+ }
+ try {
+ MappedArenaStore store = new MappedArenaStore(offset, size);
+ storeList.add(store);
+ return store;
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ fileChannel.close();
+ for (MappedArenaStore store : storeList) {
+ store.free();
+ }
+ }
+
+ class MappedArenaStore implements BytesStore {
+ private final long address;
+ private final Cleaner cleaner;
+ private final AtomicInteger refCount = new AtomicInteger(1);
+ final long offset, size, end;
+
+ MappedArenaStore(long offset, long size) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException {
+ this.offset = offset;
+ this.size = size;
+ this.end = offset + size;
+ if (randomAccessFile.length() < end) {
+ if (mode != FileChannel.MapMode.READ_WRITE) {
+ throw new IOException("Cannot resize file to " + end + " as mode is not READ_WRITE");
+ }
+
+ randomAccessFile.setLength(end);
+ }
+ this.address = map0(fileChannel, imodeFor(mode), offset, size);
+ this.cleaner = Cleaner.create(this, new Unmapper(address, size, fileChannel));
+ }
+
+ @Override
+ public ObjectSerializer objectSerializer() {
+ return objectSerializer;
+ }
+
+ @Override
+ public long address() {
+ return address;
+ }
+
+ @Override
+ public long size() {
+ return size;
+ }
+
+ @Override
+ public void free() {
+ cleaner.clean();
+ }
+
+ @NotNull
+ public DirectBytes bytes() {
+ return new DirectBytes(this, refCount);
+ }
+
+ @NotNull
+ public DirectBytes bytes(long offset, long length) {
+ return new DirectBytes(this, refCount, offset, length);
+ }
+
+ @Override
+ public File file() {
+ return file;
+ }
+ }
+
+ private static long map0(FileChannel fileChannel, int imode, long start, long size) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Method map0 = fileChannel.getClass().getDeclaredMethod("map0", int.class, long.class, long.class);
+ map0.setAccessible(true);
+ return (Long) map0.invoke(fileChannel, imode, start, size);
+ }
+
+ private static void unmap0(long address, long size) throws IOException {
+ try {
+ Method unmap0 = FileChannelImpl.class.getDeclaredMethod("unmap0", long.class, long.class);
+ unmap0.setAccessible(true);
+ unmap0.invoke(null, address, size);
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+ }
+
+ private static IOException wrap(Throwable e) {
+ if (e instanceof InvocationTargetException)
+ e = e.getCause();
+ if (e instanceof IOException)
+ return (IOException) e;
+ return new IOException(e);
+ }
+
+ private static String accessModeFor(FileChannel.MapMode mode) {
+ return mode == FileChannel.MapMode.READ_WRITE ? "rw" : "r";
+ }
+
+ private static int imodeFor(FileChannel.MapMode mode) {
+ int imode = -1;
+ if (mode == FileChannel.MapMode.READ_ONLY)
+ imode = MAP_RO;
+ else if (mode == FileChannel.MapMode.READ_WRITE)
+ imode = MAP_RW;
+ else if (mode == FileChannel.MapMode.PRIVATE)
+ imode = MAP_PV;
+ assert (imode >= 0);
+ return imode;
+ }
+
+ static class Unmapper implements Runnable {
+ private final long size;
+ private final FileChannel channel;
+ private volatile long address;
+
+ Unmapper(long address, long size, FileChannel channel) {
+ assert (address != 0);
+ this.address = address;
+ this.size = size;
+ this.channel = channel;
+ }
+
+ public void run() {
+ if (address == 0)
+ return;
+
+ try {
+ unmap0(address, size);
+ address = 0;
+
+ if (channel.isOpen()) {
+ channel.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
+
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/data-types.txt b/lang-sandbox/src/main/java/net/openhft/lang/data-types.txt
new file mode 100755
index 0000000..c3a68cb
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/data-types.txt
@@ -0,0 +1,19 @@
+sequence_push
+sequence_pop
+group_push
+group_pop
+mapping_start {data}
+mapping_end
+named_mapping {text} {data}
+numbered_mapping {number} {data}
+comment {data}
+document_start {text-type}
+document_end
+date {date-type} x
+type {text-type}
+define_alias {text-ref} {data}
+alias {text-ref}
+
+need to recognise
+- nested sequences
+- nested mappings
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/io/OffHeapLock.java b/lang-sandbox/src/main/java/net/openhft/lang/io/OffHeapLock.java
new file mode 100755
index 0000000..c980619
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/OffHeapLock.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.io;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+* Created by peter.lawrey on 03/08/14.
+*/
+public interface OffHeapLock {
+ boolean tryLock();
+
+ void busyLock();
+
+ boolean busyLock(long time, TimeUnit timeUnit);
+
+ void unlock();
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/io/OffHeapReadWriteLock.java b/lang-sandbox/src/main/java/net/openhft/lang/io/OffHeapReadWriteLock.java
new file mode 100755
index 0000000..4324956
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/OffHeapReadWriteLock.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.io;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Created by peter.lawrey on 03/08/14.
+ */
+public class OffHeapReadWriteLock {
+ private final Bytes bytes;
+ private final long offset;
+ private final ReadLock readLock;
+ private final WriteLock writeLock;
+
+ public OffHeapReadWriteLock(Bytes bytes, long offset) {
+ this.bytes = bytes;
+ this.offset = offset;
+ this.readLock = new ReadLock();
+ this.writeLock = new WriteLock();
+ }
+
+ long getLock() {
+ return bytes.readVolatileLong(offset);
+ }
+
+ boolean trySetLock(long lock0, long lock2) {
+ return bytes.compareAndSwapLong(offset, lock0, lock2);
+ }
+
+ static final String[] RW_MODES = {"none", "read", "write"};
+
+ public ReadLock readLock() {
+ return readLock;
+ }
+
+ public WriteLock writeLock() {
+ return writeLock;
+ }
+ class ReadLock implements OffHeapLock {
+ @Override
+ public boolean tryLock() {
+ long lock = getLock();
+ int rwMode = (int) (lock >>> 56) & 0x3;
+ if (rwMode < 2) {
+ long lock2 = (lock | (1L << 56)) + (1 << 16);
+ return trySetLock(lock, lock2);
+ }
+ return false;
+ }
+
+ @Override
+ public void busyLock() {
+ busyLock(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+ }
+
+ @Override
+ public boolean busyLock(long time, TimeUnit timeUnit) {
+ if (tryLock()) return true;
+ addWaitingReader(+1);
+ try {
+ long end = System.nanoTime() + timeUnit.convert(time, TimeUnit.NANOSECONDS);
+ do {
+ if (tryLock()) return true;
+ Thread.yield();
+ } while (System.nanoTime() < end);
+ } finally {
+ addWaitingReader(-1);
+ }
+ return false;
+ }
+
+ void addWaitingReader(int add) {
+ for(;;) {
+ long lock = getLock();
+ int readerWaiting = (int) lock & 0xFFFF;
+ int readerWaiting2 = readerWaiting + add;
+ if (readerWaiting2 >= 1 << 16 || readerWaiting2 < 0)
+ // todo error state
+ return;
+ if (trySetLock(lock, (lock & ~0xFFFF) + readerWaiting2))
+ return;
+ }
+ }
+
+ @Override
+ public void unlock() {
+ for (; ; ) {
+ long lock = getLock();
+ long lock2 = lock - (1 << 16);
+ if (trySetLock(lock, nextMode(lock2)))
+ return;
+ }
+ }
+ }
+
+ public String toString() {
+ long lock = getLock();
+ int rwMode = (int) (lock >>> 56) & 0x3;
+ int writerCount = (int) (lock >>> 48) & 0xFF;
+ int writerWaiting = (int) (lock >>> 32) & 0xFFFF;
+ int readerCount = (int) (lock >>> 16) & 0xFFFF;
+ int readerWaiting = (int) lock & 0xFFFF;
+ return RW_MODES[rwMode] + " w:" + writerCount + "/" + writerWaiting + " r:" + readerCount + "/" + readerWaiting;
+ }
+
+ private long nextMode(long lock) {
+ int rwMode = (int) (lock >>> 56) & 0x3;
+// int writerCount = (int) (lock >>> 48) & 0xFF;
+ int writerWaiting = (int) (lock >>> 32) & 0xFFFF;
+ int readerCount = (int) (lock >>> 16) & 0xFFFF;
+// int readerWaiting = (int) lock & 0xFFFF;
+ if ((rwMode == 1 && readerCount == 0) || (rwMode == 2 && writerWaiting == 0))
+ return lock & (~0L >>> 8); // clear mode.
+ return lock;
+ }
+
+ class WriteLock implements OffHeapLock{
+ @Override
+ public boolean tryLock() {
+ long lock = getLock();
+ int rwMode = (int) (lock >>> 56) & 0x3;
+ int writerCount = (int) (lock >>> 48) & 0xFF;
+ if ((rwMode & 1) == 0 && ( writerCount == 0)) {
+ long lock2 = (lock | (2L << 56)) + (1L << 48);
+ return trySetLock(lock, lock2);
+ }
+ return false;
+ }
+
+ @Override
+ public void busyLock() {
+ busyLock(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+ }
+
+ @Override
+ public boolean busyLock(long time, TimeUnit timeUnit) {
+ if (tryLock()) return true;
+ addWaitingWriter(+1);
+ try {
+ long end = System.nanoTime() + timeUnit.convert(time, TimeUnit.NANOSECONDS);
+ do {
+ if (tryLock()) return true;
+ Thread.yield();
+ } while (System.nanoTime() < end);
+ } finally {
+ addWaitingWriter(-1);
+ }
+ return false;
+ }
+
+ void addWaitingWriter(int add) {
+ for(;;) {
+ long lock = getLock();
+ int writerWaiting = (int) (lock >>> 32) & 0xFFFF;
+ int writerWaiting2 = writerWaiting + add;
+ if (writerWaiting2 >= 1 << 16 || writerWaiting2 < 0)
+ // todo error state
+ return;
+ if (trySetLock(lock, (lock & ~0xFFFF00000000L) + ((long) writerWaiting2 << 32)))
+ return;
+ }
+ }
+
+ @Override
+ public void unlock() {
+ for (; ; ) {
+ long lock = getLock();
+ long lock2 = lock - (1L << 48);
+ if (trySetLock(lock, nextMode(lock2)))
+ return;
+ }
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/RawCopier.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/RawCopier.java
index eaf5760..b5e224e 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/RawCopier.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/RawCopier.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,10 +34,11 @@ import static net.openhft.lang.io.NativeBytes.UNSAFE;
* User: peter.lawrey Date: 22/09/13 Time: 16:51
*/
public class RawCopier<T> {
- final int start, end;
+ final int start;
+ final int end;
private final Class<T> tClass;
- public RawCopier(Class<T> tClass) {
+ private RawCopier(Class<T> tClass) {
this.tClass = tClass;
List<Field> fields = new ArrayList<Field>();
addAllFields(fields, tClass);
@@ -93,12 +96,14 @@ public class RawCopier<T> {
}
}
- private void addAllFields(List<Field> fields, Class tClass) {
+ private static void addAllFields(List<Field> fields, Class tClass) {
if (tClass != null && tClass != Object.class)
addAllFields(fields, tClass.getSuperclass());
- for (Field field : tClass.getDeclaredFields()) {
- if (!Modifier.isStatic(field.getModifiers()))
- fields.add(field);
+ if (tClass != null) {
+ for (Field field : tClass.getDeclaredFields()) {
+ if (!Modifier.isStatic(field.getModifiers()))
+ fields.add(field);
+ }
}
}
}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java
new file mode 100644
index 0000000..4513448
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.io.serialization.direct;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static net.openhft.lang.io.serialization.direct.FieldMetadata.*;
+
+final class DirectSerializationFilter {
+ public static List<Field> stopAtFirstIneligibleField(List<Field> fields) {
+ ArrayList<Field> eligibleFields = new ArrayList<Field>();
+ for (Field f : fields) {
+ if (checkEligible(f)) {
+ eligibleFields.add(f);
+
+ } else {
+ break;
+ }
+ }
+
+ return eligibleFields.isEmpty() ?
+ Collections.<Field>emptyList() :
+ eligibleFields;
+ }
+
+ private static boolean checkEligible(Field f) {
+ return isPrimitive(f) &&
+ !isStatic(f) &&
+ !isTransient(f);
+ }
+} \ No newline at end of file
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java
index 2fcd50c..b18e521 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
import net.openhft.lang.Jvm;
@@ -12,10 +30,10 @@ public class DirectSerializationMetadata {
private static final int OBJECT_ALIGNMENT_MASK = OBJECT_ALIGNMENT - 1;
static final long NATIVE_WORD_SIZE = Jvm.is64Bit() ? 8 : 4;
- static final long OOP_SIZE = UNSAFE.arrayIndexScale(Object[].class);
+ private static final long OOP_SIZE = UNSAFE.arrayIndexScale(Object[].class);
static final long OBJECT_HEADER_SIZE = NATIVE_WORD_SIZE + OOP_SIZE; // Object header has a native sized mark word + variable sized oop to klass meta object
- public static final SerializationMetadata EmptyObjectMetadata = new SerializationMetadata(0, 0);
+ private static final SerializationMetadata EmptyObjectMetadata = new SerializationMetadata(0, 0);
public static final class SerializationMetadata {
final long start;
@@ -58,7 +76,7 @@ public class DirectSerializationMetadata {
return new Offsets(minOffset, maxOffset);
}
- static long padToObjectAlignment(long length) {
+ private static long padToObjectAlignment(long length) {
if ((length & OBJECT_ALIGNMENT_MASK) != 0) {
long padding = OBJECT_ALIGNMENT - (length & OBJECT_ALIGNMENT_MASK);
length += padding;
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java
new file mode 100644
index 0000000..00f96c5
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.io.serialization.direct;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+final class FieldMetadata {
+ public static boolean isPrimitive(Field f) {
+ return f.getType().isPrimitive();
+ }
+
+ public static boolean isPrimitiveArray(Field f) {
+ Class<?> clazz = f.getType();
+ return clazz.isArray() && clazz.getComponentType().isPrimitive();
+ }
+
+ public static boolean isStatic(Field f) {
+ return Modifier.isStatic(f.getModifiers());
+ }
+
+ public static boolean isTransient(Field f) {
+ return Modifier.isTransient(f.getModifiers());
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java
index 28ff782..5152571 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java
index 24f8a48..2520634 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
import net.openhft.lang.io.Bytes;
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java
index bb9e35d..d0f0a03 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java
@@ -1,16 +1,36 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
-import net.openhft.lang.io.NativeBytes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
-import java.util.*;
-import java.util.logging.Logger;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
-import static java.util.logging.Level.WARNING;
import static net.openhft.lang.io.serialization.direct.DirectSerializationMetadata.SerializationMetadata;
-public final class ObjectMarshallers {
- private static final Logger Log = Logger.getLogger(ObjectMarshallers.class.getName());
+final class ObjectMarshallers {
+ private static final Logger Log = LoggerFactory.getLogger(ObjectMarshallers.class);
private static final Map<Class, ObjectMarshaller> metadata = new HashMap<Class, ObjectMarshaller>();
@@ -26,12 +46,13 @@ public final class ObjectMarshallers {
if (hasIneligibleFields(fields, eligibleFields)) {
WarnAboutIneligibleFields.apply(clazz, fields, eligibleFields);
serializationMetadata = DirectSerializationMetadata.extractMetadataForPartialCopy(eligibleFields);
+
} else {
serializationMetadata = DirectSerializationMetadata.extractMetadata(eligibleFields);
}
om = new ObjectMarshaller<T>(serializationMetadata);
- Log.log(WARNING, String.format("Class %s has metadata %s", clazz.getName(), serializationMetadata));
+ Log.warn("Class {} has metadata {}", clazz.getName(), serializationMetadata);
metadata.put(clazz, om);
}
@@ -45,11 +66,11 @@ public final class ObjectMarshallers {
private static class WarnAboutIneligibleFields {
static void apply(Class clazz, List<Field> allFields, List<Field> eligibleFields) {
List<Field> ineligibleFields = allFields.subList(eligibleFields.size(), allFields.size());
- Log.log(WARNING, String.format(
- "The following fields in Class %s will not be copied by ObjectMarshaller:\n%s",
- clazz.getName(),
- commaSeparate(ineligibleFields)
- ));
+ Log.warn(
+ "The following fields in Class {} will not be copied by ObjectMarshaller:\n{}",
+ clazz.getName(),
+ commaSeparate(ineligibleFields)
+ );
}
private static String commaSeparate(Collection<Field> fields) {
@@ -57,9 +78,10 @@ public final class ObjectMarshallers {
boolean first = true;
for (Field field : fields) {
if (first) {
- sb.append("\t");
+ sb.append('\t');
sb.append(field.getName());
first = false;
+
} else {
sb.append("\n\t");
sb.append(field.getName());
diff --git a/lang/src/main/java/net/openhft/lang/model/ClassModel.java b/lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java
index 40bc614..2777560 100644
--- a/lang/src/main/java/net/openhft/lang/model/ClassModel.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueMetaModel.java b/lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java
index 75263f5..a381ad0 100644
--- a/lang/src/main/java/net/openhft/lang/model/DataValueMetaModel.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,7 +26,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
-public class DataValueMetaModel {
+class DataValueMetaModel {
private final Set<Class> ignoredClasses = new HashSet<Class>();
private final List<MethodFilter> filters = new ArrayList<MethodFilter>();
@@ -40,11 +42,11 @@ public class DataValueMetaModel {
}
}
- public void addIgnoredClass(Class aClass) {
+ void addIgnoredClass(Class aClass) {
ignoredClasses.add(aClass);
}
- public void addMethodFilter(MethodFilter filter) {
+ void addMethodFilter(MethodFilter filter) {
int pos = insertionPoint(filter);
filters.add(pos, filter);
}
@@ -55,6 +57,4 @@ public class DataValueMetaModel {
return i;
return filters.size();
}
-
-
}
diff --git a/lang/src/main/java/net/openhft/lang/model/MethodFilter.java b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java
index 32a3908..22283ba 100644
--- a/lang/src/main/java/net/openhft/lang/model/MethodFilter.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,7 +20,7 @@ package net.openhft.lang.model;
import java.lang.reflect.Method;
-public interface MethodFilter {
+interface MethodFilter {
int matches();
String nameFor(Method method, Class<?>[] parameterTypes);
diff --git a/lang/src/main/java/net/openhft/lang/model/MethodTemplate.java b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.java
index 1a38eee..f41e502 100644
--- a/lang/src/main/java/net/openhft/lang/model/MethodTemplate.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/lang/src/main/java/net/openhft/lang/model/VanillaFilter.java b/lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java
index 3ec00bc..b825675 100644
--- a/lang/src/main/java/net/openhft/lang/model/VanillaFilter.java
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/lang-sandbox/src/test/java/net/openhft/lang/io/OffHeapReadWriteLockTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/OffHeapReadWriteLockTest.java
new file mode 100644
index 0000000..7270a09
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/OffHeapReadWriteLockTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.DirectStore;
+import net.openhft.lang.io.OffHeapReadWriteLock;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class OffHeapReadWriteLockTest {
+ @Test
+ public void readCycle() {
+ OffHeapReadWriteLock ohrwl = new OffHeapReadWriteLock(DirectStore.allocate(64).bytes(), 0);
+ assertEquals("none w:0/0 r:0/0", ohrwl.toString());
+ assertTrue(ohrwl.readLock().tryLock());
+ assertEquals("read w:0/0 r:1/0", ohrwl.toString());
+ assertTrue(ohrwl.readLock().tryLock());
+ assertEquals("read w:0/0 r:2/0", ohrwl.toString());
+ ohrwl.readLock().unlock();
+ assertEquals("read w:0/0 r:1/0", ohrwl.toString());
+ ohrwl.readLock().unlock();
+ assertEquals("none w:0/0 r:0/0", ohrwl.toString());
+ }
+
+ @Test
+ public void writeCycle() {
+ OffHeapReadWriteLock ohrwl = new OffHeapReadWriteLock(DirectStore.allocate(64).bytes(), 0);
+ assertEquals("none w:0/0 r:0/0", ohrwl.toString());
+ assertTrue(ohrwl.writeLock().tryLock());
+ assertEquals("write w:1/0 r:0/0", ohrwl.toString());
+ assertFalse(ohrwl.writeLock().tryLock());
+ ohrwl.writeLock().addWaitingWriter(1);
+ assertEquals("write w:1/1 r:0/0", ohrwl.toString());
+ ohrwl.writeLock().unlock();
+ assertEquals("write w:0/1 r:0/0", ohrwl.toString());
+ assertTrue(ohrwl.writeLock().tryLock());
+ ohrwl.writeLock().addWaitingWriter(-1);
+ assertEquals("write w:1/0 r:0/0", ohrwl.toString());
+ ohrwl.writeLock().unlock();
+ assertEquals("none w:0/0 r:0/0", ohrwl.toString());
+ }
+
+ @Test
+ public void waitingCycle() {
+ OffHeapReadWriteLock ohrwl = new OffHeapReadWriteLock(DirectStore.allocate(64).bytes(), 0);
+ assertEquals("none w:0/0 r:0/0", ohrwl.toString());
+ assertTrue(ohrwl.writeLock().tryLock());
+ assertEquals("write w:1/0 r:0/0", ohrwl.toString());
+ assertFalse(ohrwl.readLock().tryLock());
+ ohrwl.readLock().addWaitingReader(2);
+ assertEquals("write w:1/0 r:0/2", ohrwl.toString());
+ ohrwl.writeLock().unlock();
+ assertEquals("none w:0/0 r:0/2", ohrwl.toString());
+ assertTrue(ohrwl.readLock().tryLock());
+ ohrwl.readLock().addWaitingReader(-1);
+ assertEquals("read w:0/0 r:1/1", ohrwl.toString());
+ assertTrue(ohrwl.readLock().tryLock());
+ ohrwl.readLock().addWaitingReader(-1);
+ }
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java
index 1b89806..53d7abf 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java
@@ -1,11 +1,13 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -52,8 +54,8 @@ public class RawCopierTest {
@Test
public void testReadWrite() {
- DirectStore ds = new DirectStore(null, 1024);
- DirectBytes db = ds.createSlice();
+ DirectStore ds = DirectStore.allocate(1024);
+ DirectBytes db = ds.bytes();
RawCopier<A> aRawCopier = RawCopier.copies(A.class);
A a = new A();
a.i = 111;
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java
index 35b5c6e..16f6b8b 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java
@@ -1,12 +1,32 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
import org.junit.Test;
import java.lang.reflect.Field;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
import static net.openhft.lang.io.serialization.direct.DirectSerializationFilter.stopAtFirstIneligibleField;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
public class DirectSerializationFilterTest {
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java
index 1c02082..4642107 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
import org.junit.Test;
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java
index 1c5879b..609d020 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java
@@ -1,9 +1,28 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
import org.junit.Test;
import java.lang.reflect.Field;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
import static net.openhft.lang.io.serialization.direct.TestClasses.*;
import static org.junit.Assert.assertEquals;
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java
index 7226a17..7c7efc9 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java
@@ -1,6 +1,25 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
-import net.openhft.lang.io.*;
+import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
import org.junit.Test;
import java.nio.ByteBuffer;
@@ -8,7 +27,6 @@ import java.util.Collections;
import static net.openhft.lang.io.serialization.direct.TestClasses.*;
import static org.junit.Assert.*;
-import static org.junit.Assert.assertEquals;
public class ObjectMarshallerTest {
@@ -22,12 +40,12 @@ public class ObjectMarshallerTest {
marshaller.write(b, p);
p.a = 0;
- b.reset();
+ b.clear();
marshaller.read(b, p);
assertEquals(55, p.a);
- b.reset();
+ b.clear();
Primitives1 newP = new Primitives1();
marshaller.read(b, newP);
@@ -47,13 +65,13 @@ public class ObjectMarshallerTest {
p.a = 0;
p.b = 0;
- b.reset();
+ b.clear();
marshaller.read(b, p);
assertEquals(55, p.a);
assertEquals(-10, p.b);
- b.reset();
+ b.clear();
Primitives2 newP = new Primitives2();
marshaller.read(b, newP);
@@ -76,14 +94,14 @@ public class ObjectMarshallerTest {
p.a = 0;
p.b = 0;
p.c = 0;
- b.reset();
+ b.clear();
marshaller.read(b, p);
assertEquals(55, p.a);
assertEquals(-10, p.b);
assertEquals(92, p.c);
- b.reset();
+ b.clear();
Primitives3 newP = new Primitives3();
marshaller.read(b, newP);
@@ -103,12 +121,12 @@ public class ObjectMarshallerTest {
marshaller.write(b, p);
p.a = false;
- b.reset();
+ b.clear();
marshaller.read(b, p);
assertTrue(p.a);
- b.reset();
+ b.clear();
Primitives4 newP = new Primitives4();
marshaller.read(b, newP);
@@ -128,13 +146,13 @@ public class ObjectMarshallerTest {
p.a = false;
p.b = 0;
- b.reset();
+ b.clear();
marshaller.read(b, p);
assertTrue(p.a);
assertEquals(Long.MIN_VALUE, p.b);
- b.reset();
+ b.clear();
Primitives5 newP = new Primitives5();
marshaller.read(b, newP);
@@ -161,7 +179,7 @@ public class ObjectMarshallerTest {
p.c = 0;
p.d = 0;
p.e = 0;
- b.reset();
+ b.clear();
marshaller.read(b, p);
assertTrue(p.a);
@@ -170,7 +188,7 @@ public class ObjectMarshallerTest {
assertEquals(Long.MAX_VALUE, p.d);
assertEquals(Double.MAX_VALUE, p.e, 0);
- b.reset();
+ b.clear();
Primitives6 newP = new Primitives6();
marshaller.read(b, newP);
@@ -210,7 +228,7 @@ public class ObjectMarshallerTest {
m.transientShort = 0;
m.transientObject = null;
- b.reset();
+ b.clear();
marshaller.read(b, m);
assertEquals(Integer.MIN_VALUE + 1, m.intField);
@@ -223,7 +241,7 @@ public class ObjectMarshallerTest {
assertNull(m.transientObject);
assertEquals(0, m.transientShort);
- b.reset();
+ b.clear();
MixedFields newM = new MixedFields();
marshaller.read(b, newM);
@@ -239,7 +257,7 @@ public class ObjectMarshallerTest {
assertEquals(0, newM.transientShort);
}
- private ByteBufferBytes createByteStore() {
- return new ByteBufferBytes(ByteBuffer.allocate(64));
+ private Bytes createByteStore() {
+ return ByteBufferBytes.wrap(ByteBuffer.allocate(64));
}
} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java
index 7b173dd..420c2f2 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java
@@ -1,6 +1,25 @@
+/*
+ * Copyright 2014 Higher Frequency Trading
+ *
+ * http://www.higherfrequencytrading.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package net.openhft.lang.io.serialization.direct;
-import java.util.*;
+import java.util.Collections;
+import java.util.List;
class TestClasses {
@@ -39,7 +58,7 @@ class TestClasses {
}
public static class MixedFields {
- public static int staticIntField ;
+ public static int staticIntField;
public static double[] staticDoubleArray;
public static List<String> staticStringList = Collections.singletonList("S1");
diff --git a/lang-test/pom.xml b/lang-test/pom.xml
new file mode 100755
index 0000000..ef93d8d
--- /dev/null
+++ b/lang-test/pom.xml
@@ -0,0 +1,233 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2015 higherfrequencytrading.com
+ ~
+ ~ This program is free software: you can redistribute it and/or modify
+ ~ it under the terms of the GNU Lesser General Public License as published by
+ ~ the Free Software Foundation, either version 3 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>net.openhft</groupId>
+ <artifactId>java-parent-pom</artifactId>
+ <version>1.1.4</version>
+ <relativePath/>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>lang-test</artifactId>
+ <version>6.7.4-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>OpenHFT/Java-Lang/lang-test</name>
+ <description>Java Lang library for High Frequency Trading (Java 6+)</description>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>third-party-bom</artifactId>
+ <type>pom</type>
+ <version>3.4.20</version>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>lang</artifactId>
+ <version>6.7.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>compiler</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>affinity</artifactId>
+ <version>3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>collections</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.sun.java</groupId>
+ <artifactId>tools</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>lang</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>affinity</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>compiler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>collections</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-native</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-mvn</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-aether</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.url</groupId>
+ <artifactId>pax-url-reference</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>4.4.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <main.basedir>${project.basedir}</main.basedir>
+ <project.build.directory>${project.build.directory}</project.build.directory>
+
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ <!--
+ generate maven dependencies versions file that can be used later
+ to install the right bundle in test phase.
+
+ The file is:
+
+ target/classes/META-INF/maven/dependencies.properties
+ -->
+ <plugin>
+ <groupId>org.apache.servicemix.tooling</groupId>
+ <artifactId>depends-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-depends-file</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Name>OpenHFT :: ${project.artifactId}</Bundle-Name>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ <Export-Package>
+ net.openhft.langosgi,
+ net.openhft.langosgi.model
+ </Export-Package>
+ <Import-Package>
+ net.openhft.lang.io.serialization,
+ net.openhft.lang.model,
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ <executions>
+ <!--
+ This execution makes sure that the manifest is available
+ when the tests are executed
+ -->
+ <execution>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <scm>
+ <url>scm:git:https://github.com/OpenHFT/Java-Lang.git</url>
+ </scm>
+
+</project>
+
diff --git a/lang-integration/src/test/java/net/openhft/lang/io/LockingViaMMapWithThreadIdMain.java b/lang-test/src/main/java/net/openhft/lang/io/LockingViaMMapWithThreadIdMain.java
index 23877c5..315fb5e 100644..100755
--- a/lang-integration/src/test/java/net/openhft/lang/io/LockingViaMMapWithThreadIdMain.java
+++ b/lang-test/src/main/java/net/openhft/lang/io/LockingViaMMapWithThreadIdMain.java
@@ -1,27 +1,26 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import net.openhft.affinity.AffinitySupport;
+import net.openhft.affinity.Affinity;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
@@ -29,8 +28,8 @@ import java.nio.channels.FileChannel;
* User: peter
* Date: 22/12/13
* Time: 11:05
- * <p/>
- * Toggled 10,000,128 times with an average delay of 20 ns on i7-4700
+ *
+ * <p>Toggled 10,000,128 times with an average delay of 20 ns on i7-4700
* Toggled 10,000,128 times with an average delay of 14 ns on i7-3970X
*/
public class LockingViaMMapWithThreadIdMain {
@@ -51,10 +50,8 @@ public class LockingViaMMapWithThreadIdMain {
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, RECORDS * RECORD_SIZE);
// set the the Thread.getId() to match the process thread id
// this way the getId() can be used across processes..
- AffinitySupport.setThreadId();
- AffinitySupport.setAffinity(toggleTo ? 1 << 3 : 1 << 2);
- ByteBufferBytes bytes = new ByteBufferBytes(mbb.order(ByteOrder.nativeOrder()));
- bytes.setCurrentThread();
+ Affinity.setAffinity(toggleTo ? 1 << 3 : 1 << 2);
+ Bytes bytes = ByteBufferBytes.wrap(mbb);
long start = 0;
for (int i = -WARMUP / RECORDS; i < (RUNS + RECORDS - 1) / RECORDS; i++) {
@@ -69,6 +66,7 @@ public class LockingViaMMapWithThreadIdMain {
if (t == 0)
if (i >= 0) {
throw new AssertionError("Didn't toggle in time !??");
+
} else {
Thread.sleep(200);
}
diff --git a/lang-osgi/src/main/java/net/openhft/langosgi/model/JavaBeanInterface.java b/lang-test/src/main/java/net/openhft/langosgi/model/JavaBeanInterface.java
index 9675d65..3ecbd22 100644..100755
--- a/lang-osgi/src/main/java/net/openhft/langosgi/model/JavaBeanInterface.java
+++ b/lang-test/src/main/java/net/openhft/langosgi/model/JavaBeanInterface.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.langosgi.model;
diff --git a/lang-test/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java b/lang-test/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java
new file mode 100644
index 0000000..23873fb
--- /dev/null
+++ b/lang-test/src/test/java/net/openhft/lang/osgi/OSGiBundleTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.osgi;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import javax.inject.Inject;
+
+import static org.junit.Assert.*;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+/**
+ * @author lburgazzoli
+ */
+@Ignore
+@RunWith(PaxExam.class)
+public class OSGiBundleTest extends OSGiTestBase {
+ @Inject
+ BundleContext context;
+
+ @Configuration
+ public Option[] config() {
+ return options(
+ systemProperty("org.osgi.framework.storage.clean").value("true"),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
+ mavenBundleAsInProject("org.slf4j","slf4j-api"),
+ mavenBundleAsInProject("org.slf4j","slf4j-simple").noStart(),
+ mavenBundleAsInProject("net.openhft","affinity"),
+ mavenBundleAsInProject("net.openhft","compiler"),
+ mavenBundleAsInProject("net.openhft","collections"),
+ mavenBundleAsInProject("net.openhft","lang"),
+ workspaceBundle("lang-test"),
+ junitBundles(),
+ systemPackage("sun.misc"),
+ systemPackage("sun.nio.ch"),
+ systemPackage("com.sun.jna"),
+ systemPackage("com.sun.jna.ptr"),
+ systemPackage("com.sun.tools.javac.api"),
+ cleanCaches()
+ );
+ }
+
+ @Test
+ public void checkInject() {
+ assertNotNull(context);
+ }
+
+ @Test
+ public void checkBundle() {
+ Boolean bundleFound = false;
+
+ Bundle[] bundles = context.getBundles();
+ for (Bundle bundle : bundles) {
+ if (bundle != null) {
+ if (bundle.getSymbolicName().equals("net.openhft.lang")) {
+ bundleFound = true;
+ assertEquals(bundle.getState(),Bundle.ACTIVE);
+ }
+ }
+ }
+
+ assertTrue(bundleFound);
+ }
+}
diff --git a/lang-test/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java b/lang-test/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java
new file mode 100644
index 0000000..14d2eb9
--- /dev/null
+++ b/lang-test/src/test/java/net/openhft/lang/osgi/OSGiCollectionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.osgi;
+
+import net.openhft.lang.collection.HugeArray;
+import net.openhft.lang.collection.HugeCollections;
+import net.openhft.langosgi.model.JavaBeanInterface;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.osgi.framework.BundleContext;
+
+import javax.inject.Inject;
+
+import static org.junit.Assert.assertNotNull;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+/**
+ * @author lburgazzoli
+ */
+@RunWith(PaxExam.class)
+public class OSGiCollectionTest extends OSGiTestBase {
+ @Inject
+ BundleContext context;
+
+ @Configuration
+ public Option[] config() {
+ return options(
+ systemProperty("org.osgi.framework.storage.clean").value("true"),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN"),
+ mavenBundleAsInProject("org.slf4j","slf4j-api"),
+ mavenBundleAsInProject("org.slf4j","slf4j-simple").noStart(),
+ mavenBundleAsInProject("net.openhft","affinity"),
+ mavenBundleAsInProject("net.openhft","compiler"),
+ mavenBundleAsInProject("net.openhft","collections"),
+ mavenBundleAsInProject("net.openhft","lang"),
+ workspaceBundle("lang-test"),
+ junitBundles(),
+ systemPackage("sun.misc"),
+ systemPackage("sun.nio.ch"),
+ systemPackage("com.sun.jna"),
+ systemPackage("com.sun.jna.ptr"),
+ systemPackage("com.sun.tools.javac.api"),
+ cleanCaches()
+ );
+ }
+
+ @Test
+ @Ignore
+ public void checkHugeArray() {
+ int length = 10 * 1000 * 1000;
+ HugeArray<JavaBeanInterface> array = HugeCollections.newArray(JavaBeanInterface.class, length);
+
+ assertNotNull(array);
+ }
+}
diff --git a/lang-test/src/test/java/net/openhft/lang/osgi/OSGiTestBase.java b/lang-test/src/test/java/net/openhft/lang/osgi/OSGiTestBase.java
new file mode 100644
index 0000000..79bd259
--- /dev/null
+++ b/lang-test/src/test/java/net/openhft/lang/osgi/OSGiTestBase.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.osgi;
+
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.MavenArtifactProvisionOption;
+
+import java.io.File;
+
+/**
+ *
+ */
+public class OSGiTestBase {
+ /**
+ *
+ * @param projectName
+ * @return
+ */
+ public static Option workspaceBundle(String projectName) {
+ String baseDir = System.getProperty("main.basedir");
+ String bundleDir = null;
+
+ bundleDir = String.format("%s/%s/target/classes",baseDir,projectName);
+ if(new File(bundleDir).exists()) {
+ return CoreOptions.bundle(String.format("reference:file:%s", bundleDir));
+ }
+
+ bundleDir = String.format("%s/../%s/target/classes",baseDir,projectName);
+ if(new File(bundleDir).exists()) {
+ return CoreOptions.bundle(String.format("reference:file:%s", bundleDir));
+ }
+
+ return null;
+ }
+
+ public static MavenArtifactProvisionOption mavenBundleAsInProject(final String groupId,final String artifactId) {
+ return CoreOptions.mavenBundle().groupId(groupId).artifactId(artifactId).versionAsInProject();
+ }
+}
+
diff --git a/lang/pom.xml b/lang/pom.xml
index 209a61a..b3210ab 100755
--- a/lang/pom.xml
+++ b/lang/pom.xml
@@ -1,146 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- ~ Copyright 2013 Peter Lawrey
+ ~ Copyright (C) 2015 higherfrequencytrading.com
~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
+ ~ This program is free software: you can redistribute it and/or modify
+ ~ it under the terms of the GNU Lesser General Public License as published by
+ ~ the Free Software Foundation, either version 3 of the License.
~
- ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU Lesser General Public License for more details.
~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program. If not, see <http://www.gnu.org/licenses />.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>net.openhft</groupId>
+ <artifactId>java-parent-pom</artifactId>
+ <version>1.1.10</version>
+ <relativePath />
+ </parent>
- <groupId>net.openhft</groupId>
+ <modelVersion>4.0.0</modelVersion>
<artifactId>lang</artifactId>
- <version>6.1.4-SNAPSHOT</version>
+ <version>6.7.6</version>
<packaging>bundle</packaging>
-
<name>OpenHFT/Java-Lang/lang</name>
<description>Java Lang library for High Frequency Trading (Java 6+)</description>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <felix.version>3.2.2</felix.version>
- <pax.exam.version>3.3.0</pax.exam.version>
- <pax.url.version>1.6.0</pax.url.version>
- </properties>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>third-party-bom</artifactId>
+ <type>pom</type>
+ <version>3.4.20</version>
+ <scope>import</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>chronicle-bom</artifactId>
+ <version>1.10.35</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+
+ </dependencies>
+ </dependencyManagement>
+
<dependencies>
+
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ </dependency>
+
<dependency>
- <groupId>org.kohsuke.jetbrains</groupId>
- <artifactId>annotations</artifactId>
- <version>9.0</version>
- <scope>compile</scope>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.java</groupId>
+ <artifactId>tools</artifactId>
</dependency>
<dependency>
<groupId>net.openhft</groupId>
<artifactId>compiler</artifactId>
- <version>2.1</version>
- <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.xerial.snappy</groupId>
+ <artifactId>snappy-java</artifactId>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
- <version>3.1</version>
<scope>test</scope>
</dependency>
+
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
- <version>4.11</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
+
<plugins>
+
<plugin>
<groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.1</version>
- <configuration>
- <source>1.6</source>
- <target>1.6</target>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-source-plugin</artifactId>
- <version>2.2</version>
- <executions>
- <execution>
- <id>attach-sources</id>
- <phase>verify</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>2.9</version>
- <executions>
- <execution>
- <id>attach-javadocs</id>
- <phase>verify</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
+ <artifactId>maven-scm-publish-plugin</artifactId>
<configuration>
- <show>public</show>
- <nohelp>true</nohelp>
+ <checkoutDirectory>${project.build.directory}/scmpublish/javadoc
+ </checkoutDirectory>
+ <checkinComment>Publishing javadoc for ${project.artifactId}:${project.version}
+ </checkinComment>
+ <content>${project.reporting.outputDirectory}</content>
+ <skipDeletedFiles>true</skipDeletedFiles>
+ <pubScmUrl>scm:git:git@github.com:OpenHFT/Java-Lang</pubScmUrl>
+ <scmBranch>gh-pages</scmBranch>
</configuration>
</plugin>
- <!-- plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-gpg-plugin</artifactId>
- <version>1.4</version>
- <configuration>
- <passphrase>${gpg.passphrase}</passphrase>
- </configuration>
- <executions>
- <execution>
- <id>sign-artifacts</id>
- <phase>verify</phase>
- <goals>
- <goal>sign</goal>
- </goals>
- </execution>
- </executions>
- </plugin -->
-
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
- <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
- <Bundle-Name>${project.artifactId}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}
+ </Bundle-SymbolicName>
+ <Bundle-Name>OpenHFT :: ${project.artifactId}</Bundle-Name>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ <Export-Package>
+ net.openhft.lang.*
+ </Export-Package>
</instructions>
</configuration>
<executions>
- <!--
- This execution makes sure that the manifest is available
- when the tests are executed
+ <!--
+ This execution makes sure that the manifest is available
+ when the tests are executed
-->
<execution>
<goals>
@@ -149,27 +144,69 @@
</execution>
</executions>
</plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
</plugins>
</build>
- <url>http://www.openhft.net</url>
- <licenses>
- <license>
- <name>The Apache Software License, Version 2.0</name>
- <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
- <distribution>repo</distribution>
- <comments>A business-friendly OSS license</comments>
- </license>
- </licenses>
-
- <developers>
- <developer>
- <name>Peter Lawrey</name>
- <email>peter.lawrey@higherfrequencytrading.com</email>
- </developer>
- </developers>
+ <profiles>
+ <profile>
+ <id>local</id>
+ <properties>
+ <localurl>http://localhost:8080</localurl>
+ </properties>
+ </profile>
+
+ <profile>
+ <!-- to use this run with the profile -->
+ <id>pitest</id>
+ <build>
+ <plugins>
+ <plugin>
+ <!-- For debugging in IntelliJ IDEA -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <project.build.directory>${project.build.directory}
+ </project.build.directory>
+ </systemPropertyVariables>
+
+ <forkMode>never</forkMode>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.pitest</groupId>
+ <artifactId>pitest-maven</artifactId>
+ <version>0.33</version>
+ <configuration>
+ <targetClasses>
+ <param>net.openhft.lang.collection.*</param>
+ </targetClasses>
+ <targetTests>
+ <param>net.openhft.lang.collection.*</param>
+ </targetTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
<scm>
- <url>scm:git:https://github.com/OpenHFT/Java-Lang.git</url>
+ <url>scm:git:git@github.com:OpenHFT/Java-Lang.git</url>
+ <connection>scm:git:git@github.com:OpenHFT/Java-Lang.git</connection>
+ <developerConnection>scm:git:git@github.com:OpenHFT/Java-Lang.git</developerConnection>
+ <tag>lang-6.7.6</tag>
</scm>
-</project> \ No newline at end of file
+
+</project>
diff --git a/lang/src/main/java/net/openhft/lang/Compare.java b/lang/src/main/java/net/openhft/lang/Compare.java
index 8d61054..c3c97ae 100644
--- a/lang/src/main/java/net/openhft/lang/Compare.java
+++ b/lang/src/main/java/net/openhft/lang/Compare.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang;
@@ -27,7 +27,7 @@ public abstract class Compare {
return a == b;
}
- public static long calcLongHashCode(boolean a) {
+ private static long calcLongHashCode(boolean a) {
return a ? 1 : 0;
}
@@ -43,7 +43,7 @@ public abstract class Compare {
return a == b;
}
- public static long calcLongHashCode(byte a) {
+ private static long calcLongHashCode(byte a) {
return a;
}
@@ -59,7 +59,7 @@ public abstract class Compare {
return a == b;
}
- public static long calcLongHashCode(char a) {
+ private static long calcLongHashCode(char a) {
return a;
}
@@ -75,7 +75,7 @@ public abstract class Compare {
return a == b;
}
- public static long calcLongHashCode(short a) {
+ private static long calcLongHashCode(short a) {
return a;
}
@@ -91,7 +91,7 @@ public abstract class Compare {
return a == b;
}
- public static long calcLongHashCode(int a) {
+ private static long calcLongHashCode(int a) {
return a;
}
@@ -107,7 +107,7 @@ public abstract class Compare {
return a == b;
}
- public static long calcLongHashCode(long a) {
+ private static long calcLongHashCode(long a) {
return a;
}
@@ -119,11 +119,11 @@ public abstract class Compare {
return a == null ? NULL_HASHCODE : calcLongHashCode(a.longValue());
}
- public static boolean isEqual(float a, float b) {
+ private static boolean isEqual(float a, float b) {
return Float.floatToRawIntBits(a) == Float.floatToRawIntBits(b);
}
- public static long calcLongHashCode(float a) {
+ private static long calcLongHashCode(float a) {
return Float.floatToRawIntBits(a);
}
@@ -135,11 +135,11 @@ public abstract class Compare {
return a == null ? NULL_HASHCODE : calcLongHashCode(a.floatValue());
}
- public static boolean isEqual(double a, double b) {
+ private static boolean isEqual(double a, double b) {
return Double.doubleToRawLongBits(a) == Double.doubleToRawLongBits(b);
}
- public static long calcLongHashCode(double a) {
+ private static long calcLongHashCode(double a) {
return Double.doubleToRawLongBits(a);
}
@@ -155,7 +155,7 @@ public abstract class Compare {
return a == null ? b == null : b != null && a.equals(b);
}
- public static long calcLongHashCode(LongHashable t) {
+ private static long calcLongHashCode(LongHashable t) {
return t.longHashCode();
}
@@ -167,6 +167,8 @@ public abstract class Compare {
}
public static long calcLongHashCode(CharSequence s) {
+ if (s == null)
+ return NULL_HASHCODE;
long hash = 0;
for (int i = 0, len = s.length(); i < len; i++) {
hash = 57 * hash + s.charAt(i);
diff --git a/lang/src/main/java/net/openhft/lang/InterruptedRuntimeException.java b/lang/src/main/java/net/openhft/lang/InterruptedRuntimeException.java
new file mode 100644
index 0000000..3a8dc05
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/InterruptedRuntimeException.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang;
+
+/**
+ * Like InterruptedException except unchecked
+ */
+public class InterruptedRuntimeException extends IllegalStateException {
+}
diff --git a/lang/src/main/java/net/openhft/lang/Jvm.java b/lang/src/main/java/net/openhft/lang/Jvm.java
index 99e07ab..4169ac0 100755
--- a/lang/src/main/java/net/openhft/lang/Jvm.java
+++ b/lang/src/main/java/net/openhft/lang/Jvm.java
@@ -1,25 +1,31 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang;
+import net.openhft.lang.io.NativeBytes;
+
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
+import java.lang.reflect.Field;
import java.util.Random;
+import java.util.Scanner;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -27,7 +33,9 @@ import java.util.logging.Logger;
*/
public enum Jvm {
;
- public static final String TMP = System.getProperty("java.io.tmpdir");
+
+ public static String TMP = System.getProperty("java.io.tmpdir");
+
private static final boolean IS64BIT = is64Bit0();
public static boolean is64Bit() {
@@ -58,17 +66,22 @@ public enum Jvm {
String pid = null;
final File self = new File("/proc/self");
try {
- if (self.exists())
+ if (self.exists()) {
pid = self.getCanonicalFile().getName();
+ }
} catch (IOException ignored) {
- // ignored
}
- if (pid == null)
- pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
+
+ if (pid == null) {
+ pid = ManagementFactory.getRuntimeMXBean().getName().split("@", 0)[0];
+ }
+
if (pid == null) {
int rpid = new Random().nextInt(1 << 16);
- Logger.getLogger(Jvm.class.getName()).warning("Unable to determine PID, picked a random number=" + rpid);
+ LoggerHolder.LOGGER.log(Level.WARNING, "Unable to determine PID, picked a random number=" + rpid);
+
return rpid;
+
} else {
return Integer.parseInt(pid);
}
@@ -84,7 +97,144 @@ public enum Jvm {
}
public static long getUniqueTid(Thread thread) {
- return (long) getProcessId() << 32 | (thread.getId() & 0xFFFFFFFFL);
+ // Assume 48 bit for 16 to 24-bit process id and 16 million threads from the start.
+ return ((long) getProcessId() << 24) | thread.getId();
+ }
+
+ private static final String OS = System.getProperty("os.name").toLowerCase();
+
+ public static boolean isWindows() {
+ return OS.startsWith("win");
+ }
+
+ public static boolean isMacOSX() {
+ return OS.contains("mac");
+ }
+
+ public static boolean isLinux() {
+ return OS.startsWith("linux");
+ }
+
+ public static boolean isUnix() {
+ return OS.contains("nix") ||
+ OS.contains("nux") ||
+ OS.contains("aix") ||
+ OS.contains("bsd") ||
+ OS.contains("sun") ||
+ OS.contains("hpux");
+ }
+
+ public static boolean isSolaris() {
+ return OS.startsWith("sun");
+ }
+
+ public static final int PID_BITS = Maths.intLog2(getPidMax());
+
+ public static long getPidMax() {
+ if (isLinux()) {
+ File file = new File("/proc/sys/kernel/pid_max");
+ if (file.canRead()) {
+ try {
+ return Maths.nextPower2(new Scanner(file).nextLong(), 1);
+ } catch (FileNotFoundException e) {
+ LoggerHolder.LOGGER.log(Level.WARNING, "", e);
+ }
+ }
+ } else if (isMacOSX()) {
+ return 1L << 24;
+ }
+
+ // the default.
+ return 1L << 16;
+ }
+
+ private static String convertStreamToString(java.io.InputStream is) {
+ java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+ public static long freePhysicalMemoryOnWindowsInBytes() throws IOException {
+ if (!isWindows()) {
+ throw new IllegalStateException("Method freePhysicalMemoryOnWindowsInBytes() should " +
+ "be called only on windows. Use Jvm.isWindows() to check the OS.");
+ }
+
+ Process pr = Runtime.getRuntime().exec("wmic OS get FreePhysicalMemory /Value");
+ try {
+ int result = pr.waitFor();
+ String output = convertStreamToString(pr.getInputStream());
+ if (result != 0) {
+ String errorOutput = convertStreamToString(pr.getErrorStream());
+ throw new IOException("Couldn't get free physical memory on windows. " +
+ "Command \"wmic OS get FreePhysicalMemory /Value\" exited with " +
+ result + " code, output: \"" + output + "\", error output: \"" +
+ errorOutput + "\"");
+ }
+ String[] parts = output.trim().split("=");
+ if (parts.length != 2) {
+ throw new IOException("Couldn't get free physical memory on windows. " +
+ "Command \"wmic OS get FreePhysicalMemory /Value\" output has unexpected " +
+ "format: \"" + output + "\"");
+ }
+ try {
+ return MemoryUnit.KILOBYTES.toBytes(Long.parseLong(parts[1]));
+ } catch (NumberFormatException e) {
+ throw new IOException("Couldn't get free physical memory on windows. " +
+ "Command \"wmic OS get FreePhysicalMemory /Value\" output has unexpected " +
+ "format: \"" + output + "\"", e);
+ }
+ } catch (InterruptedException e) {
+ throw new IOException(e);
+ }
+ }
+
+ public static void checkInterrupted() {
+ if (Thread.currentThread().isInterrupted()) throw new InterruptedRuntimeException();
+ }
+
+ /**
+ * Utility method to support throwing checked exceptions out of the streams API
+ *
+ * @param t the exception to rethrow
+ * @return the exception
+ */
+ public static RuntimeException rethrow(Throwable t) {
+ NativeBytes.UNSAFE.throwException(t);
+ throw new AssertionError();
+ }
+
+ static class LoggerHolder {
+ public static final Logger LOGGER = Logger.getLogger(Jvm.class.getName());
+ }
+
+ public static void trimStackTrace(StringBuilder sb, StackTraceElement... stes) {
+ int first = trimFirst(stes);
+ int last = trimLast(first, stes);
+ for (int i = first; i <= last; i++)
+ sb.append("\n\tat ").append(stes[i]);
+ }
+
+ private static int trimFirst(StackTraceElement[] stes) {
+ int first = 0;
+ for (; first < stes.length; first++)
+ if (!isInternal(stes[first].getClassName()))
+ break;
+ if (first > 0) first--;
+ if (first > 0) first--;
+ return first;
+ }
+
+ private static int trimLast(int first, StackTraceElement[] stes) {
+ int last = stes.length - 1;
+ for (; first < last; last--)
+ if (!isInternal(stes[last].getClassName()))
+ break;
+ if (last < stes.length - 1) last++;
+ return last;
+ }
+
+ public static boolean isInternal(String className) {
+ return className.startsWith("jdk.") || className.startsWith("sun.") || className.startsWith("java.");
}
}
diff --git a/lang/src/main/java/net/openhft/lang/LongHashable.java b/lang/src/main/java/net/openhft/lang/LongHashable.java
index 508ac7e..92a6d55 100644
--- a/lang/src/main/java/net/openhft/lang/LongHashable.java
+++ b/lang/src/main/java/net/openhft/lang/LongHashable.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang;
diff --git a/lang/src/main/java/net/openhft/lang/Maths.java b/lang/src/main/java/net/openhft/lang/Maths.java
index f293677..a89d790 100755
--- a/lang/src/main/java/net/openhft/lang/Maths.java
+++ b/lang/src/main/java/net/openhft/lang/Maths.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang;
@@ -23,7 +23,7 @@ public class Maths {
/**
* Numbers larger than this are whole numbers due to representation error.
*/
- public static final double WHOLE_NUMBER = 1L << 53;
+ private static final double WHOLE_NUMBER = 1L << 53;
private static final long[] TENS = new long[19];
static {
@@ -38,6 +38,7 @@ public class Maths {
* precision of double.
*
* @param d value to round
+ * @return rounded value
*/
public static double round2(double d) {
final double factor = 1e2;
@@ -51,6 +52,7 @@ public class Maths {
* precision of double.
*
* @param d value to round
+ * @return rounded value
*/
public static double round4(double d) {
final double factor = 1e4;
@@ -64,6 +66,7 @@ public class Maths {
* precision of double.
*
* @param d value to round
+ * @return rounded value
*/
public static double round6(double d) {
final double factor = 1e6;
@@ -77,6 +80,7 @@ public class Maths {
* precision of double.
*
* @param d value to round
+ * @return rounded value
*/
public static double round8(double d) {
final double factor = 1e8;
@@ -90,8 +94,11 @@ public class Maths {
}
public static int nextPower2(int n, int min) {
+ if (!isPowerOf2(min))
+ throw new IllegalArgumentException();
if (n < min) return min;
- if ((n & (n - 1)) == 0) return n;
+ if (isPowerOf2(n))
+ return n;
int i = min;
while (i < n) {
i *= 2;
@@ -101,8 +108,11 @@ public class Maths {
}
public static long nextPower2(long n, long min) {
+ if (!isPowerOf2(min))
+ throw new IllegalArgumentException();
if (n < min) return min;
- if ((n & (n - 1)) == 0) return n;
+ if (isPowerOf2(n))
+ return n;
long i = min;
while (i < n) {
i *= 2;
@@ -111,17 +121,24 @@ public class Maths {
return i;
}
+ public static boolean isPowerOf2(int n) {
+ return (n & (n - 1)) == 0;
+ }
+
+ public static boolean isPowerOf2(long n) {
+ return (n & (n - 1L)) == 0L;
+ }
public static int hash(int n) {
- n ^= (n >> 21) ^ (n >> 11);
- n ^= (n >> 7) ^ (n >> 4);
+ n ^= (n >>> 21) - (n >>> 11);
+ n ^= (n >>> 7) + (n >>> 4);
return n;
}
- public static int hash(long n) {
- n ^= (n >> 43) ^ (n >> 21);
- n ^= (n >> 15) ^ (n >> 7);
- return (int) n;
+ public static long hash(long n) {
+ n ^= (n >>> 41) - (n >>> 21);
+ n ^= (n >>> 15) + (n >>> 7);
+ return n;
}
public static long hash(CharSequence cs) {
@@ -131,7 +148,6 @@ public class Maths {
return hash;
}
-
/**
* Compares two {@code long} values numerically. The value returned is identical to what would be returned by:
* <pre>
@@ -141,7 +157,7 @@ public class Maths {
* @param x the first {@code long} to compare
* @param y the second {@code long} to compare
* @return the value {@code 0} if {@code x == y}; a value less than {@code 0} if {@code x < y}; and a value greater
- * than {@code 0} if {@code x > y}
+ * than {@code 0} if {@code x > y}
*/
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
@@ -151,4 +167,16 @@ public class Maths {
long l = Double.doubleToRawLongBits(num);
return (int) ((l >> 52) - 1023);
}
+
+ public static int toInt(long l, String error) {
+ if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE)
+ throw new IllegalStateException(String.format(error, l));
+ return (int) l;
+ }
+
+ public static long agitate(long l) {
+ l ^= l >> 23;
+ l += Long.rotateRight(l, 18);
+ return l;
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/MemoryUnit.java b/lang/src/main/java/net/openhft/lang/MemoryUnit.java
new file mode 100644
index 0000000..51830ae
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/MemoryUnit.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Based on java.util.concurrent.TimeUnit, which is
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package net.openhft.lang;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@code MemoryUnit} represents memory amounts at a given unit of
+ * granularity and provides utility methods to convert across units. A
+ * {@code MemoryUnit} does not maintain memory information, but only
+ * helps organize and use memory amounts representations that may be maintained
+ * separately across various contexts.
+ *
+ * <p>Note than in this class kilo-, mega- and giga- prefixes means 2^10 = 1024 multiplexing,
+ * that is more common in low-level programming, CPU and operation system contexts,
+ * not 1000 as defined by International System of Units (SI).
+ *
+ * <p>A {@code MemoryUnit} is mainly used to inform memory amount-based methods
+ * how a given memory amount parameter should be interpreted.
+ *
+ * <p>API of {@code MemoryUnit} is copied from {@link TimeUnit} enum.
+ */
+public enum MemoryUnit {
+
+ /**
+ * Memory unit representing one bit.
+ */
+ BITS {
+ @Override public long toBits(long a) { return a; }
+ @Override public long toBytes(long a) { return a/(C1/C0); }
+ @Override public long toLongs(long a) { return a/(C2/C0); }
+ @Override public long toCacheLines(long a) { return a/(C3/C0); }
+ @Override public long toKilobytes(long a) { return a/(C4/C0); }
+ @Override public long toPages(long a) { return a/(C5/C0); }
+ @Override public long toMegabytes(long a) { return a/(C6/C0); }
+ @Override public long toGigabytes(long a) { return a/(C7/C0); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toBits(a); }
+
+ @Override long alignToBytes(long a) { return y(a, C1/C0); }
+ @Override long alignToLongs(long a) { return y(a, C2/C0); }
+ @Override long alignToCacheLines(long a) { return y(a, C3/C0); }
+ @Override long alignToKilobytes(long a) { return y(a, C4/C0); }
+ @Override long alignToPages(long a) { return y(a, C5/C0); }
+ @Override long alignToMegabytes(long a) { return y(a, C6/C0); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C0); }
+ @Override public long align(long a, MemoryUnit u) { return ise(u, this); }
+ },
+
+ /**
+ * Memory unit representing one byte, i. e. 8 bits.
+ */
+ BYTES {
+ @Override public long toBits(long a) { return x(a, C1/C0, MAX/(C1/C0)); }
+ @Override public long toBytes(long a) { return a; }
+ @Override public long toLongs(long a) { return a/(C2/C1); }
+ @Override public long toCacheLines(long a) { return a/(C3/C1); }
+ @Override public long toKilobytes(long a) { return a/(C4/C1); }
+ @Override public long toPages(long a) { return a/(C5/C1); }
+ @Override public long toMegabytes(long a) { return a/(C6/C1); }
+ @Override public long toGigabytes(long a) { return a/(C7/C1); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toBytes(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return y(a, C2/C1); }
+ @Override long alignToCacheLines(long a) { return y(a, C3/C1); }
+ @Override long alignToKilobytes(long a) { return y(a, C4/C1); }
+ @Override long alignToPages(long a) { return y(a, C5/C1); }
+ @Override long alignToMegabytes(long a) { return y(a, C6/C1); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C1); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToBytes(a); }
+ },
+
+ /**
+ * Memory unit representing 8 bytes, i. e. 64-bit word,
+ * the width of Java's primitive {@code long} type.
+ */
+ LONGS {
+ @Override public long toBits(long a) { return x(a, C2/C0, MAX/(C2/C0)); }
+ @Override public long toBytes(long a) { return x(a, C2/C1, MAX/(C2/C1)); }
+ @Override public long toLongs(long a) { return a; }
+ @Override public long toCacheLines(long a) { return a/(C3/C2); }
+ @Override public long toKilobytes(long a) { return a/(C4/C2); }
+ @Override public long toPages(long a) { return a/(C5/C2); }
+ @Override public long toMegabytes(long a) { return a/(C6/C2); }
+ @Override public long toGigabytes(long a) { return a/(C7/C2); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toLongs(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return ise(this, LONGS); }
+ @Override long alignToCacheLines(long a) { return y(a, C3/C2); }
+ @Override long alignToKilobytes(long a) { return y(a, C4/C2); }
+ @Override long alignToPages(long a) { return y(a, C5/C2); }
+ @Override long alignToMegabytes(long a) { return y(a, C6/C2); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C2); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToLongs(a); }
+ },
+
+ /**
+ * Memory unit representing 64 bytes, i. e. the most common CPU cache line size.
+ */
+ CACHE_LINES {
+ @Override public long toBits(long a) { return x(a, C3/C0, MAX/(C3/C0)); }
+ @Override public long toBytes(long a) { return x(a, C3/C1, MAX/(C3/C1)); }
+ @Override public long toLongs(long a) { return x(a, C3/C2, MAX/(C3/C2)); }
+ @Override public long toCacheLines(long a) { return a; }
+ @Override public long toKilobytes(long a) { return a/(C4/C3); }
+ @Override public long toPages(long a) { return a/(C5/C3); }
+ @Override public long toMegabytes(long a) { return a/(C6/C3); }
+ @Override public long toGigabytes(long a) { return a/(C7/C3); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toCacheLines(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return ise(this, LONGS); }
+ @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); }
+ @Override long alignToKilobytes(long a) { return y(a, C4/C3); }
+ @Override long alignToPages(long a) { return y(a, C5/C3); }
+ @Override long alignToMegabytes(long a) { return y(a, C6/C3); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C3); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToCacheLines(a); }
+ },
+
+ /**
+ * Memory unit representing 1024 bytes.
+ */
+ KILOBYTES {
+ @Override public long toBits(long a) { return x(a, C4/C0, MAX/(C4/C0)); }
+ @Override public long toBytes(long a) { return x(a, C4/C1, MAX/(C4/C1)); }
+ @Override public long toLongs(long a) { return x(a, C4/C2, MAX/(C4/C2)); }
+ @Override public long toCacheLines(long a) { return x(a, C4/C3, MAX/(C4/C3)); }
+ @Override public long toKilobytes(long a) { return a; }
+ @Override public long toPages(long a) { return a/(C5/C4); }
+ @Override public long toMegabytes(long a) { return a/(C6/C4); }
+ @Override public long toGigabytes(long a) { return a/(C7/C4); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toKilobytes(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return ise(this, LONGS); }
+ @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); }
+ @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); }
+ @Override long alignToPages(long a) { return y(a, C5/C4); }
+ @Override long alignToMegabytes(long a) { return y(a, C6/C4); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C4); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToKilobytes(a); }
+ },
+
+ /**
+ * Memory unit representing 4096 bytes, i. e. the most common native memory page size.
+ */
+ PAGES {
+ @Override public long toBits(long a) { return x(a, C5/C0, MAX/(C5/C0)); }
+ @Override public long toBytes(long a) { return x(a, C5/C1, MAX/(C5/C1)); }
+ @Override public long toLongs(long a) { return x(a, C5/C2, MAX/(C5/C2)); }
+ @Override public long toCacheLines(long a) { return x(a, C5/C3, MAX/(C5/C3)); }
+ @Override public long toKilobytes(long a) { return x(a, C5/C4, MAX/(C5/C4)); }
+ @Override public long toPages(long a) { return a; }
+ @Override public long toMegabytes(long a) { return a/(C6/C5); }
+ @Override public long toGigabytes(long a) { return a/(C7/C5); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toPages(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return ise(this, LONGS); }
+ @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); }
+ @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); }
+ @Override long alignToPages(long a) { return ise(this, PAGES); }
+ @Override long alignToMegabytes(long a) { return y(a, C6/C5); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C5); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToPages(a); }
+ },
+
+ /**
+ * Memory unit representing 1024 kilobytes.
+ */
+ MEGABYTES {
+ @Override public long toBits(long a) { return x(a, C6/C0, MAX/(C6/C0)); }
+ @Override public long toBytes(long a) { return x(a, C6/C1, MAX/(C6/C1)); }
+ @Override public long toLongs(long a) { return x(a, C6/C2, MAX/(C6/C2)); }
+ @Override public long toCacheLines(long a) { return x(a, C6/C3, MAX/(C6/C3)); }
+ @Override public long toKilobytes(long a) { return x(a, C6/C4, MAX/(C6/C4)); }
+ @Override public long toPages(long a) { return x(a, C6/C5, MAX/(C6/C5)); }
+ @Override public long toMegabytes(long a) { return a; }
+ @Override public long toGigabytes(long a) { return a/(C7/C6); }
+ @Override public long convert(long a, MemoryUnit u) { return u.toMegabytes(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return ise(this, LONGS); }
+ @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); }
+ @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); }
+ @Override long alignToPages(long a) { return ise(this, PAGES); }
+ @Override long alignToMegabytes(long a) { return ise(this, MEGABYTES); }
+ @Override long alignToGigabytes(long a) { return y(a, C7/C6); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToMegabytes(a); }
+ },
+
+ /**
+ * Memory unit representing 1024 megabytes.
+ */
+ GIGABYTES {
+ @Override public long toBits(long a) { return x(a, C7/C0, MAX/(C7/C0)); }
+ @Override public long toBytes(long a) { return x(a, C7/C1, MAX/(C7/C1)); }
+ @Override public long toLongs(long a) { return x(a, C7/C2, MAX/(C7/C2)); }
+ @Override public long toCacheLines(long a) { return x(a, C7/C3, MAX/(C7/C3)); }
+ @Override public long toKilobytes(long a) { return x(a, C7/C4, MAX/(C7/C4)); }
+ @Override public long toPages(long a) { return x(a, C7/C5, MAX/(C7/C5)); }
+ @Override public long toMegabytes(long a) { return x(a, C7/C6, MAX/(C7/C6)); }
+ @Override public long toGigabytes(long a) { return a; }
+ @Override public long convert(long a, MemoryUnit u) { return u.toGigabytes(a); }
+
+ @Override long alignToBytes(long a) { return ise(this, BYTES); }
+ @Override long alignToLongs(long a) { return ise(this, LONGS); }
+ @Override long alignToCacheLines(long a) { return ise(this, CACHE_LINES); }
+ @Override long alignToKilobytes(long a) { return ise(this, KILOBYTES); }
+ @Override long alignToPages(long a) { return ise(this, PAGES); }
+ @Override long alignToMegabytes(long a) { return ise(this, MEGABYTES); }
+ @Override long alignToGigabytes(long a) { return ise(this, GIGABYTES); }
+ @Override public long align(long a, MemoryUnit u) { return u.alignToGigabytes(a); }
+ };
+
+ // Handy constants for conversion methods
+ static final long C0 = 1L;
+ static final long C1 = C0 * 8L;
+ static final long C2 = C1 * 8L;
+ static final long C3 = C2 * 8L;
+ static final long C4 = C3 * 16L;
+ static final long C5 = C4 * 4L;
+ static final long C6 = C5 * 256L;
+ static final long C7 = C6 * 1024L;
+
+ static final long MAX = Long.MAX_VALUE;
+
+ /**
+ * Scale d by m, checking for overflow.
+ * This has a short name to make above code more readable.
+ */
+ static long x(long a, long m, long over) {
+ if (a > over) return Long.MAX_VALUE;
+ if (a < -over) return Long.MIN_VALUE;
+ return a * m;
+ }
+
+ static long y(long amount, long align) {
+ if (amount == 0L)
+ return 0L;
+ long mask = ~(align - 1L);
+ if (amount > 0L) {
+ long filled = amount + align - 1L;
+ if (filled > 0L) {
+ return filled & mask;
+
+ } else {
+ long maxAlignedLong = Long.MAX_VALUE & mask;
+ if (amount <= maxAlignedLong)
+ return maxAlignedLong;
+ }
+ } else {
+ // amount is negative
+ long filled = amount - align + 1L;
+ if (filled < 0L) {
+ return filled & mask;
+
+ } else {
+ long minAlignedLong = Long.MIN_VALUE & mask;
+ if (amount >= minAlignedLong)
+ return minAlignedLong;
+ }
+ }
+ throw new IllegalArgumentException("Couldn't align " + amount + " by " + align);
+ }
+
+ static long ise(MemoryUnit unitToAlign, MemoryUnit alignmentUnit) {
+ throw new IllegalStateException("Couldn't align " + unitToAlign + " by " + alignmentUnit);
+ }
+
+ // To maintain full signature compatibility with 1.5, and to improve the
+ // clarity of the generated javadoc (see 6287639: Abstract methods in
+ // enum classes should not be listed as abstract), method convert
+ // etc. are not declared abstract but otherwise act as abstract methods.
+
+ /**
+ * Converts the given memory amount in the given unit to this unit.
+ * Conversions from finer to coarser granularities truncate, so
+ * lose precision. For example, converting {@code 7} bits
+ * to bytes results in {@code 0}. Conversions from coarser to
+ * finer granularities with arguments that would numerically
+ * overflow saturate to {@code Long.MIN_VALUE} if negative or
+ * {@code Long.MAX_VALUE} if positive.
+ *
+ * <p>For example, to convert 4096 bytes to cache lines, use:
+ * {@code MemoryUnit.CACHE_LINES.convert(4096L, MemoryUnit.BYTES)}
+ *
+ * @param sourceAmount the memory amount in the given {@code sourceUnit}
+ * @param sourceUnit the unit of the {@code sourceAmount} argument
+ * @return the converted amount in this unit,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long convert(long sourceAmount, MemoryUnit sourceUnit) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Aligns the given memory amount in the given unit to this unit. For example, aligning
+ * {@code 1000} bytes to kilobytes results in {@code 1024}. Negative values are aligned towards
+ * negative infinity: e. g. aligning {@code -5} longs to cache lines results in {@code -8}.
+ *
+ * @param amountToAlign the memory amount in the given {@code unit}
+ * @param unit the unit of the {@code amountToAlign} argument
+ * @return the aligned amount, still in the given unit
+ * @throws IllegalArgumentException if the given {@code unit} is finer than this unit,
+ * or if the aligned value overflows {@code long} bounds
+ */
+ public long align(long amountToAlign, MemoryUnit unit) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to {@code convert(align(sourceAmount, sourceUnit), sourceUnit)}.
+ *
+ * @param sourceAmount the memory amount in the given {@code sourceUnit}
+ * @param sourceUnit the unit of the {@code sourceAmount} argument
+ * @return the saturated converted amount in this unit
+ * @throws IllegalArgumentException if the given {@code sourceUnit} is finer than this unit,
+ * or if the aligned value overflows {@code long} bounds
+ */
+ public long alignAndConvert(long sourceAmount, MemoryUnit sourceUnit) {
+ return convert(align(sourceAmount, sourceUnit), sourceUnit);
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) BITS.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toBits(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) BYTES.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toBytes(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) LONGS.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toLongs(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) CACHE_LINES.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toCacheLines(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) KILOBYTES.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toKilobytes(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) PAGES.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toPages(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) MEGABYTES.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount,
+ * or {@code Long.MIN_VALUE} if conversion would negatively
+ * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+ */
+ public long toMegabytes(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ /**
+ * Equivalent to
+ * {@link #convert(long, MemoryUnit) GIGABYTES.convert(amount, this)}.
+ * @param amount the amount
+ * @return the converted amount
+ */
+ public long toGigabytes(long amount) {
+ throw new AbstractMethodError();
+ }
+
+ abstract long alignToBytes(long amount);
+ abstract long alignToLongs(long amount);
+ abstract long alignToCacheLines(long amount);
+ abstract long alignToKilobytes(long amount);
+ abstract long alignToPages(long amount);
+ abstract long alignToMegabytes(long amount);
+ abstract long alignToGigabytes(long amount);
+}
diff --git a/lang/src/main/java/net/openhft/lang/ReferenceCounted.java b/lang/src/main/java/net/openhft/lang/ReferenceCounted.java
new file mode 100644
index 0000000..c74d42d
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/ReferenceCounted.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang;
+
+public interface ReferenceCounted {
+ void reserve();
+
+ boolean release();
+
+ int refCount();
+}
diff --git a/lang/src/main/java/net/openhft/lang/collection/ATSDirectBitSet.java b/lang/src/main/java/net/openhft/lang/collection/ATSDirectBitSet.java
new file mode 100644
index 0000000..5a8194e
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/collection/ATSDirectBitSet.java
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.collection;
+
+import net.openhft.lang.io.Bytes;
+
+import static java.lang.Long.numberOfLeadingZeros;
+import static java.lang.Long.numberOfTrailingZeros;
+import static net.openhft.lang.collection.SingleThreadedDirectBitSet.*;
+
+/**
+ * DirectBitSet with input validations and ThreadSafe memory access.
+ */
+public class ATSDirectBitSet implements DirectBitSet {
+ private final Bytes bytes;
+ private final long longLength;
+
+ private ATSDirectBitSet(Bytes bytes) {
+ this.bytes = bytes;
+ assert (bytes.capacity() & 7) == 0;
+ longLength = bytes.capacity() >> 3;
+ }
+
+ public static DirectBitSet wrap(Bytes bytes) {
+ return new ATSDirectBitSet(bytes);
+ }
+
+ private static long rightShiftOneFill(long l, long shift) {
+ return (l >> shift) | ~(ALL_ONES >>> shift);
+ }
+
+ private static long leftShiftOneFill(long l, long shift) {
+ return (l << shift) | ((1L << shift) - 1L);
+ }
+
+ private long readLong(long longIndex) {
+ return bytes.readLong(firstByte(longIndex));
+ }
+
+ private long readVolatileLong(long longIndex) {
+ return bytes.readVolatileLong(firstByte(longIndex));
+ }
+
+ @Override
+ public void reserve() {
+ bytes.reserve();
+ }
+
+ @Override
+ public boolean release() {
+ return bytes.release();
+ }
+
+ @Override
+ public int refCount() {
+ return bytes.refCount();
+ }
+
+ @Override
+ public DirectBitSet flip(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ long byteIndex = firstByte(longIndex);
+ // only 6 lowest-order bits used, JLS 15.19
+ long mask = singleBit(bitIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ long l2 = l ^ mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return this;
+ }
+ }
+
+ @Override
+ public DirectBitSet flip(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ if (fromIndex < 0 || fromIndex > exclusiveToIndex ||
+ toLongIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long fromByteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(fromByteIndex);
+ long l2 = l ^ mask;
+ if (bytes.compareAndSwapLong(fromByteIndex, l, l2))
+ break;
+ }
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ while (true) {
+ long l = readVolatileLong(i);
+ long l2 = ~l;
+ if (bytes.compareAndSwapLong(firstByte(i), l, l2))
+ break;
+ }
+ }
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ while (true) {
+ long l = readVolatileLong(i);
+ long l2 = ~l;
+ if (bytes.compareAndSwapLong(firstByte(i), l, l2))
+ break;
+ }
+ }
+
+ long toByteIndex = firstByte(toLongIndex);
+ long mask = lowerBitsIncludingThis(toIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(toByteIndex);
+ long l2 = l ^ mask;
+ if (bytes.compareAndSwapLong(toByteIndex, l, l2))
+ return this;
+ }
+ }
+ } else {
+ long byteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ long l2 = l ^ mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return this;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet set(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ if ((l & mask) != 0) return this;
+ long l2 = l | mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return this;
+ }
+ }
+
+ @Override
+ public boolean setIfClear(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ long l2 = l | mask;
+ if (l == l2)
+ return false;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return true;
+ }
+ }
+
+ @Override
+ public DirectBitSet set(long bitIndex, boolean value) {
+ return value ? set(bitIndex) : clear(bitIndex);
+ }
+
+ @Override
+ public DirectBitSet set(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ if (fromIndex < 0 || fromIndex > exclusiveToIndex ||
+ toLongIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long fromByteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(fromByteIndex);
+ long l2 = l | mask;
+ if (bytes.compareAndSwapLong(fromByteIndex, l, l2))
+ break;
+ }
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ bytes.writeLong(firstByte(i), ALL_ONES);
+ }
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ bytes.writeLong(firstByte(i), ALL_ONES);
+ }
+
+ long toByteIndex = firstByte(toLongIndex);
+ long mask = lowerBitsIncludingThis(toIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(toByteIndex);
+ long l2 = l | mask;
+ if (bytes.compareAndSwapLong(toByteIndex, l, l2))
+ return this;
+ }
+ }
+ } else {
+ long byteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ long l2 = l | mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return this;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet setAll() {
+ for (long i = 0; i < longLength; i++) {
+ bytes.writeLong(firstByte(i), ALL_ONES);
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet set(long fromIndex, long toIndex, boolean value) {
+ return value ? set(fromIndex, toIndex) : clear(fromIndex, toIndex);
+ }
+
+ @Override
+ public DirectBitSet clear(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ if ((l & mask) == 0) return this;
+ long l2 = l & ~mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return this;
+ }
+ }
+
+ @Override
+ public boolean clearIfSet(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ if ((l & mask) == 0) return false;
+ long l2 = l & ~mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return true;
+ }
+ }
+
+ @Override
+ public DirectBitSet clear(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ if (fromIndex < 0 || fromIndex > exclusiveToIndex ||
+ toLongIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long fromByteIndex = firstByte(fromLongIndex);
+ long mask = lowerBitsExcludingThis(fromIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(fromByteIndex);
+ long l2 = l & mask;
+ if (bytes.compareAndSwapLong(fromByteIndex, l, l2))
+ break;
+ }
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ bytes.writeLong(firstByte(i), 0L);
+ }
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ bytes.writeLong(firstByte(i), 0L);
+ }
+
+ long toByteIndex = firstByte(toLongIndex);
+ long mask = higherBitsExcludingThis(toIndex);
+ while (true) {
+ long l = bytes.readVolatileLong(toByteIndex);
+ long l2 = l & mask;
+ if (bytes.compareAndSwapLong(toByteIndex, l, l2))
+ return this;
+ }
+ }
+ } else {
+ long byteIndex = firstByte(fromLongIndex);
+ long mask = lowerBitsExcludingThis(fromIndex) | (higherBitsExcludingThis(toIndex));
+ while (true) {
+ long l = bytes.readVolatileLong(byteIndex);
+ long l2 = l & mask;
+ if (bytes.compareAndSwapLong(byteIndex, l, l2))
+ return this;
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet clear() {
+ bytes.zeroOut();
+ return this;
+ }
+
+ @Override
+ public boolean get(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ long l = readVolatileLong(longIndex);
+ return (l & (singleBit(bitIndex))) != 0;
+ }
+
+ @Override
+ public boolean isSet(long bitIndex) {
+ return get(bitIndex);
+ }
+
+ @Override
+ public boolean isClear(long bitIndex) {
+ return !get(bitIndex);
+ }
+
+ @Override
+ public long getLong(long longIndex) {
+ if (longIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ return readVolatileLong(longIndex);
+ }
+
+ @Override
+ public long nextSetBit(long fromIndex) {
+ return bytes.nextSetBit(fromIndex);
+ }
+
+ @Override
+ public Bits setBits() {
+ return new SetBits();
+ }
+
+ @Override
+ public long clearNextSetBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long fromByteIndex = firstByte(fromLongIndex);
+ while (true) {
+ long w = bytes.readVolatileLong(fromByteIndex);
+ long l = w >>> fromIndex;
+ if (l != 0) {
+ long indexOfSetBit = fromIndex + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask))
+ return indexOfSetBit;
+
+ } else {
+ break;
+ }
+ }
+ longLoop:
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ long byteIndex = firstByte(i);
+ while (true) {
+ long l = bytes.readLong(byteIndex);
+ if (l != 0) {
+ long indexOfSetBit = firstBit(i) + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ if (bytes.compareAndSwapLong(byteIndex, l, l ^ mask))
+ return indexOfSetBit;
+
+ } else {
+ continue longLoop;
+ }
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long nextSetLong(long fromLongIndex) {
+ if (fromLongIndex < 0)
+ throw new IndexOutOfBoundsException();
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ if (readVolatileLong(fromLongIndex) != 0)
+ return fromLongIndex;
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ if (readLong(i) != 0)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long nextClearBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long l = (~readVolatileLong(fromLongIndex)) >>> fromIndex;
+ if (l != 0) {
+ return fromIndex + numberOfTrailingZeros(l);
+ }
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ l = ~readLong(i);
+ if (l != 0)
+ return firstBit(i) + numberOfTrailingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long setNextClearBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long fromByteIndex = firstByte(fromLongIndex);
+ while (true) {
+ long w = bytes.readVolatileLong(fromByteIndex);
+ long l = (~w) >>> fromIndex;
+ if (l != 0) {
+ long indexOfClearBit =
+ fromIndex + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask))
+ return indexOfClearBit;
+
+ } else {
+ break;
+ }
+ }
+ longLoop:
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ long byteIndex = firstByte(i);
+ while (true) {
+ long w = bytes.readLong(byteIndex);
+ long l = ~w;
+ if (l != 0) {
+ long indexOfClearBit = firstBit(i) + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask))
+ return indexOfClearBit;
+
+ } else {
+ continue longLoop;
+ }
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long nextClearLong(long fromLongIndex) {
+ if (fromLongIndex < 0)
+ throw new IndexOutOfBoundsException();
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ if (readVolatileLong(fromLongIndex) != ALL_ONES)
+ return fromLongIndex;
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ if (readLong(i) != ALL_ONES)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousSetBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ // the same policy for this "index out of bounds" situation
+ // as in j.u.BitSet
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ // << ~fromIndex === << (63 - (fromIndex & 63))
+ long l = readVolatileLong(fromLongIndex) << ~fromIndex;
+ if (l != 0)
+ return fromIndex - numberOfLeadingZeros(l);
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ l = readLong(i);
+ if (l != 0)
+ return lastBit(i) - numberOfLeadingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long clearPreviousSetBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ long fromByteIndex = firstByte(fromLongIndex);
+ while (true) {
+ long w = bytes.readVolatileLong(fromByteIndex);
+ long l = w << ~fromIndex;
+ if (l != 0) {
+ long indexOfSetBit = fromIndex - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask))
+ return indexOfSetBit;
+
+ } else {
+ break;
+ }
+ }
+ longLoop:
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ long byteIndex = firstByte(i);
+ while (true) {
+ long l = bytes.readLong(byteIndex);
+ if (l != 0) {
+ long indexOfSetBit = lastBit(i) - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ if (bytes.compareAndSwapLong(byteIndex, l, l ^ mask))
+ return indexOfSetBit;
+
+ } else {
+ continue longLoop;
+ }
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousSetLong(long fromLongIndex) {
+ if (checkNotFoundIndex(fromLongIndex))
+ return NOT_FOUND;
+ if (fromLongIndex >= longLength)
+ fromLongIndex = longLength - 1;
+ if (readVolatileLong(fromLongIndex) != 0)
+ return fromLongIndex;
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ if (readLong(i) != 0)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousClearBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ long l = (~readVolatileLong(fromLongIndex)) << ~fromIndex;
+ if (l != 0)
+ return fromIndex - numberOfLeadingZeros(l);
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ l = ~readLong(i);
+ if (l != 0)
+ return lastBit(i) - numberOfLeadingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long setPreviousClearBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ long fromByteIndex = firstByte(fromLongIndex);
+ while (true) {
+ long w = bytes.readVolatileLong(fromByteIndex);
+ long l = (~w) << ~fromIndex;
+ if (l != 0) {
+ long indexOfClearBit = fromIndex - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask))
+ return indexOfClearBit;
+
+ } else {
+ break;
+ }
+ }
+ longLoop:
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ long byteIndex = firstByte(i);
+ while (true) {
+ long w = bytes.readLong(byteIndex);
+ long l = ~w;
+ if (l != 0) {
+ long indexOfClearBit = lastBit(i) - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask))
+ return indexOfClearBit;
+
+ } else {
+ continue longLoop;
+ }
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousClearLong(long fromLongIndex) {
+ if (checkNotFoundIndex(fromLongIndex))
+ return NOT_FOUND;
+ if (fromLongIndex >= longLength)
+ fromLongIndex = longLength - 1;
+ if (readVolatileLong(fromLongIndex) != ALL_ONES)
+ return fromLongIndex;
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ if (readLong(i) != ALL_ONES)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long size() {
+ return longLength << 6;
+ }
+
+ @Override
+ public long cardinality() {
+ long count = Long.bitCount(bytes.readVolatileLong(0));
+ for (long i = 1; i < longLength; i++) {
+ count += Long.bitCount(readLong(i));
+ }
+ return count;
+ }
+
+ @Override
+ public DirectBitSet and(long longIndex, long value) {
+ while (true) {
+ long l = readVolatileLong(longIndex);
+ long l2 = l & value;
+ if (l == l2 || bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this;
+ }
+ }
+
+ @Override
+ public DirectBitSet or(long longIndex, long value) {
+ while (true) {
+ long l = readVolatileLong(longIndex);
+ long l2 = l | value;
+ if (l == l2 || bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this;
+ }
+ }
+
+ @Override
+ public DirectBitSet xor(long longIndex, long value) {
+ while (true) {
+ long l = readVolatileLong(longIndex);
+ long l2 = l ^ value;
+ if (bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this;
+ }
+ }
+
+ @Override
+ public DirectBitSet andNot(long longIndex, long value) {
+ while (true) {
+ long l = readVolatileLong(longIndex);
+ long l2 = l & ~value;
+ if (bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this;
+ }
+ }
+
+ /**
+ * WARNING! This implementation doesn't strictly follow the contract
+ * from {@code DirectBitSet} interface. For the sake of atomicity this
+ * implementation couldn't find and flip the range crossing native word
+ * boundary, e. g. bits from 55 to 75 (boundary is 64).
+ *
+ * @throws IllegalArgumentException if {@code numberOfBits}
+ * is out of range {@code 0 < numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long setNextNContinuousClearBits(long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return setNextClearBit(fromIndex);
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+
+ int n64Complement = 64 - numberOfBits;
+ long nTrailingOnes = ALL_ONES >>> n64Complement;
+
+ long bitIndex = fromIndex;
+ long longIndex = longWithThisBit(bitIndex);
+ long byteIndex = firstByte(longIndex);
+ long w, l;
+ if ((bitIndex & 63) > n64Complement) {
+ if (++longIndex >= longLength)
+ return NOT_FOUND;
+ byteIndex += 8;
+ bitIndex = firstBit(longIndex);
+ l = w = bytes.readVolatileLong(byteIndex);
+
+ } else {
+ if (longIndex >= longLength)
+ return NOT_FOUND;
+ w = bytes.readVolatileLong(byteIndex);
+ l = rightShiftOneFill(w, bitIndex);
+ }
+ // long loop
+ while (true) {
+ continueLongLoop:
+ {
+ // (1)
+ if ((l & 1) != 0) {
+ long x = ~l;
+ if (x != 0) {
+ int trailingOnes = numberOfTrailingZeros(x);
+ bitIndex += trailingOnes;
+ // i. e. bitIndex + numberOfBits crosses 64 boundary
+ if ((bitIndex & 63) > n64Complement)
+ break continueLongLoop;
+ // (2)
+ l = rightShiftOneFill(l, trailingOnes);
+
+ } else {
+ // all bits are ones, go to the next long
+ break continueLongLoop;
+ }
+ }
+ // bit search within a long
+ while (true) {
+ // CAS retry loop
+ while ((l & nTrailingOnes) == 0) {
+ long mask = nTrailingOnes << bitIndex;
+ if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) {
+ return bitIndex;
+
+ } else {
+ w = bytes.readLong(byteIndex);
+ l = rightShiftOneFill(w, bitIndex);
+ }
+ }
+ // n > trailing zeros > 0
+ // > 0 ensured by block (1)
+ int trailingZeros = numberOfTrailingZeros(l);
+ bitIndex += trailingZeros;
+ // (3)
+ l = rightShiftOneFill(l, trailingZeros);
+
+ long x = ~l;
+ if (x != 0) {
+ int trailingOnes = numberOfTrailingZeros(x);
+ bitIndex += trailingOnes;
+ // i. e. bitIndex + numberOfBits crosses 64 boundary
+ if ((bitIndex & 63) > n64Complement)
+ break continueLongLoop;
+ // already shifted with one-filling at least once
+ // at (2) or (3), => garanteed highest bit is 1 =>
+ // "natural" one-filling
+ l >>= trailingOnes;
+
+ } else {
+ // zeros in this long exhausted, go to the next long
+ break continueLongLoop;
+ }
+ }
+ }
+ if (++longIndex >= longLength)
+ return NOT_FOUND;
+ byteIndex += 8;
+ bitIndex = firstBit(longIndex);
+ l = w = bytes.readLong(byteIndex);
+ }
+ }
+
+ /**
+ * WARNING! This implementation doesn't strictly follow the contract
+ * from {@code DirectBitSet} interface. For the sake of atomicity this
+ * implementation couldn't find and flip the range crossing native word
+ * boundary, e. g. bits from 55 to 75 (boundary is 64).
+ *
+ * @throws IllegalArgumentException if {@code numberOfBits}
+ * is out of range {@code 0 < numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long clearNextNContinuousSetBits(long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return clearNextSetBit(fromIndex);
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+
+ int n64Complement = 64 - numberOfBits;
+ long nTrailingOnes = ALL_ONES >>> n64Complement;
+
+ long bitIndex = fromIndex;
+ long longIndex = longWithThisBit(bitIndex);
+ long byteIndex = firstByte(longIndex);
+ long w, l;
+ if ((bitIndex & 63) > n64Complement) {
+ if (++longIndex >= longLength)
+ return NOT_FOUND;
+ byteIndex += 8;
+ bitIndex = firstBit(longIndex);
+ l = w = bytes.readVolatileLong(byteIndex);
+
+ } else {
+ if (longIndex >= longLength)
+ return NOT_FOUND;
+ w = bytes.readVolatileLong(byteIndex);
+ l = w >>> bitIndex;
+ }
+ // long loop
+ while (true) {
+ continueLongLoop:
+ {
+ if ((l & 1) == 0) {
+ if (l != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ bitIndex += trailingZeros;
+ // i. e. bitIndex + numberOfBits crosses 64 boundary
+ if ((bitIndex & 63) > n64Complement)
+ break continueLongLoop;
+ l >>>= trailingZeros;
+
+ } else {
+ // all bits are zeros, go to the next long
+ break continueLongLoop;
+ }
+ }
+ // bit search within a long
+ while (true) {
+ // CAS retry loop
+ while (((~l) & nTrailingOnes) == 0) {
+ long mask = nTrailingOnes << bitIndex;
+ if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) {
+ return bitIndex;
+
+ } else {
+ w = bytes.readLong(byteIndex);
+ l = w >>> bitIndex;
+ }
+ }
+ // n > trailing ones > 0
+ int trailingOnes = numberOfTrailingZeros(~l);
+ bitIndex += trailingOnes;
+ l >>>= trailingOnes;
+
+ if (l != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ bitIndex += trailingZeros;
+ // i. e. bitIndex + numberOfBits crosses 64 boundary
+ if ((bitIndex & 63) > n64Complement)
+ break continueLongLoop;
+ l >>>= trailingZeros;
+
+ } else {
+ // ones in this long exhausted, go to the next long
+ break continueLongLoop;
+ }
+ }
+ }
+ if (++longIndex >= longLength)
+ return NOT_FOUND;
+ byteIndex += 8;
+ bitIndex = firstBit(longIndex);
+ l = w = bytes.readLong(byteIndex);
+ }
+ }
+
+ /**
+ * WARNING! This implementation doesn't strictly follow the contract
+ * from {@code DirectBitSet} interface. For the sake of atomicity this
+ * implementation couldn't find and flip the range crossing native word
+ * boundary, e. g. bits from 55 to 75 (boundary is 64).
+ *
+ * @throws IllegalArgumentException if {@code numberOfBits}
+ * is out of range {@code 0 < numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long setPreviousNContinuousClearBits(
+ long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return setPreviousClearBit(fromIndex);
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+
+ int numberOfBitsMinusOne = numberOfBits - 1;
+ long nLeadingOnes = ALL_ONES << (64 - numberOfBits);
+
+ long bitIndex = fromIndex;
+ long longIndex = longWithThisBit(bitIndex);
+ if (longIndex >= longLength) {
+ longIndex = longLength - 1;
+ bitIndex = lastBit(longIndex);
+ }
+ long byteIndex = firstByte(longIndex);
+ long w, l;
+ if ((bitIndex & 63) < numberOfBitsMinusOne) {
+ if (--longIndex < 0)
+ return NOT_FOUND;
+ byteIndex -= 8;
+ bitIndex = lastBit(longIndex);
+ l = w = bytes.readVolatileLong(byteIndex);
+
+ } else {
+ w = bytes.readVolatileLong(byteIndex);
+ // left shift by ~bitIndex === left shift by (63 - (bitIndex & 63))
+ l = leftShiftOneFill(w, ~bitIndex);
+ }
+ // long loop
+ while (true) {
+ continueLongLoop:
+ {
+ if (l < 0) { // condition means the highest bit is one
+ long x = ~l;
+ if (x != 0) {
+ int leadingOnes = numberOfLeadingZeros(x);
+ bitIndex -= leadingOnes;
+ if ((bitIndex & 63) < numberOfBitsMinusOne)
+ break continueLongLoop;
+ l = leftShiftOneFill(l, leadingOnes);
+
+ } else {
+ // all bits are ones, go to the next long
+ break continueLongLoop;
+ }
+ }
+ // bit search within a long
+ while (true) {
+ // CAS retry loop
+ while ((l & nLeadingOnes) == 0) {
+ // >>> ~bitIndex === >>> (63 - (butIndex & 63))
+ long mask = nLeadingOnes >>> ~bitIndex;
+ if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) {
+ return bitIndex - numberOfBitsMinusOne;
+
+ } else {
+ w = bytes.readLong(byteIndex);
+ l = leftShiftOneFill(w, ~bitIndex);
+ }
+ }
+ // n > leading zeros > 0
+ int leadingZeros = numberOfLeadingZeros(l);
+ bitIndex -= leadingZeros;
+ l = leftShiftOneFill(l, leadingZeros);
+
+ long x = ~l;
+ if (x != 0) {
+ int leadingOnes = numberOfLeadingZeros(x);
+ bitIndex -= leadingOnes;
+ if ((bitIndex & 63) < numberOfBitsMinusOne)
+ break continueLongLoop;
+ l = leftShiftOneFill(l, leadingOnes);
+
+ } else {
+ // zeros in this long exhausted, go to the next long
+ break continueLongLoop;
+ }
+ }
+ }
+ if (--longIndex < 0)
+ return NOT_FOUND;
+ byteIndex -= 8;
+ bitIndex = lastBit(longIndex);
+ l = w = bytes.readLong(byteIndex);
+ }
+ }
+
+ /**
+ * WARNING! This implementation doesn't strictly follow the contract
+ * from {@code DirectBitSet} interface. For the sake of atomicity this
+ * implementation couldn't find and flip the range crossing native word
+ * boundary, e. g. bits from 55 to 75 (boundary is 64).
+ *
+ * @throws IllegalArgumentException if {@code numberOfBits}
+ * is out of range {@code 0 < numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long clearPreviousNContinuousSetBits(
+ long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return clearPreviousSetBit(fromIndex);
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+
+ int numberOfBitsMinusOne = numberOfBits - 1;
+ long nLeadingOnes = ALL_ONES << (64 - numberOfBits);
+
+ long bitIndex = fromIndex;
+ long longIndex = longWithThisBit(bitIndex);
+ if (longIndex >= longLength) {
+ longIndex = longLength - 1;
+ bitIndex = lastBit(longIndex);
+ }
+ long byteIndex = firstByte(longIndex);
+ long w, l;
+ if ((bitIndex & 63) < numberOfBitsMinusOne) {
+ if (--longIndex < 0)
+ return NOT_FOUND;
+ byteIndex -= 8;
+ bitIndex = lastBit(longIndex);
+ l = w = bytes.readVolatileLong(byteIndex);
+
+ } else {
+ w = bytes.readVolatileLong(byteIndex);
+ // << ~bitIndex === << (63 - (bitIndex & 63))
+ l = w << ~bitIndex;
+ }
+ // long loop
+ while (true) {
+ continueLongLoop:
+ {
+ // condition means the highest bit is zero, but not all
+ if (l > 0) {
+ int leadingZeros = numberOfLeadingZeros(l);
+ bitIndex -= leadingZeros;
+ if ((bitIndex & 63) < numberOfBitsMinusOne)
+ break continueLongLoop;
+ l <<= leadingZeros;
+
+ } else if (l == 0) {
+ // all bits are zeros, go to the next long
+ break continueLongLoop;
+ }
+ // bit search within a long
+ while (true) {
+ // CAS retry loop
+ while (((~l) & nLeadingOnes) == 0) {
+ // >>> ~bitIndex === >>> (63 - (butIndex & 63))
+ long mask = nLeadingOnes >>> ~bitIndex;
+ if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) {
+ return bitIndex - numberOfBitsMinusOne;
+
+ } else {
+ w = bytes.readLong(byteIndex);
+ l = w << ~bitIndex;
+ }
+ }
+ // n > leading ones > 0
+ int leadingOnes = numberOfLeadingZeros(~l);
+ bitIndex -= leadingOnes;
+ l <<= leadingOnes;
+
+ if (l != 0) {
+ int leadingZeros = numberOfLeadingZeros(l);
+ bitIndex -= leadingZeros;
+ if ((bitIndex & 63) < numberOfBitsMinusOne)
+ break continueLongLoop;
+ l <<= leadingZeros;
+
+ } else {
+ // ones in this long exhausted, go to the next long
+ break continueLongLoop;
+ }
+ }
+ }
+ if (--longIndex < 0)
+ return NOT_FOUND;
+ byteIndex -= 8;
+ bitIndex = lastBit(longIndex);
+ l = w = bytes.readLong(byteIndex);
+ }
+ }
+
+ private class SetBits implements Bits {
+ private final long byteLength = longLength << 3;
+ private long byteIndex = 0;
+ private long bitIndex = 0;
+
+ @Override
+ public long next() {
+ long bitIndex = this.bitIndex;
+ if (bitIndex >= 0) {
+ long i = byteIndex;
+ long l = bytes.readVolatileLong(i) >>> bitIndex;
+ if (l != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ long index = bitIndex + trailingZeros;
+ if (((this.bitIndex = index + 1) & 63) == 0) {
+ if ((byteIndex = i + 8) == byteLength)
+ this.bitIndex = -1;
+ }
+ return index;
+ }
+ for (long lim = byteLength; (i += 8) < lim; ) {
+ if ((l = bytes.readLong(i)) != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ long index = (i << 3) + trailingZeros;
+ if (((this.bitIndex = index + 1) & 63) != 0) {
+ byteIndex = i;
+
+ } else {
+ if ((byteIndex = i + 8) == lim)
+ this.bitIndex = -1;
+ }
+ return index;
+ }
+ }
+ }
+ this.bitIndex = -1;
+ return -1;
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/collection/DirectBitSet.java b/lang/src/main/java/net/openhft/lang/collection/DirectBitSet.java
new file mode 100644
index 0000000..2416075
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/collection/DirectBitSet.java
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.collection;
+
+import net.openhft.lang.ReferenceCounted;
+
+/**
+ * Most notable logical difference of this interface with {@code java.util.BitSet}
+ * is that {@code DirectBitSet} has a rigid {@link #size},
+ * attempts to {@link #get}, {@link #set} or {@link #clear} bits at indices
+ * exceeding the size cause {@code IndexOutOfBoundsException}. There is also
+ * a {@link #setAll()} method to set all bits within the size.
+ * {@code java.util.BitSet} doesn't have such rigid capacity.
+ *
+ * @see java.util.BitSet
+ */
+public interface DirectBitSet extends ReferenceCounted {
+ /**
+ * Returned if no entry is found
+ */
+ long NOT_FOUND = -1L;
+
+ /**
+ * Sets the bit at the specified index to the complement of its
+ * current value.
+ *
+ * @param bitIndex the index of the bit to flip
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ DirectBitSet flip(long bitIndex);
+
+ /**
+ * Sets each bit from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to the complement of its current
+ * value.
+ *
+ * @param fromIndex index of the first bit to flip
+ * @param toIndex index after the last bit to flip
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code fromIndex} is larger than {@code toIndex},
+ * or {@code toIndex} is larger or equal to {@code size()}
+ */
+ DirectBitSet flip(long fromIndex, long toIndex);
+
+ /**
+ * Sets the bit at the specified index to {@code true}.
+ *
+ * @param bitIndex a bit index
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ DirectBitSet set(long bitIndex);
+
+ /**
+ * Sets the bit at the specified index to {@code true}.
+ *
+ * @param bitIndex a bit index
+ * @return true if the bit was zeroOut, or false if the bit was already set.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ boolean setIfClear(long bitIndex);
+
+ /**
+ * Clears the bit at the specified index (sets it to {@code false}).
+ *
+ * @param bitIndex a bit index
+ * @return the previous value of the bit at the specified index
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ boolean clearIfSet(long bitIndex);
+
+ /**
+ * Sets the bit at the specified index to the specified value.
+ *
+ * @param bitIndex a bit index
+ * @param value a boolean value to set
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ DirectBitSet set(long bitIndex, boolean value);
+
+ /**
+ * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to {@code true}.
+ *
+ * @param fromIndex index of the first bit to be set
+ * @param toIndex index after the last bit to be set
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code fromIndex} is larger than {@code toIndex},
+ * or {@code toIndex} is larger or equal to {@code size()}
+ */
+ DirectBitSet set(long fromIndex, long toIndex);
+
+ /**
+ * Sets all bits, {@code bs.setAll()} is equivalent
+ * of {@code bs.set(0, bs.size()}.
+ *
+ * @return this bit set back
+ */
+ DirectBitSet setAll();
+
+ /**
+ * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to the specified value.
+ *
+ * @param fromIndex index of the first bit to be set
+ * @param toIndex index after the last bit to be set
+ * @param value value to set the selected bits to
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code fromIndex} is larger than {@code toIndex},
+ * or {@code toIndex} is larger or equal to {@code size()}
+ */
+ DirectBitSet set(long fromIndex, long toIndex, boolean value);
+
+ /**
+ * Sets the bit specified by the index to {@code false}.
+ *
+ * @param bitIndex the index of the bit to be cleared
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ DirectBitSet clear(long bitIndex);
+
+ /**
+ * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to {@code false}.
+ *
+ * @param fromIndex index of the first bit to be cleared
+ * @param toIndex index after the last bit to be cleared
+ * @return this {@code DirectBitSet} back
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code fromIndex} is larger than {@code toIndex},
+ * or {@code toIndex} is larger or equal to {@code size()}
+ */
+ DirectBitSet clear(long fromIndex, long toIndex);
+
+ /**
+ * Sets all of the bits in this BitSet to {@code false}.
+ *
+ * @return this {@code DirectBitSet} back
+ */
+ DirectBitSet clear();
+
+ /**
+ * Returns the value of the bit with the specified index. The value
+ * is {@code true} if the bit with the index {@code bitIndex}
+ * is currently set in this {@code DirectBitSet}; otherwise, the result
+ * is {@code false}.
+ *
+ * @param bitIndex the bit index
+ * @return the value of the bit with the specified index
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ boolean get(long bitIndex);
+
+ /**
+ * Synonym of {@link #get(long)}.
+ *
+ * @param bitIndex the bit index
+ * @return the value of the bit with the specified index
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ boolean isSet(long bitIndex);
+
+ /**
+ * Synonym of {@code !get(long)}.
+ * @param bitIndex the bit index
+ * @return {@code true} is the bit at the specified index is clear in this
+ * bit set; if the bit is set to {@code true} then returns {@code false}
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size())}
+ */
+ boolean isClear(long bitIndex);
+
+ /**
+ * Returns the value of the long with the specified long index.
+ *
+ * @param longIndex the bit index
+ * @return the value of the long with the specified index
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * {@code (index < 0 || index >= size() / 64)}
+ */
+ long getLong(long longIndex);
+
+ /**
+ * Returns the index of the first bit that is set to {@code true}
+ * that occurs on or after the specified starting index. If no such
+ * bit exists then {@code -1} is returned.
+ *
+ * <p>To iterate over the {@code true} bits in a {@code DirectBitSet},
+ * use the following loop:
+ * <pre> {@code
+ * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+ * &nbsp;&nbsp;&nbsp;&nbsp;// operate on index i here
+ * }}</pre>
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the next set bit, or {@code -1} if there
+ * is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @see #clearNextSetBit(long)
+ */
+ long nextSetBit(long fromIndex);
+
+ /**
+ * Returns the index of the first long that contains a bit set to {@code true}
+ * that occurs on or after the specified starting index. The index is the number of longs.
+ * If no such bit exists then {@code -1} is returned.
+ *
+ * @param fromLongIndex the index to start checking from (inclusive)
+ * @return the index of the next set long, or {@code -1} if there
+ * is no such long
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ */
+ long nextSetLong(long fromLongIndex);
+
+ /**
+ * Returns the index of the first bit that is set to {@code false}
+ * that occurs on or after the specified starting index. If no such
+ * bit exists then {@code -1} is returned.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the next zeroOut bit,
+ * or {@code -1} if there is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @see #setNextClearBit(long)
+ */
+ long nextClearBit(long fromIndex);
+
+ /**
+ * Returns the index of the first long that contains a bit is set to {@code false}
+ * that occurs on or after the specified starting index. If no such
+ * bit exists then {@code -1} is returned.
+ *
+ * @param fromLongIndex the index to start checking from (inclusive)
+ * @return the index of the next long containing a zeroOut bit,
+ * or {@code -1} if there is no such long
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ */
+ long nextClearLong(long fromLongIndex);
+
+ /**
+ * Returns the index of the nearest bit that is set to {@code true}
+ * that occurs on or before the specified starting index.
+ * If no such bit exists, or if {@code -1} is given as the
+ * starting index, then {@code -1} is returned.
+ *
+ * <p>To iterate over the {@code true} bits in a {@code DirectBitSet},
+ * use the following loop:
+ * <pre> {@code
+ * for (int i = bs.size(); (i = bs.previousSetBit(i-1)) >= 0; ) {
+ * // operate on index i here
+ * }}</pre>
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the previous set bit, or {@code -1} if there
+ * is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is less
+ * than {@code -1}
+ * @see #clearPreviousSetBit(long)
+ */
+ long previousSetBit(long fromIndex);
+
+ /**
+ * Returns the index of the nearest long that contains a bit set to {@code true}
+ * that occurs on or before the specified starting index.
+ * If no such bit exists, or if {@code -1} is given as the
+ * starting index, then {@code -1} is returned.
+ *
+ * @param fromLongIndex the index to start checking from (inclusive)
+ * @return the index of the previous long containing a set bit,
+ * or {@code -1} if there is no such long
+ * @throws IndexOutOfBoundsException if the specified index is less
+ * than {@code -1}
+ */
+ long previousSetLong(long fromLongIndex);
+
+ /**
+ * Returns the index of the nearest bit that is set to {@code false}
+ * that occurs on or before the specified starting index.
+ * If no such bit exists, or if {@code -1} is given as the
+ * starting index, then {@code -1} is returned.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the previous zeroOut bit, or {@code -1} if there
+ * is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is less
+ * than {@code -1}
+ * @see #setPreviousClearBit(long)
+ */
+ long previousClearBit(long fromIndex);
+
+ /**
+ * Returns the index of the nearest long that contains a bit set to {@code false}
+ * that occurs on or before the specified starting index.
+ * If no such bit exists, or if {@code -1} is given as the
+ * starting index, then {@code -1} is returned.
+ *
+ * @param fromLongIndex the index to start checking from (inclusive)
+ * @return the index of the previous long containing a zeroOut bit,
+ * or {@code -1} if there is no such long
+ * @throws IndexOutOfBoundsException if the specified index is less
+ * than {@code -1}
+ */
+ long previousClearLong(long fromLongIndex);
+
+ /**
+ * Returns the number of bits of space actually in use by this BitSet to represent bit values.
+ * The index of the last bit in the set eligible to be set or zeroOut
+ * is {@code size() - 1}.
+ *
+ * @return the number of bits in this bit set
+ */
+ long size();
+
+ /**
+ * Returns the number of bits set to {@code true} in this {@code DirectBitSet}.
+ *
+ * @return the number of bits set to {@code true} in this {@code DirectBitSet}
+ */
+ long cardinality();
+
+ /**
+ * Performs a logical <b>AND</b> of the long at the specified index in this
+ * bit set with the argument long value.
+ *
+ * @param longIndex of long to AND
+ * @param value of long to AND
+ * @return this {@code DirectBitSet} back
+ */
+ DirectBitSet and(long longIndex, long value);
+
+ /**
+ * Performs a logical <b>OR</b> of the long at the specified index in this
+ * bit set with the argument long value.
+ *
+ * @param longIndex of long to OR
+ * @param value of long to OR
+ * @return this {@code DirectBitSet} back
+ */
+ DirectBitSet or(long longIndex, long value);
+
+ /**
+ * Performs a logical <b>XOR</b> of the long at the specified index in this
+ * bit set with the argument long value.
+ *
+ * @param longIndex of long to XOR
+ * @param value of long to XOR
+ * @return this {@code DirectBitSet} back
+ */
+ DirectBitSet xor(long longIndex, long value);
+
+ /**
+ * Clears all of the bits in the long at the specified index in this
+ * {@code DirectBitSet} whose corresponding bit is set in the specified
+ * long value.
+ *
+ * @param longIndex of long to AND NOT
+ * @param value of long to AND NOT
+ * @return this {@code DirectBitSet} back
+ */
+ DirectBitSet andNot(long longIndex, long value);
+
+ /**
+ * Finds and sets to {@code true} the first bit that is set to {@code false}
+ * that occurs on or after the specified starting index. If no such
+ * bit exists then {@code -1} is returned.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the next zeroOut bit,
+ * or {@code -1} if there is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @see #nextClearBit(long)
+ */
+ long setNextClearBit(long fromIndex);
+
+ /**
+ * Finds and clears the first bit that is set to {@code true}
+ * that occurs on or after the specified starting index. If no such
+ * bit exists then {@code -1} is returned.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the next set bit, or {@code -1} if there
+ * is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @see #nextSetBit(long)
+ */
+ long clearNextSetBit(long fromIndex);
+
+ /**
+ * Finds and sets to {@code true} the nearest bit that is set
+ * to {@code false} that occurs on or before the specified starting index.
+ * If no such bit exists, or if {@code -1} is given as the
+ * starting index, then {@code -1} is returned.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the previous zeroOut bit, or {@code -1} if there
+ * is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is less
+ * than {@code -1}
+ * @see #previousClearBit(long)
+ */
+ long setPreviousClearBit(long fromIndex);
+
+ /**
+ * Finds and clears the nearest bit that is set to {@code true}
+ * that occurs on or before the specified starting index.
+ * If no such bit exists, or if {@code -1} is given as the
+ * starting index, then {@code -1} is returned.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @return the index of the previous set bit, or {@code -1} if there
+ * is no such bit
+ * @throws IndexOutOfBoundsException if the specified index is less
+ * than {@code -1}
+ * @see #previousSetBit(long)
+ */
+ long clearPreviousSetBit(long fromIndex);
+
+ /**
+ * Finds the next {@code numberOfBits} consecutive bits set to {@code false},
+ * starting from the specified {@code fromIndex}. Then all bits of the found
+ * range are set to {@code true}. The first index of the found block
+ * is returned. If there is no such range of clear bits, {@code -1}
+ * is returned.
+ *
+ * <p>{@code fromIndex} could be the first index of the found range, thus
+ * {@code setNextNContinuousClearBits(i, 1)} is exact equivalent of
+ * {@code setNextClearBit(i)}.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @param numberOfBits how many continuous clear bits to search and set
+ * @return the index of the first bit in the found range of clear bits,
+ * or {@code -1} if there is no such range
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative
+ * @throws java.lang.IllegalArgumentException if {@code numberOfBits <= 0}
+ */
+ long setNextNContinuousClearBits(long fromIndex, int numberOfBits);
+
+ /**
+ * Finds the next {@code numberOfBits} consecutive bits set to {@code true},
+ * starting from the specified {@code fromIndex}. Then all bits of the found
+ * range are set to {@code false}. The first index of the found block
+ * is returned. If there is no such range of {@code true} bits, {@code -1}
+ * is returned.
+ *
+ * <p>{@code fromIndex} could be the first index of the found range, thus
+ * {@code clearNextNContinuousSetBits(i, 1)} is exact equivalent of
+ * {@code clearNextSetBit(i)}.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @param numberOfBits how many continuous set bits to search and clear
+ * @return the index of the first bit in the found range
+ * of {@code true} bits, or {@code -1} if there is no such range
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative
+ * @throws java.lang.IllegalArgumentException if {@code numberOfBits <= 0}
+ */
+ long clearNextNContinuousSetBits(long fromIndex, int numberOfBits);
+
+ /**
+ * Finds the previous {@code numberOfBits} consecutive bits
+ * set to {@code false}, starting from the specified {@code fromIndex}.
+ * Then all bits of the found range are set to {@code true}.
+ * The first index of the found block is returned. If there is no such
+ * range of clear bits, or if {@code -1} is given as the starting index,
+ * {@code -1} is returned.
+ *
+ * <p>{@code fromIndex} could be the last index of the found range, thus
+ * {@code setPreviousNContinuousClearBits(i, 1)} is exact equivalent of
+ * {@code setPreviousClearBit(i)}.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @param numberOfBits how many continuous clear bits to search and set
+ * @return the index of the first bit in the found range of clear bits,
+ * or {@code -1} if there is no such range
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is less
+ * than {@code -1}
+ * @throws java.lang.IllegalArgumentException if {@code numberOfBits <= 0}
+ */
+ long setPreviousNContinuousClearBits(long fromIndex, int numberOfBits);
+
+ /**
+ * Finds the previous {@code numberOfBits} consecutive bits
+ * set to {@code true}, starting from the specified {@code fromIndex}.
+ * Then all bits of the found range are set to {@code false}.
+ * The first index of the found block is returned. If there is no such
+ * range of {@code true} bits, or if {@code -1} is given as the starting
+ * index, {@code -1} is returned.
+ *
+ * <p>{@code fromIndex} could be the last index of the found range, thus
+ * {@code clearPreviousNContinuousSetBits(i, 1)} is exact equivalent of
+ * {@code clearPreviousSetBit(i)}.
+ *
+ * @param fromIndex the index to start checking from (inclusive)
+ * @param numberOfBits how many continuous set bits to search and clear
+ * @return the index of the first bit in the found range
+ * of {@code true} bits, or {@code -1} if there is no such range
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is less
+ * than {@code -1}
+ * @throws java.lang.IllegalArgumentException if {@code numberOfBits <= 0}
+ */
+ long clearPreviousNContinuousSetBits(long fromIndex, int numberOfBits);
+
+ /**
+ * An iteration of bits in a bit set.
+ *
+ * <p>Usage idiom: <pre>{@code
+ * Bits bits = bitSet.setBits();
+ * for (long bit; (bit = bits.next()) >= 0;) {
+ * // do something with the bit
+ * }}</pre>
+ */
+ interface Bits {
+ /**
+ * Returns index of the next bit in the iteration,
+ * or {@code -1} if there are no more bits.
+ *
+ * @return index of the next bit in the iteration,
+ * or {@code -1} if there are no more bits
+ */
+ long next();
+ }
+
+ /**
+ * Returns an iteration of <i>set</i> bits in <i>direct</i> order
+ * (from 0 to the end of the bit set).
+ *
+ * @return an iteration of <i>set</i> bits in <i>direct</i> order
+ */
+ Bits setBits();
+}
diff --git a/lang/src/main/java/net/openhft/lang/collection/DirectBitSetBuilder.java b/lang/src/main/java/net/openhft/lang/collection/DirectBitSetBuilder.java
new file mode 100644
index 0000000..33bdc53
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/collection/DirectBitSetBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.collection;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.DirectStore;
+
+public class DirectBitSetBuilder {
+ private boolean assertions;
+ private boolean threadSafe;
+
+ public DirectBitSetBuilder() {
+ threadSafe = true;
+ assertions = false;
+ //noinspection ConstantConditions,AssertWithSideEffects
+ assert assertions = true;
+ }
+
+ static DirectBitSet wrap(Bytes bytes) {
+ return ATSDirectBitSet.wrap(bytes);
+ }
+
+ public DirectBitSetBuilder assertions(boolean assertions) {
+ this.assertions = assertions;
+ return this;
+ }
+
+ public boolean assertions() {
+ return assertions;
+ }
+
+ public DirectBitSetBuilder threadSafe(boolean threadSafe) {
+ this.threadSafe = threadSafe;
+ return this;
+ }
+
+ public boolean threadSafe() {
+ return threadSafe;
+ }
+
+ public DirectBitSet create(long size) {
+ return wrap(DirectStore.allocate((size + 7) >>> 3).bytes());
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/collection/HugeArray.java b/lang/src/main/java/net/openhft/lang/collection/HugeArray.java
index cfe1ffb..12c5962 100644
--- a/lang/src/main/java/net/openhft/lang/collection/HugeArray.java
+++ b/lang/src/main/java/net/openhft/lang/collection/HugeArray.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection;
@@ -36,7 +36,7 @@ public interface HugeArray<T> {
T get(long index);
/**
- * Get a copy of the object in the array
+ * If the element was returned by get(long), re-index it otherwise, get a copy of the object in the array.
*
* @param index of element to copy
* @param element Copyable element to copy to.
diff --git a/lang/src/main/java/net/openhft/lang/collection/HugeCollections.java b/lang/src/main/java/net/openhft/lang/collection/HugeCollections.java
index 4dbaad2..72a937f 100644
--- a/lang/src/main/java/net/openhft/lang/collection/HugeCollections.java
+++ b/lang/src/main/java/net/openhft/lang/collection/HugeCollections.java
@@ -1,24 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection;
import net.openhft.lang.collection.impl.HugeArrayImpl;
import net.openhft.lang.collection.impl.HugeQueueImpl;
-import net.openhft.lang.model.DataValueGenerator;
/**
* User: peter.lawrey
@@ -28,21 +27,11 @@ import net.openhft.lang.model.DataValueGenerator;
public enum HugeCollections {
;
- private static final DataValueGenerator VALUE_GENERATOR = new DataValueGenerator();
-
- static {
- VALUE_GENERATOR.setDumpCode(true);
- }
-
- public static DataValueGenerator getDataValueGenerator() {
- return VALUE_GENERATOR;
- }
-
public static <T> HugeArray<T> newArray(Class<T> tClass, long length) {
- return new HugeArrayImpl<T>(VALUE_GENERATOR, tClass, length);
+ return new HugeArrayImpl<T>(tClass, length);
}
public static <T> HugeQueue<T> newQueue(Class<T> tClass, long length) {
- return new HugeQueueImpl<T>(new HugeArrayImpl<T>(VALUE_GENERATOR, tClass, length + 1), length + 1);
+ return new HugeQueueImpl<T>(new HugeArrayImpl<T>(tClass, length + 1), length + 1);
}
}
diff --git a/lang/src/main/java/net/openhft/lang/collection/HugeQueue.java b/lang/src/main/java/net/openhft/lang/collection/HugeQueue.java
index c164fc4..4d6884b 100644
--- a/lang/src/main/java/net/openhft/lang/collection/HugeQueue.java
+++ b/lang/src/main/java/net/openhft/lang/collection/HugeQueue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection;
diff --git a/lang/src/main/java/net/openhft/lang/collection/SingleThreadedDirectBitSet.java b/lang/src/main/java/net/openhft/lang/collection/SingleThreadedDirectBitSet.java
new file mode 100644
index 0000000..4a53765
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/collection/SingleThreadedDirectBitSet.java
@@ -0,0 +1,1337 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.collection;
+
+import net.openhft.lang.io.Bytes;
+
+import static java.lang.Long.numberOfLeadingZeros;
+import static java.lang.Long.numberOfTrailingZeros;
+
+/**
+ * DirectBitSet with input validations, This class is not thread safe
+ */
+public class SingleThreadedDirectBitSet implements DirectBitSet {
+
+ public static final long ALL_ONES = ~0L;
+
+ // masks
+ private Bytes bytes;
+ private long longLength;
+
+ public SingleThreadedDirectBitSet(Bytes bytes) {
+ reuse(bytes);
+ }
+
+ static long singleBit(long bitIndex) {
+ return 1L << bitIndex;
+ }
+
+ static long singleBit(int bitIndex) {
+ return 1L << bitIndex;
+ }
+
+ static long higherBitsIncludingThis(long bitIndex) {
+ return ALL_ONES << bitIndex;
+ }
+
+ // conversions
+
+ static long lowerBitsIncludingThis(long bitIndex) {
+ return ALL_ONES >>> ~bitIndex;
+ }
+
+ static long higherBitsExcludingThis(long bitIndex) {
+ return ~(ALL_ONES >>> ~bitIndex);
+ }
+
+ static long lowerBitsExcludingThis(long bitIndex) {
+ return ~(ALL_ONES << bitIndex);
+ }
+
+ static long longWithThisBit(long bitIndex) {
+ return bitIndex >> 6;
+ }
+
+ static long firstByte(long longIndex) {
+ return longIndex << 3;
+ }
+
+ static long firstBit(long longIndex) {
+ return longIndex << 6;
+ }
+
+ static long lastBit(long longIndex) {
+ return firstBit(longIndex) + 63;
+ }
+
+ static void checkNumberOfBits(int numberOfBits) {
+ if (numberOfBits <= 0 || numberOfBits > 64)
+ throw new IllegalArgumentException("Illegal number of bits: " + numberOfBits);
+ }
+
+ // checks
+
+ static boolean checkNotFoundIndex(long fromIndex) {
+ if (fromIndex < 0) {
+ if (fromIndex == NOT_FOUND)
+ return true;
+ throw new IndexOutOfBoundsException();
+ }
+ return false;
+ }
+
+ public void reuse(Bytes bytes) {
+ this.bytes = bytes;
+ longLength = bytes.capacity() >> 3;
+ }
+
+ private void checkIndex(long bitIndex, long longIndex) {
+ if (bitIndex < 0 || longIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ }
+
+ private void checkFromTo(long fromIndex, long exclusiveToIndex, long toLongIndex) {
+ if (fromIndex < 0 || fromIndex > exclusiveToIndex ||
+ toLongIndex >= longLength)
+ throw new IndexOutOfBoundsException();
+ }
+
+ private long readLong(long longIndex) {
+ return bytes.readLong(firstByte(longIndex));
+ }
+
+ private void writeLong(long longIndex, long toWrite) {
+ bytes.writeLong(firstByte(longIndex), toWrite);
+ }
+
+ @Override
+ public void reserve() {
+ bytes.reserve();
+ }
+
+ @Override
+ public boolean release() {
+ return bytes.release();
+ }
+
+ @Override
+ public int refCount() {
+ return bytes.refCount();
+ }
+
+ @Override
+ public DirectBitSet flip(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ checkIndex(bitIndex, longIndex);
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ long l = bytes.readLong(byteIndex);
+ long l2 = l ^ mask;
+ bytes.writeLong(byteIndex, l2);
+ return this;
+ }
+
+ @Override
+ public DirectBitSet flip(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ checkFromTo(fromIndex, exclusiveToIndex, toLongIndex);
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long fromByteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex);
+ long l = bytes.readLong(fromByteIndex);
+ long l2 = l ^ mask;
+ bytes.writeLong(fromByteIndex, l2);
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ writeLong(i, ~readLong(i));
+ }
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ writeLong(i, ~readLong(i));
+ }
+
+ long toByteIndex = firstByte(toLongIndex);
+ long mask = lowerBitsIncludingThis(toIndex);
+ long l = bytes.readLong(toByteIndex);
+ long l2 = l ^ mask;
+ bytes.writeLong(toByteIndex, l2);
+ }
+ } else {
+ long byteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ long l = bytes.readLong(byteIndex);
+ long l2 = l ^ mask;
+ bytes.writeLong(byteIndex, l2);
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet set(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ checkIndex(bitIndex, longIndex);
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ long l = bytes.readLong(byteIndex);
+ if ((l & mask) != 0) return this;
+ long l2 = l | mask;
+ bytes.writeLong(byteIndex, l2);
+ return this;
+ }
+
+ @Override
+ public boolean setIfClear(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ checkIndex(bitIndex, longIndex);
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ long l = bytes.readLong(byteIndex);
+ long l2 = l | mask;
+ if (l == l2)
+ return false;
+ bytes.writeLong(byteIndex, l2);
+ return true;
+ }
+
+ @Override
+ public DirectBitSet set(long bitIndex, boolean value) {
+ return value ? set(bitIndex) : clear(bitIndex);
+ }
+
+ @Override
+ public DirectBitSet set(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ checkFromTo(fromIndex, exclusiveToIndex, toLongIndex);
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long fromByteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex);
+ long l = bytes.readLong(fromByteIndex);
+ long l2 = l | mask;
+ bytes.writeLong(fromByteIndex, l2);
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ writeLong(i, ALL_ONES);
+ }
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ writeLong(i, ALL_ONES);
+ }
+
+ long toByteIndex = firstByte(toLongIndex);
+ long mask = lowerBitsIncludingThis(toIndex);
+ long l = bytes.readLong(toByteIndex);
+ long l2 = l | mask;
+ bytes.writeLong(toByteIndex, l2);
+ }
+ } else {
+ long byteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ long l = bytes.readLong(byteIndex);
+ long l2 = l | mask;
+ bytes.writeLong(byteIndex, l2);
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet setAll() {
+ for (long i = 0; i < longLength; i++) {
+ writeLong(i, ALL_ONES);
+ }
+ return this;
+ }
+
+ @Override
+ public DirectBitSet set(long fromIndex, long toIndex, boolean value) {
+ return value ? set(fromIndex, toIndex) : clear(fromIndex, toIndex);
+ }
+
+ @Override
+ public DirectBitSet clear(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ checkIndex(bitIndex, longIndex);
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ long l = bytes.readLong(byteIndex);
+ if ((l & mask) == 0) return this;
+ long l2 = l & ~mask;
+ bytes.writeLong(byteIndex, l2);
+ return this;
+ }
+
+ @Override
+ public boolean clearIfSet(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ checkIndex(bitIndex, longIndex);
+ long byteIndex = firstByte(longIndex);
+ long mask = singleBit(bitIndex);
+ long l = bytes.readLong(byteIndex);
+ if ((l & mask) == 0) return false;
+ long l2 = l & ~mask;
+ bytes.writeLong(byteIndex, l2);
+ return true;
+ }
+
+ @Override
+ public DirectBitSet clear(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ checkFromTo(fromIndex, exclusiveToIndex, toLongIndex);
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long fromByteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex);
+ long l = bytes.readLong(fromByteIndex);
+ long l2 = l & ~mask;
+ bytes.writeLong(fromByteIndex, l2);
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ writeLong(i, 0L);
+ }
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ writeLong(i, 0L);
+ }
+
+ long toByteIndex = firstByte(toLongIndex);
+ long mask = lowerBitsIncludingThis(toIndex);
+ long l = bytes.readLong(toByteIndex);
+ long l2 = l & ~mask;
+ bytes.writeLong(toByteIndex, l2);
+ }
+ } else {
+ long byteIndex = firstByte(fromLongIndex);
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ long l = bytes.readLong(byteIndex);
+ long l2 = l & ~mask;
+ bytes.writeLong(byteIndex, l2);
+ }
+ return this;
+ }
+
+ /**
+ * Checks if each bit from the specified {@code fromIndex} (inclusive) to the specified {@code
+ * exclusiveToIndex} is set to {@code true}.
+ *
+ * @param fromIndex index of the first bit to check
+ * @param exclusiveToIndex index after the last bit to check
+ * @return {@code true} if all bits in the specified range are set to {@code true}, {@code
+ * false} otherwise
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}, or {@code exclusiveToIndex} is
+ * larger or equal to {@code size()}
+ */
+ public boolean allSet(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ checkFromTo(fromIndex, exclusiveToIndex, toLongIndex);
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long mask = higherBitsIncludingThis(fromIndex);
+ if ((~(readLong(fromLongIndex)) & mask) != 0L)
+ return false;
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ if (~readLong(i) != 0L)
+ return false;
+ }
+ return true;
+
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ if (~readLong(i) != 0L)
+ return false;
+ }
+
+ long mask = lowerBitsIncludingThis(toIndex);
+ return ((~readLong(toLongIndex)) & mask) == 0L;
+ }
+ } else {
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ return ((~readLong(fromLongIndex)) & mask) == 0L;
+ }
+ }
+
+ /**
+ * Checks if each bit from the specified {@code fromIndex} (inclusive) to the specified {@code
+ * exclusiveToIndex} is set to {@code false}.
+ *
+ * @param fromIndex index of the first bit to check
+ * @param exclusiveToIndex index after the last bit to check
+ * @return {@code true} if all bits in the specified range are set to {@code false}, {@code
+ * false} otherwise
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}, or {@code exclusiveToIndex} is
+ * larger or equal to {@code size()}
+ */
+ public boolean allClear(long fromIndex, long exclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toIndex = exclusiveToIndex - 1;
+ long toLongIndex = longWithThisBit(toIndex);
+ checkFromTo(fromIndex, exclusiveToIndex, toLongIndex);
+
+ if (fromLongIndex != toLongIndex) {
+ long firstFullLongIndex = fromLongIndex;
+ if ((fromIndex & 63) != 0) {
+ long mask = higherBitsIncludingThis(fromIndex);
+ if ((readLong(fromLongIndex) & mask) != 0L)
+ return false;
+ firstFullLongIndex++;
+ }
+
+ if ((exclusiveToIndex & 63) == 0) {
+ for (long i = firstFullLongIndex; i <= toLongIndex; i++) {
+ if (readLong(i) != 0L)
+ return false;
+ }
+ return true;
+
+ } else {
+ for (long i = firstFullLongIndex; i < toLongIndex; i++) {
+ if (readLong(i) != 0L)
+ return false;
+ }
+
+ long mask = lowerBitsIncludingThis(toIndex);
+ return (readLong(toLongIndex) & mask) == 0L;
+ }
+ } else {
+ long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex);
+ return (readLong(fromLongIndex) & mask) == 0L;
+ }
+ }
+
+ @Override
+ public DirectBitSet clear() {
+ bytes.zeroOut();
+ return this;
+ }
+
+ @Override
+ public boolean get(long bitIndex) {
+ long longIndex = longWithThisBit(bitIndex);
+ checkIndex(bitIndex, longIndex);
+ long l = readLong(longIndex);
+ return (l & (singleBit(bitIndex))) != 0;
+ }
+
+ @Override
+ public boolean isSet(long bitIndex) {
+ return get(bitIndex);
+ }
+
+ @Override
+ public boolean isClear(long bitIndex) {
+ return !get(bitIndex);
+ }
+
+ @Override
+ public long getLong(long longIndex) {
+ checkIndex(longIndex, longIndex);
+ return readLong(longIndex);
+ }
+
+ @Override
+ public long nextSetBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long l = readLong(fromLongIndex) >>> fromIndex;
+ if (l != 0) {
+ return fromIndex + numberOfTrailingZeros(l);
+ }
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ l = readLong(i);
+ if (l != 0)
+ return firstBit(i) + numberOfTrailingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public Bits setBits() {
+ return new SetBits();
+ }
+
+ @Override
+ public long clearNextSetBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long fromByteIndex = firstByte(fromLongIndex);
+ long w = bytes.readLong(fromByteIndex);
+ long l = w >>> fromIndex;
+ if (l != 0) {
+ long indexOfSetBit = fromIndex + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ bytes.writeLong(fromByteIndex, w ^ mask);
+ return indexOfSetBit;
+ }
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ long byteIndex = firstByte(i);
+ l = bytes.readLong(byteIndex);
+ if (l != 0) {
+ long indexOfSetBit = firstBit(i) + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ bytes.writeLong(byteIndex, l ^ mask);
+ return indexOfSetBit;
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long nextSetLong(long fromLongIndex) {
+ if (fromLongIndex < 0)
+ throw new IndexOutOfBoundsException();
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ if (readLong(fromLongIndex) != 0)
+ return fromLongIndex;
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ if (readLong(i) != 0)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long nextClearBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long l = (~readLong(fromLongIndex)) >>> fromIndex;
+ if (l != 0) {
+ return fromIndex + numberOfTrailingZeros(l);
+ }
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ l = ~readLong(i);
+ if (l != 0)
+ return firstBit(i) + numberOfTrailingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long setNextClearBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ long fromByteIndex = firstByte(fromLongIndex);
+ long w = bytes.readLong(fromByteIndex);
+ long l = (~w) >>> fromIndex;
+ if (l != 0) {
+ long indexOfClearBit = fromIndex + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ bytes.writeLong(fromByteIndex, w ^ mask);
+ return indexOfClearBit;
+ }
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ long byteIndex = firstByte(i);
+ w = bytes.readLong(byteIndex);
+ l = ~w;
+ if (l != 0) {
+ long indexOfClearBit = firstBit(i) + numberOfTrailingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ bytes.writeLong(byteIndex, w ^ mask);
+ return indexOfClearBit;
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long nextClearLong(long fromLongIndex) {
+ if (fromLongIndex < 0)
+ throw new IndexOutOfBoundsException();
+ if (fromLongIndex >= longLength)
+ return NOT_FOUND;
+ if (readLong(fromLongIndex) != ALL_ONES)
+ return fromLongIndex;
+ for (long i = fromLongIndex + 1; i < longLength; i++) {
+ if (readLong(i) != ALL_ONES)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousSetBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ // the same policy for this "index out of bounds" situation
+ // as in j.u.BitSet
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ // << ~fromIndex === << (63 - (fromIndex & 63))
+ long l = readLong(fromLongIndex) << ~fromIndex;
+ if (l != 0)
+ return fromIndex - numberOfLeadingZeros(l);
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ l = readLong(i);
+ if (l != 0)
+ return lastBit(i) - numberOfLeadingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ private long previousSetBit(long fromIndex, long inclusiveToIndex) {
+ long fromLongIndex = longWithThisBit(fromIndex);
+ long toLongIndex = longWithThisBit(inclusiveToIndex);
+ checkFromTo(inclusiveToIndex, fromIndex + 1, toLongIndex);
+ if (fromLongIndex >= longLength) {
+ // the same policy for this "index out of bounds" situation
+ // as in j.u.BitSet
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ if (fromLongIndex != toLongIndex) {
+ // << ~fromIndex === << (63 - (fromIndex & 63))
+ long l = readLong(fromLongIndex) << ~fromIndex;
+ if (l != 0)
+ return fromIndex - numberOfLeadingZeros(l);
+ for (long i = fromLongIndex - 1; i > toLongIndex; i--) {
+ l = readLong(i);
+ if (l != 0)
+ return lastBit(i) - numberOfLeadingZeros(l);
+ }
+ fromIndex = lastBit(toLongIndex);
+ }
+ long w = readLong(toLongIndex);
+ long mask = higherBitsIncludingThis(inclusiveToIndex) & lowerBitsIncludingThis(fromIndex);
+ long l = w & mask;
+ if (l != 0) {
+ return lastBit(toLongIndex) - numberOfLeadingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long clearPreviousSetBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ long fromByteIndex = firstByte(fromLongIndex);
+ long w = bytes.readLong(fromByteIndex);
+ long l = w << ~fromIndex;
+ if (l != 0) {
+ long indexOfSetBit = fromIndex - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ bytes.writeLong(fromByteIndex, w ^ mask);
+ return indexOfSetBit;
+ }
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ long byteIndex = firstByte(i);
+ l = bytes.readLong(byteIndex);
+ if (l != 0) {
+ long indexOfSetBit = lastBit(i) - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfSetBit);
+ bytes.writeLong(byteIndex, l ^ mask);
+ return indexOfSetBit;
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousSetLong(long fromLongIndex) {
+ if (checkNotFoundIndex(fromLongIndex))
+ return NOT_FOUND;
+ if (fromLongIndex >= longLength)
+ fromLongIndex = longLength - 1;
+ if (readLong(fromLongIndex) != 0)
+ return fromLongIndex;
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ if (readLong(i) != 0)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousClearBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ long l = (~readLong(fromLongIndex)) << ~fromIndex;
+ if (l != 0)
+ return fromIndex - numberOfLeadingZeros(l);
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ l = ~readLong(i);
+ if (l != 0)
+ return lastBit(i) - numberOfLeadingZeros(l);
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long setPreviousClearBit(long fromIndex) {
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+ long fromLongIndex = longWithThisBit(fromIndex);
+ if (fromLongIndex >= longLength) {
+ fromLongIndex = longLength - 1;
+ fromIndex = size() - 1;
+ }
+ long fromByteIndex = firstByte(fromLongIndex);
+ long w = bytes.readLong(fromByteIndex);
+ long l = (~w) << ~fromIndex;
+ if (l != 0) {
+ long indexOfClearBit = fromIndex - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ bytes.writeLong(fromByteIndex, w ^ mask);
+ return indexOfClearBit;
+ }
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ long byteIndex = firstByte(i);
+ w = bytes.readLong(byteIndex);
+ l = ~w;
+ if (l != 0) {
+ long indexOfClearBit = lastBit(i) - numberOfLeadingZeros(l);
+ long mask = singleBit(indexOfClearBit);
+ bytes.writeLong(byteIndex, w ^ mask);
+ return indexOfClearBit;
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long previousClearLong(long fromLongIndex) {
+ if (checkNotFoundIndex(fromLongIndex))
+ return NOT_FOUND;
+ if (fromLongIndex >= longLength)
+ fromLongIndex = longLength - 1;
+ if (readLong(fromLongIndex) != ALL_ONES)
+ return fromLongIndex;
+ for (long i = fromLongIndex - 1; i >= 0; i--) {
+ if (readLong(i) != ALL_ONES)
+ return i;
+ }
+ return NOT_FOUND;
+ }
+
+ @Override
+ public long size() {
+ return longLength << 6;
+ }
+
+ @Override
+ public long cardinality() {
+ long count = 0;
+ for (long i = 0; i < longLength; i++) {
+ count += Long.bitCount(readLong(i));
+ }
+ return count;
+ }
+
+ @Override
+ public DirectBitSet and(long longIndex, long value) {
+ long l = readLong(longIndex);
+ long l2 = l & value;
+ writeLong(longIndex, l2);
+ return this;
+ }
+
+ @Override
+ public DirectBitSet or(long longIndex, long value) {
+ long l = readLong(longIndex);
+ long l2 = l | value;
+ writeLong(longIndex, l2);
+ return this;
+ }
+
+ @Override
+ public DirectBitSet xor(long longIndex, long value) {
+ long l = readLong(longIndex);
+ long l2 = l ^ value;
+ writeLong(longIndex, l2);
+ return this;
+ }
+
+ @Override
+ public DirectBitSet andNot(long longIndex, long value) {
+ long l = readLong(longIndex);
+ long l2 = l & ~value;
+ writeLong(longIndex, l2);
+ return this;
+ }
+
+ /**
+ * @throws IllegalArgumentException if {@code numberOfBits} is negative
+ */
+ @Override
+ public long setNextNContinuousClearBits(long fromIndex, int numberOfBits) {
+ if (numberOfBits > 64)
+ return setNextManyContinuousClearBits(fromIndex, numberOfBits);
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return setNextClearBit(fromIndex);
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+
+ long nTrailingOnes = ALL_ONES >>> (64 - numberOfBits);
+
+ long bitIndex = fromIndex;
+ long longIndex2 = longWithThisBit(bitIndex);
+ if (longIndex2 >= longLength)
+ return NOT_FOUND;
+ int bitsFromFirstWord = 64 - (((int) bitIndex) & 63);
+ long byteIndex2 = firstByte(longIndex2);
+ long w1, w2 = bytes.readLong(byteIndex2);
+ longLoop:
+ while (true) {
+ w1 = w2;
+ byteIndex2 += 8;
+ if (++longIndex2 < longLength) {
+ w2 = bytes.readLong(byteIndex2);
+
+ } else if (longIndex2 == longLength) {
+ w2 = ALL_ONES;
+
+ } else {
+ return NOT_FOUND;
+ }
+ long l;
+ // (1)
+ if (bitsFromFirstWord != 64) {
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ } else {
+ // special case, because if bitsFromFirstWord is 64
+ // w2 shift is overflowed
+ l = w1;
+ }
+ // (2)
+ if ((l & 1) != 0) {
+ long x = ~l;
+ if (x != 0) {
+ int trailingOnes = numberOfTrailingZeros(x);
+ bitIndex += trailingOnes;
+ // (3)
+ if ((bitsFromFirstWord -= trailingOnes) <= 0) {
+ bitsFromFirstWord += 64;
+ continue; // long loop
+ }
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ } else {
+ // all bits are ones, skip a whole word,
+ // bitsFromFirstWord not changed
+ bitIndex += 64;
+ continue; // long loop
+ }
+ }
+ while (true) {
+ if ((l & nTrailingOnes) == 0) {
+ long mask1 = nTrailingOnes << bitIndex;
+ bytes.writeLong(byteIndex2 - 8, w1 ^ mask1);
+ int bitsFromSecondWordToSwitch =
+ numberOfBits - bitsFromFirstWord;
+ if (bitsFromSecondWordToSwitch > 0) {
+ long mask2 = (singleBit(bitsFromSecondWordToSwitch)) - 1;
+ bytes.writeLong(byteIndex2, w2 ^ mask2);
+ }
+ return bitIndex;
+ }
+ // n > trailing zeros > 0
+ // > 0 ensured by block (2)
+ int trailingZeros = numberOfTrailingZeros(l);
+ bitIndex += trailingZeros;
+ // (4)
+ if ((bitsFromFirstWord -= trailingZeros) <= 0) {
+ bitsFromFirstWord += 64;
+ continue longLoop;
+ }
+ // (5)
+ // subtractions (3) and (4) together ensure that
+ // bitsFromFirstWord != 64, => no need in condition like (1)
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ long x = ~l;
+ if (x != 0) {
+ int trailingOnes = numberOfTrailingZeros(x);
+ bitIndex += trailingOnes;
+ if ((bitsFromFirstWord -= trailingOnes) <= 0) {
+ bitsFromFirstWord += 64;
+ continue longLoop;
+ }
+ // same as (5)
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ } else {
+ // all bits are ones, skip a whole word,
+ // bitsFromFirstWord not changed
+ bitIndex += 64;
+ continue longLoop;
+ }
+ }
+ }
+ }
+
+ private long setNextManyContinuousClearBits(long fromIndex, int numberOfBits) {
+ long size = size();
+ long testFromIndex = fromIndex;
+ while (true) {
+ long limit = fromIndex + numberOfBits;
+ if (limit > size)
+ return NOT_FOUND;
+ long needToBeZerosUntil = limit - 1;
+ long lastSetBit = previousSetBit(needToBeZerosUntil, testFromIndex);
+ if (lastSetBit == NOT_FOUND) {
+ set(fromIndex, limit);
+ return fromIndex;
+ }
+ fromIndex = lastSetBit + 1;
+ testFromIndex = limit;
+ }
+ }
+
+ /**
+ * @throws IllegalArgumentException if {@code numberOfBits} is out of range {@code 0 <
+ * numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long clearNextNContinuousSetBits(long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return clearNextSetBit(fromIndex);
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+
+ long nTrailingOnes = ALL_ONES >>> (64 - numberOfBits);
+
+ long bitIndex = fromIndex;
+ long longIndex2 = longWithThisBit(bitIndex);
+ if (longIndex2 >= longLength)
+ return NOT_FOUND;
+ int bitsFromFirstWord = 64 - (((int) bitIndex) & 63);
+ long byteIndex2 = firstByte(longIndex2);
+ long w1, w2 = bytes.readLong(byteIndex2);
+ longLoop:
+ while (true) {
+ w1 = w2;
+ byteIndex2 += 8;
+ if (++longIndex2 < longLength) {
+ w2 = bytes.readLong(byteIndex2);
+
+ } else if (longIndex2 == longLength) {
+ w2 = 0L;
+
+ } else {
+ return NOT_FOUND;
+ }
+ long l;
+ // (1)
+ if (bitsFromFirstWord != 64) {
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ } else {
+ // special case, because if bitsFromFirstWord is 64
+ // w2 shift is overflowed
+ l = w1;
+ }
+ // (2)
+ if ((l & 1) == 0) {
+ if (l != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ bitIndex += trailingZeros;
+ // (3)
+ if ((bitsFromFirstWord -= trailingZeros) <= 0) {
+ bitsFromFirstWord += 64;
+ continue; // long loop
+ }
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ } else {
+ // all bits are zeros, skip a whole word,
+ // bitsFromFirstWord not changed
+ bitIndex += 64;
+ continue; // long loop
+ }
+ }
+ while (true) {
+ if (((~l) & nTrailingOnes) == 0) {
+ long mask1 = nTrailingOnes << bitIndex;
+ bytes.writeLong(byteIndex2 - 8, w1 ^ mask1);
+ int bitsFromSecondWordToSwitch =
+ numberOfBits - bitsFromFirstWord;
+ if (bitsFromSecondWordToSwitch > 0) {
+ long mask2 = (singleBit(bitsFromSecondWordToSwitch)) - 1;
+ bytes.writeLong(byteIndex2, w2 ^ mask2);
+ }
+ return bitIndex;
+ }
+ // n > trailing ones > 0
+ // > 0 ensured by block (2)
+ int trailingOnes = numberOfTrailingZeros(~l);
+ bitIndex += trailingOnes;
+ // (4)
+ if ((bitsFromFirstWord -= trailingOnes) <= 0) {
+ bitsFromFirstWord += 64;
+ continue longLoop;
+ }
+ // (5)
+ // subtractions (3) and (4) together ensure that
+ // bitsFromFirstWord != 64, => no need in condition like (1)
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ if (l != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ bitIndex += trailingZeros;
+ if ((bitsFromFirstWord -= trailingZeros) <= 0) {
+ bitsFromFirstWord += 64;
+ continue longLoop;
+ }
+ // same as (5)
+ l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord);
+
+ } else {
+ // all bits are zeros, skip a whole word,
+ // bitsFromFirstWord not changed
+ bitIndex += 64;
+ continue longLoop;
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws IllegalArgumentException if {@code numberOfBits} is out of range {@code 0 <
+ * numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long setPreviousNContinuousClearBits(
+ long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return setPreviousClearBit(fromIndex);
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+
+ int n64Complement = 64 - numberOfBits;
+ long nLeadingOnes = higherBitsIncludingThis(n64Complement);
+
+ long higherBitBound = fromIndex + 1;
+ long lowLongIndex = longWithThisBit(fromIndex);
+ if (lowLongIndex >= longLength) {
+ lowLongIndex = longLength - 1;
+ higherBitBound = longLength << 6;
+ }
+ int bitsFromLowWord = (64 - (((int) higherBitBound) & 63)) & 63;
+ long lowByteIndex = firstByte(lowLongIndex);
+ // low word, high word
+ long hw, lw = bytes.readLong(lowByteIndex);
+ longLoop:
+ while (true) {
+ hw = lw;
+ lowByteIndex -= 8;
+ if (--lowLongIndex >= 0) {
+ lw = bytes.readLong(lowByteIndex);
+
+ } else if (lowLongIndex == -1) {
+ lw = ALL_ONES;
+
+ } else {
+ return NOT_FOUND;
+ }
+ long l;
+ if (bitsFromLowWord != 0) { // (1)
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ } else {
+ // all bits from high word, special case needed because
+ // higherBitBound is multiple of 64 and lw not shifted away
+ l = hw;
+ }
+ // (2)
+ if (l < 0) { // condition means the highest bit is one
+ long x = ~l;
+ if (x != 0) {
+ int leadingOnes = numberOfLeadingZeros(x);
+ higherBitBound -= leadingOnes;
+ bitsFromLowWord += leadingOnes; // (3)
+ int flw;
+ if ((flw = bitsFromLowWord - 64) >= 0) {
+ bitsFromLowWord = flw;
+ continue; // long loop
+ }
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ } else {
+ // all bits are ones, skip a whole word,
+ // bitsFromLowWord not changed
+ higherBitBound -= 64;
+ continue; // long loop
+ }
+ }
+ while (true) {
+ if ((l & nLeadingOnes) == 0) {
+ long hMask = nLeadingOnes >>> bitsFromLowWord;
+ bytes.writeLong(lowByteIndex + 8, hw ^ hMask);
+ // bitsFromLow - (64 - n) = n - (64 - bitsFromLow) =
+ // = n - bitsFromHigh
+ int bitsFromLowWordToSwitch =
+ bitsFromLowWord - n64Complement;
+ if (bitsFromLowWordToSwitch > 0) {
+ long lMask = ~(ALL_ONES >>> bitsFromLowWordToSwitch);
+ bytes.writeLong(lowByteIndex, lw ^ lMask);
+ }
+ return higherBitBound - numberOfBits;
+ }
+ // n > leading zeros > 0
+ // > 0 ensured by block (2)
+ int leadingZeros = numberOfLeadingZeros(l);
+ higherBitBound -= leadingZeros;
+ bitsFromLowWord += leadingZeros; // (4)
+ int flw;
+ if ((flw = bitsFromLowWord - 64) >= 0) {
+ bitsFromLowWord = flw;
+ continue longLoop;
+ }
+ // (5)
+ // additions (3) and (4) together ensure that
+ // bitsFromFirstWord > 0, => no need in condition like (1)
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ long x = ~l;
+ if (x != 0) {
+ int leadingOnes = numberOfLeadingZeros(x);
+ higherBitBound -= leadingOnes;
+ bitsFromLowWord += leadingOnes;
+ if ((flw = bitsFromLowWord - 64) >= 0) {
+ bitsFromLowWord = flw;
+ continue longLoop;
+ }
+ // same as (5)
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ } else {
+ // all bits are ones, skip a whole word,
+ // bitsFromLowWord not changed
+ higherBitBound -= 64;
+ continue longLoop;
+ }
+ }
+ }
+ }
+
+ /**
+ * @throws IllegalArgumentException if {@code numberOfBits} is out of range {@code 0 <
+ * numberOfBits && numberOfBits <= 64}
+ */
+ @Override
+ public long clearPreviousNContinuousSetBits(
+ long fromIndex, int numberOfBits) {
+ checkNumberOfBits(numberOfBits);
+ if (numberOfBits == 1)
+ return clearPreviousSetBit(fromIndex);
+ if (checkNotFoundIndex(fromIndex))
+ return NOT_FOUND;
+
+ int n64Complement = 64 - numberOfBits;
+ long nLeadingOnes = higherBitsIncludingThis(n64Complement);
+
+ long higherBitBound = fromIndex + 1;
+ long lowLongIndex = longWithThisBit(fromIndex);
+ if (lowLongIndex >= longLength) {
+ lowLongIndex = longLength - 1;
+ higherBitBound = longLength << 6;
+ }
+ int bitsFromLowWord = (64 - (((int) higherBitBound) & 63)) & 63;
+ long lowByteIndex = firstByte(lowLongIndex);
+ // low word, high word
+ long hw, lw = bytes.readLong(lowByteIndex);
+ longLoop:
+ while (true) {
+ hw = lw;
+ lowByteIndex -= 8;
+ if (--lowLongIndex >= 0) {
+ lw = bytes.readLong(lowByteIndex);
+
+ } else if (lowLongIndex == -1) {
+ lw = 0L;
+
+ } else {
+ return NOT_FOUND;
+ }
+ long l;
+ if (bitsFromLowWord != 0) { // (1)
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ } else {
+ // all bits from high word, special case needed because
+ // higherBitBound is multiple of 64 and lw not shifted away
+ l = hw;
+ }
+ // (2)
+ if (l > 0) { // condition means the highest bit is zero, but not all
+ int leadingZeros = numberOfLeadingZeros(l);
+ higherBitBound -= leadingZeros;
+ bitsFromLowWord += leadingZeros; // (3)
+ int flw;
+ if ((flw = bitsFromLowWord - 64) >= 0) {
+ bitsFromLowWord = flw;
+ continue; // long loop
+ }
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ } else if (l == 0) {
+ // all bits are zeros, skip a whole word,
+ // bitsFromLowWord not changed
+ higherBitBound -= 64;
+ continue; // long loop
+ }
+ while (true) {
+ if (((~l) & nLeadingOnes) == 0) {
+ long hMask = nLeadingOnes >>> bitsFromLowWord;
+ bytes.writeLong(lowByteIndex + 8, hw ^ hMask);
+ // bitsFromLow - (64 - n) = n - (64 - bitsFromLow) =
+ // = n - bitsFromHigh
+ int bitsFromLowWordToSwitch =
+ bitsFromLowWord - n64Complement;
+ if (bitsFromLowWordToSwitch > 0) {
+ long lMask = ~(ALL_ONES >>> bitsFromLowWordToSwitch);
+ bytes.writeLong(lowByteIndex, lw ^ lMask);
+ }
+ return higherBitBound - numberOfBits;
+ }
+ // n > leading ones > 0
+ // > 0 ensured by block (2)
+ int leadingOnes = numberOfLeadingZeros(~l);
+ higherBitBound -= leadingOnes;
+ bitsFromLowWord += leadingOnes; // (4)
+ int flw;
+ if ((flw = bitsFromLowWord - 64) >= 0) {
+ bitsFromLowWord = flw;
+ continue longLoop;
+ }
+ // (5)
+ // additions (3) and (4) together ensure that
+ // bitsFromFirstWord > 0, => no need in condition like (1)
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ if (l != 0) {
+ int leadingZeros = numberOfLeadingZeros(l);
+ higherBitBound -= leadingZeros;
+ bitsFromLowWord += leadingZeros;
+ if ((flw = bitsFromLowWord - 64) >= 0) {
+ bitsFromLowWord = flw;
+ continue longLoop;
+ }
+ // same as (5)
+ l = (lw >>> higherBitBound) | (hw << bitsFromLowWord);
+
+ } else {
+ // all bits are zeros, skip a whole word,
+ // bitsFromLowWord not changed
+ higherBitBound -= 64;
+ continue longLoop;
+ }
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("SingleThreadedBitSet{");
+ sb.append("size=" + size());
+ sb.append(", cardinality=" + cardinality());
+ sb.append(", bits=[");
+ for (long i = 0L; i < longLength; i++) {
+ sb.append(Long.toBinaryString(readLong(i)));
+ }
+ sb.append("]}");
+ return sb.toString();
+ }
+
+ private class SetBits implements Bits {
+ private final long byteLength = longLength << 3;
+ private long byteIndex = 0;
+ private long bitIndex = -1;
+ private long currentWord = bytes.readLong(0);
+
+ @Override
+ public long next() {
+ long l;
+ if ((l = currentWord) != 0) {
+ int trailingZeros = numberOfTrailingZeros(l);
+ currentWord = (l >>> trailingZeros) >>> 1;
+ return bitIndex += trailingZeros + 1;
+ }
+ for (long i = byteIndex, lim = byteLength; (i += 8) < lim; ) {
+ if ((l = bytes.readLong(i)) != 0) {
+ byteIndex = i;
+ int trailingZeros = numberOfTrailingZeros(l);
+ currentWord = (l >>> trailingZeros) >>> 1;
+ return bitIndex = (i << 3) + trailingZeros;
+ }
+ }
+ currentWord = 0;
+ byteIndex = byteLength;
+ return -1;
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/collection/impl/HugeArrayImpl.java b/lang/src/main/java/net/openhft/lang/collection/impl/HugeArrayImpl.java
index 97cf6dc..e3ac007 100644
--- a/lang/src/main/java/net/openhft/lang/collection/impl/HugeArrayImpl.java
+++ b/lang/src/main/java/net/openhft/lang/collection/impl/HugeArrayImpl.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection.impl;
@@ -21,7 +21,7 @@ import net.openhft.lang.io.DirectBytes;
import net.openhft.lang.io.DirectStore;
import net.openhft.lang.model.Byteable;
import net.openhft.lang.model.Copyable;
-import net.openhft.lang.model.DataValueGenerator;
+import net.openhft.lang.model.DataValueClasses;
import java.util.ArrayList;
import java.util.List;
@@ -31,29 +31,26 @@ import java.util.List;
*/
public class HugeArrayImpl<T> implements HugeArray<T> {
private static final int MAX_SIZE = 10;
-
- private final DataValueGenerator valueGenerator;
private final Class<T> tClass;
private final long length;
private final int size;
private final DirectStore store;
private final List<T> freeList = new ArrayList<T>(MAX_SIZE);
- public HugeArrayImpl(DataValueGenerator valueGenerator, Class<T> tClass, long length) {
- this.valueGenerator = valueGenerator;
+ public HugeArrayImpl(Class<T> tClass, long length) {
this.tClass = tClass;
this.length = length;
- T ref = valueGenerator.nativeInstance(tClass);
+ T ref = DataValueClasses.newDirectReference(tClass);
size = ((Byteable) ref).maxSize();
- store = new DirectStore(null, length * size);
- ((Byteable) ref).bytes(store.createSlice());
+ store = DirectStore.allocate(length * size);
+ ((Byteable) ref).bytes(store.bytes(), 0L);
recycle(ref);
}
private T createRef() {
- T ref = valueGenerator.nativeInstance(tClass);
- ((Byteable) ref).bytes(store.createSlice());
+ T ref = DataValueClasses.newDirectReference(tClass);
+ ((Byteable) ref).bytes(store.bytes(), 0L);
return ref;
}
@@ -65,13 +62,19 @@ public class HugeArrayImpl<T> implements HugeArray<T> {
@Override
public T get(long index) {
T t = acquire();
- DirectBytes bytes = (DirectBytes) ((Byteable) t).bytes();
+ Byteable byteable = (Byteable) t;
+ DirectBytes bytes = (DirectBytes) byteable.bytes();
bytes.positionAndSize(index * size, size);
return t;
}
@Override
public void get(long index, T element) {
+ if (tClass.isInstance(element)) {
+ DirectBytes bytes = (DirectBytes) ((Byteable) element).bytes();
+ bytes.positionAndSize(index * size, size);
+ return;
+ }
T t = acquire();
DirectBytes bytes = (DirectBytes) ((Byteable) t).bytes();
bytes.positionAndSize(index * size, size);
diff --git a/lang/src/main/java/net/openhft/lang/collection/impl/HugeQueueImpl.java b/lang/src/main/java/net/openhft/lang/collection/impl/HugeQueueImpl.java
index 620efc9..60b3fbc 100644
--- a/lang/src/main/java/net/openhft/lang/collection/impl/HugeQueueImpl.java
+++ b/lang/src/main/java/net/openhft/lang/collection/impl/HugeQueueImpl.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection.impl;
diff --git a/lang/src/main/java/net/openhft/lang/io/AbstractBytes.java b/lang/src/main/java/net/openhft/lang/io/AbstractBytes.java
index e167835..15a0279 100755
--- a/lang/src/main/java/net/openhft/lang/io/AbstractBytes.java
+++ b/lang/src/main/java/net/openhft/lang/io/AbstractBytes.java
@@ -1,66 +1,76 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
import net.openhft.lang.Jvm;
import net.openhft.lang.Maths;
-import net.openhft.lang.io.serialization.BytesMarshallable;
-import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.io.serialization.BytesMarshallableSerializer;
import net.openhft.lang.io.serialization.BytesMarshallerFactory;
-import net.openhft.lang.io.serialization.CompactBytesMarshaller;
-import net.openhft.lang.io.serialization.impl.NoMarshaller;
+import net.openhft.lang.io.serialization.JDKZObjectSerializer;
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.io.serialization.impl.StringBuilderPool;
import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
+import net.openhft.lang.io.view.BytesInputStream;
+import net.openhft.lang.io.view.BytesOutputStream;
+import net.openhft.lang.model.Byteable;
+import net.openhft.lang.pool.EnumInterner;
import net.openhft.lang.pool.StringInterner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.*;
+import java.lang.reflect.Field;
import java.math.BigInteger;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
+import static java.lang.Long.numberOfTrailingZeros;
+
/**
* @author peter.lawrey
*/
@SuppressWarnings("MagicNumber")
public abstract class AbstractBytes implements Bytes {
- public static final long BUSY_LOCK_LIMIT = 10L * 1000 * 1000 * 1000;
- public static final int INT_LOCK_MASK = 0xFFFFFF;
- public static final int UNSIGNED_BYTE_MASK = 0xFF;
- public static final int UNSIGNED_SHORT_MASK = 0xFFFF;
+ public static final int END_OF_BUFFER = -1;
public static final long UNSIGNED_INT_MASK = 0xFFFFFFFFL;
+ public static final int SLEEP_THRESHOLD = 20 * 1000 * 1000;
+ // todo add tests before using in ChronicleMap
+ static final int RW_LOCK_LIMIT = 30;
+ static final long RW_READ_LOCKED = 1L << 0;
+ static final long RW_WRITE_WAITING = 1L << RW_LOCK_LIMIT;
+ static final long RW_WRITE_LOCKED = 1L << 2 * RW_LOCK_LIMIT;
+ static final int RW_LOCK_MASK = (1 << RW_LOCK_LIMIT) - 1;
+ static final char[] HEXI_DECIMAL = "0123456789ABCDEF".toCharArray();
+ private static final long BUSY_LOCK_LIMIT = 20L * 1000 * 1000 * 1000;
+ private static final int INT_LOCK_MASK;
+ private static final int UNSIGNED_BYTE_MASK = 0xFF;
+ private static final int UNSIGNED_SHORT_MASK = 0xFFFF;
+ private static final int USHORT_EXTENDED = UNSIGNED_SHORT_MASK;
// extra 1 for decimal place.
- static final int MAX_NUMBER_LENGTH = 1 + (int) Math.ceil(Math.log10(Long.MAX_VALUE));
- static final byte[] RADIX_PARSE = new byte[256];
-
- static {
- Arrays.fill(RADIX_PARSE, (byte) -1);
- for (int i = 0; i < 10; i++)
- RADIX_PARSE['0' + i] = (byte) i;
- for (int i = 0; i < 26; i++)
- RADIX_PARSE['A' + i] = RADIX_PARSE['a' + i] = (byte) (i + 10);
- }
-
- private static final Logger LOGGER = Logger.getLogger(AbstractBytes.class.getName());
+ private static final int MAX_NUMBER_LENGTH = 1 + (int) Math.ceil(Math.log10(Long.MAX_VALUE));
+ private static final byte[] RADIX_PARSE = new byte[256];
+ //private static final Logger LOGGER = Logger.getLogger(AbstractBytes.class.getName());
private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
private static final byte[] MIN_VALUE_TEXT = ("" + Long.MIN_VALUE).getBytes();
private static final byte[] Infinity = "Infinity".getBytes();
@@ -73,39 +83,49 @@ public abstract class AbstractBytes implements Bytes {
private static final short SHORT_MIN_VALUE = Short.MIN_VALUE;
private static final short SHORT_EXTENDED = Short.MIN_VALUE + 1;
private static final short SHORT_MAX_VALUE = Short.MIN_VALUE + 2;
- private static final int USHORT_EXTENDED = UNSIGNED_SHORT_MASK;
// RandomDataInput
private static final int INT_MIN_VALUE = Integer.MIN_VALUE;
private static final int INT_EXTENDED = Integer.MIN_VALUE + 1;
private static final int INT_MAX_VALUE = Integer.MIN_VALUE + 2;
private static final long MAX_VALUE_DIVIDE_10 = Long.MAX_VALUE / 10;
- private static final byte NULL = 'N';
- private static final byte ENUMED = 'E';
- private static final byte SERIALIZED = 'S';
private static final byte[] RADIX = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
- static boolean ID_LIMIT_WARNED = false;
+ private static final StringBuilderPool sbp = new StringBuilderPool();
+ private static final ThreadLocal<DateCache> dateCacheTL = new ThreadLocal<DateCache>();
+ private static final FastStringOperations STRING_OPS = createFastStringOperations();
+ private static boolean ID_LIMIT_WARNED = false;
+
+ static {
+ Arrays.fill(RADIX_PARSE, (byte) -1);
+ for (int i = 0; i < 10; i++)
+ RADIX_PARSE['0' + i] = (byte) i;
+ for (int i = 0; i < 26; i++)
+ RADIX_PARSE['A' + i] = RADIX_PARSE['a' + i] = (byte) (i + 10);
+ INT_LOCK_MASK = 0xFFFFFF;
+ }
+
+ final AtomicInteger refCount;
private final byte[] numberBuffer = new byte[MAX_NUMBER_LENGTH];
protected boolean finished;
- protected BytesMarshallerFactory bytesMarshallerFactory;
+ volatile Thread singleThread = null;
+ private ObjectSerializer objectSerializer;
private StringInterner stringInterner = null;
- private BytesInputStream inputStream = null;
- private BytesOutputStream outputStream = null;
- private StringBuilder utfReader = null;
- private SimpleDateFormat dateFormat = null;
- private long lastDay = Long.MIN_VALUE;
- @Nullable
- private byte[] lastDateStr = null;
+ private boolean selfTerminating = false;
- protected AbstractBytes() {
- this(new VanillaBytesMarshallerFactory());
+ AbstractBytes() {
+ this(new VanillaBytesMarshallerFactory(), new AtomicInteger(1));
}
- protected AbstractBytes(BytesMarshallerFactory bytesMarshallerFactory) {
+ AbstractBytes(BytesMarshallerFactory bytesMarshallerFactory, AtomicInteger refCount) {
+ this(BytesMarshallableSerializer.create(bytesMarshallerFactory, JDKZObjectSerializer.INSTANCE), refCount);
+ }
+
+ AbstractBytes(ObjectSerializer objectSerializer, AtomicInteger refCount) {
this.finished = false;
- this.bytesMarshallerFactory = bytesMarshallerFactory;
+ this.refCount = refCount;
+ setObjectSerializer(objectSerializer);
}
- static boolean equalsCaseIgnore(StringBuilder sb, String s) {
+ private static boolean equalsCaseIgnore(StringBuilder sb, String s) {
if (sb.length() != s.length())
return false;
for (int i = 0; i < s.length(); i++)
@@ -171,21 +191,490 @@ public abstract class AbstractBytes implements Bytes {
}
private static void warnIdLimit(long id) {
- LOGGER.log(Level.WARNING, "High thread id may result in collisions id: " + id);
+ LoggerHolder.LOGGER.log(Level.WARNING, "High thread id may result in collisions id: " + id);
ID_LIMIT_WARNED = true;
}
- protected StringInterner stringInterner() {
+ static int returnOrThrowEndOfBuffer(boolean selfTerminating) {
+ if (selfTerminating) return END_OF_BUFFER;
+ throw new BufferUnderflowException();
+ }
+
+ public static void readUTF2(Bytes bytes, @NotNull Appendable appendable, int utflen, int count) throws IOException {
+ while (count < utflen) {
+ int c = bytes.readUnsignedByte();
+ switch (c >> 4) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ /* 0xxxxxxx */
+ count++;
+ appendable.append((char) c);
+ break;
+
+ case 12:
+ case 13: {
+ /* 110x xxxx 10xx xxxx */
+ count += 2;
+ if (count > utflen)
+ throw new UTFDataFormatException(
+ "malformed input: partial character at end");
+ int char2 = bytes.readUnsignedByte();
+ if ((char2 & 0xC0) != 0x80)
+ throw new UTFDataFormatException(
+ "malformed input around byte " + count + " was " + char2);
+ int c2 = (char) (((c & 0x1F) << 6) |
+ (char2 & 0x3F));
+ appendable.append((char) c2);
+ break;
+ }
+
+ case 14: {
+ /* 1110 xxxx 10xx xxxx 10xx xxxx */
+ count += 3;
+ if (count > utflen)
+ throw new UTFDataFormatException(
+ "malformed input: partial character at end");
+ int char2 = bytes.readUnsignedByte();
+ int char3 = bytes.readUnsignedByte();
+
+ if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+ throw new UTFDataFormatException(
+ "malformed input around byte " + (count - 1) + " was " + char2 + " " + char3);
+ int c3 = (char) (((c & 0x0F) << 12) |
+ ((char2 & 0x3F) << 6) |
+ (char3 & 0x3F));
+ appendable.append((char) c3);
+ break;
+ }
+
+ default:
+ /* 10xx xxxx, 1111 xxxx */
+ throw new UTFDataFormatException(
+ "malformed input around byte " + count);
+ }
+ }
+ }
+
+ public static long findUTFLength(@NotNull CharSequence str) {
+ if (str instanceof String)
+ return findUTFLength((String) str);
+ int strlen = str.length();
+ long utflen = strlen;
+
+ for (int i = 0; i < strlen; i++) {
+ char c = str.charAt(i);
+ if ((c > 0x007F)) {
+ if (c > 0x07FF) {
+ utflen += 2;
+
+ } else {
+ utflen += 1;
+ }
+ }
+ }
+ return utflen;
+ }
+
+ public static long findUTFLength(@NotNull CharSequence str, int strlen) {
+ long utflen = 0L;
+
+ for (int i = 0; i < strlen; ++i) {
+ long c = (long) str.charAt(i);
+ if (c >= 0L && c <= 127L) {
+ ++utflen;
+ } else if (c > 2047L) {
+ utflen += 3L;
+ } else {
+ utflen += 2L;
+ }
+ }
+
+ return utflen;
+ }
+
+ public static long findUTFLength(@NotNull String str) {
+ return STRING_OPS.getUtf8EncodedStringLength(str);
+ }
+
+ private static FastStringOperations createFastStringOperations() {
+ try {
+ return new FastStringOperations16();
+ } catch (Exception e) {
+ // do nothing
+ }
+
+ try {
+ return new FastStringOperations17();
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static void writeUTF0(Bytes bytes, @NotNull CharSequence str, int strlen) {
+ if (bytes instanceof DirectBytes) {
+ DirectBytes db = (DirectBytes) bytes;
+ if (str instanceof String)
+ writeUTF1(db, STRING_OPS.extractChars((String) str), strlen);
+ else
+ writeUTF1(db, str, strlen);
+ } else {
+ writeUTF1(bytes, str, strlen);
+ }
+ }
+
+ static void writeUTF1(DirectBytes bytes, @NotNull CharSequence str, int strlen) {
+ int c;
+ int i;
+ for (i = 0; i < strlen; i++) {
+ c = str.charAt(i);
+ if (!((c >= 0x0000) && (c <= 0x007F)))
+// if (c + Integer.MIN_VALUE - 1 <= Integer.MIN_VALUE + 0x007F-1)
+ break;
+ NativeBytes.UNSAFE.putByte(bytes.positionAddr + i, (byte) c);
+ }
+ bytes.skip(i);
+ if (i < strlen)
+ writeUTF2(bytes, str, strlen, i);
+ }
+
+ static void writeUTF1(DirectBytes bytes, @NotNull char[] chars, int strlen) {
+ int c;
+ int i;
+ ascii:
+ {
+ for (i = 0; i < strlen; i++) {
+ c = chars[i];
+ if (!((c >= 0x0000) && (c <= 0x007F)))
+ break ascii;
+ NativeBytes.UNSAFE.putByte(bytes.positionAddr + i, (byte) c);
+ }
+ bytes.skip(i);
+ return;
+ }
+ bytes.skip(i);
+ if (i < strlen)
+ writeUTF2(bytes, chars, strlen, i);
+ }
+
+ public static void writeUTF1(Bytes bytes, @NotNull CharSequence str, int strlen) {
+ int c;
+ int i;
+ for (i = 0; i < strlen; i++) {
+ c = str.charAt(i);
+ if (!((c >= 0x0000) && (c <= 0x007F)))
+ break;
+ bytes.write(c);
+ }
+ if (i < strlen)
+ writeUTF2(bytes, str, strlen, i);
+ }
+
+ private static void writeUTF2(Bytes bytes, CharSequence str, int strlen, int i) {
+ int c;
+ for (; i < strlen; i++) {
+ c = str.charAt(i);
+ writeUTFchar(bytes, c);
+ }
+ }
+
+ private static void writeUTFchar(Bytes bytes, int c) {
+ if ((c >= 0x0000) && (c <= 0x007F)) {
+ bytes.write(c);
+
+ } else if (c > 0x07FF) {
+ bytes.write((byte) (0xE0 | ((c >> 12) & 0x0F)));
+ bytes.write((byte) (0x80 | ((c >> 6) & 0x3F)));
+ bytes.write((byte) (0x80 | (c & 0x3F)));
+
+ } else {
+ bytes.write((byte) (0xC0 | ((c >> 6) & 0x1F)));
+ bytes.write((byte) (0x80 | c & 0x3F));
+ }
+ }
+
+ private static void writeUTF2(Bytes bytes, char[] str, int strlen, int i) {
+ int c;
+ for (; i < strlen; i++) {
+ c = str[i];
+ writeUTFchar(bytes, c);
+ }
+ }
+
+ static void checkArrayOffs(int arrayLength, int off, int len) {
+ if ((len | off) < 0 | ((off + len) & 0xffffffffL) > arrayLength)
+ throw new IndexOutOfBoundsException();
+ }
+
+ /**
+ * display the hex data of {@link Bytes} from the position() to the limit()
+ *
+ * @param buffer the buffer you wish to toString()
+ * @return hex representation of the buffer, from example [0D ,OA, FF]
+ */
+ public static String toHex(@NotNull final Bytes buffer) {
+ if (buffer.remaining() == 0)
+ return "";
+
+ final Bytes slice = buffer.slice();
+ final StringBuilder builder = new StringBuilder("[");
+
+ while (slice.remaining() > 0) {
+ final byte b = slice.readByte();
+ builder.append(((char) b) + "(" + String.format("%02X ", b).trim() + ")");
+ builder.append(",");
+ }
+
+ // remove the last comma
+ builder.deleteCharAt(builder.length() - 1);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /**
+ * display the buffer as a string
+ *
+ * @param buffer the buffer you wish to toString()
+ * @return hex representation of the buffer, from example [0D ,OA, FF]
+ */
+ public static String toString(@NotNull final Bytes buffer) {
+ final Bytes slice = buffer.slice();
+ final StringBuilder builder = new StringBuilder("");
+
+ while (slice.remaining() > 0) {
+ final byte b = slice.readByte();
+ builder.append((char) b);
+ }
+ return builder.toString();
+ }
+
+ static int rwReadLocked(long lock) {
+ return (int) (lock & RW_LOCK_MASK);
+ }
+
+ static int rwWriteWaiting(long lock) {
+ return (int) ((lock >>> RW_LOCK_LIMIT) & RW_LOCK_MASK);
+ }
+
+ static int rwWriteLocked(long lock) {
+ return (int) (lock >>> (2 * RW_LOCK_LIMIT));
+ }
+
+ public static String toHexString(@NotNull final Bytes bytes, long offset, long len) throws BufferUnderflowException {
+ if (len == 0)
+ return "";
+
+ int width = 16;
+ int[] lastLine = new int[width];
+ String sep = "";
+ long position = bytes.position();
+ long limit = bytes.limit();
+
+ try {
+
+ bytes.limit(offset + len);
+ bytes.position(offset);
+
+ final StringBuilder builder = new StringBuilder();
+ long start = offset / width * width;
+ long end = (offset + len + width - 1) / width * width;
+ for (long i = start; i < end; i += width) {
+ // check for duplicate rows
+ if (i + width < end) {
+ boolean same = true;
+
+ for (int j = 0; j < width && i + j < offset + len; j++) {
+ int ch = bytes.readUnsignedByte(i + j);
+ same &= (ch == lastLine[j]);
+ lastLine[j] = ch;
+ }
+ if (i > start && same) {
+ sep = "........\n";
+ continue;
+ }
+ }
+ builder.append(sep);
+ sep = "";
+ String str = Long.toHexString(i);
+ for (int j = str.length(); j < 8; j++)
+ builder.append('0');
+ builder.append(str);
+ for (int j = 0; j < width; j++) {
+ if (j == width / 2)
+ builder.append(' ');
+ if (i + j < start || i + j >= offset + len) {
+ builder.append(" ");
+
+ } else {
+ builder.append(' ');
+ int ch = bytes.readUnsignedByte(i + j);
+ builder.append(HEXI_DECIMAL[ch >> 4]);
+ builder.append(HEXI_DECIMAL[ch & 15]);
+ }
+ }
+ builder.append(' ');
+ for (int j = 0; j < width; j++) {
+ if (j == width / 2)
+ builder.append(' ');
+ if (i + j < start || i + j >= offset + len) {
+ builder.append(' ');
+
+ } else {
+ int ch = bytes.readUnsignedByte(i + j);
+ if (ch < ' ' || ch > 126)
+ ch = '\u00B7';
+ builder.append((char) ch);
+ }
+ }
+ builder.append("\n");
+ }
+ return builder.toString();
+ } finally {
+ bytes.limit(limit);
+ bytes.position(position);
+ }
+ }
+
+ protected void setObjectSerializer(ObjectSerializer objectSerializer) {
+ this.objectSerializer = objectSerializer;
+ }
+
+ /**
+ * clearing the volatile singleThread is a write barrier.
+ */
+ @Override
+ public void clearThreadAssociation() {
+ singleThread = null;
+ }
+
+ boolean checkSingleThread() {
+ Thread t = Thread.currentThread();
+ if (singleThread != t)
+ setThreadOrThrowException(t);
+ return true;
+ }
+
+ private void setThreadOrThrowException(Thread t) {
+ if (singleThread == null)
+ singleThread = t;
+ else
+ throw new IllegalStateException("Altered by thread " + singleThread + " and " + t);
+ }
+
+ public void readUTF0(@NotNull Appendable appendable, int utflen)
+ throws IOException {
+ int count = 0;
+
+ while (count < utflen) {
+ int c = readUnsignedByteOrThrow();
+ if (c >= 128) {
+ position(position() - 1);
+ readUTF2(this, appendable, utflen, count);
+ break;
+ }
+ count++;
+ appendable.append((char) c);
+ }
+ }
+
+ @Override
+ public boolean read8bitText(@NotNull StringBuilder stringBuilder) throws StreamCorruptedException {
+ long len = readStopBit();
+ if (len < 1) {
+ stringBuilder.setLength(0);
+ if (len == -1)
+ return false;
+ if (len == 0)
+ return true;
+ throw new StreamCorruptedException("UTF length invalid " + len + " remaining: " + remaining());
+ }
+ if (len > remaining() || len > Integer.MAX_VALUE)
+ throw new StreamCorruptedException("UTF length invalid " + len + " remaining: " + remaining());
+ int ilen = (int) len;
+ for (int i = 0; i < ilen; i++)
+ stringBuilder.append((char) readUnsignedByte());
+ return true;
+ }
+
+ @Override
+ public void write8bitText(@Nullable CharSequence s) {
+ if (s == null) {
+ writeStopBit(-1);
+ return;
+ }
+ writeStopBit(s.length());
+ for (int i = 0; i < s.length(); i++)
+ writeUnsignedByte(s.charAt(i));
+ }
+
+ @Override
+ public long size() {
+ return capacity();
+ }
+
+ @Override
+ public void free() {
+ throw new UnsupportedOperationException("Forcing a free() via Bytes is unsafe, try reserve() + release()");
+ }
+
+ @Override
+ public void reserve() {
+ if (refCount.get() < 1) throw new IllegalStateException();
+ refCount.incrementAndGet();
+ }
+
+ @Override
+ public boolean release() {
+ if (refCount.get() < 1) throw new IllegalStateException();
+ if (refCount.decrementAndGet() > 0) return false;
+ cleanup();
+ return true;
+ }
+
+ protected abstract void cleanup();
+
+ @Override
+ public int refCount() {
+ return refCount.get();
+ }
+
+ StringInterner stringInterner() {
if (stringInterner == null)
stringInterner = new StringInterner(8 * 1024);
return stringInterner;
}
@Override
+ public void selfTerminating(boolean selfTerminating) {
+ this.selfTerminating = selfTerminating;
+ }
+
+ // RandomDataOutput
+
+ @Override
+ public boolean selfTerminating() {
+ return selfTerminating;
+ }
+
+ @Override
+ public int readUnsignedByteOrThrow() throws BufferUnderflowException {
+ return readByteOrThrow(selfTerminating);
+ }
+
+ public int readByteOrThrow(boolean selfTerminating) throws BufferUnderflowException {
+ return remaining() < 1 ? returnOrThrowEndOfBuffer(selfTerminating) : readUnsignedByte();
+ }
+
+ @Override
public Boolean parseBoolean(@NotNull StopCharTester tester) {
- StringBuilder sb = acquireUtfReader();
- parseUTF(sb, tester);
+ StringBuilder sb = acquireStringBuilder();
+ parseUtf8(sb, tester);
if (sb.length() == 0)
return null;
switch (sb.charAt(0)) {
@@ -215,16 +704,18 @@ public abstract class AbstractBytes implements Bytes {
}
@Override
+ public void readFully(@NotNull char[] data) {
+ readFully(data, 0, data.length);
+ }
+
+ @Override
public int skipBytes(int n) {
- long position = position();
- int n2 = (int) Math.min(n, capacity() - position);
- position(position + n2);
- return n2;
+ return (int) skip(n);
}
@Override
public boolean readBoolean() {
- return readByte() != 0;
+ return readByteOrThrow(false) != 0;
}
@Override
@@ -255,11 +746,12 @@ public abstract class AbstractBytes implements Bytes {
@NotNull
@Override
public String readLine() {
- StringBuilder input = acquireUtfReader();
+ StringBuilder input = acquireStringBuilder();
EOL:
while (position() < capacity()) {
- int c = readUnsignedByte();
+ int c = readUnsignedByteOrThrow();
switch (c) {
+ case END_OF_BUFFER:
case '\n':
break EOL;
case '\r':
@@ -278,14 +770,17 @@ public abstract class AbstractBytes implements Bytes {
@Nullable
@Override
public String readUTFΔ() {
- if (readUTFΔ(acquireUtfReader()))
+ StringBuilder utfReader = acquireStringBuilder();
+ if (readUTFΔ(utfReader))
return utfReader.length() == 0 ? "" : stringInterner().intern(utfReader);
return null;
}
+ // locking at it temporarily changes position.
+ // todo write a version without changing the position.
@Nullable
@Override
- public String readUTFΔ(long offset) throws IllegalStateException {
+ public synchronized String readUTFΔ(long offset) throws IllegalStateException {
long position = position();
try {
position(offset);
@@ -295,15 +790,9 @@ public abstract class AbstractBytes implements Bytes {
}
}
- // RandomDataOutput
-
@NotNull
- private StringBuilder acquireUtfReader() {
- if (utfReader == null)
- utfReader = new StringBuilder();
- else
- utfReader.setLength(0);
- return utfReader;
+ private StringBuilder acquireStringBuilder() {
+ return sbp.acquireStringBuilder();
}
@Override
@@ -319,93 +808,27 @@ public abstract class AbstractBytes implements Bytes {
@SuppressWarnings("MagicNumber")
private boolean appendUTF0(@NotNull Appendable appendable) throws IOException {
long len = readStopBit();
- if (len < -1 || len > Integer.MAX_VALUE)
- throw new StreamCorruptedException("UTF length invalid " + len);
if (len == -1)
return false;
+ else if (len == 0)
+ return true;
+ if (len < -1 || len > remaining())
+ throw new StreamCorruptedException("UTF length invalid " + len + " remaining: " + remaining());
int utflen = (int) len;
readUTF0(appendable, utflen);
return true;
}
- private void readUTF0(@NotNull Appendable appendable, int utflen) throws IOException {
- int count = 0;
- while (count < utflen) {
- int c = readByte();
- if (c < 0) {
- position(position() - 1);
- break;
- }
- count++;
- appendable.append((char) c);
- }
-
- while (count < utflen) {
- int c = readUnsignedByte();
- switch (c >> 4) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- /* 0xxxxxxx */
- count++;
- appendable.append((char) c);
- break;
- case 12:
- case 13: {
- /* 110x xxxx 10xx xxxx */
- count += 2;
- if (count > utflen)
- throw new UTFDataFormatException(
- "malformed input: partial character at end");
- int char2 = readUnsignedByte();
- if ((char2 & 0xC0) != 0x80)
- throw new UTFDataFormatException(
- "malformed input around byte " + count);
- int c2 = (char) (((c & 0x1F) << 6) |
- (char2 & 0x3F));
- appendable.append((char) c2);
- break;
- }
- case 14: {
- /* 1110 xxxx 10xx xxxx 10xx xxxx */
- count += 3;
- if (count > utflen)
- throw new UTFDataFormatException(
- "malformed input: partial character at end");
- int char2 = readUnsignedByte();
- int char3 = readUnsignedByte();
-
- if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
- throw new UTFDataFormatException(
- "malformed input around byte " + (count - 1));
- int c3 = (char) (((c & 0x0F) << 12) |
- ((char2 & 0x3F) << 6) |
- (char3 & 0x3F));
- appendable.append((char) c3);
- break;
- }
- default:
- /* 10xx xxxx, 1111 xxxx */
- throw new UTFDataFormatException(
- "malformed input around byte " + count);
- }
- }
- }
-
@NotNull
@Override
- public String parseUTF(@NotNull StopCharTester tester) {
- parseUTF(acquireUtfReader(), tester);
+ public String parseUtf8(@NotNull StopCharTester tester) {
+ StringBuilder utfReader = acquireStringBuilder();
+ parseUtf8(utfReader, tester);
return stringInterner().intern(utfReader);
}
@Override
- public void parseUTF(@NotNull StringBuilder builder, @NotNull StopCharTester tester) {
+ public void parseUtf8(@NotNull StringBuilder builder, @NotNull StopCharTester tester) {
builder.setLength(0);
try {
readUTF0(builder, tester);
@@ -415,19 +838,23 @@ public abstract class AbstractBytes implements Bytes {
}
private void readUTF0(@NotNull Appendable appendable, @NotNull StopCharTester tester) throws IOException {
- while (remaining() > 0) {
- int c = readByte();
- if (c < 0) {
+ while (true) {
+ int c = readUnsignedByteOrThrow();
+ if (c >= 128) {
position(position() - 1);
+ readUTF2(appendable, tester);
break;
}
if (tester.isStopChar(c))
return;
appendable.append((char) c);
}
+ }
- while (remaining() > 0) {
- int c = readUnsignedByte();
+ // used by Chronicle Map 3.x
+ public void readUTF2(@NotNull Appendable appendable, @NotNull StopCharTester tester) throws IOException {
+ while (true) {
+ int c = readUnsignedByteOrThrow();
switch (c >> 4) {
case 0:
case 1:
@@ -442,6 +869,7 @@ public abstract class AbstractBytes implements Bytes {
return;
appendable.append((char) c);
break;
+
case 12:
case 13: {
/* 110x xxxx 10xx xxxx */
@@ -456,9 +884,9 @@ public abstract class AbstractBytes implements Bytes {
appendable.append((char) c2);
break;
}
+
case 14: {
/* 1110 xxxx 10xx xxxx 10xx xxxx */
-
int char2 = readUnsignedByte();
int char3 = readUnsignedByte();
@@ -473,6 +901,7 @@ public abstract class AbstractBytes implements Bytes {
appendable.append((char) c3);
break;
}
+
default:
/* 10xx xxxx, 1111 xxxx */
throw new UTFDataFormatException(
@@ -491,7 +920,7 @@ public abstract class AbstractBytes implements Bytes {
@Override
public boolean skipTo(@NotNull StopCharTester tester) {
while (remaining() > 0) {
- int ch = readByte();
+ int ch = readUnsignedByteOrThrow();
if (tester.isStopChar(ch))
return true;
}
@@ -503,7 +932,8 @@ public abstract class AbstractBytes implements Bytes {
public String readUTF() {
try {
int len = readUnsignedShort();
- readUTF0(acquireUtfReader(), len);
+ StringBuilder utfReader = acquireStringBuilder();
+ readUTF0(utfReader, len);
return utfReader.length() == 0 ? "" : stringInterner().intern(utfReader);
} catch (IOException unexpected) {
throw new AssertionError(unexpected);
@@ -622,16 +1052,47 @@ public abstract class AbstractBytes implements Bytes {
}
@Override
+ public long readIncompleteLong(long offset) {
+ long left = remaining();
+ if (left >= 8)
+ return readLong(offset);
+ if (left == 4)
+ return readInt(offset);
+ long l = 0;
+ for (int i = 0, remaining = (int) left; i < remaining; i++) {
+ l |= (long) readUnsignedByte(offset + i) << (i * 8);
+ }
+ return l;
+ }
+
+ @Override
public long readStopBit() {
- long l = 0, b;
- int count = 0;
+ long l;
+ if ((l = readByte()) >= 0)
+ return l;
+ return readStopBit0(l);
+ }
+
+ private long readStopBit0(long l) {
+ l &= 0x7FL;
+ long b;
+ int count = 7;
while ((b = readByte()) < 0) {
l |= (b & 0x7FL) << count;
count += 7;
}
- if (b == 0 && count > 0)
+ if (b != 0) {
+ if (count > 56)
+ throw new IllegalStateException(
+ "Cannot read more than 9 stop bits of positive value");
+ return l | (b << count);
+
+ } else {
+ if (count > 63)
+ throw new IllegalStateException(
+ "Cannot read more than 10 stop bits of negative value");
return ~l;
- return l | (b << count);
+ }
}
@Override
@@ -644,7 +1105,12 @@ public abstract class AbstractBytes implements Bytes {
@Override
public void read(@NotNull ByteBuffer bb) {
- int len = (int) Math.min(bb.remaining(), remaining());
+ read(bb, bb.remaining());
+ }
+
+ @Override
+ public void read(@NotNull ByteBuffer bb, int length) {
+ int len = (int) Math.min(length, remaining());
if (bb.order() == byteOrder()) {
while (len >= 8) {
bb.putLong(readLong());
@@ -660,24 +1126,22 @@ public abstract class AbstractBytes implements Bytes {
// // RandomOutputStream
@Override
public void write(@NotNull byte[] bytes) {
- int length = bytes.length;
- checkWrite(length);
- write(bytes, 0, length);
+ write(bytes, 0, bytes.length);
}
- private void checkWrite(int length) {
+ private void checkWrite(long length) {
if (length > remaining())
throw new IllegalStateException("Cannot write " + length + " only " + remaining() + " remaining");
}
@Override
public void writeBoolean(boolean v) {
- write(v ? -1 : 0);
+ write(v ? 'Y' : 0);
}
@Override
public void writeBoolean(long offset, boolean v) {
- writeByte(offset, v ? -1 : 0);
+ writeByte(offset, v ? 'Y' : 0);
}
@Override
@@ -689,50 +1153,58 @@ public abstract class AbstractBytes implements Bytes {
@Override
public void writeChars(@NotNull String s) {
- int len = s.length();
+ writeChars((CharSequence) s);
+ }
+
+ @Override
+ public void writeChars(@NotNull CharSequence cs) {
+ int len = cs.length();
for (int i = 0; i < len; i++)
- writeChar(s.charAt(i));
+ writeChar(cs.charAt(i));
}
@Override
public void writeUTF(@NotNull String str) {
- long strlen = str.length();
- long utflen = findUTFLength(str, strlen);
+ long utflen = findUTFLength(str);
if (utflen > 65535)
throw new IllegalStateException("String too long " + utflen + " when encoded, max: 65535");
writeUnsignedShort((int) utflen);
- writeUTF0(str, strlen);
+ checkUFTLength(utflen);
+ writeUTF0(this, str, str.length());
}
@Override
- public void writeUTFΔ(@Nullable CharSequence str) {
+ public void writeUTFΔ(@Nullable CharSequence str) throws IllegalArgumentException {
if (str == null) {
writeStopBit(-1);
return;
}
- long strlen = str.length();
- long utflen = findUTFLength(str, strlen);
+ long utflen = findUTFLength(str);
writeStopBit(utflen);
- writeUTF0(str, strlen);
+ checkUFTLength(utflen);
+ writeUTF0(this, str, str.length());
}
+ // locking at it temporarily changes position.
+ // todo write a version without changing the position.
@Override
- public void writeUTFΔ(long offset, int maxSize, @Nullable CharSequence s) throws IllegalStateException {
+ public synchronized void writeUTFΔ(long offset, int maxSize, @Nullable CharSequence s) throws IllegalStateException {
assert maxSize > 1;
- if (s == null) {
- writeStopBit(-1);
- return;
- }
- long strlen = s.length();
- long utflen = findUTFLength(s, strlen);
- long totalSize = IOTools.stopBitLength(utflen) + utflen;
- if (totalSize > maxSize)
- throw new IllegalStateException("Attempted to write " + totalSize + " byte String, when only " + maxSize + " allowed");
long position = position();
try {
position(offset);
+ if (s == null) {
+ writeStopBit(-1);
+ return;
+ }
+ long utflen = findUTFLength(s);
+ long totalSize = IOTools.stopBitLength(utflen) + utflen;
+ if (totalSize > maxSize)
+ throw new IllegalStateException("Attempted to write " + totalSize + " byte String, when only " + maxSize + " allowed");
+
writeStopBit(utflen);
- writeUTF0(s, strlen);
+ writeUTF0(this, s, s.length());
+ zeroOut(position(), offset + maxSize);
} finally {
position(position);
}
@@ -740,56 +1212,15 @@ public abstract class AbstractBytes implements Bytes {
@NotNull
public ByteStringAppender append(@NotNull CharSequence str) {
- if (str == null)
- return this;
- long strlen = str.length();
- writeUTF0(str, strlen);
+ int strlen = str.length();
+ writeUTF0(this, str, strlen);
return this;
}
- private long findUTFLength(@NotNull CharSequence str, long strlen) {
- long utflen = 0, c;/* use charAt instead of copying String to char array */
- for (int i = 0; i < strlen; i++) {
- c = str.charAt(i);
- if ((c >= 0x0000) && (c <= 0x007F)) {
- utflen++;
- } else if (c > 0x07FF) {
- utflen += 3;
- } else {
- utflen += 2;
- }
- }
-
+ private void checkUFTLength(long utflen) throws IllegalArgumentException {
if (utflen > remaining())
throw new IllegalArgumentException(
"encoded string too long: " + utflen + " bytes, remaining=" + remaining());
- return utflen;
- }
-
- private void writeUTF0(@NotNull CharSequence str, long strlen) {
- int c;
- int i;
- for (i = 0; i < strlen; i++) {
- c = str.charAt(i);
- if (!((c >= 0x0000) && (c <= 0x007F)))
- break;
- write(c);
- }
-
- for (; i < strlen; i++) {
- c = str.charAt(i);
- if ((c >= 0x0000) && (c <= 0x007F)) {
- write(c);
-
- } else if (c > 0x07FF) {
- write((byte) (0xE0 | ((c >> 12) & 0x0F)));
- write((byte) (0x80 | ((c >> 6) & 0x3F)));
- write((byte) (0x80 | (c & 0x3F)));
- } else {
- write((byte) (0xC0 | ((c >> 6) & 0x1F)));
- write((byte) (0x80 | c & 0x3F));
- }
- }
}
@Override
@@ -815,14 +1246,49 @@ public abstract class AbstractBytes implements Bytes {
}
@Override
+ public void write(long offset, Bytes bytes) {
+ long length = bytes.remaining();
+ checkWrite(length);
+ long i;
+ for (i = 0; i < length - 7; i += 8)
+ writeLong(offset + i, bytes.readLong());
+ for (; i < length; i++)
+ writeByte(offset + i, bytes.readByte());
+ }
+
+ @Override
public void write(byte[] bytes, int off, int len) {
- checkWrite(bytes.length);
+ checkArrayOffs(bytes.length, off, len);
+ checkWrite(len);
for (int i = 0; i < len; i++)
write(bytes[off + i]);
}
@Override
+ public void write(long offset, byte[] bytes, int off, int len) {
+ checkArrayOffs(bytes.length, off, len);
+ checkWrite(len);
+
+ for (int i = 0; i < len; i++)
+ writeByte(offset + i, bytes[off + i]);
+ }
+
+ @Override
+ public void write(@NotNull char[] data) {
+ write(data, 0, data.length);
+ }
+
+ @Override
+ public void write(@NotNull char[] data, int off, int len) {
+ checkArrayOffs(data.length, off, len);
+ checkWrite(len * 2);
+
+ for (int i = 0; i < len; i++)
+ writeChar(data[off + i]);
+ }
+
+ @Override
public void writeUnsignedShort(int v) {
writeShort(v);
}
@@ -841,6 +1307,7 @@ public abstract class AbstractBytes implements Bytes {
case Short.MIN_VALUE:
writeByte(BYTE_MIN_VALUE);
break;
+
case Short.MAX_VALUE:
writeByte(BYTE_MAX_VALUE);
break;
@@ -855,6 +1322,7 @@ public abstract class AbstractBytes implements Bytes {
public void writeCompactUnsignedShort(int v) {
if (v >= 0 && v < USHORT_EXTENDED) {
writeByte(v);
+
} else {
writeUnsignedShort(USHORT_EXTENDED);
writeUnsignedShort(v);
@@ -866,6 +1334,7 @@ public abstract class AbstractBytes implements Bytes {
if (byteOrder() == ByteOrder.BIG_ENDIAN) {
writeUnsignedByte(v >>> 16);
writeUnsignedShort(v);
+
} else {
writeUnsignedByte(v);
writeUnsignedShort(v >>> 8);
@@ -877,6 +1346,7 @@ public abstract class AbstractBytes implements Bytes {
if (byteOrder() == ByteOrder.BIG_ENDIAN) {
writeUnsignedByte(offset, v >>> 16);
writeUnsignedShort(offset + 1, v);
+
} else {
writeUnsignedByte(offset, v);
writeUnsignedShort(offset + 1, v >>> 8);
@@ -902,6 +1372,7 @@ public abstract class AbstractBytes implements Bytes {
case Integer.MIN_VALUE:
writeShort(SHORT_MIN_VALUE);
break;
+
case Integer.MAX_VALUE:
writeShort(SHORT_MAX_VALUE);
break;
@@ -916,6 +1387,7 @@ public abstract class AbstractBytes implements Bytes {
public void writeCompactUnsignedInt(long v) {
if (v >= 0 && v < USHORT_EXTENDED) {
writeShort((int) v);
+
} else {
writeShort(USHORT_EXTENDED);
writeUnsignedInt(v);
@@ -927,6 +1399,7 @@ public abstract class AbstractBytes implements Bytes {
if (byteOrder() == ByteOrder.BIG_ENDIAN) {
writeUnsignedShort((int) (v >>> 32));
writeUnsignedInt(v);
+
} else {
writeUnsignedShort((int) v);
writeUnsignedInt(v >>> 16);
@@ -938,6 +1411,7 @@ public abstract class AbstractBytes implements Bytes {
if (byteOrder() == ByteOrder.BIG_ENDIAN) {
writeUnsignedShort(offset, (int) (v >>> 32));
writeUnsignedInt(offset + 2, v);
+
} else {
writeUnsignedShort(offset, (int) v);
writeUnsignedInt(offset + 2, v >>> 16);
@@ -958,31 +1432,42 @@ public abstract class AbstractBytes implements Bytes {
} else {
writeInt(INT_EXTENDED);
writeLong(v);
-
}
}
@Override
public void writeStopBit(long n) {
+ if ((n & ~0x7F) == 0) {
+ write((int) (n & 0x7f));
+ return;
+ }
+ if ((n & ~0x3FFF) == 0) {
+ write((int) ((n & 0x7f) | 0x80));
+ write((int) (n >> 7));
+ return;
+ }
+ writeStopBit0(n);
+ }
+
+ private void writeStopBit0(long n) {
boolean neg = false;
if (n < 0) {
neg = true;
n = ~n;
}
- while (true) {
- long n2 = n >>> 7;
- if (n2 != 0) {
- writeByte((byte) (0x80 | (n & 0x7F)));
- n = n2;
- } else {
- if (neg) {
- writeByte((byte) (0x80 | (n & 0x7F)));
- writeByte(0);
- } else {
- writeByte((byte) (n & 0x7F));
- }
- break;
- }
+
+ long n2;
+ while ((n2 = n >>> 7) != 0) {
+ write((byte) (0x80L | n));
+ n = n2;
+ }
+ // final byte
+ if (!neg) {
+ write((byte) n);
+
+ } else {
+ write((byte) (0x80L | n));
+ write(0);
}
}
@@ -991,6 +1476,7 @@ public abstract class AbstractBytes implements Bytes {
float f = (float) v;
if (f == v) {
writeFloat(f);
+
} else {
writeFloat(Float.NaN);
writeDouble(v);
@@ -1006,23 +1492,7 @@ public abstract class AbstractBytes implements Bytes {
writeByte(bb.get());
}
- @Deprecated
- @Override
- public void writeStartToPosition(@NotNull Bytes bb) {
- final long position = bb.position();
- long offset = 0;
- if (position > remaining())
- throw new IndexOutOfBoundsException("Trying to write " + position + " when only " + remaining() + " left");
- // TODO optimise this to use Unsafe copy memory
- while (position - offset >= 8) {
- writeLong(bb.readLong(offset));
- offset += 8;
- }
- while (position - offset >= 1)
- writeByte(bb.readByte(offset++));
- }
-
- // // ByteStringAppender
+ // ByteStringAppender
@NotNull
@Override
public ByteStringAppender append(@NotNull CharSequence s, int start, int end) {
@@ -1105,18 +1575,19 @@ public abstract class AbstractBytes implements Bytes {
@NotNull
@Override
public ByteStringAppender appendDateMillis(long timeInMS) {
- if (dateFormat == null) {
- dateFormat = new SimpleDateFormat("yyyy/MM/dd");
- dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+ DateCache dateCache = dateCacheTL.get();
+ if (dateCache == null) {
+ dateCacheTL.set(dateCache = new DateCache());
}
long date = timeInMS / 86400000;
- if (lastDay != date) {
- lastDateStr = dateFormat.format(new Date(timeInMS)).getBytes(ISO_8859_1);
- lastDay = date;
+ if (dateCache.lastDay != date) {
+ dateCache.lastDateStr = dateCache.dateFormat.format(new Date(timeInMS)).getBytes(ISO_8859_1);
+ dateCache.lastDay = date;
+
} else {
- assert lastDateStr != null;
+ assert dateCache.lastDateStr != null;
}
- write(lastDateStr);
+ write(dateCache.lastDateStr);
return this;
}
@@ -1168,13 +1639,16 @@ public abstract class AbstractBytes implements Bytes {
if (exp == 0 && mantissa == 0) {
writeByte('0');
return this;
+
} else if (exp == 2047) {
if (mantissa == 0) {
write(Infinity);
+
} else {
write(NaN);
}
return this;
+
} else if (exp > 0) {
mantissa += 1L << 52;
}
@@ -1283,8 +1757,26 @@ public abstract class AbstractBytes implements Bytes {
int exp = 0;
boolean negative = false;
int decimalPlaces = Integer.MIN_VALUE;
+ int ch = readUnsignedByteOrThrow();
+ switch (ch) {
+ case 'N':
+ if (compareRest("aN"))
+ return Double.NaN;
+ skip(-1);
+ return Double.NaN;
+ case 'I':
+ if (compareRest("nfinity"))
+ return Double.POSITIVE_INFINITY;
+ skip(-1);
+ return Double.NaN;
+ case '-':
+ if (compareRest("Infinity"))
+ return Double.NEGATIVE_INFINITY;
+ negative = true;
+ ch = readUnsignedByteOrThrow();
+ break;
+ }
while (true) {
- byte ch = readByte();
if (ch >= '0' && ch <= '9') {
while (value >= MAX_VALUE_DIVIDE_10) {
value >>>= 1;
@@ -1292,18 +1784,31 @@ public abstract class AbstractBytes implements Bytes {
}
value = value * 10 + (ch - '0');
decimalPlaces++;
- } else if (ch == '-') {
- negative = true;
+
} else if (ch == '.') {
decimalPlaces = 0;
+
} else {
break;
}
+ ch = readUnsignedByteOrThrow();
}
return asDouble(value, exp, negative, decimalPlaces);
}
+ protected boolean compareRest(String s) {
+ if (s.length() > remaining())
+ return false;
+ long position = position();
+ for (int i = 0; i < s.length(); i++) {
+ if (readUnsignedByte(position + i) != s.charAt(i))
+ return false;
+ }
+ skip(s.length());
+ return true;
+ }
+
@NotNull
@Override
public <E> ByteStringAppender append(@NotNull Iterable<E> list, @NotNull CharSequence separator) {
@@ -1321,7 +1826,7 @@ public abstract class AbstractBytes implements Bytes {
}
@NotNull
- public <E> ByteStringAppender append(@NotNull List<E> list, @NotNull CharSequence separator) {
+ <E> ByteStringAppender append(@NotNull List<E> list, @NotNull CharSequence separator) {
for (int i = 0; i < list.size(); i++) {
if (i > 0)
append(separator);
@@ -1338,15 +1843,18 @@ public abstract class AbstractBytes implements Bytes {
long num = 0, scale = Long.MIN_VALUE;
boolean negative = false;
while (true) {
- byte b = readByte();
+ int b = readUnsignedByteOrThrow();
// if (b >= '0' && b <= '9')
if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE) {
num = num * 10 + b - '0';
scale++;
+
} else if (b == '.') {
scale = 0;
+
} else if (b == '-') {
negative = true;
+
} else {
break;
}
@@ -1362,7 +1870,7 @@ public abstract class AbstractBytes implements Bytes {
long num = 0;
boolean negative = false;
while (true) {
- byte b = readByte();
+ int b = readUnsignedByteOrThrow();
// if (b >= '0' && b <= '9')
if ((b - ('0' + Integer.MIN_VALUE)) <= 9 + Integer.MIN_VALUE)
num = num * 10 + b - '0';
@@ -1381,10 +1889,11 @@ public abstract class AbstractBytes implements Bytes {
long num = 0;
boolean negative = false;
while (true) {
- byte b = readByte();
+ int b = readUnsignedByteOrThrow();
byte rp = RADIX_PARSE[b];
if (rp >= 0 && rp < base) {
num = num * base + rp;
+
} else if (b == '-')
negative = true;
else
@@ -1475,7 +1984,6 @@ public abstract class AbstractBytes implements Bytes {
if (num <= 0)
return 2;
numberBuffer[1] = (byte) (num % 10L + '0');
- num /= 10;
return 1;
}
@@ -1640,7 +2148,7 @@ public abstract class AbstractBytes implements Bytes {
@NotNull
@Override
public ByteStringAppender append(@NotNull MutableDecimal md) {
- StringBuilder sb = acquireUtfReader();
+ StringBuilder sb = acquireStringBuilder();
md.toString(sb);
append(sb);
return this;
@@ -1649,51 +2157,125 @@ public abstract class AbstractBytes implements Bytes {
@NotNull
@Override
public InputStream inputStream() {
- if (inputStream == null)
- inputStream = new BytesInputStream();
- return inputStream;
+ return new BytesInputStream(this);
}
@NotNull
@Override
public OutputStream outputStream() {
- if (outputStream == null)
- outputStream = new BytesOutputStream();
- return outputStream;
+ return new BytesOutputStream(this);
}
@NotNull
@Override
- public BytesMarshallerFactory bytesMarshallerFactory() {
- return bytesMarshallerFactory == null ? bytesMarshallerFactory = new VanillaBytesMarshallerFactory() : bytesMarshallerFactory;
+ public ObjectSerializer objectSerializer() {
+ return objectSerializer;
}
@SuppressWarnings("unchecked")
@Override
public <E> void writeEnum(@Nullable E e) {
- Class aClass;
- if (e == null || e instanceof CharSequence)
- aClass = String.class;
- else
- aClass = (Class) e.getClass();
- BytesMarshaller<E> em = bytesMarshallerFactory().acquireMarshaller(aClass, true);
- em.write(this, e);
+ if (e == null) {
+ write8bitText(null);
+ return;
+ }
+ if (e instanceof CharSequence) {
+ write8bitText((CharSequence) e);
+ return;
+ }
+ if (e instanceof Enum) {
+ write8bitText(e.toString());
+ return;
+ }
+
+ Class aClass = (Class) e.getClass();
+ writeInstance(aClass, e);
+ }
+
+ @Override
+ public void writeEnum(long offset, int len, Object e) {
+ long pos = position();
+ long lim = limit();
+ try {
+ position(offset);
+ limit(offset + len);
+ writeEnum(e);
+ } finally {
+ limit(lim);
+ position(pos);
+ }
}
@SuppressWarnings("unchecked")
@Override
public <E> E readEnum(@NotNull Class<E> eClass) {
- BytesMarshaller<E> em = bytesMarshallerFactory().acquireMarshaller(eClass, true);
- return em.read(this);
+ if (Enum.class.isAssignableFrom(eClass))
+ return (E) readEnum2((Class<Enum>) (Class) eClass);
+ if (String.class.isAssignableFrom(eClass))
+ return (E) readUTFΔ();
+ return readInstance(eClass, null);
+ }
+
+ @Override
+ public <E> E readEnum(long offset, int maxSize, Class<E> eClass) {
+ long pos = position();
+ long lim = limit();
+ try {
+ position(offset);
+ limit(offset + maxSize);
+ if (Enum.class.isAssignableFrom(eClass))
+ return (E) readEnum2((Class<Enum>) (Class) eClass);
+ if (String.class.isAssignableFrom(eClass))
+ return (E) readUTFΔ();
+ return readInstance(eClass, null);
+ } finally {
+ limit(lim);
+ position(pos);
+ }
+ }
+
+ @Override
+ public long nextSetBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long maxBit = capacity() << 3;
+ long fromLongIndex = fromIndex & ~63;
+ if (fromLongIndex >= maxBit)
+ return -1;
+ long firstByte = fromLongIndex >>> 3;
+ if ((fromIndex & 63) != 0) {
+ long l = readVolatileLong(firstByte) >>> fromIndex;
+ if (l != 0) {
+ return fromIndex + numberOfTrailingZeros(l);
+ }
+ firstByte += 8;
+ }
+ for (long i = firstByte; i < capacity(); i += 8) {
+ long l = readLong(i);
+ if (l != 0)
+ return (i << 3) + numberOfTrailingZeros(l);
+ }
+ return -1;
+ }
+
+ private <E extends Enum<E>> E readEnum2(Class<E> eClass) {
+ try {
+ StringBuilder sb = acquireStringBuilder();
+ if (read8bitText(sb))
+ return EnumInterner.intern(eClass, sb);
+ return null;
+ } catch (StreamCorruptedException e) {
+ throw new IllegalStateException(e);
+ }
}
@SuppressWarnings("unchecked")
@Override
public <E extends Enum<E>> E parseEnum(@NotNull Class<E> eClass, @NotNull StopCharTester tester) {
- String text = parseUTF(tester);
+ String text = parseUtf8(tester);
if (text.isEmpty())
return null;
- return Enum.valueOf(eClass, text);
+ return EnumInterner.intern(eClass, text);
}
@Override
@@ -1714,11 +2296,13 @@ public abstract class AbstractBytes implements Bytes {
@Override
public <E> void readList(@NotNull Collection<E> list, @NotNull Class<E> eClass) {
- int len = (int) readStopBit();
+ long len = readStopBit();
+ if (len < 0 || len > Integer.MAX_VALUE)
+ throw new IllegalStateException("Invalid length: " + len);
list.clear();
for (int i = 0; i < len; i++) {
@SuppressWarnings("unchecked")
- E e = (E) readEnum(eClass);
+ E e = readEnum(eClass);
list.add(e);
}
}
@@ -1726,7 +2310,10 @@ public abstract class AbstractBytes implements Bytes {
@Override
@NotNull
public <K, V> Map<K, V> readMap(@NotNull Map<K, V> map, @NotNull Class<K> kClass, @NotNull Class<V> vClass) {
- int len = (int) readStopBit();
+ long len = readStopBit();
+ if (len < 0 || len > Integer.MAX_VALUE)
+ throw new IllegalStateException("Invalid length: " + len);
+
map.clear();
for (int i = 0; i < len; i++)
map.put(readEnum(kClass), readEnum(vClass));
@@ -1740,7 +2327,7 @@ public abstract class AbstractBytes implements Bytes {
@Override
public int read() {
- return remaining() > 0 ? readByte() : -1;
+ return remaining() > 0 ? readUnsignedByte() : -1;
}
@Override
@@ -1753,11 +2340,11 @@ public abstract class AbstractBytes implements Bytes {
@Override
public long skip(long n) {
- if (n < 0)
+ if (n < -position())
throw new IllegalArgumentException("Skip bytes out of range, was " + n);
if (n > remaining())
n = remaining();
- skipBytes((int) n);
+ position(position() + n);
return n;
}
@@ -1784,9 +2371,18 @@ public abstract class AbstractBytes implements Bytes {
}
@Override
- public void reset() {
+ public AbstractBytes clear() {
finished = false;
position(0L);
+ limit(capacity());
+ return this;
+ }
+
+ @Override
+ public Bytes flip() {
+ limit(position());
+ position(0);
+ return this;
}
@Override
@@ -1797,26 +2393,10 @@ public abstract class AbstractBytes implements Bytes {
@Nullable
@Override
public Object readObject() {
- byte type = readByte();
- switch (type) {
- case NULL:
- return null;
- case ENUMED: {
- Class clazz = readEnum(Class.class);
- return readEnum(clazz);
- }
- case SERIALIZED: {
- try {
- return new ObjectInputStream(this.inputStream()).readObject();
- } catch (Exception e) {
- throw new IllegalStateException(e);
- }
- }
- default:
- BytesMarshaller<Object> m = bytesMarshallerFactory().getMarshaller(type);
- if (m == null)
- throw new IllegalStateException("Unknown type " + (char) type);
- return m.read(this);
+ try {
+ return objectSerializer.readSerializable(this, null, null);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
}
}
@@ -1829,82 +2409,83 @@ public abstract class AbstractBytes implements Bytes {
throw new ClassCastException("Cannot convert " + o.getClass().getName() + " to " + tClass.getName() + " was " + o);
}
- @SuppressWarnings("unchecked")
+ @Nullable
@Override
- public void writeObject(@Nullable Object obj) {
- if (obj == null) {
- writeByte(NULL);
- return;
+ @SuppressWarnings("unchecked")
+ public <T> T readInstance(@NotNull Class<T> objClass, T obj) {
+ try {
+ return objectSerializer.readSerializable(this, objClass, obj);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
}
+ }
- Class<?> clazz = obj.getClass();
- final BytesMarshallerFactory bytesMarshallerFactory = bytesMarshallerFactory();
- BytesMarshaller em = bytesMarshallerFactory.acquireMarshaller(clazz, false);
- if (em == NoMarshaller.INSTANCE && autoGenerateMarshaller(obj))
- em = bytesMarshallerFactory.acquireMarshaller(clazz, true);
-
- if (em != NoMarshaller.INSTANCE) {
- if (em instanceof CompactBytesMarshaller) {
- writeByte(((CompactBytesMarshaller) em).code());
- em.write(this, obj);
- return;
- }
- writeByte(ENUMED);
- writeEnum(clazz);
- em.write(this, obj);
- return;
- }
- writeByte(SERIALIZED);
- // TODO this is the lame implementation, but it works.
+ @SuppressWarnings("unchecked")
+ @Override
+ public void writeObject(@Nullable Object obj) {
try {
- ObjectOutputStream oos = new ObjectOutputStream(this.outputStream());
- oos.writeObject(obj);
- } catch (IOException e) {
+ objectSerializer.writeSerializable(this, obj, null);
+ } catch (Exception e) {
throw new IllegalStateException(e);
}
checkEndOfBuffer();
}
- protected boolean autoGenerateMarshaller(Object obj) {
- return (obj instanceof Comparable && obj.getClass().getPackage().getName().startsWith("java"))
- || obj instanceof Externalizable
- || obj instanceof BytesMarshallable;
+ @Override
+ public <OBJ> void writeInstance(@NotNull Class<OBJ> objClass, @NotNull OBJ obj) {
+ try {
+ objectSerializer.writeSerializable(this, obj, objClass);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ checkEndOfBuffer();
}
@Override
public boolean tryLockInt(long offset) {
- long id = shortThreadId();
- return tryLockNanos4a(offset, (int) id);
+ return tryLockNanos4a(offset);
}
@Override
public boolean tryLockNanosInt(long offset, long nanos) {
- long id = shortThreadId();
int limit = nanos <= 10000 ? (int) nanos / 10 : 1000;
for (int i = 0; i < limit; i++)
- if (tryLockNanos4a(offset, (int) id))
+ if (tryLockNanos4a(offset))
return true;
if (nanos <= 10000)
return false;
long end = System.nanoTime() + nanos - 10000;
do {
- if (tryLockNanos4a(offset, (int) id))
+ if (tryLockNanos4a(offset))
return true;
} while (end > System.nanoTime() && !currentThread().isInterrupted());
return false;
}
- private boolean tryLockNanos4a(long offset, int id) {
+ private boolean tryLockNanos4a(long offset) {
+ //lowId = bottom 24 bytes of the thread id
int lowId = shortThreadId();
+ //Use the top 8 bytes as a counter, and the bottom 24 bytes as the thread id
int firstValue = ((1 << 24) | lowId);
+ //If the cas works, it was unlocked and we now atomically have the lock
if (compareAndSwapInt(offset, 0, firstValue))
return true;
- long currentValue = readUnsignedInt(offset);
+ //The cas failed so get the value of the current lock
+ int currentValue = readInt(offset);
+ //if the bottom 24 bytes match our thread id ...
+ // TODO but what if we're in a different process?
if ((currentValue & INT_LOCK_MASK) == lowId) {
- if (currentValue >= (255L << 24))
- throw new IllegalStateException("Reentred 255 times without an unlock");
+ //then if the counter in the top 8 bytes is 255, throw an exception
+ if ((currentValue >>> 24) >= 255)
+ throw new IllegalStateException("Reentered 255 times without an unlock - if you are using this to lock across processes, there could be a thread id conflict letting one process 'steal' the lock from another process. To avoid this, call AffinitySupport.setThreadId() during startup which will make all threads have unique ids");
+ //otherwise increase the counter in the top 8 bytes by one
currentValue += 1 << 24;
- writeOrderedInt(offset, (int) currentValue);
+ //and store it - no other threads can successfully write at this point
+ //because their cas will fail (the value is not 0), so no update concurrency
+ //conflict, but we do want other threads to read the value we write
+ writeOrderedInt(offset, currentValue);
+ //we've got the lock - and incremented it, so return true
+ return true;
}
return false;
}
@@ -1925,18 +2506,25 @@ public abstract class AbstractBytes implements Bytes {
int firstValue = ((1 << 24) | lowId);
if (compareAndSwapInt(offset, firstValue, 0))
return;
- // try to chek the lowId and the count.
+ // try to cheek the lowId and the count.
unlockFailedInt(offset, lowId);
}
- private Thread currentThread;
- private int shortThreadId = Integer.MIN_VALUE;
+ @Override
+ public void resetLockInt(long offset) {
+ writeOrderedInt(offset, 0);
+ }
+
+ @Override
+ public int threadIdForLockInt(long offset) {
+ return readVolatileInt(offset) & INT_LOCK_MASK;
+ }
- public int shortThreadId() {
- return shortThreadId > 0 ? shortThreadId : shortThreadId0();
+ int shortThreadId() {
+ return shortThreadId0();
}
- protected int shortThreadId0() {
+ int shortThreadId0() {
final int tid = (int) getId() & INT_LOCK_MASK;
if (!ID_LIMIT_WARNED && tid > 1 << 24) {
warnIdLimit(tid);
@@ -1944,13 +2532,8 @@ public abstract class AbstractBytes implements Bytes {
return tid;
}
- public void setCurrentThread() {
- currentThread = Thread.currentThread();
- shortThreadId = shortThreadId0();
- }
-
- public Thread currentThread() {
- return currentThread == null ? Thread.currentThread() : currentThread;
+ Thread currentThread() {
+ return Thread.currentThread();
}
@Override
@@ -1959,7 +2542,7 @@ public abstract class AbstractBytes implements Bytes {
return tryLockNanos8a(offset, id);
}
- public long uniqueTid() {
+ long uniqueTid() {
return Jvm.getUniqueTid(currentThread());
}
@@ -1972,11 +2555,41 @@ public abstract class AbstractBytes implements Bytes {
return true;
if (nanos <= 10000)
return false;
- long end = System.nanoTime() + nanos - 10000;
+ return tryLockNanosLong0(offset, nanos, id);
+ }
+
+ private boolean tryLockNanosLong0(long offset, long nanos, long id) {
+ long nanos0 = Math.min(nanos, SLEEP_THRESHOLD);
+ long start = System.nanoTime();
+ long end0 = start + nanos0 - 10000;
do {
if (tryLockNanos8a(offset, id))
return true;
- } while (end > System.nanoTime() && !currentThread().isInterrupted());
+ } while (end0 > System.nanoTime() && !currentThread().isInterrupted());
+
+ long end = start + nanos - SLEEP_THRESHOLD;
+ if (LoggerHolder.LOGGER.isLoggable(Level.FINE)) {
+ LoggerHolder.LOGGER.log(Level.FINE, Thread.currentThread().getName() + ", waiting for lock");
+ }
+
+ try {
+ do {
+ if (tryLockNanos8a(offset, id)) {
+ long millis = (System.nanoTime() - start) / 1000000;
+ if (millis > 200) {
+ LoggerHolder.LOGGER.log(Level.WARNING,
+ Thread.currentThread().getName() +
+ ", to obtain a lock took " +
+ millis / 1e3 + " seconds"
+ );
+ }
+ return true;
+ }
+ Thread.sleep(1);
+ } while (end > System.nanoTime());
+ } catch (InterruptedException ignored) {
+ Thread.currentThread().interrupt();
+ }
return false;
}
@@ -1985,9 +2598,16 @@ public abstract class AbstractBytes implements Bytes {
if (compareAndSwapLong(offset, 0, firstValue))
return true;
long currentValue = readLong(offset);
- if ((currentValue & (1L << 48) - 1) == id) {
+ long lockedId = currentValue & ((1L << 48) - 1);
+ if (lockedId == 0) {
+ int count = (int) (currentValue >>> 48);
+ if (count != 0)
+ LoggerHolder.LOGGER.log(Level.WARNING, "Lock held by threadId 0 !?");
+ return compareAndSwapLong(offset, currentValue, firstValue);
+ }
+ if (lockedId == id) {
if (currentValue >>> 48 == 65535)
- throw new IllegalStateException("Reentred 65535 times without an unlock");
+ throw new IllegalStateException("Reentered 65535 times without an unlock");
currentValue += 1L << 48;
writeOrderedLong(offset, currentValue);
return true;
@@ -2015,18 +2635,30 @@ public abstract class AbstractBytes implements Bytes {
unlockFailedLong(offset, id);
}
- protected long getId() {
+ @Override
+ public void resetLockLong(long offset) {
+ writeOrderedLong(offset, 0L);
+ }
+
+ @Override
+ public long threadIdForLockLong(long offset) {
+ return readVolatileLong(offset);
+ }
+
+ long getId() {
return currentThread().getId();
}
private void unlockFailedInt(long offset, int lowId) throws IllegalMonitorStateException {
- long currentValue = readUnsignedInt(offset);
+ long currentValue = readInt(offset);
long holderId = currentValue & INT_LOCK_MASK;
if (holderId == lowId) {
currentValue -= 1 << 24;
writeOrderedInt(offset, (int) currentValue);
+
} else if (currentValue == 0) {
- throw new IllegalMonitorStateException("No thread holds this lock");
+ LoggerHolder.LOGGER.log(Level.WARNING, "No thread holds this lock, threadId: " + shortThreadId());
+
} else {
throw new IllegalMonitorStateException("Thread " + holderId + " holds this lock, " + (currentValue >>> 24) + " times");
}
@@ -2038,8 +2670,10 @@ public abstract class AbstractBytes implements Bytes {
if (holderId == id) {
currentValue -= 1L << 48;
writeOrderedLong(offset, currentValue);
+
} else if (currentValue == 0) {
throw new IllegalMonitorStateException("No thread holds this lock");
+
} else {
throw new IllegalMonitorStateException("Process " + ((currentValue >>> 32) & 0xFFFF)
+ " thread " + (holderId & (-1L >>> 32))
@@ -2089,7 +2723,7 @@ public abstract class AbstractBytes implements Bytes {
public short addShort(long offset, short s) {
short s2 = readShort(offset);
s2 += s;
- writeByte(offset, s2);
+ writeShort(offset, s2);
return s2;
}
@@ -2198,20 +2832,19 @@ public abstract class AbstractBytes implements Bytes {
@Override
public int length() {
- return (int) Math.min(Integer.MAX_VALUE, remaining());
+ if (position() == 0)
+ return (int) Math.min(limit(), Integer.MAX_VALUE);
+ else if (position() == limit() || limit() == capacity())
+ return (int) Math.min(position(), Integer.MAX_VALUE);
+ else
+ throw new IllegalStateException();
}
@Override
public char charAt(int index) {
- return (char) readUnsignedByte(index);
- }
-
- @Override
- public CharSequence subSequence(int start, int end) {
- StringBuilder sb = new StringBuilder(end - start + 1);
- for (int i = start; i < end; i++)
- sb.append(charAt(i));
- return sb;
+ if (index < 0 || index >= length())
+ throw new IndexOutOfBoundsException();
+ return (char) readUnsignedByte(position() + index);
}
@Override
@@ -2225,99 +2858,407 @@ public abstract class AbstractBytes implements Bytes {
@Override
public void writeMarshallable(@NotNull Bytes out) {
out.write(this, position(), remaining());
+ }
+ @Override
+ public void write(RandomDataInput bytes) {
+ long toWrite = bytes.remaining();
+ write(bytes, bytes.position(), toWrite);
+ bytes.skip(toWrite);
}
@Override
- public void write(BytesCommon bytes, long position, long length) {
- if (length > bytes.remaining())
+ public void write(RandomDataInput bytes, long position, long length) {
+ if (length > remaining())
throw new IllegalArgumentException("Attempt to write " + length + " bytes with " + remaining() + " remaining");
- RandomDataInput rdi = (RandomDataInput) bytes;
if (bytes.byteOrder() == byteOrder()) {
while (length >= 8) {
- writeLong(rdi.readLong(position));
+ writeLong(bytes.readLong(position));
position += 8;
length -= 8;
}
}
while (length >= 1) {
- writeByte(rdi.readByte(position));
+ writeByte(bytes.readByte(position));
position++;
length--;
}
}
- protected class BytesInputStream extends InputStream {
- private long mark = 0;
+ @Override
+ public void write(@NotNull Byteable byteable) {
+ if (byteable.bytes() == null) {
+ throw new IllegalArgumentException("Attempt to write an unitialized Byteable object");
+ }
- @Override
- public int available() throws IOException {
- long remaining = remaining();
- return (int) Math.min(Integer.MAX_VALUE, remaining);
+ write(byteable.bytes(), byteable.offset(), byteable.maxSize());
+ }
+
+ @Override
+ public boolean startsWith(RandomDataInput input) {
+ return compare(position(), input, input.position(), input.remaining());
+ }
+
+ @Override
+ public boolean compare(long offset, RandomDataInput input, long inputOffset, long len) {
+ if (offset < 0 || inputOffset < 0 || len < 0)
+ throw new IndexOutOfBoundsException();
+ if (offset + len < 0 || offset + len > capacity() || inputOffset + len < 0 ||
+ inputOffset + len > input.capacity()) {
+ return false;
+ }
+ long i = 0L;
+ for (; i < len - 7L; i += 8L) {
+ if (readLong(offset + i) != input.readLong(inputOffset + i))
+ return false;
+ }
+ if (i < len - 3L) {
+ if (readInt(offset + i) != input.readInt(inputOffset + i))
+ return false;
+ i += 4L;
+ }
+ if (i < len - 1L) {
+ if (readChar(offset + i) != input.readChar(inputOffset + i))
+ return false;
+ i += 2L;
+ }
+ if (i < len) {
+ if (readByte(offset + i) != input.readByte(inputOffset + i))
+ return false;
}
+ return true;
+ }
- @Override
- public void close() throws IOException {
- finish();
+ @NotNull
+ @Override
+ public String toString() {
+ long remaining = remaining();
+ if (remaining < 0 || remaining > 1L << 48)
+ return "invalid remaining: " + remaining();
+ if (remaining > 1 << 20)
+ remaining = 1 << 20;
+ char[] chars = new char[(int) remaining];
+ long pos = position();
+ for (int i = 0; i < remaining; i++) {
+ chars[i] = (char) readUnsignedByte(i + pos);
}
+ return new String(chars);
+ }
- @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod")
- @Override
- public void mark(int readlimit) {
- mark = position();
+ @NotNull
+ @Override
+ public String toDebugString() {
+ return toDebugString(64);
+ }
+
+ @NotNull
+ @Override
+ public String toDebugString(long limit) {
+ StringBuilder sb = new StringBuilder(200);
+ sb.append("[pos: ").append(position()).append(", lim: ").append(limit()).append(", cap: ")
+ .append(capacity()).append(" ] ");
+ toString(sb, position() - limit, position(), position() + limit);
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toHexString(long limit) {
+ return toHexString(this, position(), Math.min(remaining(), limit));
+ }
+
+ @Override
+ public void toString(Appendable sb, long start, long position, long end) {
+ try {
+ // before
+ if (start < 0) start = 0;
+ if (position > start) {
+ for (long i = start; i < position; i++) {
+ append(sb, i);
+ }
+ sb.append('\u2016');
+ }
+ if (end > limit())
+ end = limit();
+ // after
+ for (long i = position; i < end; i++) {
+ append(sb, i);
+ }
+ } catch (IOException e) {
+ try {
+ sb.append(e.toString());
+ } catch (IOException e1) {
+ throw new AssertionError(e);
+ }
}
+ }
- @Override
- public boolean markSupported() {
- return true;
+ @Override
+ public ByteBuffer sliceAsByteBuffer(@Nullable ByteBuffer toReuse) {
+ throw new UnsupportedOperationException();
+ }
+
+ private void append(Appendable sb, long i) throws IOException {
+ int b = readUnsignedByte(i);
+ if (b == 0)
+ sb.append('\u0660');
+ else if (b < 21)
+ sb.append((char) (b + 0x2487));
+ else
+ sb.append((char) b);
+ }
+
+ @Override
+ public void asString(Appendable appendable) {
+ try {
+ for (long i = position(); i < limit(); i++)
+ append(appendable, i);
+ } catch (IOException e) {
+ throw new AssertionError(e);
}
+ }
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- return AbstractBytes.this.read(b, off, len);
+ @Override
+ public CharSequence asString() {
+ StringBuilder sb = new StringBuilder();
+ asString(sb);
+ return sb;
+ }
+
+ @Override
+ public boolean compareAndSwapDouble(long offset, double expected, double value) {
+ long exp = Double.doubleToRawLongBits(expected);
+ long val = Double.doubleToRawLongBits(value);
+ return compareAndSwapLong(offset, exp, val);
+ }
+
+ public File file() {
+ return null;
+ }
+
+ // read/write lock support.
+ // short path in a small method so it can be inlined.
+ public boolean tryRWReadLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ long lock = readVolatileLong(offset);
+ int writersWaiting = rwWriteWaiting(lock);
+ int writersLocked = rwWriteLocked(lock);
+ // readers wait for waiting writers
+ if (writersLocked <= 0 && writersWaiting <= 0) {
+ // increment readers locked.
+ int readersLocked = rwReadLocked(lock);
+ if (readersLocked >= RW_LOCK_MASK)
+ throw new IllegalStateException("readersLocked has reached a limit of " + readersLocked);
+ if (compareAndSwapLong(offset, lock, lock + RW_READ_LOCKED))
+ return true;
}
+ return tryRWReadLock0(offset, timeOutNS);
+ }
- @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod")
- @Override
- public void reset() throws IOException {
- position(mark);
+ private boolean tryRWReadLock0(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ long end = System.nanoTime() + timeOutNS;
+ // wait for no write locks, nor waiting writes.
+ for (; ; ) {
+ long lock = readVolatileLong(offset);
+ int writersWaiting = rwWriteWaiting(lock);
+ int writersLocked = rwWriteLocked(lock);
+ if (writersLocked <= 0 && writersWaiting <= 0) {
+ // increment readers locked.
+ int readersLocked = rwReadLocked(lock);
+ if (readersLocked >= RW_LOCK_MASK)
+ throw new IllegalStateException("readersLocked has reached a limit of " + readersLocked);
+ // add to the readLock count and decrease the readWaiting count.
+ if (compareAndSwapLong(offset, lock, lock + RW_READ_LOCKED))
+ return true;
+ }
+ if (System.nanoTime() > end)
+ return false;
+
+ if (currentThread().isInterrupted())
+ throw new InterruptedException("Unable to obtain lock, interrupted");
}
+ }
- @Override
- public long skip(long n) throws IOException {
- if (n > Integer.MAX_VALUE)
- throw new IOException("Skip too large");
- return skipBytes((int) n);
+ public boolean tryRWWriteLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ long lock = readVolatileLong(offset);
+ int readersLocked = rwReadLocked(lock);
+ int writersLocked = rwWriteLocked(lock);
+ // writers don't wait for waiting readers.
+ if (readersLocked <= 0 && writersLocked <= 0) {
+ if (compareAndSwapLong(offset, lock, lock + RW_WRITE_LOCKED))
+ return true;
}
+ return tryRWWriteLock0(offset, timeOutNS);
+ }
- @Override
- public int read() throws IOException {
- if (remaining() > 0)
- return readUnsignedByte();
- return -1;
+ private boolean tryRWWriteLock0(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ for (; ; ) {
+ long lock = readVolatileLong(offset);
+ int writersWaiting = rwWriteWaiting(lock);
+ if (writersWaiting >= RW_LOCK_MASK)
+ throw new IllegalStateException("writersWaiting has reached a limit of " + writersWaiting);
+ if (compareAndSwapLong(offset, lock, lock + RW_WRITE_WAITING))
+ break;
+ }
+ long end = System.nanoTime() + timeOutNS;
+ // wait for no write locks.
+ for (; ; ) {
+ long lock = readVolatileLong(offset);
+ int readersLocked = rwReadLocked(lock);
+ int writersWaiting = rwWriteWaiting(lock);
+ int writersLocked = rwWriteLocked(lock);
+ if (readersLocked <= 0 && writersLocked <= 0) {
+ // increment readers locked.
+ if (writersWaiting <= 0) {
+ System.err.println("writersWaiting has underflowed");
+ return false;
+ }
+ // add to the readLock count and decrease the readWaiting count.
+ if (compareAndSwapLong(offset, lock, lock + RW_WRITE_LOCKED - RW_WRITE_WAITING))
+ return true;
+ }
+ boolean interrupted = currentThread().isInterrupted();
+ if (interrupted || System.nanoTime() > end) {
+ // release waiting
+ for (; ; ) {
+ if (writersWaiting <= 0)
+ throw new IllegalStateException("writersWaiting has underflowed");
+ if (compareAndSwapLong(offset, lock, lock - RW_WRITE_WAITING))
+ break;
+ lock = readVolatileLong(offset);
+ writersWaiting = rwWriteWaiting(lock);
+ }
+ if (interrupted)
+ throw new InterruptedException("Unable to obtain lock, interrupted");
+ return false;
+ }
}
}
- protected class BytesOutputStream extends OutputStream {
- @Override
- public void close() throws IOException {
- finish();
+ public void unlockRWReadLock(long offset) {
+ for (; ; ) {
+ long lock = readVolatileLong(offset);
+ int readersLocked = rwReadLocked(lock);
+ if (readersLocked <= 0)
+ throw new IllegalMonitorStateException("readerLock underflow");
+ if (compareAndSwapLong(offset, lock, lock - RW_READ_LOCKED))
+ return;
}
+ }
- @Override
- public void write(@NotNull byte[] b) throws IOException {
- AbstractBytes.this.write(b);
+ public void unlockRWWriteLock(long offset) {
+ for (; ; ) {
+ long lock = readVolatileLong(offset);
+ int writersLocked = rwWriteLocked(lock);
+ if (writersLocked != 1)
+ throw new IllegalMonitorStateException("writersLock underflow " + writersLocked);
+ if (compareAndSwapLong(offset, lock, lock - RW_WRITE_LOCKED))
+ return;
+ }
+ }
+
+ String dumpRWLock(long offset) {
+ long lock = readVolatileLong(offset);
+ int readersLocked = rwReadLocked(lock);
+ int writersWaiting = rwWriteWaiting(lock);
+ int writersLocked = rwWriteLocked(lock);
+ return "writerLocked: " + writersLocked
+ + ", writersWaiting: " + writersWaiting
+ + ", readersLocked: " + readersLocked;
+ }
+
+ static class DateCache {
+ final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
+ private long lastDay = Long.MIN_VALUE;
+ @Nullable
+ private byte[] lastDateStr = null;
+
+ DateCache() {
+ dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+ }
+
+ static class LoggerHolder {
+ public static final Logger LOGGER = Logger.getLogger(AbstractBytes.class.getName());
+ }
+
+ abstract static class FastStringOperations {
+ abstract long getUtf8EncodedStringLength(@NotNull String string);
+
+ final int getUtf8CharSize(char c) {
+ if ((c > 0x007F)) {
+ if (c > 0x07FF) {
+ return 3;
+ } else {
+ return 2;
+ }
+ }
+ return 1;
+ }
+
+ abstract char[] extractChars(String string);
+ }
+
+ private static class FastStringOperations17 extends FastStringOperations {
+ final Field valueField;
+
+ private FastStringOperations17() throws SecurityException, NoSuchFieldException {
+ valueField = String.class.getDeclaredField("value");
+ valueField.setAccessible(true);
+ }
+
+ char[] extractChars(String string) {
+ try {
+ return (char[]) valueField.get(string);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
}
@Override
- public void write(byte[] b, int off, int len) throws IOException {
- AbstractBytes.this.write(b, off, len);
+ long getUtf8EncodedStringLength(String string) {
+ char[] chars = extractChars(string);
+ long utflen = chars.length;
+ for (char c : chars) {
+ if ((c > 0x007F)) {
+ if (c > 0x07FF) {
+ utflen += 2;
+ } else {
+ utflen++;
+ }
+ }
+ }
+ return utflen;
+ }
+ }
+
+ private static final class FastStringOperations16 extends FastStringOperations17 {
+ private final Field offsetField, countField;
+
+ private FastStringOperations16() throws SecurityException, NoSuchFieldException {
+ super();
+ offsetField = String.class.getDeclaredField("offset");
+ offsetField.setAccessible(true);
+ countField = String.class.getDeclaredField("count");
+ countField.setAccessible(true);
}
@Override
- public void write(int b) throws IOException {
- checkWrite(1);
- writeUnsignedByte(b);
+ long getUtf8EncodedStringLength(String string) {
+ final char[] chars = extractChars(string);
+ final int startIndex, endIndex;
+
+ try {
+ startIndex = offsetField.getInt(string);
+ endIndex = startIndex + countField.getInt(string);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+
+ long utflen = 0;
+ for (int i = startIndex; i < endIndex; ++i) {
+ utflen += getUtf8CharSize(chars[i]);
+ }
+ return utflen;
}
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/AbstractMappedStore.java b/lang/src/main/java/net/openhft/lang/io/AbstractMappedStore.java
new file mode 100644
index 0000000..3708e1b
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/AbstractMappedStore.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.channels.FileChannel;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.model.constraints.NotNull;
+import sun.misc.Cleaner;
+import sun.nio.ch.FileChannelImpl;
+
+abstract class AbstractMappedStore implements BytesStore, Closeable {
+ private static final int MAP_RO = 0;
+ private static final int MAP_RW = 1;
+ private static final int MAP_PV = 2;
+
+ // retain to prevent GC.
+ private final File file;
+ private final RandomAccessFile raf;
+ private final Cleaner cleaner;
+ private final AtomicInteger refCount = new AtomicInteger(1);
+ private final FileChannel.MapMode mode;
+ protected final MmapInfoHolder mmapInfoHolder;
+ private ObjectSerializer objectSerializer;
+
+ AbstractMappedStore(MmapInfoHolder mmapInfoHolder, File file, FileChannel.MapMode mode,
+ long startInFile, long size, ObjectSerializer objectSerializer)
+ throws IOException {
+ validateSize(size);
+ this.file = file;
+ this.mmapInfoHolder = mmapInfoHolder;
+ this.mmapInfoHolder.setSize(size);
+ this.objectSerializer = objectSerializer;
+ this.mode = mode;
+
+ try {
+ this.raf = new RandomAccessFile(file, accesModeFor(mode));
+ resizeIfNeeded(startInFile, size);
+ map(startInFile);
+ this.cleaner = Cleaner.create(this, new Unmapper(mmapInfoHolder, raf));
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+ }
+
+ protected static void validateSize(long size) {
+ if (size <= 0 || size > 128L << 40) {
+ throw new IllegalArgumentException("invalid size: " + size);
+ }
+ }
+
+ protected final void resizeIfNeeded(long startInFile, long newSize) throws IOException {
+ if (file.getAbsolutePath().startsWith("/dev/")) {
+ return;
+ }
+ if (startInFile > 0) {
+ if (raf.length() >= startInFile + newSize) {
+ return;
+ }
+ } else if (startInFile == 0) {
+ if (raf.length() == newSize) {
+ return;
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "Start offset in file needs to be positive: " + startInFile);
+ }
+ if (mode != FileChannel.MapMode.READ_WRITE) {
+ throw new IOException(
+ "Cannot resize file to " + newSize + " as mode is not READ_WRITE");
+ }
+
+ raf.setLength(startInFile + newSize);
+ }
+
+ protected final void map(long startInFile) throws IOException {
+ try {
+ mmapInfoHolder.setAddress(
+ map0(raf.getChannel(), imodeFor(mode), startInFile, mmapInfoHolder.getSize()));
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+ }
+
+ protected final void unmapAndSyncToDisk() throws IOException {
+ unmap0(mmapInfoHolder.getAddress(), mmapInfoHolder.getSize());
+ syncToDisk();
+ }
+
+ public final void syncToDisk() throws IOException {
+ raf.getChannel().force(true);
+ }
+
+ private static long map0(FileChannel fileChannel, int imode, long start, long size)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Method map0 = fileChannel.getClass().getDeclaredMethod(
+ "map0", int.class, long.class, long.class);
+ map0.setAccessible(true);
+ return (Long) map0.invoke(fileChannel, imode, start, size);
+ }
+
+ private static void unmap0(long address, long size) throws IOException {
+ try {
+ Method unmap0 = FileChannelImpl.class.getDeclaredMethod(
+ "unmap0", long.class, long.class);
+ unmap0.setAccessible(true);
+ unmap0.invoke(null, address, size);
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+ }
+
+ private static IOException wrap(Throwable e) {
+ if (e instanceof InvocationTargetException)
+ e = e.getCause();
+ if (e instanceof IOException)
+ return (IOException) e;
+ return new IOException(e);
+ }
+
+ private static String accesModeFor(FileChannel.MapMode mode) {
+ return mode == FileChannel.MapMode.READ_WRITE ? "rw" : "r";
+ }
+
+ private static int imodeFor(FileChannel.MapMode mode) {
+ int imode = -1;
+ if (mode == FileChannel.MapMode.READ_ONLY)
+ imode = MAP_RO;
+ else if (mode == FileChannel.MapMode.READ_WRITE)
+ imode = MAP_RW;
+ else if (mode == FileChannel.MapMode.PRIVATE)
+ imode = MAP_PV;
+ assert (imode >= 0);
+ return imode;
+ }
+
+ @Override
+ public final ObjectSerializer objectSerializer() {
+ return objectSerializer;
+ }
+
+ @Override
+ public final long address() {
+ return mmapInfoHolder.getAddress();
+ }
+
+ @Override
+ public final long size() {
+ return mmapInfoHolder.getSize();
+ }
+
+ @Override
+ public final void free() {
+ cleaner.clean();
+ }
+
+ @Override
+ public final void close() {
+ free();
+ }
+
+ @NotNull
+ public final DirectBytes bytes() {
+ return new DirectBytes(this, refCount);
+ }
+
+ @NotNull
+ public final DirectBytes bytes(long offset, long length) {
+ return new DirectBytes(this, refCount, offset, length);
+ }
+
+ public final File file() {
+ return file;
+ }
+
+ static final class MmapInfoHolder {
+ private long address, size;
+ private volatile boolean locked;
+
+ private void checkLock() {
+ if (locked) {
+ throw new IllegalStateException();
+ }
+ }
+
+ void lock() {
+ this.locked = true;
+ }
+
+ void setAddress(long address) {
+ checkLock();
+ this.address = address;
+ }
+
+ long getAddress() {
+ return address;
+ }
+
+ void setSize(long size) {
+ checkLock();
+ this.size = size;
+ }
+
+ long getSize() {
+ return size;
+ }
+ }
+
+ private static final class Unmapper implements Runnable {
+ private final MmapInfoHolder mmapInfoHolder;
+ private final RandomAccessFile raf;
+ /*
+ * This is not for synchronization (since calling this from multiple
+ * threads through .free / .close is an user error!) but rather to make
+ * sure that if an explicit cleanup was performed, the cleaner does not
+ * retry cleaning up the resources.
+ */
+ private volatile boolean cleanedUp;
+
+ Unmapper(MmapInfoHolder mmapInfo, RandomAccessFile raf) {
+ this.mmapInfoHolder = mmapInfo;
+ this.raf = raf;
+ }
+
+ public void run() {
+ if (cleanedUp) {
+ return;
+ }
+ cleanedUp = true;
+
+ try {
+ unmap0(mmapInfoHolder.getAddress(), mmapInfoHolder.getSize());
+ raf.getChannel().force(true);
+ // this also closes the underlying channel as per the documentation
+ raf.close();
+ } catch (IOException e) {
+ UnmapperLoggerHolder.LOGGER.log(Level.SEVERE,
+ "An exception has occurred while cleaning up a MappedStore instance: " +
+ e.getMessage(), e);
+ }
+ }
+ }
+
+ private static final class UnmapperLoggerHolder {
+ private static final Logger LOGGER = Logger.getLogger(Unmapper.class.getName());
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/BoundsCheckingDirectBytes.java b/lang/src/main/java/net/openhft/lang/io/BoundsCheckingDirectBytes.java
new file mode 100644
index 0000000..eaa7062
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/BoundsCheckingDirectBytes.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.model.constraints.NotNull;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unlike {@link net.openhft.lang.io.NativeBytes}, always throw check bounds and exceptions on all write methods,
+ * including that write a single primitive, e. g. {@link #writeInt(int)}. {@code NativeBytes} throw exceptions only if
+ * Java assertions enabled.
+ */
+public class BoundsCheckingDirectBytes extends DirectBytes {
+
+ public BoundsCheckingDirectBytes(@NotNull BytesStore store, AtomicInteger refCount) {
+ super(store, refCount);
+ }
+
+ @Override
+ void positionChecks(long positionAddr) {
+ actualPositionChecks(positionAddr);
+ }
+
+ @Override
+ void offsetChecks(long offset, long len) {
+ actualOffsetChecks(offset, len);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/BoundsCheckingNativeBytes.java b/lang/src/main/java/net/openhft/lang/io/BoundsCheckingNativeBytes.java
new file mode 100644
index 0000000..1deef28
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/BoundsCheckingNativeBytes.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.ObjectSerializer;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unlike {@link NativeBytes}, always throw check bounds and exceptions on
+ * all write methods, including that write a single primitive, e. g. {@link #writeInt(int)}.
+ * {@code NativeBytes} throw exceptions only if Java assertions enabled.
+ */
+public class BoundsCheckingNativeBytes extends NativeBytes {
+
+ public BoundsCheckingNativeBytes(long startAddr, long capacityAddr) {
+ super(startAddr, capacityAddr);
+ }
+
+ public BoundsCheckingNativeBytes(ObjectSerializer objectSerializer,
+ long startAddr, long capacityAddr,
+ AtomicInteger refCount) {
+ super(objectSerializer, startAddr, capacityAddr, refCount);
+ }
+
+ public BoundsCheckingNativeBytes(NativeBytes bytes) {
+ super(bytes);
+ }
+
+ @Override
+ void positionChecks(long positionAddr) {
+ actualPositionChecks(positionAddr);
+ }
+
+ @Override
+ void offsetChecks(long offset, long len) {
+ actualOffsetChecks(offset, len);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/ByteBufferBytes.java b/lang/src/main/java/net/openhft/lang/io/ByteBufferBytes.java
index 5b85e87..f23a8df 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/ByteBufferBytes.java
+++ b/lang/src/main/java/net/openhft/lang/io/ByteBufferBytes.java
@@ -1,65 +1,187 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.io.serialization.BytesMarshallableSerializer;
+import net.openhft.lang.io.serialization.JDKZObjectSerializer;
+import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
+import net.openhft.lang.model.constraints.NotNull;
import sun.nio.ch.DirectBuffer;
import java.io.EOFException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* @author peter.lawrey
*/
-public class ByteBufferBytes extends AbstractBytes {
- protected final ByteBuffer buffer;
- protected int start, position, limit;
- protected AtomicBoolean barrier;
-
+public class ByteBufferBytes extends AbstractBytes implements IByteBufferBytes {
+ private final ByteBuffer buffer;
+ private final int start;
+ private final int capacity;
+ private int position;
+ private int limit;
+ private AtomicBoolean barrier;
+
+ /**
+ * Use the ByteBufferBytes.wrap(ByteBuffer) as DirectByteBuffer more efficient
+ */
+ @Deprecated
public ByteBufferBytes(ByteBuffer buffer) {
this(buffer, 0, buffer.capacity());
}
- public ByteBufferBytes(ByteBuffer buffer, int start, int limit) {
+ /**
+ * Use the ByteBufferBytes.wrap(ByteBuffer) as DirectByteBuffer more efficient
+ *
+ * @param buffer the buffer to populate
+ * @param start start of buffer
+ * * @param capacity len of buffer
+ */
+ @Deprecated
+ public ByteBufferBytes(ByteBuffer buffer, int start, int capacity) {
+ super(BytesMarshallableSerializer.create(new VanillaBytesMarshallerFactory(), JDKZObjectSerializer.INSTANCE), new AtomicInteger(1));
+ // We should set order to native, because compare-and-swap operations
+ // end up with native ops. Bytes interfaces handles only native order.
+ buffer.order(ByteOrder.nativeOrder());
this.buffer = buffer;
this.start = position = start;
- this.limit = limit;
+ this.capacity = limit = (capacity + start);
+ }
+
+ public static IByteBufferBytes wrap(ByteBuffer buffer) {
+ if (buffer instanceof DirectBuffer) {
+ return new DirectByteBufferBytes(buffer);
+ }
+
+ return new ByteBufferBytes(buffer.slice());
+ }
+
+ public static IByteBufferBytes wrap(ByteBuffer buffer, int start, int capacity) {
+ if (buffer instanceof DirectBuffer) {
+ return new DirectByteBufferBytes(buffer, start, capacity);
+ }
+
+ return new ByteBufferBytes(buffer.slice(), start, capacity);
+ }
+
+ @Override
+ public ByteBufferBytes slice() {
+ return new ByteBufferBytes(buffer(), position, limit - position);
+ }
+
+ @Override
+ public ByteBufferBytes slice(long offset, long length) {
+ long sliceStart = position + offset;
+ assert sliceStart >= start && sliceStart < capacity;
+ long sliceEnd = sliceStart + length;
+ assert sliceEnd > sliceStart && sliceEnd <= capacity;
+ return new ByteBufferBytes(buffer(), (int) sliceStart, (int) length);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ int subStart = position + start;
+ if (subStart < position || subStart > limit)
+ throw new IndexOutOfBoundsException();
+ int subEnd = position + end;
+ if (subEnd < subStart || subEnd > limit)
+ throw new IndexOutOfBoundsException();
+ if (start == end)
+ return "";
+ return new ByteBufferBytes(buffer(), subStart, end - start);
+ }
+
+ @Override
+ public ByteBufferBytes bytes() {
+ return new ByteBufferBytes(buffer(), start, capacity - start);
+ }
+
+ @Override
+ public ByteBufferBytes bytes(long offset, long length) {
+ long sliceStart = start + offset;
+ assert sliceStart >= start && sliceStart < capacity;
+ long sliceEnd = sliceStart + length;
+ assert sliceEnd > sliceStart && sliceEnd <= capacity;
+ return new ByteBufferBytes(buffer(), (int) sliceStart, (int) length);
+ }
+
+ @Override
+ public long address() {
+ if (buffer instanceof DirectBuffer) {
+ long address = ((DirectBuffer) buffer).address();
+ if (address == 0)
+ throw new IllegalStateException("This buffer has no address, is it empty?");
+ return address;
+ }
+ throw new IllegalStateException("A heap ByteBuffer doesn't have a fixed address");
+ }
+
+ @Override
+ public Bytes zeroOut() {
+ clear();
+ int i = start;
+ for (; i < capacity - 7; i++)
+ buffer.putLong(i, 0L);
+ for (; i < capacity; i++)
+ buffer.put(i, (byte) 0);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end) {
+ if (start < 0 || end > limit())
+ throw new IllegalArgumentException("start: " + start + ", end: " + end);
+ if (start >= end)
+ return this;
+ int i = (int) (this.start + start);
+ int j = (int) (this.start + end);
+ for (; i < j - 7; i++)
+ buffer.putLong(i, 0L);
+ for (; i < j; i++)
+ buffer.put(i, (byte) 0);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end, boolean ifNotZero) {
+ // ByteBuffers are allocated in memory eagerly.
+ return zeroOut(start, end);
}
public ByteBuffer buffer() {
return buffer;
}
- protected void readBarrier() {
+ void readBarrier() {
if (barrier == null) barrier = new AtomicBoolean();
barrier.get();
}
- protected void writeBarrier() {
+ void writeBarrier() {
if (barrier == null) barrier = new AtomicBoolean();
barrier.lazySet(false);
}
@Override
public int read(@NotNull byte[] bytes, int off, int len) {
- if (len < 0 || off < 0 || off + len > bytes.length)
- throw new IllegalArgumentException();
+ checkArrayOffs(bytes.length, off, len);
long left = remaining();
if (left <= 0) return -1;
int len2 = (int) Math.min(left, len);
@@ -70,7 +192,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public byte readByte() {
- if (position < limit)
+ if (position < capacity)
return buffer.get(position++);
throw new IndexOutOfBoundsException();
}
@@ -78,15 +200,14 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public byte readByte(long offset) {
int pos = (int) (start + offset);
- if (pos < limit)
+ if (pos < capacity)
return buffer.get(pos);
throw new IndexOutOfBoundsException();
}
@Override
public void readFully(@NotNull byte[] b, int off, int len) {
- if (len < 0 || off < 0 || off + len > b.length)
- throw new IllegalArgumentException();
+ checkArrayOffs(b.length, off, len);
long left = remaining();
if (left < len)
throw new IllegalStateException(new EOFException());
@@ -95,8 +216,28 @@ public class ByteBufferBytes extends AbstractBytes {
}
@Override
+ public void readFully(@NotNull char[] data, int off, int len) {
+ checkArrayOffs(data.length, off, len);
+ long left = remaining();
+ if (left < len * 2L)
+ throw new IllegalStateException(new EOFException());
+ for (int i = 0; i < len; i++)
+ data[off + i] = readChar();
+ }
+
+ @Override
+ public void readFully(long offset, byte[] bytes, int off, int len) {
+ checkArrayOffs(bytes.length, off, len);
+ long left = remaining();
+ if (left < len)
+ throw new IllegalStateException(new EOFException());
+ for (int i = 0; i < len; i++)
+ bytes[off + i] = readByte(offset + i);
+ }
+
+ @Override
public short readShort() {
- if (position + 2 <= limit) {
+ if (position + 2 <= capacity) {
short s = buffer.getShort(position);
position += 2;
return s;
@@ -107,14 +248,14 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public short readShort(long offset) {
int pos = (int) (start + offset);
- if (pos + 2 <= limit)
+ if (pos + 2 <= capacity)
return buffer.getShort(pos);
throw new IndexOutOfBoundsException();
}
@Override
public char readChar() {
- if (position + 2 <= limit) {
+ if (position + 2 <= capacity) {
char ch = buffer.getChar(position);
position += 2;
return ch;
@@ -125,14 +266,14 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public char readChar(long offset) {
int pos = (int) (start + offset);
- if (pos + 2 <= limit)
+ if (pos + 2 <= capacity)
return buffer.getChar(pos);
throw new IndexOutOfBoundsException();
}
@Override
public int readInt() {
- if (position + 4 <= limit) {
+ if (position + 4 <= capacity) {
int i = buffer.getInt(position);
position += 4;
return i;
@@ -143,7 +284,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public int readInt(long offset) {
int pos = (int) (start + offset);
- if (pos + 4 <= limit)
+ if (pos + 4 <= capacity)
return buffer.getInt(pos);
throw new IndexOutOfBoundsException();
}
@@ -162,7 +303,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public long readLong() {
- if (position + 8 <= limit) {
+ if (position + 8 <= capacity) {
long l = buffer.getLong(position);
position += 8;
return l;
@@ -173,7 +314,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public long readLong(long offset) {
int pos = (int) (start + offset);
- if (pos + 8 <= limit)
+ if (pos + 8 <= capacity)
return buffer.getLong(pos);
throw new IndexOutOfBoundsException();
}
@@ -192,7 +333,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public float readFloat() {
- if (position + 4 <= limit) {
+ if (position + 4 <= capacity) {
float f = buffer.getFloat(position);
position += 4;
return f;
@@ -203,14 +344,14 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public float readFloat(long offset) {
int pos = (int) (start + offset);
- if (pos + 4 <= limit)
+ if (pos + 4 <= capacity)
return buffer.getFloat(pos);
throw new IndexOutOfBoundsException();
}
@Override
public double readDouble() {
- if (position + 8 <= limit) {
+ if (position + 8 <= capacity) {
double d = buffer.getDouble(position);
position += 8;
return d;
@@ -221,14 +362,14 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public double readDouble(long offset) {
int pos = (int) (start + offset);
- if (pos + 8 <= limit)
+ if (pos + 8 <= capacity)
return buffer.getDouble(pos);
throw new IndexOutOfBoundsException();
}
@Override
public void write(int b) {
- if (position < limit)
+ if (position < capacity)
buffer.put(position++, (byte) b);
else
throw new IndexOutOfBoundsException();
@@ -237,7 +378,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeByte(long offset, int b) {
int pos = (int) (start + offset);
- if (pos < limit)
+ if (pos < capacity)
buffer.put(pos, (byte) b);
else
throw new IndexOutOfBoundsException();
@@ -245,9 +386,10 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeShort(int v) {
- if (position + 2 <= limit) {
+ if (position + 2 <= capacity) {
buffer.putShort(position, (short) v);
position += 2;
+
} else {
throw new IndexOutOfBoundsException();
}
@@ -256,7 +398,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeShort(long offset, int v) {
int pos = (int) (start + offset);
- if (pos + 2 <= limit)
+ if (pos + 2 <= capacity)
buffer.putShort(pos, (short) v);
else
throw new IndexOutOfBoundsException();
@@ -264,9 +406,10 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeChar(int v) {
- if (position + 2 <= limit) {
+ if (position + 2 <= capacity) {
buffer.putChar(position, (char) v);
position += 2;
+
} else {
throw new IndexOutOfBoundsException();
}
@@ -275,7 +418,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeChar(long offset, int v) {
int pos = (int) (start + offset);
- if (pos + 2 <= limit)
+ if (pos + 2 <= capacity)
buffer.putChar(pos, (char) v);
else
throw new IndexOutOfBoundsException();
@@ -283,9 +426,10 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeInt(int v) {
- if (position + 4 <= limit) {
+ if (position + 4 <= capacity) {
buffer.putInt(position, v);
position += 4;
+
} else {
throw new IndexOutOfBoundsException();
}
@@ -294,7 +438,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeInt(long offset, int v) {
int pos = (int) (start + offset);
- if (pos + 4 <= limit)
+ if (pos + 4 <= capacity)
buffer.putInt(pos, v);
else
throw new IndexOutOfBoundsException();
@@ -321,9 +465,10 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeLong(long v) {
- if (position + 8 <= limit) {
+ if (position + 8 <= capacity) {
buffer.putLong(position, v);
position += 8;
+
} else {
throw new IndexOutOfBoundsException();
}
@@ -332,7 +477,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeLong(long offset, long v) {
int pos = (int) (start + offset);
- if (pos + 8 <= limit)
+ if (pos + 8 <= capacity)
buffer.putLong(pos, v);
else
throw new IndexOutOfBoundsException();
@@ -359,9 +504,10 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeFloat(float v) {
- if (position + 4 <= limit) {
+ if (position + 4 <= capacity) {
buffer.putFloat(position, v);
position += 4;
+
} else {
throw new IndexOutOfBoundsException();
}
@@ -370,7 +516,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeFloat(long offset, float v) {
int pos = (int) (start + offset);
- if (pos + 4 <= limit)
+ if (pos + 4 <= capacity)
buffer.putFloat(pos, v);
else
throw new IndexOutOfBoundsException();
@@ -378,9 +524,10 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeDouble(double v) {
- if (position + 8 <= limit) {
+ if (position + 8 <= capacity) {
buffer.putDouble(position, v);
position += 8;
+
} else {
throw new IndexOutOfBoundsException();
}
@@ -389,7 +536,7 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void writeDouble(long offset, double v) {
int pos = (int) (start + offset);
- if (pos + 8 <= limit)
+ if (pos + 8 <= capacity)
buffer.putDouble(pos, v);
else
throw new IndexOutOfBoundsException();
@@ -411,15 +558,19 @@ public class ByteBufferBytes extends AbstractBytes {
}
@Override
- public void position(long position) {
+ public ByteBufferBytes position(long position) {
if (start + position > Integer.MAX_VALUE)
- throw new IndexOutOfBoundsException("Position to large");
+ throw new IllegalArgumentException("Position to large");
+ if (position < 0)
+ throw new IllegalArgumentException("Position to small");
+
this.position = (int) (start + position);
+ return this;
}
@Override
public long capacity() {
- return limit - start;
+ return capacity - start;
}
@Override
@@ -427,6 +578,17 @@ public class ByteBufferBytes extends AbstractBytes {
return limit - position;
}
+ @Override
+ public long limit() {
+ return limit - start;
+ }
+
+ @Override
+ public ByteBufferBytes limit(long limit) {
+ this.limit = (int) (start + limit);
+ return this;
+ }
+
@NotNull
@Override
public ByteOrder byteOrder() {
@@ -435,7 +597,25 @@ public class ByteBufferBytes extends AbstractBytes {
@Override
public void checkEndOfBuffer() throws IndexOutOfBoundsException {
- if (position < start || position > limit)
+ if (position < start || position > limit()) {
throw new IndexOutOfBoundsException();
+ }
+ }
+
+ @Override
+ protected void cleanup() {
+ IOTools.clean(buffer);
+ }
+
+ @Override
+ public Bytes load() {
+ int pageSize = NativeBytes.UNSAFE.pageSize();
+ for (int offset = start; offset < capacity; offset += pageSize)
+ buffer.get(offset);
+ return this;
+ }
+
+ public void alignPositionAddr(int powerOf2) {
+ position = (position + powerOf2 - 1) & ~(powerOf2 - 1);
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/ByteBufferReuse.java b/lang/src/main/java/net/openhft/lang/io/ByteBufferReuse.java
new file mode 100644
index 0000000..e14c9e0
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/ByteBufferReuse.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import sun.misc.Unsafe;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+
+interface ByteBufferReuse {
+ ByteBufferReuse INSTANCE = Inner.getReuse();
+
+ ByteBuffer reuse(long addr, int cap, Object att, ByteBuffer toReuse);
+
+ class Inner extends Reuses implements Opcodes {
+ private static ByteBufferReuse getReuse() {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+
+ final String reuseImplClassName = "net/openhft/lang/io/ByteBufferReuseImpl";
+ cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, reuseImplClassName, null,
+ "sun/reflect/MagicAccessorImpl",
+ new String[]{"net/openhft/lang/io/ByteBufferReuse"});
+
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ String attachedBufferFieldName = getAttachedBufferFieldName();
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "reuse",
+ "(JILjava/lang/Object;Ljava/nio/ByteBuffer;)Ljava/nio/ByteBuffer;",
+ null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 5);
+ String directByteBuffer = "java/nio/DirectByteBuffer";
+ mv.visitTypeInsn(INSTANCEOF, directByteBuffer);
+ Label l0 = new Label();
+ mv.visitJumpInsn(IFEQ, l0);
+ mv.visitVarInsn(ALOAD, 5);
+ mv.visitTypeInsn(CHECKCAST, directByteBuffer);
+ mv.visitVarInsn(ASTORE, 6);
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitFieldInsn(GETFIELD, directByteBuffer, attachedBufferFieldName, "Ljava/lang/Object;");
+ String settableAtt = "net/openhft/lang/io/SettableAtt";
+ mv.visitTypeInsn(INSTANCEOF, settableAtt);
+ mv.visitJumpInsn(IFEQ, l0);
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitVarInsn(LLOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, directByteBuffer, "address", "J");
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitInsn(ICONST_M1);
+ mv.visitFieldInsn(PUTFIELD, directByteBuffer, "mark", "I");
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitInsn(ICONST_0);
+ mv.visitFieldInsn(PUTFIELD, directByteBuffer, "position", "I");
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitVarInsn(ILOAD, 3);
+ mv.visitFieldInsn(PUTFIELD, directByteBuffer, "limit", "I");
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitVarInsn(ILOAD, 3);
+ mv.visitFieldInsn(PUTFIELD, directByteBuffer, "capacity", "I");
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitFieldInsn(GETFIELD, directByteBuffer, attachedBufferFieldName, "Ljava/lang/Object;");
+ mv.visitTypeInsn(CHECKCAST, settableAtt);
+ mv.visitVarInsn(ALOAD, 4);
+ mv.visitFieldInsn(PUTFIELD, settableAtt, "att", "Ljava/lang/Object;");
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitInsn(ARETURN);
+ mv.visitLabel(l0);
+ mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ mv.visitTypeInsn(NEW, settableAtt);
+ mv.visitInsn(DUP);
+ mv.visitMethodInsn(INVOKESPECIAL, settableAtt, "<init>", "()V", false);
+ mv.visitVarInsn(ASTORE, 6);
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitVarInsn(ALOAD, 4);
+ mv.visitFieldInsn(PUTFIELD, settableAtt, "att", "Ljava/lang/Object;");
+ mv.visitTypeInsn(NEW, directByteBuffer);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(LLOAD, 1);
+ mv.visitVarInsn(ILOAD, 3);
+ mv.visitVarInsn(ALOAD, 6);
+ mv.visitMethodInsn(INVOKESPECIAL, directByteBuffer, "<init>",
+ "(JILjava/lang/Object;)V", false);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(6, 7);
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+
+ final byte[] impl = cw.toByteArray();
+
+ final Unsafe unsafe = NativeBytes.UNSAFE;
+ Class clazz = AccessController.doPrivileged(new PrivilegedAction<Class>() {
+ @Override
+ public Class run() {
+ ClassLoader cl = MAGIC_CLASS_LOADER;
+ return unsafe.defineClass(reuseImplClassName, impl, 0, impl.length, cl, null);
+ }
+ });
+ try {
+ return (ByteBufferReuse) clazz.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static String getAttachedBufferFieldName() {
+ try {
+ Class<?> clazz = Class.forName("java.nio.DirectByteBuffer");
+ String[] possibleFieldNames = new String[] { "att",
+ "viewedBuffer" };
+ for (String possibleFieldName : possibleFieldNames) {
+ try {
+ clazz.getDeclaredField(possibleFieldName);
+ return possibleFieldName;
+ } catch (Exception e) {
+ continue;
+ }
+ }
+
+ throw new RuntimeException(
+ "Failed to find any of the possible field names on DirectByteBuffer: "
+ + Arrays.toString(possibleFieldNames));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/ByteStringAppender.java b/lang/src/main/java/net/openhft/lang/io/ByteStringAppender.java
index fd36102..281ba9a 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/ByteStringAppender.java
+++ b/lang/src/main/java/net/openhft/lang/io/ByteStringAppender.java
@@ -1,23 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
/**
* @author peter.lawrey
diff --git a/lang/src/main/java/net/openhft/lang/io/ByteStringParser.java b/lang/src/main/java/net/openhft/lang/io/ByteStringParser.java
index 10132cc..d80c3bf 100755
--- a/lang/src/main/java/net/openhft/lang/io/ByteStringParser.java
+++ b/lang/src/main/java/net/openhft/lang/io/ByteStringParser.java
@@ -1,69 +1,91 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.nio.BufferUnderflowException;
/**
* @author peter.lawrey
*/
public interface ByteStringParser extends BytesCommon {
/**
- * Return true or false, or null if it could not be detected as true or false. Case is not important
- * <p/>
- * false: f, false, n, no, 0
- * <p/>
- * true: t, true, y, yes, 1
+ * If set to true, the end of the Bytes will be the end of any consuming String, double or long.
+ * If false, incomplete reads will throw a BufferUnderflowException
+
+ * @param selfTerminate if true, the end of the Buffer is silent.
+ */
+ void selfTerminating(boolean selfTerminate);
+
+ /**
+ * @return if this Bytes self terminates.
+ */
+ boolean selfTerminating();
+
+ /**
+ * @return the next unsigned byte or -1 if selfTerminating and the end is reached.
+ * @throws BufferUnderflowException if the end is reached and selfTerminating is false.
+ */
+ int readUnsignedByteOrThrow() throws BufferUnderflowException;
+
+ /**
+ * Return true or false, or null if it could not be detected
+ * as true or false. Case is not important
+ *
+ * <p>false: f, false, n, no, 0
+ *
+ * <p>true: t, true, y, yes, 1
*
* @param tester to detect the end of the text.
* @return true, false, or null if neither.
*/
- Boolean parseBoolean(@NotNull StopCharTester tester);
+ Boolean parseBoolean(@NotNull StopCharTester tester) throws BufferUnderflowException;
/**
* Populate a StringBuilder with the UTF encoded text until the end.
*
- * @param builder to clear and append to.
+ * @param builder to zeroOut and append to.
* @param tester to detect when to stop.
*/
- void parseUTF(@NotNull StringBuilder builder, @NotNull StopCharTester tester);
+ void parseUtf8(@NotNull StringBuilder builder, @NotNull StopCharTester tester) throws BufferUnderflowException;
@NotNull
- String parseUTF(@NotNull StopCharTester tester);
+ String parseUtf8(@NotNull StopCharTester tester) throws BufferUnderflowException;
@Nullable
- <E extends Enum<E>> E parseEnum(@NotNull Class<E> eClass, @NotNull StopCharTester tester);
+ <E extends Enum<E>> E parseEnum(@NotNull Class<E> eClass, @NotNull StopCharTester tester) throws BufferUnderflowException;
@NotNull
- MutableDecimal parseDecimal(@NotNull MutableDecimal decimal);
+ MutableDecimal parseDecimal(@NotNull MutableDecimal decimal) throws BufferUnderflowException;
/**
* @return the next long, stopping at the first invalid character
*/
- long parseLong();
+ long parseLong() throws BufferUnderflowException;
/**
* @param base to use.
* @return the next long, stopping at the first invalid character
*/
- long parseLong(int base);
+ long parseLong(int base) throws BufferUnderflowException;
- double parseDouble();
+ double parseDouble() throws BufferUnderflowException;
/**
* Make sure we just read a stop character
@@ -80,4 +102,18 @@ public interface ByteStringParser extends BytesCommon {
* @return true if we stopped at a stop character, false if we ran out of data.
*/
boolean skipTo(@NotNull StopCharTester tester);
+
+ /**
+ * Dump the contents of this Bytes as text in the Appendable.
+ *
+ * @param appendable to append to
+ */
+ void asString(Appendable appendable);
+
+ /**
+ * Dump the contents of Bytes as a CharSequence
+ *
+ * @return the CharSequence for these Bytes.
+ */
+ CharSequence asString();
}
diff --git a/lang/src/main/java/net/openhft/lang/io/Bytes.java b/lang/src/main/java/net/openhft/lang/io/Bytes.java
index c520613..e9a21be 100755
--- a/lang/src/main/java/net/openhft/lang/io/Bytes.java
+++ b/lang/src/main/java/net/openhft/lang/io/Bytes.java
@@ -1,26 +1,33 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
+import net.openhft.lang.ReferenceCounted;
import net.openhft.lang.io.serialization.BytesMarshallable;
/**
* @author peter.lawrey
*/
-public interface Bytes extends RandomDataInput, RandomDataOutput, RandomDataUpdate,
- ByteStringAppender, ByteStringParser, CharSequence, BytesMarshallable {
+public interface Bytes extends RandomDataInput, RandomDataOutput, RandomDataUpdate, BytesStore,
+ ByteStringAppender, ByteStringParser, CharSequence, BytesMarshallable, ReferenceCounted {
+
+ /**
+ * Needed if the buffer is created in one thread and used in another.
+ */
+ void clearThreadAssociation();
+
}
diff --git a/lang/src/main/java/net/openhft/lang/io/BytesCommon.java b/lang/src/main/java/net/openhft/lang/io/BytesCommon.java
index 0549f61..88eb529 100755
--- a/lang/src/main/java/net/openhft/lang/io/BytesCommon.java
+++ b/lang/src/main/java/net/openhft/lang/io/BytesCommon.java
@@ -1,26 +1,28 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import net.openhft.lang.io.serialization.BytesMarshallerFactory;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.model.constraints.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
@@ -28,14 +30,27 @@ import java.nio.ByteOrder;
*/
public interface BytesCommon {
/**
- * @return the offset read/written so far
+ * @return the offset read/written which must be &gt;= limit()
*/
long position();
/**
* @param position to skip to
+ * @return this bytes object back
+ * @throws java.lang.IllegalArgumentException if positions &lt; 0 || position &gt;= limit
*/
- void position(long position);
+ Bytes position(long position) throws IllegalArgumentException;
+
+ /**
+ * @return the current limit which must be &gt;= capacity()
+ */
+ long limit();
+
+ /**
+ * @param limit the new limit which must be &gt;= capacity()
+ * @return this bytes object back
+ */
+ Bytes limit(long limit);
/**
* @return space available
@@ -60,9 +75,46 @@ public interface BytesCommon {
boolean isFinished();
/**
- * Start again, unfinished, position() == 0
+ * Clears this buffer. The position is set to zero, the limit is set to
+ * the capacity, and the mark is discarded.
+ *
+ * <p> Invoke this method before using a sequence of channel-read or
+ * <i>put</i> operations to fill this buffer. For example:
+ * <pre>{@code
+ * buf.clear(); // Prepare buffer for reading
+ * in.read(buf); // Read data
+ * }</pre>
+ *
+ * <p>This method does not actually erase the data in the buffer, but it
+ * is named as if it did because it will most often be used in situations
+ * in which that might as well be the case. </p>
+ *
+ * @return This buffer
*/
- void reset();
+ Bytes clear();
+
+ /**
+ * Flips this buffer. The limit is set to the current position and then
+ * the position is set to zero. If the mark is defined then it is
+ * discarded.
+ *
+ * <p> After a sequence of channel-read or <i>put</i> operations, invoke
+ * this method to prepare for a sequence of channel-write or relative
+ * <i>get</i> operations. For example:
+ * <pre>{@code
+ * buf.put(magic); // Prepend header
+ * in.read(buf); // Read data into rest of buffer
+ * buf.flip(); // Flip buffer
+ * out.write(buf); // Write header + data to channel
+ * }</pre>
+ *
+ * <p> This method is often used in conjunction with the {@link
+ * java.nio.ByteBuffer#compact compact} method when transferring data from
+ * one place to another. </p>
+ *
+ * @return This buffer
+ */
+ Bytes flip();
/**
* @return Byte order for reading binary
@@ -86,7 +138,7 @@ public interface BytesCommon {
* @return the factory for marshallers.
*/
@NotNull
- BytesMarshallerFactory bytesMarshallerFactory();
+ ObjectSerializer objectSerializer();
/**
* @throws IndexOutOfBoundsException if the bounds of the Bytes has been exceeded.
@@ -94,11 +146,98 @@ public interface BytesCommon {
void checkEndOfBuffer() throws IndexOutOfBoundsException;
/**
- * Copy from one Bytes to another, moves the position by length
+ * Access every page to ensure those pages are in memory.
+ *
+ * @return this.
+ */
+ Bytes load();
+
+ /**
+ * Write a portion of the Bytes to an Appendable for printing.
+ *
+ * @param sb to append to
+ * @param start first byte
+ * @param position where to place a cursor or 0 = none.
+ * @param end last byte to append.
+ */
+ void toString(Appendable sb, long start, long position, long end);
+
+ /**
+ * Align the position address to a power of 2.
*
- * @param bytes to copy
- * @param position to copy from
- * @param length to copy
+ * @param alignment power of 2 to align to.
*/
- void write(BytesCommon bytes, long position, long length);
+ void alignPositionAddr(int alignment);
+
+ /**
+ * Creates a new bytes whose content is a shared subsequence of this bytes'
+ * content.
+ *
+ * <p>The content of the new bytes will start at this bytes' current
+ * position. Changes to this bytes' content will be visible in the new bytes,
+ * and vice versa; the two bytes' position and limit values will be
+ * independent.
+ *
+ * <p>The new bytes' position will be zero, its capacity and its limit
+ * will be the number of bytes remaining in this bytes.
+ *
+ * <p>{@code slice()} is equivalent of {@code slice(0, remaining())}.
+ *
+ * @return the new bytes
+ * @see #slice(long, long)
+ */
+ Bytes slice();
+
+ /**
+ * Returns a {@code ByteBuffer} whose content is a shared subsequence of this bytes' content.
+ *
+ * <p>The content of the returned {@code ByteBuffer} will start at this bytes' current
+ * position. Changes to this bytes' content will be visible in the returned {@code ByteBuffer},
+ * and vice versa; this bytes' and the returned {@code ByteBuffer}'s position and limit values
+ * will be independent.
+ *
+ * <p>The returned {@code ByteBuffer}'s position will be zero, its capacity and its limit
+ * will be the number of bytes remaining in this bytes.
+ *
+ * <p>If this bytes object is able to reuse to given {@code toReuse} {@code ByteBuffer}, it will
+ * be reused and returned back from this method, otherwise a new {@code ByteBuffer} instance
+ * is created and returned.
+ *
+ * @param toReuse a {@code ByteBuffer} to reuse
+ * @return a {@code ByteBuffer} view of this {@code Bytes}
+ * @see #slice()
+ * @see ByteBuffer#slice()
+ */
+ ByteBuffer sliceAsByteBuffer(@Nullable ByteBuffer toReuse);
+
+ /**
+ * Creates a new bytes whose content is a shared subsequence of this bytes'
+ * content.
+ *
+ * <p>The content of the new bytes will start at this bytes' current
+ * {@link #position()}{@code + offset}. Changes to this bytes' content
+ * will be visible in the new bytes, and vice versa; the two bytes'
+ * position and limit values will be independent.
+ *
+ * <p>The new bytes' position will be zero, its capacity and its limit
+ * will be equal to {@code length}.
+ *
+ * <p>{@code offset} can be negative (if current bytes' position is positive)
+ * and {@code length} can run out of current bytes' limit, the restriction
+ * is that new bytes' should be within this bytes' absolute bounds.
+ *
+ * @param offset relative offset of the new bytes from the current bytes'
+ * position
+ * @param length capacity of the new bytes
+ * @return the new bytes
+ * @see #slice()
+ */
+ Bytes slice(long offset, long length);
+
+ @NotNull
+ String toDebugString();
+
+ String toDebugString(long limit);
+
+ String toHexString(long limit);
}
diff --git a/lang/src/main/java/net/openhft/lang/io/BytesHasher.java b/lang/src/main/java/net/openhft/lang/io/BytesHasher.java
new file mode 100644
index 0000000..cb9535f
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/BytesHasher.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+public interface BytesHasher {
+ /**
+ * Provide a 64-bit hash for the bytes in Bytes between the bytes.position() and bytes.limit();
+ *
+ * @param bytes to hash
+ * @return 64-bit hash
+ */
+ long hash(Bytes bytes);
+
+ /**
+ * Provide a 64-bit hash for the bytes between offset and limit
+ *
+ * @param bytes to hash
+ * @param offset the start inclusive
+ * @param limit the end exclusive
+ * @return 64-bit hash.
+ */
+ long hash(Bytes bytes, long offset, long limit);
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/BytesStore.java b/lang/src/main/java/net/openhft/lang/io/BytesStore.java
new file mode 100644
index 0000000..b6ec3a9
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/BytesStore.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.ObjectSerializer;
+
+import java.io.File;
+
+public interface BytesStore {
+ /**
+ * Create a bytes whose content is the whole bytes store. Call of this
+ * method is equivalent to {@code bytes(0, size())} call.
+ *
+ * @return the new bytes
+ * @see #bytes(long, long)
+ */
+ Bytes bytes();
+
+ /**
+ * Slice a {@code Bytes} object with start address of
+ * {@link #address() address}{@code + offset} and capacity of {@code length}.
+ *
+ * <p>If this {@code BytesStore} is {@code Bytes} itself rather than natural
+ * {@code BytesStore} object, this method will offset the new bytes from the
+ * bytes' start, not from bytes' position like
+ * {@link Bytes#slice(long, long)}.
+ *
+ * <p>{@code offset} should be non-negative, {@code length} should be positive,
+ * {@code offset + length} should be less or equal to {@link #size() size}.
+ *
+ * @param offset offset of the new bytes from the bytes store address
+ * @param length capacity and limit of the new bytes
+ * @return the sliced {@code Bytes}
+ * @see #bytes()
+ */
+ Bytes bytes(long offset, long length);
+
+ long address();
+
+ long size();
+
+ void free();
+
+ ObjectSerializer objectSerializer();
+
+ File file();
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/CharBufferReuse.java b/lang/src/main/java/net/openhft/lang/io/CharBufferReuse.java
new file mode 100644
index 0000000..89ef031
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/CharBufferReuse.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import sun.misc.Unsafe;
+
+import java.nio.CharBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+interface CharBufferReuse {
+ CharBufferReuse INSTANCE = Inner.getReuse();
+
+ CharBuffer reuse(CharSequence cs, CharBuffer toReuse);
+
+ class Inner extends Reuses implements Opcodes {
+ private static CharBufferReuse getReuse() {
+ ClassWriter cw = new ClassWriter(0);
+ MethodVisitor mv;
+
+ final String reuseImplClassName = "net/openhft/lang/io/CharBufferReuseImpl";
+ cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, reuseImplClassName, null,
+ "sun/reflect/MagicAccessorImpl",
+ new String[] {"net/openhft/lang/io/CharBufferReuse"});
+
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ mv.visitInsn(RETURN);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "reuse",
+ "(Ljava/lang/CharSequence;Ljava/nio/CharBuffer;)Ljava/nio/CharBuffer;",
+ null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 2);
+ String stringCharBuffer = "java/nio/StringCharBuffer";
+ mv.visitTypeInsn(INSTANCEOF, stringCharBuffer);
+ Label l0 = new Label();
+ mv.visitJumpInsn(IFEQ, l0);
+ mv.visitVarInsn(ALOAD, 2);
+ mv.visitTypeInsn(CHECKCAST, stringCharBuffer);
+ mv.visitVarInsn(ASTORE, 3);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitInsn(ICONST_M1);
+ mv.visitFieldInsn(PUTFIELD, stringCharBuffer, "mark", "I");
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitInsn(ICONST_0);
+ mv.visitFieldInsn(PUTFIELD, stringCharBuffer, "position", "I");
+ mv.visitVarInsn(ALOAD, 1);
+ String charSequence = "java/lang/CharSequence";
+ mv.visitMethodInsn(INVOKEINTERFACE, charSequence, "length", "()I", true);
+ mv.visitVarInsn(ISTORE, 4);
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ILOAD, 4);
+ mv.visitFieldInsn(PUTFIELD, stringCharBuffer, "limit", "I");
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ILOAD, 4);
+ mv.visitFieldInsn(PUTFIELD, stringCharBuffer, "capacity", "I");
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, stringCharBuffer, "str", "Ljava/lang/CharSequence;");
+ mv.visitVarInsn(ALOAD, 3);
+ mv.visitInsn(ARETURN);
+ mv.visitLabel(l0);
+ mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ mv.visitTypeInsn(NEW, stringCharBuffer);
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitInsn(ICONST_0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitMethodInsn(INVOKEINTERFACE, charSequence, "length", "()I", true);
+ mv.visitMethodInsn(INVOKESPECIAL, stringCharBuffer, "<init>",
+ "(Ljava/lang/CharSequence;II)V", false);
+ mv.visitInsn(ARETURN);
+ mv.visitMaxs(5, 5);
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+
+ final byte[] impl = cw.toByteArray();
+
+ final Unsafe unsafe = NativeBytes.UNSAFE;
+ Class clazz = AccessController.doPrivileged(new PrivilegedAction<Class>() {
+ @Override
+ public Class run() {
+ ClassLoader cl = MAGIC_CLASS_LOADER;
+ return unsafe.defineClass(reuseImplClassName, impl, 0, impl.length, cl, null);
+ }
+ });
+ try {
+ return (CharBufferReuse) clazz.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/CharBuffers.java b/lang/src/main/java/net/openhft/lang/io/CharBuffers.java
new file mode 100644
index 0000000..546aeb6
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/CharBuffers.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import java.nio.CharBuffer;
+
+public final class CharBuffers {
+
+ public static CharBuffer wrap(CharSequence cs, CharBuffer toReuse) {
+ return CharBufferReuse.INSTANCE.reuse(cs, toReuse);
+ }
+
+ private CharBuffers() {}
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/CheckedBytes.java b/lang/src/main/java/net/openhft/lang/io/CheckedBytes.java
new file mode 100755
index 0000000..31e7526
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/CheckedBytes.java
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by Fernflower decompiler)
+//
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.model.Byteable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StreamCorruptedException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+public class CheckedBytes implements Bytes {
+ private final Bytes bytes;
+ volatile boolean isClosed = false;
+
+ public CheckedBytes(Bytes bytes) {
+ this.checkNotClosed();
+ this.bytes = bytes;
+ }
+
+ public void clearThreadAssociation() {
+ this.checkNotClosed();
+ this.bytes.clearThreadAssociation();
+ }
+
+ public long size() {
+ this.checkNotClosed();
+ return this.bytes.size();
+ }
+
+ void checkNotClosed() {
+ if(this.isClosed) {
+ System.err.print("Thread " + Thread.currentThread().getName() + " performing processing " + "after free()");
+ ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
+ ThreadInfo[] arr$ = threads;
+ int len$ = threads.length;
+
+ for(int i$ = 0; i$ < len$; ++i$) {
+ ThreadInfo info = arr$[i$];
+ System.out.print(info);
+ }
+
+ System.exit(-1);
+ }
+ }
+ public void free() {
+ this.isClosed = true;
+ this.bytes.free();
+ }
+
+ public void reserve() {
+ this.checkNotClosed();
+ this.bytes.reserve();
+ }
+
+ public boolean release() {
+ this.checkNotClosed();
+ return this.bytes.release();
+ }
+
+ public int refCount() {
+ this.checkNotClosed();
+ return this.bytes.refCount();
+ }
+
+ public void selfTerminating(boolean selfTerminating) {
+ this.checkNotClosed();
+ this.bytes.selfTerminating(selfTerminating);
+ }
+
+ public boolean selfTerminating() {
+ this.checkNotClosed();
+ return this.bytes.selfTerminating();
+ }
+
+ public int readUnsignedByteOrThrow() throws BufferUnderflowException {
+ return this.bytes.readUnsignedByteOrThrow();
+ }
+
+ public void write(long offset, Bytes bytes) {
+ bytes.write(offset, bytes);
+ }
+
+ public Boolean parseBoolean(@NotNull StopCharTester tester) {
+ this.checkNotClosed();
+ return this.bytes.parseBoolean(tester);
+ }
+
+ public void readFully(@NotNull byte[] bytes) {
+ this.checkNotClosed();
+ this.bytes.readFully(bytes);
+ }
+
+ public void readFully(@NotNull char[] data) {
+ this.checkNotClosed();
+ this.bytes.readFully(data);
+ }
+
+ public int skipBytes(int n) {
+ this.checkNotClosed();
+ return this.bytes.skipBytes(n);
+ }
+
+ public boolean readBoolean() {
+ this.checkNotClosed();
+ return this.bytes.readBoolean();
+ }
+
+ public boolean readBoolean(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readBoolean(offset);
+ }
+
+ public int readUnsignedByte() {
+ this.checkNotClosed();
+ return this.bytes.readUnsignedByte();
+ }
+
+ public int readUnsignedByte(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readUnsignedByte(offset);
+ }
+
+ public int readUnsignedShort() {
+ this.checkNotClosed();
+ return this.bytes.readUnsignedShort();
+ }
+
+ public int readUnsignedShort(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readUnsignedShort(offset);
+ }
+
+ @NotNull
+ public String readLine() {
+ this.checkNotClosed();
+ return this.bytes.readLine();
+ }
+
+ @Nullable
+ public String readUTFΔ() {
+ this.checkNotClosed();
+ return this.bytes.readUTFΔ();
+ }
+
+ @Nullable
+ public String readUTFΔ(long offset) throws IllegalStateException {
+ return this.bytes.readUTFΔ(offset);
+ }
+
+ public boolean readUTFΔ(@NotNull StringBuilder stringBuilder) {
+ this.checkNotClosed();
+ return this.bytes.readUTFΔ(stringBuilder);
+ }
+
+ @Override
+ public boolean read8bitText(@NotNull StringBuilder stringBuilder) throws StreamCorruptedException {
+ return false;
+ }
+
+ @NotNull
+ public String parseUtf8(@NotNull StopCharTester tester) {
+ this.checkNotClosed();
+ return this.bytes.parseUtf8(tester);
+ }
+
+ public void parseUtf8(@NotNull StringBuilder builder, @NotNull StopCharTester tester) {
+ this.checkNotClosed();
+ this.bytes.parseUtf8(builder, tester);
+ }
+
+ public boolean stepBackAndSkipTo(@NotNull StopCharTester tester) {
+ this.checkNotClosed();
+ return this.bytes.stepBackAndSkipTo(tester);
+ }
+
+ public boolean skipTo(@NotNull StopCharTester tester) {
+ this.checkNotClosed();
+ return this.bytes.skipTo(tester);
+ }
+
+ @NotNull
+ public String readUTF() {
+ this.checkNotClosed();
+ return this.bytes.readUTF();
+ }
+
+ public short readCompactShort() {
+ this.checkNotClosed();
+ return this.bytes.readCompactShort();
+ }
+
+ public int readCompactUnsignedShort() {
+ this.checkNotClosed();
+ return this.bytes.readCompactUnsignedShort();
+ }
+
+ public int readInt24() {
+ this.checkNotClosed();
+ return this.bytes.readInt24();
+ }
+
+ public int readInt24(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readInt24(offset);
+ }
+
+ public long readUnsignedInt() {
+ this.checkNotClosed();
+ return this.bytes.readUnsignedInt();
+ }
+
+ public long readUnsignedInt(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readUnsignedInt(offset);
+ }
+
+ public int readCompactInt() {
+ this.checkNotClosed();
+ return this.bytes.readCompactInt();
+ }
+
+ public long readCompactUnsignedInt() {
+ this.checkNotClosed();
+ return this.bytes.readCompactUnsignedInt();
+ }
+
+ public long readInt48() {
+ this.checkNotClosed();
+ return this.bytes.readInt48();
+ }
+
+ public long readInt48(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readInt48(offset);
+ }
+
+ public long readCompactLong() {
+ this.checkNotClosed();
+ return this.bytes.readCompactLong();
+ }
+
+ public long readStopBit() {
+ this.checkNotClosed();
+ return this.bytes.readStopBit();
+ }
+
+ public double readCompactDouble() {
+ this.checkNotClosed();
+ return this.bytes.readCompactDouble();
+ }
+
+ public void read(@NotNull ByteBuffer bb) {
+ this.checkNotClosed();
+ this.bytes.read(bb);
+ }
+
+ public void read(@NotNull ByteBuffer bb, int length) {
+ this.checkNotClosed();
+ this.bytes.read(bb, length);
+ }
+
+ public void write(@NotNull byte[] bytes) {
+ this.checkNotClosed();
+ this.bytes.write(bytes);
+ }
+
+ public void writeBoolean(boolean v) {
+ this.checkNotClosed();
+ this.bytes.writeBoolean(v);
+ }
+
+ public void writeBoolean(long offset, boolean v) {
+ this.checkNotClosed();
+ this.bytes.writeBoolean(offset, v);
+ }
+
+ public void writeBytes(@NotNull String s) {
+ this.checkNotClosed();
+ this.bytes.writeBytes(s);
+ }
+
+ public void writeChars(@NotNull String s) {
+ this.checkNotClosed();
+ this.bytes.writeChars(s);
+ }
+
+ public void writeChars(@NotNull CharSequence cs) {
+ this.checkNotClosed();
+ this.bytes.writeChars(cs);
+ }
+
+ public void writeUTF(@NotNull String str) {
+ this.checkNotClosed();
+ this.bytes.writeUTF(str);
+ }
+
+ public void writeUTFΔ(@Nullable CharSequence str) throws IllegalArgumentException {
+ this.bytes.writeUTFΔ(str);
+ }
+
+ public void writeUTFΔ(long offset, int maxSize, @Nullable CharSequence s) throws IllegalStateException {
+ this.bytes.writeUTFΔ(offset, maxSize, s);
+ }
+
+ @Override
+ public void write8bitText(@Nullable CharSequence s) {
+
+ }
+
+ @NotNull
+ public ByteStringAppender append(@NotNull CharSequence str) {
+ this.checkNotClosed();
+ return this.bytes.append(str);
+ }
+
+ public void writeByte(int v) {
+ this.checkNotClosed();
+ this.bytes.writeByte(v);
+ }
+
+ public void writeUnsignedByte(int v) {
+ this.checkNotClosed();
+ this.bytes.writeUnsignedByte(v);
+ }
+
+ public void writeUnsignedByte(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeUnsignedByte(offset, v);
+ }
+
+ public void write(@NotNull char[] data) {
+ this.checkNotClosed();
+ this.bytes.write(data);
+ }
+
+ public void write(@NotNull char[] data, int off, int len) {
+ this.checkNotClosed();
+ this.bytes.write(data, off, len);
+ }
+
+ public void writeUnsignedShort(int v) {
+ this.checkNotClosed();
+ this.bytes.writeUnsignedShort(v);
+ }
+
+ public void writeUnsignedShort(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeUnsignedShort(offset, v);
+ }
+
+ public void writeCompactShort(int v) {
+ this.checkNotClosed();
+ this.bytes.writeCompactShort(v);
+ }
+
+ public void writeCompactUnsignedShort(int v) {
+ this.checkNotClosed();
+ this.bytes.writeCompactUnsignedShort(v);
+ }
+
+ public void writeInt24(int v) {
+ this.checkNotClosed();
+ this.bytes.writeInt24(v);
+ }
+
+ public void writeInt24(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeInt24(offset, v);
+ }
+
+ public void writeUnsignedInt(long v) {
+ this.checkNotClosed();
+ this.bytes.writeUnsignedInt(v);
+ }
+
+ public void writeUnsignedInt(long offset, long v) {
+ this.checkNotClosed();
+ this.bytes.writeUnsignedInt(offset, v);
+ }
+
+ public void writeCompactInt(int v) {
+ this.checkNotClosed();
+ this.bytes.writeCompactInt(v);
+ }
+
+ public void writeCompactUnsignedInt(long v) {
+ this.checkNotClosed();
+ this.bytes.writeCompactUnsignedInt(v);
+ }
+
+ public void writeInt48(long v) {
+ this.checkNotClosed();
+ this.bytes.writeInt48(v);
+ }
+
+ public void writeInt48(long offset, long v) {
+ this.checkNotClosed();
+ this.bytes.writeInt48(offset, v);
+ }
+
+ public void writeCompactLong(long v) {
+ this.checkNotClosed();
+ this.bytes.writeCompactLong(v);
+ }
+
+ public void writeStopBit(long n) {
+ this.checkNotClosed();
+ this.bytes.writeStopBit(n);
+ }
+
+ public void writeCompactDouble(double v) {
+ this.checkNotClosed();
+ this.bytes.writeCompactDouble(v);
+ }
+
+ public void write(@NotNull ByteBuffer bb) {
+ this.checkNotClosed();
+ this.bytes.write(bb);
+ }
+
+ @NotNull
+ public ByteStringAppender append(@NotNull CharSequence s, int start, int end) {
+ this.checkNotClosed();
+ return this.bytes.append(s, start, end);
+ }
+
+ @NotNull
+ public ByteStringAppender append(@Nullable Enum value) {
+ this.checkNotClosed();
+ return this.bytes.append(value);
+ }
+
+ @NotNull
+ public ByteStringAppender append(boolean b) {
+ this.checkNotClosed();
+ return this.bytes.append(b);
+ }
+
+ @NotNull
+ public ByteStringAppender append(char c) {
+ this.checkNotClosed();
+ return this.bytes.append(c);
+ }
+
+ @NotNull
+ public ByteStringAppender append(int num) {
+ this.checkNotClosed();
+ return this.bytes.append(num);
+ }
+
+ @NotNull
+ public ByteStringAppender append(long num) {
+ this.checkNotClosed();
+ return this.bytes.append(num);
+ }
+
+ @NotNull
+ public ByteStringAppender append(long num, int base) {
+ this.checkNotClosed();
+ return this.bytes.append(num, base);
+ }
+
+ @NotNull
+ public ByteStringAppender appendDateMillis(long timeInMS) {
+ this.checkNotClosed();
+ return this.bytes.appendDateMillis(timeInMS);
+ }
+
+ @NotNull
+ public ByteStringAppender appendDateTimeMillis(long timeInMS) {
+ this.checkNotClosed();
+ return this.bytes.appendDateTimeMillis(timeInMS);
+ }
+
+ @NotNull
+ public ByteStringAppender appendTimeMillis(long timeInMS) {
+ this.checkNotClosed();
+ return this.bytes.appendTimeMillis(timeInMS);
+ }
+
+ @NotNull
+ public ByteStringAppender append(double d) {
+ this.checkNotClosed();
+ return this.bytes.append(d);
+ }
+
+ public double parseDouble() {
+ this.checkNotClosed();
+ return this.bytes.parseDouble();
+ }
+
+ @NotNull
+ public <E> ByteStringAppender append(@NotNull Iterable<E> list, @NotNull CharSequence separator) {
+ this.checkNotClosed();
+ return this.bytes.append(list, separator);
+ }
+
+ @NotNull
+ <E> ByteStringAppender append(@NotNull List<E> list, @NotNull CharSequence separator) {
+ this.checkNotClosed();
+ return this.bytes.append(list, separator);
+ }
+
+ @NotNull
+ public MutableDecimal parseDecimal(@NotNull MutableDecimal decimal) {
+ this.checkNotClosed();
+ return this.bytes.parseDecimal(decimal);
+ }
+
+ public long parseLong() {
+ this.checkNotClosed();
+ return this.bytes.parseLong();
+ }
+
+ public long parseLong(int base) {
+ this.checkNotClosed();
+ return this.bytes.parseLong(base);
+ }
+
+ @NotNull
+ public ByteStringAppender append(double d, int precision) {
+ this.checkNotClosed();
+ return this.bytes.append(d, precision);
+ }
+
+ @NotNull
+ public ByteStringAppender append(@NotNull MutableDecimal md) {
+ this.checkNotClosed();
+ return this.bytes.append(md);
+ }
+
+ @NotNull
+ public InputStream inputStream() {
+ this.checkNotClosed();
+ return this.bytes.inputStream();
+ }
+
+ @NotNull
+ public OutputStream outputStream() {
+ this.checkNotClosed();
+ return this.bytes.outputStream();
+ }
+
+ @NotNull
+ public ObjectSerializer objectSerializer() {
+ this.checkNotClosed();
+ return this.bytes.objectSerializer();
+ }
+
+ public <E> void writeEnum(@Nullable E e) {
+ this.checkNotClosed();
+ this.bytes.writeEnum(e);
+ }
+
+ public <E> E readEnum(@NotNull Class<E> eClass) {
+ this.checkNotClosed();
+ return this.bytes.readEnum(eClass);
+ }
+
+ @Override
+ public <E> E readEnum(long offset, int maxSize, Class<E> eClass) {
+ this.checkNotClosed();
+ return this.bytes.readEnum(offset, maxSize, eClass);
+ }
+
+ @Override
+ public void writeEnum(long offset, int maxSize, Object object) {
+ this.checkNotClosed();
+ this.bytes.writeEnum(offset, maxSize, object);
+ }
+
+ public <E extends Enum<E>> E parseEnum(@NotNull Class<E> eClass, @NotNull StopCharTester tester) {
+ this.checkNotClosed();
+ return this.bytes.parseEnum(eClass, tester);
+ }
+
+ public <E> void writeList(@NotNull Collection<E> list) {
+ this.checkNotClosed();
+ this.bytes.writeList(list);
+ }
+
+ public <K, V> void writeMap(@NotNull Map<K, V> map) {
+ this.checkNotClosed();
+ this.bytes.writeMap(map);
+ }
+
+ public <E> void readList(@NotNull Collection<E> list, @NotNull Class<E> eClass) {
+ this.checkNotClosed();
+ this.bytes.readList(list, eClass);
+ }
+
+ @NotNull
+ public <K, V> Map<K, V> readMap(@NotNull Map<K, V> map, @NotNull Class<K> kClass, @NotNull Class<V> vClass) {
+ this.checkNotClosed();
+ return this.bytes.readMap(map, kClass, vClass);
+ }
+
+ public int available() {
+ this.checkNotClosed();
+ return this.bytes.available();
+ }
+
+ public int read() {
+ this.checkNotClosed();
+ return this.bytes.read();
+ }
+
+ public int read(@NotNull byte[] bytes) {
+ this.checkNotClosed();
+ return this.bytes.read(bytes);
+ }
+
+ public long skip(long n) {
+ this.checkNotClosed();
+ return this.bytes.skip(n);
+ }
+
+ public void close() {
+ this.checkNotClosed();
+ this.bytes.close();
+ }
+
+ public void finish() throws IndexOutOfBoundsException {
+ this.bytes.finish();
+ }
+
+ public boolean isFinished() {
+ this.checkNotClosed();
+ return this.bytes.isFinished();
+ }
+
+ public Bytes clear() {
+ this.checkNotClosed();
+ return this.bytes.clear();
+ }
+
+ public Bytes flip() {
+ this.checkNotClosed();
+ return this.bytes.flip();
+ }
+
+ public void flush() {
+ this.checkNotClosed();
+ this.bytes.flush();
+ }
+
+ @Nullable
+ public Object readObject() {
+ this.checkNotClosed();
+ return this.bytes.readObject();
+ }
+
+ @Nullable
+ public <T> T readObject(Class<T> tClass) throws IllegalStateException {
+ return this.bytes.readObject(tClass);
+ }
+
+ @Nullable
+ public <T> T readInstance(@NotNull Class<T> objClass, T obj) {
+ this.checkNotClosed();
+ return this.bytes.readInstance(objClass, obj);
+ }
+
+ public void writeObject(@Nullable Object obj) {
+ this.checkNotClosed();
+ this.bytes.writeObject(obj);
+ }
+
+ public <OBJ> void writeInstance(@NotNull Class<OBJ> objClass, @NotNull OBJ obj) {
+ this.checkNotClosed();
+ this.bytes.writeInstance(objClass, obj);
+ }
+
+ public boolean tryLockInt(long offset) {
+ this.checkNotClosed();
+ return this.bytes.tryLockInt(offset);
+ }
+
+ public boolean tryLockNanosInt(long offset, long nanos) {
+ this.checkNotClosed();
+ return this.bytes.tryLockNanosInt(offset, nanos);
+ }
+
+ public void busyLockInt(long offset) throws InterruptedException, IllegalStateException {
+ this.bytes.busyLockInt(offset);
+ }
+
+ public void unlockInt(long offset) throws IllegalMonitorStateException {
+ this.bytes.unlockInt(offset);
+ }
+
+ public void resetLockInt(long offset) {
+ this.checkNotClosed();
+ this.bytes.resetLockInt(offset);
+ }
+
+ public int threadIdForLockInt(long offset) {
+ this.checkNotClosed();
+ return this.bytes.threadIdForLockInt(offset);
+ }
+
+ public boolean tryLockLong(long offset) {
+ this.checkNotClosed();
+ return this.bytes.tryLockLong(offset);
+ }
+
+ public boolean tryLockNanosLong(long offset, long nanos) {
+ this.checkNotClosed();
+ return this.bytes.tryLockNanosLong(offset, nanos);
+ }
+
+ public void busyLockLong(long offset) throws InterruptedException, IllegalStateException {
+ this.bytes.busyLockLong(offset);
+ }
+
+ public void unlockLong(long offset) throws IllegalMonitorStateException {
+ this.bytes.unlockLong(offset);
+ }
+
+ public void resetLockLong(long offset) {
+ this.checkNotClosed();
+ this.bytes.resetLockLong(offset);
+ }
+
+ public long threadIdForLockLong(long offset) {
+ this.checkNotClosed();
+ return this.bytes.threadIdForLockLong(offset);
+ }
+
+ public int getAndAdd(long offset, int delta) {
+ this.checkNotClosed();
+ return this.bytes.getAndAdd(offset, delta);
+ }
+
+ public int addAndGetInt(long offset, int delta) {
+ this.checkNotClosed();
+ return this.bytes.addAndGetInt(offset, delta);
+ }
+
+ public byte addByte(long offset, byte b) {
+ this.checkNotClosed();
+ return this.bytes.addByte(offset, b);
+ }
+
+ public int addUnsignedByte(long offset, int i) {
+ this.checkNotClosed();
+ return this.bytes.addUnsignedByte(offset, i);
+ }
+
+ public short addShort(long offset, short s) {
+ this.checkNotClosed();
+ return this.bytes.addShort(offset, s);
+ }
+
+ public int addUnsignedShort(long offset, int i) {
+ this.checkNotClosed();
+ return this.bytes.addUnsignedShort(offset, i);
+ }
+
+ public int addInt(long offset, int i) {
+ this.checkNotClosed();
+ return this.bytes.addInt(offset, i);
+ }
+
+ public long addUnsignedInt(long offset, long i) {
+ this.checkNotClosed();
+ return this.bytes.addUnsignedInt(offset, i);
+ }
+
+ public long addLong(long offset, long i) {
+ this.checkNotClosed();
+ return this.bytes.addLong(offset, i);
+ }
+
+ public float addFloat(long offset, float f) {
+ this.checkNotClosed();
+ return this.bytes.addFloat(offset, f);
+ }
+
+ public double addDouble(long offset, double d) {
+ this.checkNotClosed();
+ return this.bytes.addDouble(offset, d);
+ }
+
+ public int addAtomicInt(long offset, int i) {
+ this.checkNotClosed();
+ return this.bytes.addAtomicInt(offset, i);
+ }
+
+ public long addAtomicLong(long offset, long delta) {
+ this.checkNotClosed();
+ return this.bytes.addAtomicLong(offset, delta);
+ }
+
+ public float addAtomicFloat(long offset, float delta) {
+ this.checkNotClosed();
+ return this.bytes.addAtomicFloat(offset, delta);
+ }
+
+ public double addAtomicDouble(long offset, double delta) {
+ this.checkNotClosed();
+ return this.bytes.addAtomicDouble(offset, delta);
+ }
+
+ public float readVolatileFloat(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readVolatileFloat(offset);
+ }
+
+ public double readVolatileDouble(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readVolatileDouble(offset);
+ }
+
+ public void writeOrderedFloat(long offset, float v) {
+ this.checkNotClosed();
+ this.bytes.writeOrderedFloat(offset, v);
+ }
+
+ public void writeOrderedDouble(long offset, double v) {
+ this.checkNotClosed();
+ this.bytes.writeOrderedDouble(offset, v);
+ }
+
+ public int length() {
+ this.checkNotClosed();
+ return this.bytes.length();
+ }
+
+ public char charAt(int index) {
+ this.checkNotClosed();
+ return this.bytes.charAt(index);
+ }
+
+ public void readMarshallable(@NotNull Bytes in) throws IllegalStateException {
+ this.bytes.readMarshallable(in);
+ }
+
+ public void writeMarshallable(@NotNull Bytes out) {
+ this.checkNotClosed();
+ this.bytes.writeMarshallable(out);
+ }
+
+ public void write(RandomDataInput bytes) {
+ this.checkNotClosed();
+ this.bytes.write(bytes);
+ }
+
+ public void write(Byteable byteable) {
+ this.checkNotClosed();
+ this.bytes.write(byteable);
+ }
+
+ public boolean startsWith(RandomDataInput input) {
+ this.checkNotClosed();
+ return this.bytes.startsWith(input);
+ }
+
+ @NotNull
+ public String toString() {
+ this.checkNotClosed();
+ return this.bytes.toString();
+ }
+
+ @NotNull
+ public String toDebugString() {
+ this.checkNotClosed();
+ return this.bytes.toDebugString();
+ }
+
+ @NotNull
+ public String toDebugString(long limit) {
+ this.checkNotClosed();
+ return this.bytes.toDebugString(limit);
+ }
+
+ @Override
+ public String toHexString(long limit) {
+ this.checkNotClosed();
+ return this.bytes.toHexString(limit);
+ }
+
+ public void toString(Appendable sb, long start, long position, long end) {
+ this.checkNotClosed();
+ this.bytes.toString(sb, start, position, end);
+ }
+
+ public void asString(Appendable appendable) {
+ this.checkNotClosed();
+ this.bytes.asString(appendable);
+ }
+
+ public CharSequence asString() {
+ this.checkNotClosed();
+ return this.bytes.asString();
+ }
+
+ public boolean compareAndSwapDouble(long offset, double expected, double value) {
+ this.checkNotClosed();
+ return this.bytes.compareAndSwapDouble(offset, expected, value);
+ }
+
+ public File file() {
+ this.checkNotClosed();
+ return this.bytes.file();
+ }
+
+ public boolean tryRWReadLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ return this.bytes.tryRWReadLock(offset, timeOutNS);
+ }
+
+ public boolean tryRWWriteLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ return this.bytes.tryRWWriteLock(offset, timeOutNS);
+ }
+
+ public void unlockRWReadLock(long offset) {
+ this.checkNotClosed();
+ this.bytes.unlockRWReadLock(offset);
+ }
+
+ public void unlockRWWriteLock(long offset) {
+ this.checkNotClosed();
+ this.bytes.unlockRWWriteLock(offset);
+ }
+
+ public Bytes slice() {
+ this.checkNotClosed();
+ return this.bytes.slice();
+ }
+
+ public Bytes slice(long offset, long length) {
+ this.checkNotClosed();
+ return this.bytes.slice(offset, length);
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ this.checkNotClosed();
+ return this.bytes.subSequence(start, end);
+ }
+
+ public Bytes bytes() {
+ this.checkNotClosed();
+ return this.bytes.bytes();
+ }
+
+ public Bytes bytes(long offset, long length) {
+ this.checkNotClosed();
+ return this.bytes.bytes(offset, length);
+ }
+
+ public long address() {
+ this.checkNotClosed();
+ return this.bytes.address();
+ }
+
+ public Bytes zeroOut() {
+ this.checkNotClosed();
+ return this.bytes.zeroOut();
+ }
+
+ public Bytes zeroOut(long start, long end) {
+ this.checkNotClosed();
+ return this.bytes.zeroOut(start, end);
+ }
+
+ public Bytes zeroOut(long start, long end, boolean ifNotZero) {
+ this.checkNotClosed();
+ return this.bytes.zeroOut(start, end, ifNotZero);
+ }
+
+ public int read(@NotNull byte[] bytes, int off, int len) {
+ this.checkNotClosed();
+ return this.bytes.read(bytes, off, len);
+ }
+
+ public byte readByte() {
+ this.checkNotClosed();
+ return this.bytes.readByte();
+ }
+
+ public byte readByte(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readByte(offset);
+ }
+
+ public void readFully(@NotNull byte[] b, int off, int len) {
+ this.checkNotClosed();
+ this.bytes.readFully(b, off, len);
+ }
+
+ public void readFully(long offset, byte[] bytes, int off, int len) {
+ this.checkNotClosed();
+ this.bytes.readFully(offset, bytes, off, len);
+ }
+
+ public void readFully(@NotNull char[] data, int off, int len) {
+ this.checkNotClosed();
+ this.bytes.readFully(data, off, len);
+ }
+
+ public short readShort() {
+ this.checkNotClosed();
+ return this.bytes.readShort();
+ }
+
+ public short readShort(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readShort(offset);
+ }
+
+ public char readChar() {
+ this.checkNotClosed();
+ return this.bytes.readChar();
+ }
+
+ public char readChar(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readChar(offset);
+ }
+
+ public int readInt() {
+ this.checkNotClosed();
+ return this.bytes.readInt();
+ }
+
+ public int readInt(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readInt(offset);
+ }
+
+ public int readVolatileInt() {
+ this.checkNotClosed();
+ return this.bytes.readVolatileInt();
+ }
+
+ public int readVolatileInt(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readVolatileInt(offset);
+ }
+
+ public long readLong() {
+ this.checkNotClosed();
+ return this.bytes.readLong();
+ }
+
+ @Override
+ public long readIncompleteLong(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readIncompleteLong(offset);
+ }
+
+ public long readLong(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readLong(offset);
+ }
+
+ public long readVolatileLong() {
+ this.checkNotClosed();
+ return this.bytes.readVolatileLong();
+ }
+
+ public long readVolatileLong(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readVolatileLong(offset);
+ }
+
+ public float readFloat() {
+ this.checkNotClosed();
+ return this.bytes.readFloat();
+ }
+
+ public float readFloat(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readFloat(offset);
+ }
+
+ public double readDouble() {
+ this.checkNotClosed();
+ return this.bytes.readDouble();
+ }
+
+ public double readDouble(long offset) {
+ this.checkNotClosed();
+ return this.bytes.readDouble(offset);
+ }
+
+ public void write(int b) {
+ this.checkNotClosed();
+ this.bytes.write(b);
+ }
+
+ public void writeByte(long offset, int b) {
+ this.checkNotClosed();
+ this.bytes.writeByte(offset, b);
+ }
+
+ public void write(long offset, @NotNull byte[] bytes) {
+ this.checkNotClosed();
+ this.bytes.write(offset, bytes);
+ }
+
+ public void write(byte[] bytes, int off, int len) {
+ this.checkNotClosed();
+ this.bytes.write(bytes, off, len);
+ }
+
+ public void write(long offset, byte[] bytes, int off, int len) {
+ this.checkNotClosed();
+ this.bytes.write(offset, bytes, off, len);
+ }
+
+ public void writeShort(int v) {
+ this.checkNotClosed();
+ this.bytes.writeShort(v);
+ }
+
+ public void writeShort(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeShort(offset, v);
+ }
+
+ public void writeChar(int v) {
+ this.checkNotClosed();
+ this.bytes.writeChar(v);
+ }
+
+ public void writeChar(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeChar(offset, v);
+ }
+
+ public void writeInt(int v) {
+ this.checkNotClosed();
+ this.bytes.writeInt(v);
+ }
+
+ public void writeInt(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeInt(offset, v);
+ }
+
+ public void writeOrderedInt(int v) {
+ this.checkNotClosed();
+ this.bytes.writeOrderedInt(v);
+ }
+
+ public void writeOrderedInt(long offset, int v) {
+ this.checkNotClosed();
+ this.bytes.writeOrderedInt(offset, v);
+ }
+
+ public boolean compareAndSwapInt(long offset, int expected, int x) {
+ this.checkNotClosed();
+ return this.bytes.compareAndSwapInt(offset, expected, x);
+ }
+
+ public void writeLong(long v) {
+ this.checkNotClosed();
+ this.bytes.writeLong(v);
+ }
+
+ public void writeLong(long offset, long v) {
+ this.checkNotClosed();
+ this.bytes.writeLong(offset, v);
+ }
+
+ public void writeOrderedLong(long v) {
+ this.checkNotClosed();
+ this.bytes.writeOrderedLong(v);
+ }
+
+ public void writeOrderedLong(long offset, long v) {
+ this.checkNotClosed();
+ this.bytes.writeOrderedLong(offset, v);
+ }
+
+ public boolean compareAndSwapLong(long offset, long expected, long x) {
+ this.checkNotClosed();
+ return this.bytes.compareAndSwapLong(offset, expected, x);
+ }
+
+ public void writeFloat(float v) {
+ this.checkNotClosed();
+ this.bytes.writeFloat(v);
+ }
+
+ public void writeFloat(long offset, float v) {
+ this.checkNotClosed();
+ this.bytes.writeFloat(offset, v);
+ }
+
+ public void writeDouble(double v) {
+ this.checkNotClosed();
+ this.bytes.writeDouble(v);
+ }
+
+ public void writeDouble(long offset, double v) {
+ this.checkNotClosed();
+ this.bytes.writeDouble(offset, v);
+ }
+
+ public void readObject(Object object, int start, int end) {
+ this.checkNotClosed();
+ this.bytes.readObject(object, start, end);
+ }
+
+ public void writeObject(Object object, int start, int end) {
+ this.checkNotClosed();
+ this.bytes.writeObject(object, start, end);
+ }
+
+ public boolean compare(long offset, RandomDataInput input, long inputOffset, long len) {
+ this.checkNotClosed();
+ return this.bytes.compare(offset, input, inputOffset, len);
+ }
+
+ public long position() {
+ this.checkNotClosed();
+ return this.bytes.position();
+ }
+
+ public Bytes position(long position) {
+ this.checkNotClosed();
+ return this.bytes.position(position);
+ }
+
+ public void write(RandomDataInput bytes, long position, long length) {
+ this.checkNotClosed();
+ this.bytes.write(bytes, position, length);
+ }
+
+ public long capacity() {
+ this.checkNotClosed();
+ return this.bytes.capacity();
+ }
+
+ public long remaining() {
+ this.checkNotClosed();
+ return this.bytes.remaining();
+ }
+
+ public long limit() {
+ this.checkNotClosed();
+ return this.bytes.limit();
+ }
+
+ public Bytes limit(long limit) {
+ this.checkNotClosed();
+ return this.bytes.limit(limit);
+ }
+
+ @NotNull
+ public ByteOrder byteOrder() {
+ this.checkNotClosed();
+ return this.bytes.byteOrder();
+ }
+
+ public void checkEndOfBuffer() throws IndexOutOfBoundsException {
+ this.bytes.checkEndOfBuffer();
+ }
+
+ public Bytes load() {
+ this.checkNotClosed();
+ return this.bytes.load();
+ }
+
+ public void alignPositionAddr(int powerOf2) {
+ this.checkNotClosed();
+ this.bytes.alignPositionAddr(powerOf2);
+ }
+
+ public ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse) {
+ this.checkNotClosed();
+ return this.bytes.sliceAsByteBuffer(toReuse);
+ }
+
+ @Override
+ public long nextSetBit(long fromIndex) {
+ this.checkNotClosed();
+ return this.bytes.nextSetBit(fromIndex);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/ChronicleUnsafe.java b/lang/src/main/java/net/openhft/lang/io/ChronicleUnsafe.java
new file mode 100644
index 0000000..4f1576b
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/ChronicleUnsafe.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.model.constraints.NotNull;
+import sun.misc.Unsafe;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+/**
+ * Created by Rob Austin
+ */
+public class ChronicleUnsafe {
+
+ private final MappedFile mappedFile;
+ private MappedMemory mappedMemory = null;
+ public static final Unsafe UNSAFE;
+
+ static {
+ try {
+ @SuppressWarnings("ALL")
+ Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+ theUnsafe.setAccessible(true);
+ UNSAFE = (Unsafe) theUnsafe.get(null);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private long chunkSize;
+ private long offset;
+ private final long mask;
+ private long last = -1;
+
+ /**
+ * @param mappedFile a until that able to map block of memory to a file
+ * @throws IllegalStateException if the block size is not a power of 2
+ */
+ public ChronicleUnsafe(@NotNull MappedFile mappedFile) {
+ long blockSize = mappedFile.blockSize();
+
+ if (((blockSize & -blockSize) != blockSize))
+ throw new IllegalStateException("the block size has to be a power of 2");
+
+ this.mappedFile = mappedFile;
+ this.chunkSize = mappedFile.blockSize();
+
+ long shift = (int) (Math.log(blockSize) / Math.log(2));
+
+ mask = ~((1L << shift) - 1L);
+ }
+
+ public long toAddress(long address) {
+ return (mask & address ^ this.last) == 0 ? address + offset : toAddress0(address);
+ }
+
+ public long toAddress0(long address) {
+ int index = (int) ((address / chunkSize));
+ long remainder = address - (((long) index) * chunkSize);
+
+ // index == 0 is the header, so we wont reference count the header
+ if (mappedMemory != null && mappedMemory.index() != 0)
+ mappedFile.release(mappedMemory);
+
+ try {
+ this.mappedMemory = mappedFile.acquire(index);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ long result = mappedMemory.bytes().address() + remainder;
+ this.offset = result - address;
+ this.last = mask & address;
+ return result;
+ }
+
+ public long toRemainingInChunk(long address) {
+ int chunk = (int) ((address / chunkSize));
+ long remainder = address - (((long) chunk) * chunkSize);
+
+ return mappedMemory.bytes().capacity() - remainder;
+ }
+
+ public int arrayBaseOffset(Class<?> aClass) {
+ return UNSAFE.arrayBaseOffset(aClass);
+ }
+
+ public int pageSize() {
+ throw new UnsupportedOperationException("todo (pageSize)");
+ }
+
+ public long allocateMemory(int aVoid) {
+ throw new UnsupportedOperationException("todo (allocateMemory)");
+ }
+
+ public long getLong(byte[] bytes, long address) {
+ return UNSAFE.getLong(bytes, toAddress(address));
+ }
+
+ public long getLong(Object object, long address) {
+ return UNSAFE.getLong(object, toAddress(address));
+ }
+
+ public void setMemory(long startAddress, long len, byte defaultValue) {
+ long remaining = len;
+ while (remaining > 0) {
+ long address = toAddress(startAddress);
+ long remainingInChunk = toRemainingInChunk(startAddress);
+ if (remainingInChunk > remaining)
+ remainingInChunk = remaining;
+ UNSAFE.setMemory(address, remainingInChunk, defaultValue);
+ startAddress += remainingInChunk;
+ remaining -= remainingInChunk;
+ }
+ }
+
+ public byte getByte(long address) {
+ return UNSAFE.getByte(toAddress(address));
+ }
+
+ public void putByte(long address, byte value) {
+ UNSAFE.putByte(toAddress(address), value);
+ }
+
+ public void putLong(long address, long value) {
+ UNSAFE.putLong(toAddress(address), value);
+ }
+
+ public long getLong(long address) {
+ return UNSAFE.getLong(toAddress(address));
+ }
+
+ public void copyMemory(Object o, long positionAddr, Object bytes, long i, long len2) {
+ throw new UnsupportedOperationException("todo (copyMemory)");
+ }
+
+ public short getShort(long address) {
+ return UNSAFE.getShort(toAddress(address));
+ }
+
+ public char getChar(long address) {
+ return UNSAFE.getChar(toAddress(address));
+ }
+
+ public int getInt(long address) {
+ return UNSAFE.getInt(toAddress(address));
+ }
+
+ public int getIntVolatile(Object o, long address) {
+ return UNSAFE.getIntVolatile(o, toAddress(address));
+ }
+
+ public long getLongVolatile(Object o, long address) {
+ return UNSAFE.getLongVolatile(o, toAddress(address));
+ }
+
+ public float getFloat(long address) {
+ return UNSAFE.getFloat(toAddress(address));
+ }
+
+ public double getDouble(long address) {
+ return UNSAFE.getDouble(toAddress(address));
+ }
+
+ public void putShort(long address, short v) {
+ UNSAFE.putShort(toAddress(address), v);
+ }
+
+ public void putChar(long address, char v) {
+ UNSAFE.putChar(toAddress(address), v);
+ }
+
+ public void putInt(long address, int v) {
+ UNSAFE.putInt(toAddress(address), v);
+ }
+
+ public void putOrderedInt(Object o, long address, int v) {
+ UNSAFE.putOrderedInt(o, toAddress(address), v);
+ }
+
+ public boolean compareAndSwapInt(Object o, long address, int expected, int v) {
+ return UNSAFE.compareAndSwapInt(o, toAddress(address), expected, v);
+ }
+
+ public void putOrderedLong(Object o, long address, long v) {
+ UNSAFE.putOrderedLong(o, toAddress(address), v);
+ }
+
+ public boolean compareAndSwapLong(Object o, long address, long expected, long v) {
+ return UNSAFE.compareAndSwapLong(o, toAddress(address), expected, v);
+ }
+
+ public void putFloat(long address, float v) {
+ UNSAFE.putFloat(toAddress(address), v);
+ }
+
+ public void putDouble(long address, double v) {
+ UNSAFE.putDouble(toAddress(address), v);
+ }
+
+ public void putLong(Object o, long address, long aLong) {
+ UNSAFE.putLong(o, toAddress(address), aLong);
+ }
+
+ public void putByte(Object o, long address, byte aByte) {
+ UNSAFE.putByte(o, toAddress(address), aByte);
+ }
+
+ public byte getByte(Object o, long address) {
+ return UNSAFE.getByte(o, toAddress(address));
+ }
+
+ public void copyMemory(long l, long positionAddr, long length) {
+ throw new UnsupportedOperationException("todo (copyMemory)");
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/DirectByteBufferBytes.java b/lang/src/main/java/net/openhft/lang/io/DirectByteBufferBytes.java
new file mode 100644
index 0000000..938dd74
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/DirectByteBufferBytes.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import sun.nio.ch.DirectBuffer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class DirectByteBufferBytes extends NativeBytes implements IByteBufferBytes {
+ private ByteBuffer buffer;
+
+ public DirectByteBufferBytes(int capacity) {
+ this(ByteBuffer.allocateDirect(capacity).order(ByteOrder.nativeOrder()), 0, capacity);
+ }
+
+ public DirectByteBufferBytes(final ByteBuffer buffer) {
+ this(buffer, 0, buffer.capacity());
+ }
+
+ public DirectByteBufferBytes(final ByteBuffer buffer, int start, int capacity) {
+ super(
+ ((DirectBuffer) buffer).address() + start,
+ ((DirectBuffer) buffer).address() + capacity
+ );
+
+ this.buffer = buffer;
+ }
+
+ @Override
+ public ByteBuffer buffer() {
+ return buffer;
+ }
+
+ @Override
+ public ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse) {
+ return sliceAsByteBuffer(toReuse, buffer);
+ }
+
+ protected DirectByteBufferBytes resize(int newCapacity, boolean cleanup, boolean preserveData) {
+ if(newCapacity != capacity()) {
+ final ByteBuffer oldBuffer = this.buffer;
+ final long oldAddress = this.startAddr;
+ final long oldPosition = position();
+
+ if(preserveData && (oldPosition > newCapacity)) {
+ throw new IllegalArgumentException(
+ "Capacity can't be less than currently used data (size=" + oldPosition
+ + ", capacity=" + newCapacity + ")"
+ );
+ }
+
+ this.buffer = ByteBuffer.allocateDirect(newCapacity).order(ByteOrder.nativeOrder());
+ setStartPositionAddress(((DirectBuffer) buffer).address());
+ this.capacityAddr = this.startAddr + newCapacity;
+ this.limitAddr = this.capacityAddr;
+
+ if (preserveData && (oldPosition > 0)) {
+ UNSAFE.copyMemory(oldAddress, this.startAddr, Math.min(newCapacity, oldPosition));
+ this.positionAddr = this.startAddr + Math.min(newCapacity, oldPosition);
+ }
+
+ if(cleanup) {
+ IOTools.clean(oldBuffer);
+ }
+ }
+
+ return this;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/DirectBytes.java b/lang/src/main/java/net/openhft/lang/io/DirectBytes.java
index 7e783e4..0f83371 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/DirectBytes.java
+++ b/lang/src/main/java/net/openhft/lang/io/DirectBytes.java
@@ -1,43 +1,62 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* @author peter.lawrey
*/
public class DirectBytes extends NativeBytes {
@NotNull
- private final DirectStore store;
+ private final BytesStore store;
- DirectBytes(@NotNull DirectStore store) {
- super(store.bytesMarshallerFactory, store.address, store.address, store.address + store.size);
+ public DirectBytes(@NotNull BytesStore store, AtomicInteger refCount) {
+ super(store.objectSerializer(), store.address(), store.address() + store.size(), refCount);
+ this.store = store;
+ }
+
+ public DirectBytes(@NotNull BytesStore store, AtomicInteger refCount, long offset, long length) {
+ super(store.objectSerializer(), store.address() + offset, store.address() + offset + length, refCount);
this.store = store;
}
public void positionAndSize(long offset, long size) {
- if (offset < 0 || size < 0 || offset + size > store.size)
+ if (offset < 0 || size < 0 || offset + size > store.size())
throw new IllegalArgumentException();
- startAddr = positionAddr = store.address + offset;
- limitAddr = startAddr + size;
+
+ setStartPositionAddress(store.address() + offset);
+ capacityAddr = limitAddr = startAddr + size;
}
- public DirectStore store() {
+ public BytesStore store() {
return store;
}
+
+ @Override
+ protected void cleanup() {
+ store.free();
+ }
+
+ @Override
+ public ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse) {
+ return sliceAsByteBuffer(toReuse, store);
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/io/DirectStore.java b/lang/src/main/java/net/openhft/lang/io/DirectStore.java
index 7099165..ca1b4a3 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/DirectStore.java
+++ b/lang/src/main/java/net/openhft/lang/io/DirectStore.java
@@ -1,45 +1,57 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
+import net.openhft.lang.io.serialization.BytesMarshallableSerializer;
import net.openhft.lang.io.serialization.BytesMarshallerFactory;
+import net.openhft.lang.io.serialization.JDKZObjectSerializer;
+import net.openhft.lang.io.serialization.ObjectSerializer;
import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
import sun.misc.Cleaner;
+import java.io.File;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* @author peter.lawrey
*/
-public class DirectStore {
- protected BytesMarshallerFactory bytesMarshallerFactory;
+public class DirectStore implements BytesStore, AutoCloseable {
+ private final ObjectSerializer objectSerializer;
private final Cleaner cleaner;
- protected long address;
- protected long size;
+ private final Deallocator deallocator;
+ private long address;
+ private long size;
+ private final AtomicInteger refCount = new AtomicInteger(1);
public DirectStore(long size) {
this(new VanillaBytesMarshallerFactory(), size);
}
- public DirectStore(BytesMarshallerFactory bytesMarshallerFactory, long size) {
+ private DirectStore(BytesMarshallerFactory bytesMarshallerFactory, long size) {
this(bytesMarshallerFactory, size, true);
}
- public DirectStore(BytesMarshallerFactory bytesMarshallerFactory, long size, boolean zeroOut) {
- this.bytesMarshallerFactory = bytesMarshallerFactory;
+ private DirectStore(BytesMarshallerFactory bytesMarshallerFactory, long size, boolean zeroOut) {
+ this(BytesMarshallableSerializer.create(bytesMarshallerFactory, JDKZObjectSerializer.INSTANCE), size, zeroOut);
+ }
+
+ public DirectStore(ObjectSerializer objectSerializer, long size, boolean zeroOut) {
+ this.objectSerializer = objectSerializer;
address = NativeBytes.UNSAFE.allocateMemory(size);
// System.out.println("old value " + Integer.toHexString(NativeBytes.UNSAFE.getInt(null, address)));
@@ -49,36 +61,65 @@ public class DirectStore {
}
this.size = size;
- cleaner = Cleaner.create(this, new Runnable() {
- @Override
- public void run() {
- if (address != 0)
- NativeBytes.UNSAFE.freeMemory(address);
- address = DirectStore.this.size = 0;
- }
- });
+ deallocator = new Deallocator(address);
+ cleaner = Cleaner.create(this, deallocator);
+ }
+
+ @Override
+ public ObjectSerializer objectSerializer() {
+ return objectSerializer;
}
@NotNull
public static DirectStore allocate(long size) {
- return new DirectStore(null, size);
+ return new DirectStore(new VanillaBytesMarshallerFactory(), size);
}
@NotNull
public static DirectStore allocateLazy(long size) {
- return new DirectStore(null, size, false);
+ return new DirectStore(new VanillaBytesMarshallerFactory(), size, false);
}
-/* public void resize(long newSize) {
- if (newSize == size)
- return;
- address = NativeBytes.UNSAFE.reallocateMemory(address, newSize);
+ /**
+ * Resizes this {@code DirectStore} to the {@code newSize}.
+ *
+ * <p>If {@code zeroOut} is {@code false}, the memory past the old size is not zeroed out and
+ * will generally be garbage.
+ *
+ * <p>{@code DirectStore} don't keep track of the child {@code DirectBytes} instances, so after
+ * the resize they might point to the wrong memory. Use at your own risk.
+ *
+ * @param newSize new size of this {@code DirectStore}
+ * @param zeroOut if the memory past the old size should be zeroed out on increasing resize
+ * @throws IllegalArgumentException if the {@code newSize} is not positive
+ */
+ public void resize(long newSize, boolean zeroOut) {
+ if (newSize <= 0)
+ throw new IllegalArgumentException("Given newSize is " + newSize +
+ " but should be positive");
+ address = deallocator.address = NativeBytes.UNSAFE.reallocateMemory(address, newSize);
+ if (zeroOut && newSize > size) {
+ NativeBytes.UNSAFE.setMemory(address + size, newSize - size, (byte) 0);
+ }
size = newSize;
- }*/
+ }
+ @SuppressWarnings("ConstantConditions")
@NotNull
- public DirectBytes createSlice() {
- return new DirectBytes(this);
+ public DirectBytes bytes() {
+ boolean debug = false;
+ assert debug = true;
+ return debug ? new BoundsCheckingDirectBytes(this, refCount) : new DirectBytes(this, refCount);
+ }
+
+ @NotNull
+ public DirectBytes bytes(long offset, long length) {
+ return new DirectBytes(this, refCount, offset, length);
+ }
+
+ @Override
+ public long address() {
+ return address;
}
public void free() {
@@ -89,8 +130,41 @@ public class DirectStore {
return size;
}
- public BytesMarshallerFactory bytesMarshallerFactory() {
- return bytesMarshallerFactory;
+ public static BytesStore allocateLazy(long sizeInBytes, ObjectSerializer objectSerializer) {
+ return new DirectStore(objectSerializer, sizeInBytes, false);
+ }
+
+ @Override
+ public File file() {
+ return null;
+ }
+
+ /**
+ * calls free
+ */
+ @Override
+ public void close() {
+ free();
}
+ /**
+ * Static nested class instead of anonymous because the latter would hold a strong reference to
+ * this DirectStore preventing it from becoming phantom-reachable.
+ */
+ private static class Deallocator implements Runnable {
+ private volatile long address;
+
+ Deallocator(long address) {
+ assert address != 0;
+ this.address = address;
+ }
+
+ @Override
+ public void run() {
+ if (address == 0)
+ return;
+ NativeBytes.UNSAFE.freeMemory(address);
+ address = 0;
+ }
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/io/EscapingStopCharTester.java b/lang/src/main/java/net/openhft/lang/io/EscapingStopCharTester.java
new file mode 100755
index 0000000..235f55e
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/EscapingStopCharTester.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+/**
+ * Created by peter.lawrey on 16/01/15.
+ */
+public class EscapingStopCharTester implements StopCharTester {
+ private final StopCharTester sct;
+ private boolean escaped = false;
+
+ EscapingStopCharTester(StopCharTester sct) {
+ this.sct = sct;
+ }
+
+ public static StopCharTester escaping(StopCharTester sct) {
+ return new EscapingStopCharTester(sct);
+ }
+
+ @Override
+ public boolean isStopChar(int ch) throws IllegalStateException {
+ if (escaped) {
+ escaped = false;
+ return false;
+ }
+ if (ch == '\\') {
+ escaped = true;
+ return false;
+ }
+ return sct.isStopChar(ch);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/FileLifecycleListener.java b/lang/src/main/java/net/openhft/lang/io/FileLifecycleListener.java
new file mode 100755
index 0000000..71ddec4
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/FileLifecycleListener.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ * Created by peter.lawrey on 05/08/2015.
+ */
+public interface FileLifecycleListener {
+ enum EventType {
+ NEW,
+ MMAP,
+ UNMAP,
+ GROW,
+ SYNC,
+ DELETE,
+ CLOSE
+ }
+
+ enum FileLifecycleListeners implements FileLifecycleListener {
+ IGNORE {
+ @Override
+ public void onEvent(EventType type, File file, long timeInNanos) {
+ }
+ },
+ CONSOLE {
+ @Override
+ public void onEvent(EventType type, File file, long timeInNanos) {
+ System.out.println(
+ "File " + file + " took " + timeInNanos / 1000 / 1e3 + " ms. to " + type);
+ }
+ },
+ LOG {
+ @Override
+ public void onEvent(EventType type, File file, long timeInNanos) {
+ LoggerFactory.getLogger(FileLifecycleListeners.class).info(
+ "File " + file + " took " + timeInNanos / 1000 / 1e3 + " ms. to " + type);
+ }
+ }
+ }
+
+ void onEvent(EventType type, File file, long timeInNanos);
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/IByteBufferBytes.java b/lang/src/main/java/net/openhft/lang/io/IByteBufferBytes.java
new file mode 100755
index 0000000..43997b2
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/IByteBufferBytes.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Created by peter.lawrey on 27/01/15.
+ */
+public interface IByteBufferBytes extends Bytes {
+ /**
+ * Obtain the underlying ByteBuffer
+ */
+ ByteBuffer buffer();
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/IOTools.java b/lang/src/main/java/net/openhft/lang/io/IOTools.java
index 854e8fe..b87cb68 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/IOTools.java
+++ b/lang/src/main/java/net/openhft/lang/io/IOTools.java
@@ -1,29 +1,32 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
+import org.slf4j.LoggerFactory;
+import sun.misc.Cleaner;
+import sun.nio.ch.DirectBuffer;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
+import java.nio.ByteBuffer;
import java.nio.charset.Charset;
-import java.util.logging.Logger;
/**
* @author peter.lawrey
@@ -61,7 +64,7 @@ public enum IOTools {
deleteDir(new File(dirPath));
}
- public static void deleteDir(File dir) {
+ private static void deleteDir(File dir) {
// delete one level.
if (dir.isDirectory()) {
File[] files = dir.listFiles();
@@ -69,11 +72,19 @@ public enum IOTools {
for (File file : files)
if (file.isDirectory()) {
deleteDir(file);
+
} else if (!file.delete()) {
- Logger.getLogger(IOTools.class.getName()).info("... unable to delete " + file);
+ LoggerFactory.getLogger(IOTools.class).info("... unable to delete {}", file);
}
-
}
dir.delete();
}
+
+ public static void clean(ByteBuffer bb) {
+ if (bb instanceof DirectBuffer) {
+ Cleaner cl = ((DirectBuffer) bb).cleaner();
+ if (cl != null)
+ cl.clean();
+ }
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/io/MappedFile.java b/lang/src/main/java/net/openhft/lang/io/MappedFile.java
index f4907b9..6174cbd 100644..100755
--- a/lang/src/main/java/net/openhft/lang/io/MappedFile.java
+++ b/lang/src/main/java/net/openhft/lang/io/MappedFile.java
@@ -1,22 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
+import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -26,29 +27,29 @@ import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
-import java.util.logging.Logger;
/**
* This manages the full life cycle of a file and its mappings.
*/
public class MappedFile {
- private final FileChannel fileChannel;
- private final String basePath;
+ private final String filename;
private final long blockSize;
private final long overlapSize;
+
+ private final FileChannel fileChannel;
private final List<MappedMemory> maps = new ArrayList<MappedMemory>();
// short list of the last two mappings.
private volatile MappedMemory map0, map1;
- public MappedFile(String basePath, long blockSize) throws FileNotFoundException {
- this(basePath, blockSize, 0L);
+ public MappedFile(String filename, long blockSize) throws FileNotFoundException {
+ this(filename, blockSize, 0L);
}
- public MappedFile(String basePath, long blockSize, long overlapSize) throws FileNotFoundException {
- this.basePath = basePath;
+ public MappedFile(String filename, long blockSize, long overlapSize) throws FileNotFoundException {
+ this.filename = filename;
this.blockSize = blockSize;
this.overlapSize = overlapSize;
- fileChannel = new RandomAccessFile(basePath, "rw").getChannel();
+ fileChannel = new RandomAccessFile(filename, "rw").getChannel();
}
public static MappedByteBuffer getMap(@NotNull FileChannel fileChannel, long start, int size) throws IOException {
@@ -66,26 +67,22 @@ public class MappedFile {
if (e.getMessage() == null || !e.getMessage().endsWith("user-mapped section open")) {
throw e;
}
- if (i < 10)
- //noinspection CallToThreadYield
- Thread.yield();
- else
- try {
- //noinspection BusyWait
- Thread.sleep(1);
- } catch (InterruptedException ignored) {
- Thread.currentThread().interrupt();
- throw e;
- }
+ try {
+ //noinspection BusyWait
+ Thread.sleep(1);
+ } catch (InterruptedException ignored) {
+ Thread.currentThread().interrupt();
+ throw e;
+ }
}
}
}
- public MappedMemory acquire(long index) throws IOException {
- return acquire(index, false);
+ public String name() {
+ return filename;
}
- public MappedMemory acquire(long index, boolean prefetch) throws IOException {
+ public MappedMemory acquire(long index) throws IOException {
MappedMemory map0 = this.map0, map1 = this.map1;
if (map0 != null && map0.index() == index) {
map0.reserve();
@@ -95,10 +92,29 @@ public class MappedFile {
map1.reserve();
return map1;
}
- return acquire0(index, prefetch);
+ return acquire0(index);
+ }
+
+ /**
+ * gets the refCount a given index, or returns 0, if the there is no mapping for this index
+ *
+ * @param index
+ * @return the mapping at this {@code index}
+ * @throws IndexOutOfBoundsException if the index is out of range
+ */
+ public int getRefCount(long index) {
+ try {
+ for (MappedMemory m : maps) {
+ if (m.index() == index)
+ return m.refCount();
+ }
+ } catch (Exception e) {
+ return 0;
+ }
+ return 0;
}
- private synchronized MappedMemory acquire0(long index, boolean prefetch) throws IOException {
+ private synchronized MappedMemory acquire0(long index) throws IOException {
if (map1 != null)
map1.release();
map1 = map0;
@@ -130,8 +146,10 @@ public class MappedFile {
count++;
}
}
- if (count > 1)
- Logger.getLogger(MappedFile.class.getName()).info(basePath + " memory mappings left unreleased, num= " + count);
+ if (count > 1) {
+ LoggerFactory.getLogger(MappedFile.class).info("{} memory mappings left unreleased, num= {}", filename, count);
+ }
+
maps.clear();
fileChannel.close();
}
@@ -143,4 +161,17 @@ public class MappedFile {
return 0;
}
}
+
+ public long blockSize() {
+ return blockSize;
+ }
+
+ public void release(MappedMemory mappedMemory) {
+ if (mappedMemory.release()) {
+ if (map0 == mappedMemory)
+ map0 = null;
+ if (map1 == mappedMemory)
+ map1 = null;
+ }
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/io/MappedMemory.java b/lang/src/main/java/net/openhft/lang/io/MappedMemory.java
index df97ef5..6fe488d 100644
--- a/lang/src/main/java/net/openhft/lang/io/MappedMemory.java
+++ b/lang/src/main/java/net/openhft/lang/io/MappedMemory.java
@@ -1,57 +1,66 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import sun.misc.Cleaner;
+import net.openhft.lang.ReferenceCounted;
+import net.openhft.lang.io.serialization.ObjectSerializer;
import sun.nio.ch.DirectBuffer;
+import java.io.File;
import java.nio.MappedByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
-public class MappedMemory {
+public class MappedMemory implements ReferenceCounted, BytesStore {
private final MappedByteBuffer buffer;
+ private final DirectByteBufferBytes bytes;
private final long index;
- private final AtomicInteger refCount = new AtomicInteger(1);
+ private final AtomicInteger refCount = new AtomicInteger(0);
private volatile boolean unmapped = false;
public MappedMemory(MappedByteBuffer buffer, long index) {
this.buffer = buffer;
this.index = index;
- }
-
- private static void unmap(MappedByteBuffer bb) {
- Cleaner cl = ((DirectBuffer) bb).cleaner();
- if (cl != null)
- cl.clean();
+ bytes = new DirectByteBufferBytes(buffer);
}
public long index() {
return index;
}
+ @Override
public void reserve() {
if (unmapped) throw new IllegalStateException();
refCount.incrementAndGet();
}
- public void release() {
+ /**
+ * @return true if release cause the ref count to drop to zero and the resource was freed
+ */
+ @Override
+ public boolean release() {
if (unmapped) throw new IllegalStateException();
- if (refCount.decrementAndGet() > 0) return;
+ if (refCount.decrementAndGet() > 0) return false;
close();
+ return true;
+ }
+
+ @Override
+ public int refCount() {
+ return refCount.get();
}
public MappedByteBuffer buffer() {
@@ -62,8 +71,33 @@ public class MappedMemory {
return ((DirectBuffer) buffer).address();
}
- public int refCount() {
- return refCount.get();
+ @Override
+ public long size() {
+ return bytes.capacity();
+ }
+
+ @Override
+ public void free() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ObjectSerializer objectSerializer() {
+ return null;
+ }
+
+ @Override
+ public File file() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Bytes bytes() {
+ return bytes;
+ }
+
+ @Override
+ public Bytes bytes(long offset, long length) {
+ throw new UnsupportedOperationException();
}
public static void release(MappedMemory mapmem) {
@@ -77,7 +111,7 @@ public class MappedMemory {
}
public void close() {
- unmap(buffer);
+ IOTools.clean(buffer);
unmapped = true;
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/MappedNativeBytes.java b/lang/src/main/java/net/openhft/lang/io/MappedNativeBytes.java
new file mode 100755
index 0000000..79f4e9c
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/MappedNativeBytes.java
@@ -0,0 +1,730 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import org.jetbrains.annotations.NotNull;
+import sun.misc.Unsafe;
+
+import java.io.EOFException;
+import java.lang.reflect.Field;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * works in conjunction with a MappedFile to map additional memory blocks when required This
+ * implementation is very similar to {@code NativeBytes}, accept that the memory address resolution
+ * is left to ChronicleUnsafe, rather than being part of this class.
+ */
+public class MappedNativeBytes extends AbstractBytes {
+
+ @NotNull
+ public final ThreadLocal<ChronicleUnsafe> threadLocal = new ThreadLocal<ChronicleUnsafe>();
+
+ static final int BYTES_OFFSET;
+ static final int CHARS_OFFSET;
+
+ static {
+ try {
+ @SuppressWarnings("ALL")
+ Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+ theUnsafe.setAccessible(true);
+ Unsafe unsafe = (Unsafe) theUnsafe.get(null);
+ BYTES_OFFSET = unsafe.arrayBaseOffset(byte[].class);
+ CHARS_OFFSET = unsafe.arrayBaseOffset(char[].class);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+ private final boolean isSingleThreaded;
+
+ protected long start;
+ protected long position;
+ protected long limit;
+ protected long capacity;
+ private final MappedFile mappedFile;
+ private final ChronicleUnsafe chronicleUnsafe;
+
+ public MappedNativeBytes(@NotNull final MappedFile mappedFile, boolean isSingleThreaded) {
+ this.isSingleThreaded = isSingleThreaded;
+ this.mappedFile = mappedFile;
+ this.start = 0;
+ this.position = start;
+ this.limit = this.capacity = Long.MAX_VALUE;
+ this.chronicleUnsafe = (isSingleThreaded) ? new ChronicleUnsafe(mappedFile) : null;
+ }
+
+ public MappedNativeBytes(ObjectSerializer objectSerializer,
+ long sliceStart,
+ long capacity,
+ @NotNull AtomicInteger refCount,
+ @NotNull MappedFile mappedFile,
+ boolean singleThreaded) {
+ this.isSingleThreaded = singleThreaded;
+ setObjectSerializer(objectSerializer);
+ this.start = sliceStart;
+ this.position = 0;
+ this.capacity = capacity;
+ this.refCount.set(refCount.get());
+ this.mappedFile = mappedFile;
+ this.chronicleUnsafe = (isSingleThreaded) ? new ChronicleUnsafe(mappedFile) : null;
+ }
+
+ @Override
+ public MappedNativeBytes slice() {
+ return new MappedNativeBytes(objectSerializer(), position, limit, refCount, mappedFile, isSingleThreaded);
+ }
+
+ @Override
+ public MappedNativeBytes slice(long offset, long length) {
+ long sliceStart = position + offset;
+ assert sliceStart >= start && sliceStart < capacity;
+ long sliceEnd = sliceStart + length;
+ assert sliceEnd > sliceStart && sliceEnd <= capacity;
+ return new MappedNativeBytes(objectSerializer(), sliceStart, sliceEnd, refCount, mappedFile, isSingleThreaded);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ long subStart = position + start;
+ if (subStart < position || subStart > limit)
+ throw new IndexOutOfBoundsException();
+ long subEnd = position + end;
+ if (subEnd < subStart || subEnd > limit)
+ throw new IndexOutOfBoundsException();
+ if (start == end)
+ return "";
+ return new MappedNativeBytes(objectSerializer(), subStart, subEnd, refCount, mappedFile, isSingleThreaded);
+ }
+
+ @Override
+ public MappedNativeBytes bytes() {
+ return new MappedNativeBytes(objectSerializer(), start, capacity, refCount, mappedFile, isSingleThreaded);
+ }
+
+ @Override
+ public MappedNativeBytes bytes(long offset, long length) {
+ long sliceStart = start + offset;
+ assert sliceStart >= start && sliceStart < capacity;
+ long sliceEnd = sliceStart + length;
+ assert sliceEnd > sliceStart && sliceEnd <= capacity;
+ return new MappedNativeBytes(objectSerializer(), sliceStart, sliceEnd, refCount, mappedFile, isSingleThreaded);
+ }
+
+ @Override
+ public long address() {
+ return start;
+ }
+
+ @Override
+ public Bytes zeroOut() {
+ clear();
+ getChronicleUnsafe().setMemory(start, capacity(), (byte) 0);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end) {
+ if (start < 0 || end > limit())
+ throw new IllegalArgumentException("start: " + start + ", end: " + end);
+ if (start >= end)
+ return this;
+ getChronicleUnsafe().setMemory(this.start + start, end - start, (byte) 0);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end, boolean ifNotZero) {
+ return ifNotZero ? zeroOutDirty(start, end) : zeroOut(start, end);
+ }
+
+ private Bytes zeroOutDirty(long start, long end) {
+ if (start < 0 || end > limit())
+ throw new IllegalArgumentException("start: " + start + ", end: " + end);
+ if (start >= end)
+ return this;
+ // get unaligned leading bytes
+ ChronicleUnsafe unsafe = getChronicleUnsafe();
+ while (start < end && (start & 7) != 0) {
+ byte b = unsafe.getByte(this.start + start);
+ if (b != 0)
+ unsafe.putByte(this.start + start, (byte) 0);
+ start++;
+ }
+ // check 64-bit aligned access
+ while (start < end - 7) {
+ long l = unsafe.getLong(this.start + start);
+ if (l != 0)
+ unsafe.putLong(this.start + start, 0L);
+ start += 8;
+ }
+ // check unaligned tail
+ while (start < end) {
+ byte b = unsafe.getByte(this.start + start);
+ if (b != 0)
+ unsafe.putByte(this.start + start, (byte) 0);
+ start++;
+ }
+ return this;
+ }
+
+ @Override
+ public int read(@NotNull byte[] bytes, int off, int len) {
+ if (len < 0 || off < 0 || off + len > bytes.length)
+ throw new IllegalArgumentException();
+ long left = remaining();
+ if (left <= 0) return -1;
+ int len2 = (int) Math.min(len, left);
+ getChronicleUnsafe().copyMemory(null, position, bytes, BYTES_OFFSET + off, len2);
+ addPosition(len2);
+ return len2;
+ }
+
+ @Override
+ public byte readByte() {
+ byte aByte = getChronicleUnsafe().getByte(position);
+ addPosition(1);
+ return aByte;
+ }
+
+ @Override
+ public byte readByte(long offset) {
+ return getChronicleUnsafe().getByte(start + offset);
+ }
+
+ @Override
+ public void readFully(@NotNull byte[] b, int off, int len) {
+ checkArrayOffs(b.length, off, len);
+ long left = remaining();
+ if (left < len)
+ throw new IllegalStateException(new EOFException());
+ getChronicleUnsafe().copyMemory(null, position, b, BYTES_OFFSET + off, len);
+ addPosition(len);
+ }
+
+ @Override
+ public void readFully(long offset, byte[] bytes, int off, int len) {
+ checkArrayOffs(bytes.length, off, len);
+ getChronicleUnsafe().copyMemory(null, start + offset, bytes, BYTES_OFFSET + off, len);
+ }
+
+ @Override
+ public void readFully(@NotNull char[] data, int off, int len) {
+ checkArrayOffs(data.length, off, len);
+ long bytesOff = off * 2L;
+ long bytesLen = len * 2L;
+ long left = remaining();
+ if (left < bytesLen)
+ throw new IllegalStateException(new EOFException());
+ getChronicleUnsafe().copyMemory(null, position, data, BYTES_OFFSET + bytesOff, bytesLen);
+ addPosition(bytesLen);
+ }
+
+ @Override
+ public short readShort() {
+ short s = getChronicleUnsafe().getShort(position);
+ addPosition(2);
+ return s;
+ }
+
+ @Override
+ public short readShort(long offset) {
+ return getChronicleUnsafe().getShort(start + offset);
+ }
+
+ @Override
+ public char readChar() {
+ char ch = getChronicleUnsafe().getChar(position);
+ addPosition(2);
+ return ch;
+ }
+
+ @Override
+ public char readChar(long offset) {
+ return getChronicleUnsafe().getChar(start + offset);
+ }
+
+ @Override
+ public int readInt() {
+ int i = getChronicleUnsafe().getInt(position);
+ addPosition(4);
+ return i;
+ }
+
+ @Override
+ public int readInt(long offset) {
+ return getChronicleUnsafe().getInt(start + offset);
+ }
+
+ @Override
+ public int readVolatileInt() {
+ int i = getChronicleUnsafe().getIntVolatile(null, position);
+ addPosition(4);
+ return i;
+ }
+
+ @Override
+ public int readVolatileInt(long offset) {
+ return getChronicleUnsafe().getIntVolatile(null, start + offset);
+ }
+
+ @Override
+ public long readLong() {
+ long l = getChronicleUnsafe().getLong(position);
+ addPosition(8);
+ return l;
+ }
+
+ @Override
+ public long readLong(long offset) {
+ return getChronicleUnsafe().getLong(start + offset);
+ }
+
+ @Override
+ public long readVolatileLong() {
+ long l = getChronicleUnsafe().getLongVolatile(null, position);
+ addPosition(8);
+ return l;
+ }
+
+ @Override
+ public long readVolatileLong(long offset) {
+ return getChronicleUnsafe().getLongVolatile(null, start + offset);
+ }
+
+ @Override
+ public float readFloat() {
+ float f = getChronicleUnsafe().getFloat(position);
+ addPosition(4);
+ return f;
+ }
+
+ @Override
+ public float readFloat(long offset) {
+ return getChronicleUnsafe().getFloat(start + offset);
+ }
+
+ @Override
+ public double readDouble() {
+ double d = getChronicleUnsafe().getDouble(position);
+ addPosition(8);
+ return d;
+ }
+
+ @Override
+ public double readDouble(long offset) {
+ return getChronicleUnsafe().getDouble(start + offset);
+ }
+
+ @Override
+ public void write(int b) {
+ getChronicleUnsafe().putByte(position, (byte) b);
+ incrementPositionAddr(1);
+ }
+
+ @Override
+ public void writeByte(long offset, int b) {
+ offsetChecks(offset, 1L);
+ getChronicleUnsafe().putByte(start + offset, (byte) b);
+ }
+
+ @Override
+ public void write(long offset, @NotNull byte[] bytes) {
+ if (offset < 0 || offset + bytes.length > capacity())
+ throw new IllegalArgumentException();
+ getChronicleUnsafe().copyMemory(bytes, BYTES_OFFSET, null, start + offset, bytes.length);
+ addPosition(bytes.length);
+ }
+
+ @Override
+ public void write(byte[] bytes, int off, int len) {
+ if (off < 0 || off + len > bytes.length || len > remaining())
+ throw new IllegalArgumentException();
+ getChronicleUnsafe().copyMemory(bytes, BYTES_OFFSET + off, null, position, len);
+ addPosition(len);
+ }
+
+ @Override
+ public void write(long offset, byte[] bytes, int off, int len) {
+ if (offset < 0 || off + len > bytes.length || offset + len > capacity())
+ throw new IllegalArgumentException();
+ getChronicleUnsafe().copyMemory(bytes, BYTES_OFFSET + off, null, start + offset, len);
+ }
+
+ @Override
+ public void writeShort(int v) {
+ positionChecks(position + 2L);
+ getChronicleUnsafe().putShort(position, (short) v);
+ position += 2L;
+ }
+
+ private long incrementPositionAddr(long value) {
+ positionAddr(positionAddr() + value);
+ return positionAddr();
+ }
+
+ @Override
+ public void writeShort(long offset, int v) {
+ offsetChecks(offset, 2L);
+ getChronicleUnsafe().putShort(start + offset, (short) v);
+ }
+
+ @Override
+ public void writeChar(int v) {
+ positionChecks(position + 2L);
+ getChronicleUnsafe().putChar(position, (char) v);
+ position += 2L;
+ }
+
+ void addPosition(long delta) {
+ positionAddr(positionAddr() + delta);
+ }
+
+ @Override
+ public void writeChar(long offset, int v) {
+ offsetChecks(offset, 2L);
+ getChronicleUnsafe().putChar(start + offset, (char) v);
+ }
+
+ @Override
+ public void writeInt(int v) {
+ positionChecks(position + 4L);
+ getChronicleUnsafe().putInt(position, v);
+ position += 4L;
+ }
+
+ @Override
+ public void writeInt(long offset, int v) {
+ offsetChecks(offset, 4L);
+ getChronicleUnsafe().putInt(start + offset, v);
+ }
+
+ @Override
+ public void writeOrderedInt(int v) {
+ positionChecks(position + 4L);
+ getChronicleUnsafe().putOrderedInt(null, position, v);
+ position += 4L;
+ }
+
+ @Override
+ public void writeOrderedInt(long offset, int v) {
+ offsetChecks(offset, 4L);
+ getChronicleUnsafe().putOrderedInt(null, start + offset, v);
+ }
+
+ @Override
+ public boolean compareAndSwapInt(long offset, int expected, int x) {
+ offsetChecks(offset, 4L);
+ return getChronicleUnsafe().compareAndSwapInt(null, start + offset, expected, x);
+ }
+
+ @Override
+ public void writeLong(long v) {
+ positionChecks(position + 8L);
+ getChronicleUnsafe().putLong(position, v);
+ position += 8L;
+ }
+
+ @Override
+ public void writeLong(long offset, long v) {
+ offsetChecks(offset, 8L);
+ getChronicleUnsafe().putLong(start + offset, v);
+ }
+
+ @Override
+ public void writeOrderedLong(long v) {
+ positionChecks(position + 8L);
+ getChronicleUnsafe().putOrderedLong(null, position, v);
+ position += 8L;
+ }
+
+ @Override
+ public void writeOrderedLong(long offset, long v) {
+ offsetChecks(offset, 8L);
+ getChronicleUnsafe().putOrderedLong(null, start + offset, v);
+ }
+
+ @Override
+ public boolean compareAndSwapLong(long offset, long expected, long x) {
+ offsetChecks(offset, 8L);
+ return getChronicleUnsafe().compareAndSwapLong(null, start + offset, expected, x);
+ }
+
+ @Override
+ public void writeFloat(float v) {
+ positionChecks(position + 4L);
+ getChronicleUnsafe().putFloat(position, v);
+ position += 4L;
+ }
+
+ @Override
+ public void writeFloat(long offset, float v) {
+ offsetChecks(offset, 4L);
+ getChronicleUnsafe().putFloat(start + offset, v);
+ }
+
+ @Override
+ public void writeDouble(double v) {
+ positionChecks(position + 8L);
+ getChronicleUnsafe().putDouble(position, v);
+ position += 8L;
+ }
+
+ @Override
+ public void writeDouble(long offset, double v) {
+ offsetChecks(offset, 8L);
+ getChronicleUnsafe().putDouble(start + offset, v);
+ }
+
+ @Override
+ public void readObject(Object object, int start, int end) {
+ int len = end - start;
+ if (position + len >= limit)
+ throw new IndexOutOfBoundsException("Length out of bounds len: " + len);
+
+ ChronicleUnsafe unsafe = getChronicleUnsafe();
+ for (; len >= 8; len -= 8) {
+ unsafe.putLong(object, (long) start, unsafe.getLong(position));
+ incrementPositionAddr(8L);
+ start += 8;
+ }
+ for (; len > 0; len--) {
+ unsafe.putByte(object, (long) start, unsafe.getByte(position));
+ incrementPositionAddr(1L);
+ start++;
+ }
+ }
+
+ @Override
+ public void writeObject(Object object, int start, int end) {
+ int len = end - start;
+
+ ChronicleUnsafe unsafe = getChronicleUnsafe();
+ for (; len >= 8; len -= 8) {
+ positionChecks(position + 8L);
+ unsafe.putLong(position, unsafe.getLong(object, (long) start));
+ position += 8;
+ start += 8;
+ }
+ for (; len > 0; len--) {
+ positionChecks(position + 1L);
+ unsafe.putByte(position, unsafe.getByte(object, (long) start));
+ position++;
+ start++;
+ }
+ }
+
+ @Override
+ public boolean compare(long offset, RandomDataInput input, long inputOffset, long len) {
+ if (offset < 0 || inputOffset < 0 || len < 0)
+ throw new IndexOutOfBoundsException();
+ if (offset + len < 0 || offset + len > capacity() || inputOffset + len < 0 ||
+ inputOffset + len > input.capacity()) {
+ return false;
+ }
+ long i = 0L;
+ ChronicleUnsafe unsafe = getChronicleUnsafe();
+ for (; i < len - 7L; i += 8L) {
+ if (unsafe.getLong(start + offset + i) != input.readLong(inputOffset + i))
+ return false;
+ }
+ if (i < len - 3L) {
+ if (unsafe.getInt(start + offset + i) != input.readInt(inputOffset + i))
+ return false;
+ i += 4L;
+ }
+ if (i < len - 1L) {
+ if (unsafe.getChar(start + offset + i) != input.readChar(inputOffset + i))
+ return false;
+ i += 2L;
+ }
+ if (i < len) {
+ if (unsafe.getByte(start + offset + i) != input.readByte(inputOffset + i))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public long position() {
+ return (position - start);
+ }
+
+ @Override
+ public MappedNativeBytes position(long position) {
+ if (position < 0 || position > limit())
+ throw new IndexOutOfBoundsException("position: " + position + " limit: " + limit());
+
+ positionAddr(start + position);
+ return this;
+ }
+
+ /**
+ * Change the position acknowleging there is no thread safety assumptions. Best effort setting
+ * is fine. *
+ *
+ * @param position to set if we can.
+ * @return this
+ */
+ public MappedNativeBytes lazyPosition(long position) {
+ if (position < 0 || position > limit())
+ throw new IndexOutOfBoundsException("position: " + position + " limit: " + limit());
+
+ // assume we don't need to no check thread safety.
+
+ positionAddr(start + position);
+ return this;
+ }
+
+ @Override
+ public void write(RandomDataInput bytes, long position, long length) {
+ if (length > remaining())
+ throw new IllegalArgumentException("Attempt to write " + length + " bytes with " + remaining() + " remaining");
+ if (bytes instanceof MappedNativeBytes) {
+ getChronicleUnsafe().copyMemory(((MappedNativeBytes) bytes).start + position, this.position, length);
+ skip(length);
+
+ } else {
+ super.write(bytes, position, length);
+ }
+ }
+
+ @Override
+ public long capacity() {
+ return (capacity - start);
+ }
+
+ @Override
+ public long remaining() {
+ return (limit - position);
+ }
+
+ @Override
+ public long limit() {
+ return (limit - start);
+ }
+
+ @Override
+ public MappedNativeBytes limit(long limit) {
+ if (limit < 0 || limit > capacity()) {
+ throw new IllegalArgumentException("limit: " + limit + " capacity: " + capacity());
+ }
+
+ this.limit = start + limit;
+ return this;
+ }
+
+ @NotNull
+ @Override
+ public ByteOrder byteOrder() {
+ return ByteOrder.nativeOrder();
+ }
+
+ @Override
+ public void checkEndOfBuffer() throws IndexOutOfBoundsException {
+ if (position() > limit()) {
+ throw new IndexOutOfBoundsException(
+ "position is beyond the end of the buffer " + position() + " > " + limit());
+ }
+ }
+
+ public long startAddr() {
+ return start;
+ }
+
+ long capacityAddr() {
+ return capacity;
+ }
+
+ @Override
+ protected void cleanup() {
+ // TODO nothing to do.
+ }
+
+ @Override
+ public Bytes load() {
+ ChronicleUnsafe unsafe = getChronicleUnsafe();
+ int pageSize = unsafe.pageSize();
+ for (long addr = start; addr < capacity; addr += pageSize)
+ unsafe.getByte(addr);
+ return this;
+ }
+
+ public void alignPositionAddr(int powerOf2) {
+ long value = (position + powerOf2 - 1) & ~(powerOf2 - 1);
+ positionAddr(value);
+ }
+
+ public void positionAddr(long positionAddr) {
+ positionChecks(positionAddr);
+ this.position = positionAddr;
+ }
+
+ void positionChecks(long positionAddr) {
+ assert actualPositionChecks(positionAddr);
+ }
+
+ boolean actualPositionChecks(long positionAddr) {
+ if (positionAddr < start)
+ throw new IndexOutOfBoundsException("position before the start by " + (start - positionAddr) + " bytes");
+ if (positionAddr > limit)
+ throw new IndexOutOfBoundsException("position after the limit by " + (positionAddr - limit) + " bytes");
+
+ return true;
+ }
+
+ void offsetChecks(long offset, long len) {
+ assert actualOffsetChecks(offset, len);
+ }
+
+ boolean actualOffsetChecks(long offset, long len) {
+ if (offset < 0L || offset + len > capacity())
+ throw new IndexOutOfBoundsException("offset out of bounds: " + offset + ", len: " +
+ len + ", capacity: " + capacity());
+ return true;
+ }
+
+ public long positionAddr() {
+ return position;
+ }
+
+ @Override
+ public ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse) {
+ return sliceAsByteBuffer(toReuse, null);
+ }
+
+ protected ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse, Object att) {
+ return ByteBufferReuse.INSTANCE.reuse(position, (int) remaining(), att, toReuse);
+ }
+
+ // todo : we should move this lookup further up the stack, so that it can be done, just ONCE, for example once by a single threaded appender
+ // todo : hence the constructor should be give then instance of chronicleUnsafe to use
+ @NotNull
+ public ChronicleUnsafe getChronicleUnsafe() {
+ if (isSingleThreaded)
+ return chronicleUnsafe;
+
+ ChronicleUnsafe chronicleUnsafe = threadLocal.get();
+ if (chronicleUnsafe == null) {
+ chronicleUnsafe = new ChronicleUnsafe(mappedFile);
+ threadLocal.set(chronicleUnsafe);
+ }
+
+ return chronicleUnsafe;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/MappedStore.java b/lang/src/main/java/net/openhft/lang/io/MappedStore.java
new file mode 100644
index 0000000..df6b9f2
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/MappedStore.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.BytesMarshallableSerializer;
+import net.openhft.lang.io.serialization.BytesMarshallerFactory;
+import net.openhft.lang.io.serialization.JDKZObjectSerializer;
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+public class MappedStore extends AbstractMappedStore {
+ public MappedStore(File file, FileChannel.MapMode mode, long size) throws IOException {
+ this(file, mode, size, new VanillaBytesMarshallerFactory());
+ }
+
+ @Deprecated
+ public MappedStore(File file, FileChannel.MapMode mode, long size,
+ BytesMarshallerFactory bytesMarshallerFactory) throws IOException {
+ this(file, mode, size, BytesMarshallableSerializer.create(
+ bytesMarshallerFactory, JDKZObjectSerializer.INSTANCE));
+ }
+
+ public MappedStore(File file, FileChannel.MapMode mode, long size,
+ ObjectSerializer objectSerializer) throws IOException {
+ this(file, mode, 0L, size, objectSerializer);
+ }
+
+ public MappedStore(File file, FileChannel.MapMode mode, long startInFile, long size,
+ ObjectSerializer objectSerializer) throws IOException {
+ super(new MmapInfoHolder(), file, mode, startInFile, size, objectSerializer);
+ mmapInfoHolder.lock();
+ }
+}
+
diff --git a/lang/src/main/java/net/openhft/lang/io/MultiStoreBytes.java b/lang/src/main/java/net/openhft/lang/io/MultiStoreBytes.java
index c2b6679..b9107e0 100644
--- a/lang/src/main/java/net/openhft/lang/io/MultiStoreBytes.java
+++ b/lang/src/main/java/net/openhft/lang/io/MultiStoreBytes.java
@@ -1,40 +1,57 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
public class MultiStoreBytes extends NativeBytes {
- private DirectStore store;
+ private Bytes underlyingBytes;
+ private long underlyingOffset;
public MultiStoreBytes() {
- super(NO_PAGE, NO_PAGE, NO_PAGE);
- this.store = store;
+ super(NO_PAGE, NO_PAGE);
}
- public void storePositionAndSize(DirectStore store, long offset, long size) {
- if (offset < 0 || size < 0 || offset + size > store.size)
- throw new IllegalArgumentException();
- this.store = store;
- this.bytesMarshallerFactory = store.bytesMarshallerFactory;
- startAddr = positionAddr = store.address + offset;
- limitAddr = startAddr + size;
+ public void storePositionAndSize(BytesStore store, long offset, long size) {
+ if (offset < 0 || size < 0 || offset + size > store.size())
+ throw new IllegalArgumentException("offset: " + offset + ", size: " + size + ", store.size: " + store.size());
+ setObjectSerializer(store.objectSerializer());
+
+ setStartPositionAddress(store.address() + offset);
+ capacityAddr = limitAddr = startAddr + size;
+ underlyingBytes = null;
+ underlyingOffset = 0;
+ }
+
+ public void setBytesOffset(Bytes bytes, long offset) {
+ setObjectSerializer(bytes.objectSerializer());
+
+ long bytesAddr = bytes.address();
+ setStartPositionAddress(bytesAddr + offset);
+ capacityAddr = limitAddr = bytesAddr + bytes.capacity();
+ underlyingBytes = bytes;
+ underlyingOffset = offset;
+ }
+
+ public Bytes underlyingBytes() {
+ if (underlyingBytes == null) throw new IllegalStateException();
+ return underlyingBytes;
}
- public DirectStore store() {
- return store;
+ public long underlyingOffset() {
+ return underlyingOffset;
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/MutableDecimal.java b/lang/src/main/java/net/openhft/lang/io/MutableDecimal.java
index 773ce07..c3037c1 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/MutableDecimal.java
+++ b/lang/src/main/java/net/openhft/lang/io/MutableDecimal.java
@@ -1,32 +1,31 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
import java.math.BigDecimal;
-import java.math.RoundingMode;
/**
* @author peter.lawrey
*/
@SuppressWarnings({"CompareToUsesNonFinalVariable", "NonFinalFieldReferenceInEquals", "NonFinalFieldReferencedInHashCode"})
public class MutableDecimal extends Number implements Comparable<MutableDecimal> {
- static final double[] TENS = new double[16];
+ private static final double[] TENS = new double[16];
static {
TENS[0] = 1;
@@ -54,15 +53,13 @@ public class MutableDecimal extends Number implements Comparable<MutableDecimal>
set(d, precision);
}
- public void set(double d, int precision) {
- double d2 = precision > 0 ? d * tens(precision) : d / tens(-precision);
- scale = precision;
- if (Math.abs(d2) < 1e16) {
- value = Math.round(d2);
- } else {
- BigDecimal bd = BigDecimal.valueOf(d).setScale(precision, RoundingMode.HALF_UP);
- value = bd.unscaledValue().longValue();
+ void set(double d, int precision) {
+ while (d > Long.MAX_VALUE) {
+ d /= 10;
+ precision++;
}
+ value = Math.round(d);
+ this.scale = precision;
}
public void set(long value, int scale) {
@@ -74,7 +71,7 @@ public class MutableDecimal extends Number implements Comparable<MutableDecimal>
return value;
}
- public int scale() {
+ int scale() {
return scale;
}
@@ -135,6 +132,7 @@ public class MutableDecimal extends Number implements Comparable<MutableDecimal>
if (digit < 0) {
digit = 8;
v = (v >>> 1) / 5;
+
} else {
v /= 10;
}
diff --git a/lang/src/main/java/net/openhft/lang/io/NativeBytes.java b/lang/src/main/java/net/openhft/lang/io/NativeBytes.java
index 2a974d7..96aba3a 100755
--- a/lang/src/main/java/net/openhft/lang/io/NativeBytes.java
+++ b/lang/src/main/java/net/openhft/lang/io/NativeBytes.java
@@ -1,28 +1,35 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
import net.openhft.lang.io.serialization.BytesMarshallerFactory;
+import net.openhft.lang.io.serialization.ObjectSerializer;
import org.jetbrains.annotations.NotNull;
import sun.misc.Unsafe;
import java.io.EOFException;
+import java.io.IOException;
import java.lang.reflect.Field;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.lang.Long.numberOfTrailingZeros;
/**
* @author peter.lawrey
@@ -34,7 +41,9 @@ public class NativeBytes extends AbstractBytes {
@NotNull
@SuppressWarnings("ALL")
public static final Unsafe UNSAFE;
+ protected static final long NO_PAGE;
static final int BYTES_OFFSET;
+ static final int CHARS_OFFSET;
static {
try {
@@ -43,36 +52,64 @@ public class NativeBytes extends AbstractBytes {
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
BYTES_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
-
+ CHARS_OFFSET = UNSAFE.arrayBaseOffset(char[].class);
} catch (Exception e) {
throw new AssertionError(e);
}
+ NO_PAGE = UNSAFE.allocateMemory(UNSAFE.pageSize());
}
- protected static final long NO_PAGE = UNSAFE.allocateMemory(UNSAFE.pageSize());
-
protected long startAddr;
protected long positionAddr;
protected long limitAddr;
+ protected long capacityAddr;
- public NativeBytes(long startAddr, long positionAddr, long limitAddr) {
- this.startAddr = startAddr;
- this.positionAddr = positionAddr;
- this.limitAddr = limitAddr;
+ public NativeBytes(long startAddr, long capacityAddr) {
+ super();
+ setStartPositionAddress(startAddr);
+ if (startAddr > capacityAddr)
+ throw new IllegalArgumentException("Missorted capacity address");
+ this.limitAddr =
+ this.capacityAddr = capacityAddr;
+ positionChecks(positionAddr);
}
- public NativeBytes(BytesMarshallerFactory bytesMarshallerFactory, long startAddr, long positionAddr, long limitAddr) {
- super(bytesMarshallerFactory);
- this.startAddr = startAddr;
- this.positionAddr = positionAddr;
- this.limitAddr = limitAddr;
+ /**
+ * @deprecated Use {@link #NativeBytes(ObjectSerializer, long, long, AtomicInteger)} instead
+ */
+ @Deprecated
+ public NativeBytes(BytesMarshallerFactory bytesMarshallerFactory,
+ long startAddr, long capacityAddr, AtomicInteger refCount) {
+ super(bytesMarshallerFactory, refCount);
+
+ setStartPositionAddress(startAddr);
+ this.limitAddr =
+ this.capacityAddr = capacityAddr;
+ positionChecks(positionAddr);
+ }
+
+ public NativeBytes(ObjectSerializer objectSerializer,
+ long startAddr, long capacityAddr, AtomicInteger refCount) {
+ super(objectSerializer, refCount);
+
+ setStartPositionAddress(startAddr);
+ this.limitAddr =
+ this.capacityAddr = capacityAddr;
+ positionChecks(positionAddr);
}
public NativeBytes(NativeBytes bytes) {
- super(bytes.bytesMarshallerFactory());
- this.startAddr = bytes.startAddr;
+ super(bytes.objectSerializer(), new AtomicInteger(1));
+ setStartPositionAddress(bytes.startAddr);
+
this.positionAddr = bytes.positionAddr;
this.limitAddr = bytes.limitAddr;
+ this.capacityAddr = bytes.capacityAddr;
+ positionChecks(positionAddr);
+ }
+
+ public static NativeBytes wrap(long address, long capacity) {
+ return new NativeBytes(address, address + capacity);
}
public static long longHash(byte[] bytes, int off, int len) {
@@ -85,6 +122,177 @@ public class NativeBytes extends AbstractBytes {
return hash;
}
+ static long nextSetBit0(int firstByte, int maximum, long startAddr) {
+ for (int i = firstByte; i < maximum; i += 8) {
+ long l = UNSAFE.getLong(startAddr + i);
+ if (l != 0)
+ return (i << 3) + numberOfTrailingZeros(l);
+ }
+ return -1;
+ }
+
+ static long nextSetBit0(long firstByte, long maximum, long startAddr) {
+ for (long i = firstByte; i < maximum; i += 8) {
+ long l = UNSAFE.getLong(startAddr + i);
+ if (l != 0)
+ return (i << 3) + numberOfTrailingZeros(l);
+ }
+ return -1;
+ }
+
+ public void setStartPositionAddress(long startAddr) {
+ if ((startAddr & ~0x3fff) == 0)
+ throw new AssertionError("Invalid address " + Long.toHexString(startAddr));
+ this.positionAddr =
+ this.startAddr = startAddr;
+ }
+
+ // optimised to reduce overhead.
+ public void readUTF0(@NotNull Appendable appendable, int utflen)
+ throws IOException {
+ if (utflen > remaining())
+ throw new BufferUnderflowException();
+ if (appendable instanceof StringBuilder)
+ readUTF1((StringBuilder) appendable, utflen);
+ else
+ readUTF1(appendable, utflen);
+ }
+
+ private void readUTF1(@NotNull StringBuilder sb, int utflen)
+ throws IOException {
+ int count = 0;
+ sb.ensureCapacity(utflen);
+ char[] chars = StringBuilderUtils.extractChars(sb);
+ ascii:
+ try {
+ while (count < utflen) {
+ int c = UNSAFE.getByte(positionAddr++) & 0xFF;
+ if (c >= 128) {
+ break ascii;
+ }
+ chars[count++] = (char) c;
+ }
+ return;
+ } finally {
+ StringBuilderUtils.setCount(sb, count);
+ }
+
+ positionAddr--;
+ readUTF2(this, sb, utflen, count);
+ }
+
+ private void readUTF1(@NotNull Appendable appendable, int utflen)
+ throws IOException {
+ int count = 0;
+ while (count < utflen) {
+ int c = UNSAFE.getByte(positionAddr++) & 0xFF;
+ if (c >= 128) {
+ positionAddr--;
+ readUTF2(this, appendable, utflen, count);
+ break;
+ }
+ count++;
+ appendable.append((char) c);
+ }
+ }
+
+ @Override
+ public NativeBytes slice() {
+ return new NativeBytes(objectSerializer(), positionAddr, limitAddr, refCount);
+ }
+
+ @Override
+ public NativeBytes slice(long offset, long length) {
+ long sliceStart = positionAddr + offset;
+ assert sliceStart >= startAddr && sliceStart < capacityAddr;
+ long sliceEnd = sliceStart + length;
+ assert sliceEnd > sliceStart && sliceEnd <= capacityAddr;
+ return new NativeBytes(objectSerializer(), sliceStart, sliceEnd, refCount);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ long subStart = positionAddr + start;
+ if (subStart < positionAddr || subStart > limitAddr)
+ throw new IndexOutOfBoundsException();
+ long subEnd = positionAddr + end;
+ if (subEnd < subStart || subEnd > limitAddr)
+ throw new IndexOutOfBoundsException();
+ if (start == end)
+ return "";
+ return new NativeBytes(objectSerializer(), subStart, subEnd, refCount);
+ }
+
+ @Override
+ public NativeBytes bytes() {
+ return new NativeBytes(objectSerializer(), startAddr, capacityAddr, refCount);
+ }
+
+ @Override
+ public NativeBytes bytes(long offset, long length) {
+ long sliceStart = startAddr + offset;
+ assert sliceStart >= startAddr && sliceStart < capacityAddr;
+ long sliceEnd = sliceStart + length;
+ assert sliceEnd > sliceStart && sliceEnd <= capacityAddr;
+ return new NativeBytes(objectSerializer(), sliceStart, sliceEnd, refCount);
+ }
+
+ @Override
+ public long address() {
+ return startAddr;
+ }
+
+ @Override
+ public Bytes zeroOut() {
+ clear();
+ UNSAFE.setMemory(startAddr, capacity(), (byte) 0);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end) {
+ if (start < 0 || end > limit())
+ throw new IllegalArgumentException("start: " + start + ", end: " + end);
+ if (start >= end)
+ return this;
+ UNSAFE.setMemory(startAddr + start, end - start, (byte) 0);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end, boolean ifNotZero) {
+ return ifNotZero ? zeroOutDirty(start, end) : zeroOut(start, end);
+ }
+
+ private Bytes zeroOutDirty(long start, long end) {
+ if (start < 0 || end > limit())
+ throw new IllegalArgumentException("start: " + start + ", end: " + end);
+ if (start >= end)
+ return this;
+ // get unaligned leading bytes
+ while (start < end && (start & 7) != 0) {
+ byte b = UNSAFE.getByte(startAddr + start);
+ if (b != 0)
+ UNSAFE.putByte(startAddr + start, (byte) 0);
+ start++;
+ }
+ // check 64-bit aligned access
+ while (start < end - 7) {
+ long l = UNSAFE.getLong(startAddr + start);
+ if (l != 0)
+ UNSAFE.putLong(startAddr + start, 0L);
+ start += 8;
+ }
+ // check unaligned tail
+ while (start < end) {
+ byte b = UNSAFE.getByte(startAddr + start);
+ if (b != 0)
+ UNSAFE.putByte(startAddr + start, (byte) 0);
+ start++;
+ }
+ return this;
+ }
+
@Override
public int read(@NotNull byte[] bytes, int off, int len) {
if (len < 0 || off < 0 || off + len > bytes.length)
@@ -93,13 +301,15 @@ public class NativeBytes extends AbstractBytes {
if (left <= 0) return -1;
int len2 = (int) Math.min(len, left);
UNSAFE.copyMemory(null, positionAddr, bytes, BYTES_OFFSET + off, len2);
- positionAddr += len2;
+ addPosition(len2);
return len2;
}
@Override
public byte readByte() {
- return UNSAFE.getByte(positionAddr++);
+ byte aByte = UNSAFE.getByte(positionAddr);
+ addPosition(1);
+ return aByte;
}
@Override
@@ -109,19 +319,36 @@ public class NativeBytes extends AbstractBytes {
@Override
public void readFully(@NotNull byte[] b, int off, int len) {
- if (len < 0 || off < 0 || off + len > b.length)
- throw new IllegalArgumentException();
+ checkArrayOffs(b.length, off, len);
long left = remaining();
if (left < len)
throw new IllegalStateException(new EOFException());
UNSAFE.copyMemory(null, positionAddr, b, BYTES_OFFSET + off, len);
- positionAddr += len;
+ addPosition(len);
+ }
+
+ @Override
+ public void readFully(long offset, byte[] bytes, int off, int len) {
+ checkArrayOffs(bytes.length, off, len);
+ UNSAFE.copyMemory(null, startAddr + offset, bytes, BYTES_OFFSET + off, len);
+ }
+
+ @Override
+ public void readFully(@NotNull char[] data, int off, int len) {
+ checkArrayOffs(data.length, off, len);
+ long bytesOff = off * 2L;
+ long bytesLen = len * 2L;
+ long left = remaining();
+ if (left < bytesLen)
+ throw new IllegalStateException(new EOFException());
+ UNSAFE.copyMemory(null, positionAddr, data, BYTES_OFFSET + bytesOff, bytesLen);
+ addPosition(bytesLen);
}
@Override
public short readShort() {
short s = UNSAFE.getShort(positionAddr);
- positionAddr += 2;
+ addPosition(2);
return s;
}
@@ -133,7 +360,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public char readChar() {
char ch = UNSAFE.getChar(positionAddr);
- positionAddr += 2;
+ addPosition(2);
return ch;
}
@@ -145,7 +372,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public int readInt() {
int i = UNSAFE.getInt(positionAddr);
- positionAddr += 4;
+ addPosition(4);
return i;
}
@@ -157,7 +384,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public int readVolatileInt() {
int i = UNSAFE.getIntVolatile(null, positionAddr);
- positionAddr += 4;
+ addPosition(4);
return i;
}
@@ -169,7 +396,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public long readLong() {
long l = UNSAFE.getLong(positionAddr);
- positionAddr += 8;
+ addPosition(8);
return l;
}
@@ -181,7 +408,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public long readVolatileLong() {
long l = UNSAFE.getLongVolatile(null, positionAddr);
- positionAddr += 8;
+ addPosition(8);
return l;
}
@@ -193,7 +420,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public float readFloat() {
float f = UNSAFE.getFloat(positionAddr);
- positionAddr += 4;
+ addPosition(4);
return f;
}
@@ -205,7 +432,7 @@ public class NativeBytes extends AbstractBytes {
@Override
public double readDouble() {
double d = UNSAFE.getDouble(positionAddr);
- positionAddr += 8;
+ addPosition(8);
return d;
}
@@ -216,11 +443,13 @@ public class NativeBytes extends AbstractBytes {
@Override
public void write(int b) {
- UNSAFE.putByte(positionAddr++, (byte) b);
+ UNSAFE.putByte(positionAddr, (byte) b);
+ incrementPositionAddr(1);
}
@Override
public void writeByte(long offset, int b) {
+ offsetChecks(offset, 1L);
UNSAFE.putByte(startAddr + offset, (byte) b);
}
@@ -229,124 +458,163 @@ public class NativeBytes extends AbstractBytes {
if (offset < 0 || offset + bytes.length > capacity())
throw new IllegalArgumentException();
UNSAFE.copyMemory(bytes, BYTES_OFFSET, null, startAddr + offset, bytes.length);
- positionAddr += bytes.length;
+ addPosition(bytes.length);
}
@Override
public void write(byte[] bytes, int off, int len) {
+ if (off < 0 || off + len > bytes.length || len > remaining())
+ throw new IllegalArgumentException();
UNSAFE.copyMemory(bytes, BYTES_OFFSET + off, null, positionAddr, len);
- positionAddr += len;
+ addPosition(len);
+ }
+
+ @Override
+ public void write(long offset, byte[] bytes, int off, int len) {
+ if (offset < 0 || off + len > bytes.length || offset + len > capacity())
+ throw new IllegalArgumentException();
+ UNSAFE.copyMemory(bytes, BYTES_OFFSET + off, null, startAddr + offset, len);
}
@Override
public void writeShort(int v) {
+ positionChecks(positionAddr + 2L);
UNSAFE.putShort(positionAddr, (short) v);
- positionAddr += 2;
+ positionAddr += 2L;
+ }
+
+ private long incrementPositionAddr(long value) {
+ positionAddr(positionAddr() + value);
+ return positionAddr();
}
@Override
public void writeShort(long offset, int v) {
+ offsetChecks(offset, 2L);
UNSAFE.putShort(startAddr + offset, (short) v);
}
@Override
public void writeChar(int v) {
+ positionChecks(positionAddr + 2L);
UNSAFE.putChar(positionAddr, (char) v);
- positionAddr += 2;
+ positionAddr += 2L;
+ }
+
+ void addPosition(long delta) {
+ positionAddr(positionAddr() + delta);
}
@Override
public void writeChar(long offset, int v) {
+ offsetChecks(offset, 2L);
UNSAFE.putChar(startAddr + offset, (char) v);
}
@Override
public void writeInt(int v) {
- UNSAFE.putInt(null, positionAddr, v);
- positionAddr += 4;
+ positionChecks(positionAddr + 4L);
+ UNSAFE.putInt(positionAddr, v);
+ positionAddr += 4L;
}
@Override
public void writeInt(long offset, int v) {
+ offsetChecks(offset, 4L);
UNSAFE.putInt(startAddr + offset, v);
}
@Override
public void writeOrderedInt(int v) {
+ positionChecks(positionAddr + 4L);
UNSAFE.putOrderedInt(null, positionAddr, v);
- positionAddr += 4;
+ positionAddr += 4L;
}
@Override
public void writeOrderedInt(long offset, int v) {
+ offsetChecks(offset, 4L);
UNSAFE.putOrderedInt(null, startAddr + offset, v);
}
@Override
public boolean compareAndSwapInt(long offset, int expected, int x) {
+ offsetChecks(offset, 4L);
return UNSAFE.compareAndSwapInt(null, startAddr + offset, expected, x);
}
@Override
public void writeLong(long v) {
+ positionChecks(positionAddr + 8L);
UNSAFE.putLong(positionAddr, v);
- positionAddr += 8;
+ positionAddr += 8L;
}
@Override
public void writeLong(long offset, long v) {
+ offsetChecks(offset, 8L);
UNSAFE.putLong(startAddr + offset, v);
}
@Override
public void writeOrderedLong(long v) {
+ positionChecks(positionAddr + 8L);
UNSAFE.putOrderedLong(null, positionAddr, v);
- positionAddr += 8;
+ positionAddr += 8L;
}
@Override
public void writeOrderedLong(long offset, long v) {
+ offsetChecks(offset, 8L);
UNSAFE.putOrderedLong(null, startAddr + offset, v);
}
@Override
public boolean compareAndSwapLong(long offset, long expected, long x) {
+ offsetChecks(offset, 8L);
return UNSAFE.compareAndSwapLong(null, startAddr + offset, expected, x);
}
@Override
public void writeFloat(float v) {
+ positionChecks(positionAddr + 4L);
UNSAFE.putFloat(positionAddr, v);
- positionAddr += 4;
+ positionAddr += 4L;
}
@Override
public void writeFloat(long offset, float v) {
+ offsetChecks(offset, 4L);
UNSAFE.putFloat(startAddr + offset, v);
}
@Override
public void writeDouble(double v) {
+ positionChecks(positionAddr + 8L);
UNSAFE.putDouble(positionAddr, v);
- positionAddr += 8;
+ positionAddr += 8L;
}
@Override
public void writeDouble(long offset, double v) {
+ offsetChecks(offset, 8L);
UNSAFE.putDouble(startAddr + offset, v);
}
@Override
public void readObject(Object object, int start, int end) {
int len = end - start;
+ if (positionAddr + len >= limitAddr)
+ throw new IndexOutOfBoundsException("Length out of bounds len: " + len);
+
for (; len >= 8; len -= 8) {
UNSAFE.putLong(object, (long) start, UNSAFE.getLong(positionAddr));
- positionAddr += 8;
+ incrementPositionAddr(8L);
start += 8;
}
for (; len > 0; len--) {
UNSAFE.putByte(object, (long) start, UNSAFE.getByte(positionAddr));
- positionAddr++;
+ incrementPositionAddr(1L);
start++;
}
}
@@ -354,12 +622,15 @@ public class NativeBytes extends AbstractBytes {
@Override
public void writeObject(Object object, int start, int end) {
int len = end - start;
+
for (; len >= 8; len -= 8) {
+ positionChecks(positionAddr + 8L);
UNSAFE.putLong(positionAddr, UNSAFE.getLong(object, (long) start));
positionAddr += 8;
start += 8;
}
for (; len > 0; len--) {
+ positionChecks(positionAddr + 1L);
UNSAFE.putByte(positionAddr, UNSAFE.getByte(object, (long) start));
positionAddr++;
start++;
@@ -367,18 +638,82 @@ public class NativeBytes extends AbstractBytes {
}
@Override
+ public boolean compare(long offset, RandomDataInput input, long inputOffset, long len) {
+ if (offset < 0 || inputOffset < 0 || len < 0)
+ throw new IndexOutOfBoundsException();
+ if (offset + len < 0 || offset + len > capacity() || inputOffset + len < 0 ||
+ inputOffset + len > input.capacity()) {
+ return false;
+ }
+ long i = 0L;
+ for (; i < len - 7L; i += 8L) {
+ if (UNSAFE.getLong(startAddr + offset + i) != input.readLong(inputOffset + i))
+ return false;
+ }
+ if (i < len - 3L) {
+ if (UNSAFE.getInt(startAddr + offset + i) != input.readInt(inputOffset + i))
+ return false;
+ i += 4L;
+ }
+ if (i < len - 1L) {
+ if (UNSAFE.getChar(startAddr + offset + i) != input.readChar(inputOffset + i))
+ return false;
+ i += 2L;
+ }
+ if (i < len) {
+ if (UNSAFE.getByte(startAddr + offset + i) != input.readByte(inputOffset + i))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public long position() {
return (positionAddr - startAddr);
}
@Override
- public void position(long position) {
- this.positionAddr = startAddr + position;
+ public NativeBytes position(long position) {
+ if (position < 0 || position > limit())
+ throw new IndexOutOfBoundsException("position: " + position + " limit: " + limit());
+
+ positionAddr(startAddr + position);
+ return this;
+ }
+
+ /**
+ * Change the position acknowleging there is no thread safety assumptions. Best effort setting
+ * is fine. *
+ *
+ * @param position to set if we can.
+ * @return this
+ */
+ public NativeBytes lazyPosition(long position) {
+ if (position < 0 || position > limit())
+ throw new IndexOutOfBoundsException("position: " + position + " limit: " + limit());
+
+ // assume we don't need to no check thread safety.
+
+ positionAddr(startAddr + position);
+ return this;
+ }
+
+ @Override
+ public void write(RandomDataInput bytes, long position, long length) {
+ if (length > remaining())
+ throw new IllegalArgumentException("Attempt to write " + length + " bytes with " + remaining() + " remaining");
+ if (bytes instanceof NativeBytes) {
+ UNSAFE.copyMemory(((NativeBytes) bytes).startAddr + position, positionAddr, length);
+ skip(length);
+
+ } else {
+ super.write(bytes, position, length);
+ }
}
@Override
public long capacity() {
- return (limitAddr - startAddr);
+ return (capacityAddr - startAddr);
}
@Override
@@ -386,6 +721,21 @@ public class NativeBytes extends AbstractBytes {
return (limitAddr - positionAddr);
}
+ @Override
+ public long limit() {
+ return (limitAddr - startAddr);
+ }
+
+ @Override
+ public NativeBytes limit(long limit) {
+ if (limit < 0 || limit > capacity()) {
+ throw new IllegalArgumentException("limit: " + limit + " capacity: " + capacity());
+ }
+
+ limitAddr = startAddr + limit;
+ return this;
+ }
+
@NotNull
@Override
public ByteOrder byteOrder() {
@@ -394,23 +744,107 @@ public class NativeBytes extends AbstractBytes {
@Override
public void checkEndOfBuffer() throws IndexOutOfBoundsException {
- if (position() > capacity())
- throw new IndexOutOfBoundsException("position is beyond the end of the buffer " + position() + " > " + capacity());
+ if (position() > limit()) {
+ throw new IndexOutOfBoundsException(
+ "position is beyond the end of the buffer " + position() + " > " + limit());
+ }
}
public long startAddr() {
return startAddr;
}
- public long positionAddr() {
- return positionAddr;
+ long capacityAddr() {
+ return capacityAddr;
+ }
+
+ @Override
+ protected void cleanup() {
+ // TODO nothing to do.
+ }
+
+ @Override
+ public Bytes load() {
+ int pageSize = UNSAFE.pageSize();
+ for (long addr = startAddr; addr < capacityAddr; addr += pageSize)
+ UNSAFE.getByte(addr);
+ return this;
+ }
+
+ public void alignPositionAddr(int powerOf2) {
+ long value = (positionAddr + powerOf2 - 1) & ~(powerOf2 - 1);
+ positionAddr(value);
}
public void positionAddr(long positionAddr) {
+ positionChecks(positionAddr);
this.positionAddr = positionAddr;
}
- public long limitAddr() {
- return limitAddr;
+ void positionChecks(long positionAddr) {
+ assert actualPositionChecks(positionAddr);
+ }
+
+ boolean actualPositionChecks(long positionAddr) {
+ if (positionAddr < startAddr)
+ throw new IndexOutOfBoundsException("position before the start by " + (startAddr - positionAddr) + " bytes");
+ if (positionAddr > limitAddr)
+ throw new IndexOutOfBoundsException("position after the limit by " + (positionAddr - limitAddr) + " bytes");
+
+ return true;
+ }
+
+ void offsetChecks(long offset, long len) {
+ assert actualOffsetChecks(offset, len);
+ }
+
+ boolean actualOffsetChecks(long offset, long len) {
+ if (offset < 0L || offset + len > capacity())
+ throw new IndexOutOfBoundsException("offset out of bounds: " + offset + ", len: " +
+ len + ", capacity: " + capacity());
+ return true;
+ }
+
+ public long positionAddr() {
+ return positionAddr;
+ }
+
+ @Override
+ public ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse) {
+ return sliceAsByteBuffer(toReuse, null);
+ }
+
+ protected ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse, Object att) {
+ return ByteBufferReuse.INSTANCE.reuse(positionAddr, (int) remaining(), att, toReuse);
+ }
+
+ void address(long address) {
+ setStartPositionAddress(address);
+ }
+
+ void capacity(long capacity) {
+ this.limitAddr = this.capacityAddr = capacity;
+ }
+
+ @Override
+ public long nextSetBit(long fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException();
+ long capacity = capacity();
+ long maxBit = capacity << 3;
+ long fromLongIndex = fromIndex & ~63;
+ if (fromLongIndex >= maxBit)
+ return -1;
+ long firstByte = fromLongIndex >>> 3;
+ if ((fromIndex & 63) != 0) {
+ long l = UNSAFE.getLongVolatile(null, startAddr + firstByte) >>> fromIndex;
+ if (l != 0) {
+ return fromIndex + numberOfTrailingZeros(l);
+ }
+ firstByte += 8;
+ }
+ if (capacity < Integer.MAX_VALUE)
+ return nextSetBit0((int) firstByte, (int) capacity, startAddr);
+ return nextSetBit0(firstByte, capacity, startAddr);
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/RandomDataInput.java b/lang/src/main/java/net/openhft/lang/io/RandomDataInput.java
index 3581b0f..10f97e3 100755
--- a/lang/src/main/java/net/openhft/lang/io/RandomDataInput.java
+++ b/lang/src/main/java/net/openhft/lang/io/RandomDataInput.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.ObjectInput;
+import java.io.StreamCorruptedException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Map;
@@ -30,21 +31,22 @@ import java.util.RandomAccess;
*/
public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon {
/**
- * Reads some bytes from an input stream and stores them into the buffer array <code>b</code>. The number of bytes
+ * <p>Reads some bytes from an input stream and stores them into the buffer array <code>b</code>. The number of bytes
* read is equal to the length of <code>b</code>.
- * <p/>
- * This method blocks until one of the following conditions occurs:<p> <ul> <li><code>b.length</code> bytes of input
- * data are available, in which case a normal return is made.
- * <p/>
- * <li>End of file is detected, in which case an <code>EOFException</code> is thrown.
- * <p/>
- * <li>An I/O error occurs, in which case an <code>IOException</code> other than <code>EOFException</code> is
- * thrown. </ul>
- * <p/>
- * If <code>b</code> is <code>null</code>, a <code>NullPointerException</code> is thrown. If <code>b.length</code>
- * is zero, then no bytes are read. Otherwise, the first byte read is stored into element <code>b[0]</code>, the
- * next one into <code>b[1]</code>, and so on. If an exception is thrown from this method, then it may be that some
- * but not all bytes of <code>b</code> have been updated with data from the input stream.
+ * </p><p>
+ * This method blocks until one of the following conditions occurs:
+ * </p>
+ * <ul>
+ * <li><code>b.length</code> bytes of input data are available, in which case a normal return is made. </li>
+ * <li>End of file is detected, in which case an <code>EOFException</code> is thrown.</li>
+ * <li>An I/O error occurs, in which case an <code>IOException</code> other than <code>EOFException</code> is thrown.</li>
+ * </ul>
+ * <p>
+ * If <code>bytes</code> is <code>null</code>, a <code>NullPointerException</code> is thrown. If <code>bytes.length</code>
+ * is zero, then no bytes are read. Otherwise, the first byte read is stored into element <code>bytes[0]</code>, the
+ * next one into <code>bytes[1]</code>, and so on. If an exception is thrown from this method, then it may be that some
+ * but not all bytes of <code>bytes</code> have been updated with data from the input stream.
+ * </p>
*
* @param bytes the buffer into which the data is read.
*/
@@ -52,21 +54,22 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
void readFully(@NotNull byte[] bytes);
/**
- * Reads <code>len</code> bytes from an input stream.
- * <p/>
- * This method blocks until one of the following conditions occurs:<p> <ul> <li><code>len</code> bytes of input data
- * are available, in which case a normal return is made.
- * <p/>
- * <li>End of file is detected, in which case an <code>EOFException</code> is thrown.
- * <p/>
- * <li>An I/O error occurs, in which case an <code>IOException</code> other than <code>EOFException</code> is
- * thrown. </ul>
- * <p/>
- * If <code>b</code> is <code>null</code>, a <code>NullPointerException</code> is thrown. If <code>off</code> is
+ * <p>Reads <code>len</code> bytes from an input stream.
+ * </p><p>
+ * This method blocks until one of the following conditions occurs:
+ * </p>
+ * <ul>
+ * <li><code>len</code> bytes of input data are available, in which case a normal return is made.</li>
+ * <li>End of file is detected, in which case an <code>EOFException</code> is thrown.</li>
+ * <li>An I/O error occurs, in which case an <code>IOException</code> other than <code>EOFException</code> is thrown. </li>
+ * </ul>
+ * <p>
+ * If <code>bytes</code> is <code>null</code>, a <code>NullPointerException</code> is thrown. If <code>off</code> is
* negative, or <code>len</code> is negative, or <code>off+len</code> is greater than the length of the array
- * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is thrown. If <code>len</code> is zero, then no
- * bytes are read. Otherwise, the first byte read is stored into element <code>b[off]</code>, the next one into
- * <code>b[off+1]</code>, and so on. The number of bytes read is, at most, equal to <code>len</code>.
+ * <code>bytes</code>, then an <code>IndexOutOfBoundsException</code> is thrown. If <code>len</code> is zero, then no
+ * bytes are read. Otherwise, the first byte read is stored into element <code>bytes[off]</code>, the next one into
+ * <code>bytes[off+1]</code>, and so on. The number of bytes read is, at most, equal to <code>len</code>.
+ * </p>
*
* @param bytes the buffer into which the data is read.
* @param off an int specifying the offset into the data.
@@ -75,6 +78,12 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
@Override
void readFully(@NotNull byte[] bytes, int off, int len);
+ void readFully(long offset, @NotNull byte[] bytes, int off, int len);
+
+ void readFully(@NotNull char[] data);
+
+ void readFully(@NotNull char[] data, int off, int len);
+
/**
* Makes an attempt to skip over <code>n</code> bytes of data from the input stream, discarding the skipped bytes.
* However, it may skip over some smaller number of bytes, possibly zero. This may result from any of a number of
@@ -153,7 +162,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads two input bytes and returns a <code>short</code> value. Let <code>a</code> be the first byte read and
* <code>b</code> be the second byte on big endian machines, and the opposite on little endian machines. The value
* returned is:
- * <p><pre><code>(short)((a &lt;&lt; 8) | (b &amp; 0xff))
+ * <pre><code>(short)((a &lt;&lt; 8) | (b &amp; 0xff))
* </code></pre>
* This method is suitable for reading the bytes written by the <code>writeShort</code> method of interface
* <code>DataOutput</code>.
@@ -167,7 +176,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads two input bytes and returns a <code>short</code> value. Let <code>a</code> be the first byte read and
* <code>b</code> be the second byte on big endian machines, and the opposite on little endian machines. The value
* returned is:
- * <p><pre><code>
+ * <pre><code>
* (short)((a &lt;&lt; 8) | (b &amp; 0xff))
* </code></pre>
* This method is suitable for reading the bytes written by the <code>writeShort</code> method of interface
@@ -182,7 +191,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads two input bytes and returns an <code>int</code> value in the range <code>0</code> through
* <code>65535</code>. Let <code>a</code> be the first byte read and <code>b</code> be the second byte on big endian
* machines, and the opposite on little endian machines. The value returned is:
- * <p><pre><code>
+ * <pre><code>
* (((a &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
* </code></pre>
* This method is suitable for reading the bytes written by the <code>writeUnsignedShort</code> method of interface
@@ -198,7 +207,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads two input bytes and returns an <code>int</code> value in the range <code>0</code> through
* <code>65535</code>. Let <code>a</code> be the first byte read and <code>b</code> be the second byte on big endian
* machines, and the opposite on little endian machines. The value returned is:
- * <p><pre><code>
+ * <pre><code>
* (((a &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
* </code></pre>
* This method is suitable for reading the bytes written by the <code>writeShort</code> method of interface
@@ -214,8 +223,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads one or three input bytes and returns a <code>short</code> value. Let <code>a</code> be the first byte read.
* This mapped as follows; Byte.MIN_VALUE =&gt; Short.MIN_VALUE, Byte.MAX_VALUE =&gt; Short.MAX_VALUE, Byte.MIN_VALUE+2 to
* Byte.MAX_VALUE-1 =&gt; same as short value, Byte.MIN_VALUE+1 =&gt; readShort().
- * <p/>
- * This method is suitable for reading the bytes written by the <code>writeCompactShort</code> method of interface
+ *
+ * <p>This method is suitable for reading the bytes written by the <code>writeCompactShort</code> method of interface
* <code>RandomDataOutput</code>.
*
* @return the 16-bit value read.
@@ -225,8 +234,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads one or three input bytes and returns a <code>short</code> value. Let <code>a</code> be the first byte read.
* This mapped as follows; -1 =&gt; readUnsignedShort(), default =&gt; (a &amp; 0xFF)
- * <p/>
- * This method is suitable for reading the bytes written by the <code>writeCompactUnsignedShort</code> method of
+ *
+ * <p>This method is suitable for reading the bytes written by the <code>writeCompactUnsignedShort</code> method of
* interface <code>RandomDataOutput</code>.
*
* @return the unsigned 16-bit value read.
@@ -237,7 +246,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads two input bytes and returns a <code>char</code> value. Let <code>a</code> be the first byte read and
* <code>b</code> be the second byte on big endian machines, and the opposite on little endian machines. The value
* returned is:
- * <p><pre><code>(char)((a &lt;&lt; 8) | (b &amp; 0xff))
+ * <pre><code>(char)((a &lt;&lt; 8) | (b &amp; 0xff))
* </code></pre>
* This method is suitable for reading bytes written by the <code>writeChar</code> method of interface
* <code>DataOutput</code>.
@@ -251,7 +260,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads two input bytes and returns a <code>char</code> value. Let <code>a</code> be the first byte read and
* <code>b</code> be the second byte on big endian machines, and the opposite on little endian machines. The value
* returned is:
- * <p><pre><code>(char)((a &lt;&lt; 8) | (b &amp; 0xff))
+ * <pre><code>(char)((a &lt;&lt; 8) | (b &amp; 0xff))
* </code></pre>
* This method is suitable for reading bytes written by the <code>writeChar</code> method of interface
* <code>RandomDataOutput</code>.
@@ -264,7 +273,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads three input bytes and returns a 24-bit <code>int</code> value. Let <code>a-c</code> be the first through
* third bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* ((((a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8))) &gt;&gt; 8
* </code></pre>
@@ -278,7 +287,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads three input bytes and returns a 24-bit <code>int</code> value. Let <code>a-c</code> be the first through
* third bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* ((((a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8))) &gt;&gt; 8
* </code></pre>
@@ -293,7 +302,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads four input bytes and returns an <code>int</code> value. Let <code>a-d</code> be the first through fourth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* (((a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8) | (d &amp; 0xff))
* </code></pre>
@@ -308,7 +317,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads four input bytes and returns an <code>int</code> value. Let <code>a-d</code> be the first through fourth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* (((a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8) | (d &amp; 0xff))
* </code></pre>
@@ -324,7 +333,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* This is the same as readInt() except a read barrier is performed first. <p> Reads four input bytes and returns
* an <code>int</code> value. Let <code>a-d</code> be the first through fourth bytes read on big endian machines,
* and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* (((a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8) | (d &amp; 0xff))
* </code></pre>
@@ -339,7 +348,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* This is the same as readInt() except a read barrier is performed first. <p> Reads four input bytes and returns
* an <code>int</code> value. Let <code>a-d</code> be the first through fourth bytes read on big endian machines,
* and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* (((a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8) | (d &amp; 0xff))
* </code></pre>
@@ -354,7 +363,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads four input bytes and returns an <code>int</code> value. Let <code>a-d</code> be the first through fourth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* ((((long) a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8) | (d &amp;
* 0xff))
@@ -369,7 +378,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads four input bytes and returns an <code>int</code> value. Let <code>a-d</code> be the first through fourth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre>
+ * <pre>
* <code>
* ((((long) a &amp; 0xff) &lt;&lt; 24) | ((b &amp; 0xff) &lt;&lt; 16) | ((c &amp; 0xff) &lt;&lt; 8) | (d &amp;
* 0xff))
@@ -387,8 +396,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* with readShort(). This mapped as follows; Short.MIN_VALUE =&gt; Integer.MIN_VALUE, Short.MAX_VALUE =&gt;
* Integer.MAX_VALUE, Short.MIN_VALUE+2 to Short.MAX_VALUE-1 =&gt; same as short value, Short.MIN_VALUE+1 =&gt;
* readInt().
- * <p/>
- * This method is suitable for reading the bytes written by the <code>writeCompactInt</code> method of interface
+ *
+ * <p>This method is suitable for reading the bytes written by the <code>writeCompactInt</code> method of interface
* <code>RandomDataOutput</code>.
*
* @return the 32-bit value read.
@@ -398,8 +407,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads two or six input bytes and returns an <code>int</code> value. Let <code>a</code> be the first short read
* with readShort(). This mapped as follows; -1 =&gt; readUnsignedInt(), default =&gt; (a &amp; 0xFFFF)
- * <p/>
- * This method is suitable for reading the bytes written by the <code>writeCompactUnsignedInt</code> method of
+ *
+ * <p>This method is suitable for reading the bytes written by the <code>writeCompactUnsignedInt</code> method of
* interface <code>RandomDataOutput</code>.
*
* @return the unsigned 32-bit value read.
@@ -409,7 +418,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads eight input bytes and returns a <code>long</code> value. Let <code>a-h</code> be the first through eighth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre> <code>
+ * <pre> <code>
* (((long)(a &amp; 0xff) &lt;&lt; 56) |
* ((long)(b &amp; 0xff) &lt;&lt; 48) |
* ((long)(c &amp; 0xff) &lt;&lt; 40) |
@@ -419,8 +428,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* ((long)(g &amp; 0xff) &lt;&lt; 8) |
* ((long)(h &amp; 0xff)))
* </code></pre>
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeLong</code> method of interface
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeLong</code> method of interface
* <code>DataOutput</code>.
*
* @return the <code>long</code> value read.
@@ -429,9 +438,17 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
long readLong();
/**
+ * Same as readLong except the remaining() can be less than 8.
+ *
+ * @param offset base
+ * @return long.
+ */
+ long readIncompleteLong(long offset);
+
+ /**
* Reads eight input bytes and returns a <code>long</code> value. Let <code>a-h</code> be the first through eighth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre> <code>
+ * <pre> <code>
* (((long)(a &amp; 0xff) &lt;&lt; 56) |
* ((long)(b &amp; 0xff) &lt;&lt; 48) |
* ((long)(c &amp; 0xff) &lt;&lt; 40) |
@@ -441,8 +458,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* ((long)(g &amp; 0xff) &lt;&lt; 8) |
* ((long)(h &amp; 0xff)))
* </code></pre>
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeLong</code> method of interface
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeLong</code> method of interface
* <code>RandomDataOutput</code>.
*
* @param offset of the long to read
@@ -452,10 +469,10 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* This is the same readLong() except a dread barrier is performed first
- * <p/>
- * Reads eight input bytes and returns a <code>long</code> value. Let <code>a-h</code> be the first through eighth
+ *
+ * <p>Reads eight input bytes and returns a <code>long</code> value. Let <code>a-h</code> be the first through eighth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre> <code>
+ * <pre> <code>
* (((long)(a &amp; 0xff) &lt;&lt; 56) |
* ((long)(b &amp; 0xff) &lt;&lt; 48) |
* ((long)(c &amp; 0xff) &lt;&lt; 40) |
@@ -465,8 +482,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* ((long)(g &amp; 0xff) &lt;&lt; 8) |
* ((long)(h &amp; 0xff)))
* </code></pre>
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeOrderedLong</code> or
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeOrderedLong</code> or
* <code>writeVolatileLong</code> method of interface <code>RandomDataOutput</code>.
*
* @return the <code>long</code> value read.
@@ -475,10 +492,10 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* This is the same readLong() except a dread barrier is performed first
- * <p/>
- * Reads eight input bytes and returns a <code>long</code> value. Let <code>a-h</code> be the first through eighth
+ *
+ * <p>Reads eight input bytes and returns a <code>long</code> value. Let <code>a-h</code> be the first through eighth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre> <code>
+ * <pre> <code>
* (((long)(a &amp; 0xff) &lt;&lt; 56) |
* ((long)(b &amp; 0xff) &lt;&lt; 48) |
* ((long)(c &amp; 0xff) &lt;&lt; 40) |
@@ -488,8 +505,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* ((long)(g &amp; 0xff) &lt;&lt; 8) |
* ((long)(h &amp; 0xff)))
* </code></pre>
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeOrderedLong</code> or
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeOrderedLong</code> or
* <code>writeVolatileLong</code> method of interface <code>RandomDataOutput</code>.
*
* @param offset of the long to read
@@ -500,7 +517,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads six input bytes and returns a <code>long</code> value. Let <code>a-f</code> be the first through sixth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre> <code>
+ * <pre> <code>
* (((long)(a &amp; 0xff) &lt;&lt; 56) |
* ((long)(b &amp; 0xff) &lt;&lt; 48) |
* ((long)(c &amp; 0xff) &lt;&lt; 40) |
@@ -508,8 +525,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* ((long)(e &amp; 0xff) &lt;&lt; 24) |
* ((long)(f &amp; 0xff) &lt;&lt; 16)) &gt;&gt; 16
* </code></pre>
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeInt48</code> method of interface
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeInt48</code> method of interface
* <code>RandomDataOutput</code>.
*
* @return the <code>long</code> value read.
@@ -519,7 +536,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads six input bytes and returns a <code>long</code> value. Let <code>a-f</code> be the first through sixth
* bytes read on big endian machines, and the opposite on little endian machines. The value returned is:
- * <p><pre> <code>
+ * <pre> <code>
* (((long)(a &amp; 0xff) &lt;&lt; 56) |
* ((long)(b &amp; 0xff) &lt;&lt; 48) |
* ((long)(c &amp; 0xff) &lt;&lt; 40) |
@@ -527,8 +544,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* ((long)(e &amp; 0xff) &lt;&lt; 24) |
* ((long)(f &amp; 0xff) &lt;&lt; 16)) &gt;&gt; 16
* </code></pre>
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeInt48</code> method of interface
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeInt48</code> method of interface
* <code>RandomDataOutput</code>.
*
* @param offset of the long to read
@@ -540,8 +557,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads four or twelve input bytes and returns a <code>long</code> value. Let <code>a</code> be the first int read
* with readInt(). This mapped as follows; Integer.MIN_VALUE =&gt; Long.MIN_VALUE, Integer.MAX_VALUE =&gt; Long.MAX_VALUE,
* Integer.MIN_VALUE+2 to Integer.MAX_VALUE-1 =&gt; same as short value, Integer.MIN_VALUE+1 =&gt; readLong().
- * <p/>
- * This method is suitable for reading the bytes written by the <code>writeCompactLong</code> method of interface
+ *
+ * <p>This method is suitable for reading the bytes written by the <code>writeCompactLong</code> method of interface
* <code>RandomDataOutput</code>.
*
* @return the 64-bit value read.
@@ -550,14 +567,14 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Reads between one and ten bytes with are stop encoded with support for negative numbers
- * <p><pre><code>
+ * <pre><code>
* long l = 0, b;
* int count = 0;
* while ((b = readByte()) &lt; 0) {
* l |= (b &amp; 0x7FL) &lt;&lt; count;
* count += 7;
* }
- * if (b == 0 && count &gt; 0)
+ * if (b == 0 &amp;&amp; count &gt; 0)
* return ~l;
* return l | (b &lt;&lt; count);
* </code></pre>
@@ -593,8 +610,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* This is the same as readFloat() except a read barrier is performed first. <p> Reads four input bytes and returns
* a <code>float</code> value.
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeOrderedFloat</code> method of interface <code>RandomDataOutput</code>.
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeOrderedFloat</code> method of interface <code>RandomDataOutput</code>.
*
* @param offset to read from
* @return the <code>int</code> value read.
@@ -635,8 +652,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* This is the same as readDouble() except a read barrier is performed first. <p> Reads four input bytes and returns
* a <code>float</code> value.
- * <p/>
- * This method is suitable for reading bytes written by the <code>writeOrderedFloat</code> method of interface <code>RandomDataOutput</code>.
+ *
+ * <p>This method is suitable for reading bytes written by the <code>writeOrderedFloat</code> method of interface <code>RandomDataOutput</code>.
*
* @param offset to read from
* @return the <code>int</code> value read.
@@ -648,8 +665,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* into a character, until it encounters a line terminator or end of file; the characters read are then returned as
* a <code>String</code>. Note that because this method processes bytes, it does not support input of the full
* Unicode character set.
- * <p/>
- * If end of file is encountered before even one byte can be read, then <code>null</code> is returned. Otherwise,
+ *
+ * <p>If end of file is encountered before even one byte can be read, then <code>null</code> is returned. Otherwise,
* each byte that is read is converted to type <code>char</code> by zero-extension. If the character
* <code>'\n'</code> is encountered, it is discarded and reading ceases. If the character <code>'\r'</code> is
* encountered, it is discarded and, if the following byte converts &#32;to the character <code>'\n'</code>, then
@@ -660,7 +677,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* <code>(char)256</code>.
*
* @return the next line of text from the input stream, or <CODE>null</CODE> if the end of file is encountered
- * before a byte can be read.
+ * before a byte can be read.
*/
@Override
@Nullable
@@ -670,43 +687,43 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
* Reads in a string that has been encoded using a <a href="#modified-utf-8">modified UTF-8</a> format. The general
* contract of <code>readUTF</code> is that it reads a representation of a Unicode character string encoded in
* modified UTF-8 format; this string of characters is then returned as a <code>String</code>.
- * <p/>
- * First, two bytes are read and used to construct an unsigned 16-bit integer in exactly the manner of the
+ *
+ * <p>First, two bytes are read and used to construct an unsigned 16-bit integer in exactly the manner of the
* <code>readUnsignedShort</code> method . This integer value is called the <i>UTF length</i> and specifies the
* number of additional bytes to be read. These bytes are then converted to characters by considering them in
* groups. The length of each group is computed from the value of the first byte of the group. The byte following a
* group, if any, is the first byte of the next group.
- * <p/>
- * If the first byte of a group matches the bit pattern <code>0xxxxxxx</code> (where <code>x</code> means "may be
+ *
+ * <p>If the first byte of a group matches the bit pattern <code>0xxxxxxx</code> (where <code>x</code> means "may be
* <code>0</code> or <code>1</code>"), then the group consists of just that byte. The byte is zero-extended to form
* a character.
- * <p/>
- * If the first byte of a group matches the bit pattern <code>110xxxxx</code>, then the group consists of that byte
+ *
+ * <p>If the first byte of a group matches the bit pattern <code>110xxxxx</code>, then the group consists of that byte
* <code>a</code> and a second byte <code>b</code>. If there is no byte <code>b</code> (because byte <code>a</code>
* was the last of the bytes to be read), or if byte <code>b</code> does not match the bit pattern
* <code>10xxxxxx</code>, then a <code>UTFDataFormatException</code> is thrown. Otherwise, the group is converted to
- * the character:<p>
+ * the character:
* <pre><code>(char)(((a&amp; 0x1F) &lt;&lt; 6) | (b &amp; 0x3F))
* </code></pre>
* If the first byte of a group matches the bit pattern <code>1110xxxx</code>, then the group consists of that byte
* <code>a</code> and two more bytes <code>b</code> and <code>c</code>. If there is no byte <code>c</code> (because
* byte <code>a</code> was one of the last two of the bytes to be read), or either byte <code>b</code> or byte
* <code>c</code> does not match the bit pattern <code>10xxxxxx</code>, then a <code>UTFDataFormatException</code>
- * is thrown. Otherwise, the group is converted to the character:<p>
+ * is thrown. Otherwise, the group is converted to the character:
* <pre><code>
* (char)(((a &amp; 0x0F) &lt;&lt; 12) | ((b &amp; 0x3F) &lt;&lt; 6) | (c &amp; 0x3F))
* </code></pre>
* If the first byte of a group matches the pattern <code>1111xxxx</code> or the pattern <code>10xxxxxx</code>, then
* a <code>UTFDataFormatException</code> is thrown.
- * <p/>
- * If end of file is encountered at any time during this entire process, then an <code>EOFException</code> is
+ *
+ * <p>If end of file is encountered at any time during this entire process, then an <code>EOFException</code> is
* thrown.
- * <p/>
- * After every group has been converted to a character by this process, the characters are gathered, in the same
+ *
+ * <p>After every group has been converted to a character by this process, the characters are gathered, in the same
* order in which their corresponding groups were read from the input stream, to form a <code>String</code>, which
* is returned.
- * <p/>
- * The <code>writeUTF</code> method of interface <code>DataOutput</code> may be used to write data that is suitable
+ *
+ * <p>The <code>writeUTF</code> method of interface <code>DataOutput</code> may be used to write data that is suitable
* for reading by this method.
*
* @return a Unicode string.
@@ -726,7 +743,7 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
String readUTFΔ();
/**
- * The same as readUTFΔ() except an offset and maximum length is given.
+ * The same as readUTFΔ() except an offset is given.
*
* @param offset to read from
* @return a Unicode string or <code>null</code> if <code>writeUTFΔ(null)</code> was called
@@ -738,10 +755,13 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* The same as readUTFΔ() except the chars are copied to a truncated StringBuilder.
*
+ * @param stringBuilder to copy chars to
* @return <code>true</code> if there was a String, or <code>false</code> if it was <code>null</code>
*/
boolean readUTFΔ(@NotNull StringBuilder stringBuilder);
+ boolean read8bitText(@NotNull StringBuilder stringBuilder) throws StreamCorruptedException;
+
/**
* Copy bytes into a ByteBuffer to the minimum of the length <code>remaining()</code> in the ByteBuffer or the
* Excerpt.
@@ -751,12 +771,22 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
void read(@NotNull ByteBuffer bb);
/**
+ * Copy bytes into a ByteBuffer to the minimum of the length in the ByteBuffer or the
+ * Excerpt.
+ *
+ * @param bb to copy into
+ * @param length number of bytes to copy
+ */
+ void read(@NotNull ByteBuffer bb, int length);
+
+ /**
* Read a String with <code>readUTFΔ</code> which is converted to an enumerable type. i.e. where there is a one to
* one mapping between an object and it's toString().
- * <p/>
- * This is suitable to read an object written using <code>writeEnum()</code> in the <code>RandomDataOutput</code>
+ *
+ * <p>This is suitable to read an object written using <code>writeEnum()</code> in the <code>RandomDataOutput</code>
* interface
*
+ * @param <E> the enum class
* @param eClass to decode the String as
* @return the decoded value. <code>null</code> with be return if null was written.
*/
@@ -764,21 +794,27 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
<E> E readEnum(@NotNull Class<E> eClass);
/**
- * Read a stop bit encoded length and populates this Collection after clear()ing it.
- * <p/>
- * This is suitable to reading a list written using <code>writeList()</code> in the <code>RandomDataOutput</code>
+ * Read a stop bit encoded length and populates this Collection after zeroOut()ing it.
+ *
+ * <p>This is suitable to reading a list written using <code>writeList()</code> in the <code>RandomDataOutput</code>
* interface
*
+ * @param <E> the list element class
+ * @param eClass the list element class
* @param list to populate
*/
<E> void readList(@NotNull Collection<E> list, @NotNull Class<E> eClass);
/**
- * Read a stop bit encoded length and populates this Map after clear()ing it.
- * <p/>
- * This is suitable to reading a list written using <code>writeMap()</code> in the <code>RandomDataOutput</code>
+ * Read a stop bit encoded length and populates this Map after zeroOut()ing it.
+ *
+ * <p>This is suitable to reading a list written using <code>writeMap()</code> in the <code>RandomDataOutput</code>
* interface
*
+ * @param <K> the map key class
+ * @param <V> the map value class
+ * @param kClass the map key class
+ * @param vClass the map value class
* @param map to populate
* @return the map
*/
@@ -800,6 +836,8 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
/**
* Read and return an object. The class that implements this interface defines where the object is "read" from.
*
+ * @param <T> the class of the object to read
+ * @param tClass the class of the object to read
* @return the object read from the stream
* @throws IllegalStateException the class of a serialized object cannot be found or any of the usual Input/Output
* related exceptions occur.
@@ -809,7 +847,18 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
<T> T readObject(Class<T> tClass) throws IllegalStateException;
/**
- * Reads a byte of data. This method will block if no input is available.
+ * Read an instance of a class assuming objClass was provided when written.
+ *
+ * @param <T> the class of the object to read
+ * @param objClass class to write
+ * @param obj to reuse or null if a new object is needed
+ * @return the object read from the stream
+ */
+ @Nullable
+ <T> T readInstance(@NotNull Class<T> objClass, T obj);
+
+ /**
+ * Reads a byte of data. This method is non blocking.
*
* @return the byte read, or -1 if the end of the stream is reached.
*/
@@ -865,4 +914,18 @@ public interface RandomDataInput extends ObjectInput, RandomAccess, BytesCommon
*/
@Override
void close();
+
+ boolean startsWith(RandomDataInput input);
+
+ boolean compare(long offset, RandomDataInput input, long inputOffset, long len);
+
+ <E> E readEnum(long offset, int maxSize, Class<E> eClass);
+
+ /**
+ * From a given bit index, find the next bit with is set.
+ *
+ * @param fromIndex first bit to scan.
+ * @return first bit equals or after it which is set.
+ */
+ long nextSetBit(long fromIndex);
}
diff --git a/lang/src/main/java/net/openhft/lang/io/RandomDataOutput.java b/lang/src/main/java/net/openhft/lang/io/RandomDataOutput.java
index 92a1a4c..d10f430 100755
--- a/lang/src/main/java/net/openhft/lang/io/RandomDataOutput.java
+++ b/lang/src/main/java/net/openhft/lang/io/RandomDataOutput.java
@@ -1,21 +1,22 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
+import net.openhft.lang.model.Byteable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,14 +30,50 @@ import java.util.RandomAccess;
* @author peter.lawrey
*/
public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommon {
+
+ /**
+ * Copies the contents of a RandomDataInput from the position to the limit.
+ *
+ * <p> This method transfers the bytes remaining in the given source
+ * buffer into this buffer. If there are more bytes remaining in the
+ * source buffer than in this buffer, that is, if
+ * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+ * then no bytes are transferred and a {@link
+ * java.nio.BufferOverflowException} is thrown.
+ *
+ * <p> Otherwise, this method copies
+ * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> bytes from the given
+ * buffer into this buffer, starting at each buffer's current position.
+ * The positions of both buffers are then incremented by <i>n</i>.
+ *
+ * <p> In other words, an invocation of this method of the form
+ * <tt>dst.write(src)</tt> has exactly the same effect as the loop
+ *
+ * <pre>
+ * while (src.hasRemaining())
+ * dst.writeByte(src.readByte());
+ * </pre>
+
+ * @param bytes to copy
+ */
+ void write(RandomDataInput bytes);
+
+ /**
+ * Copy from one Bytes to another, moves the position of "this" RandomDataOutput by the length.
+ * The position of the RandomDataInput is not used or altered.
+ *
+ * @param bytes to copy
+ * @param position to copy from
+ * @param length to copy
+ */
+ void write(RandomDataInput bytes, long position, long length);
+
/**
- * Copy from one Bytes to another. Copied from the start to the current position.
+ * Copies the contents of a Byteable from the offset for maxSize bytes, moves the position of "this" RandomDataOutput by the maxSize
*
- * @param bytes to copy from
- * @deprecated Use write(BytesCommon bytes, long position, long length) instead.
+ * @param byteable to copy
*/
- @Deprecated
- void writeStartToPosition(Bytes bytes);
+ void write(@NotNull Byteable byteable);
/**
* Writes to the output stream the eight low-order bits of the argument <code>b</code>. The 24 high-order bits of
@@ -113,6 +150,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
*/
void write(long offset, byte[] bytes);
+ void write(long offset, Bytes bytes);
+
/**
* Writes <code>len</code> bytes from array <code>bytes</code>, in order, to the output stream. If
* <code>bytes</code> is <code>null</code>, a <code>NullPointerException</code> is thrown. If <code>off</code> is
@@ -128,6 +167,12 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
@Override
void write(byte[] bytes, int off, int len);
+ void write(long offset, byte[] bytes, int off, int len);
+
+ void write(@NotNull char[] data);
+
+ void write(@NotNull char[] data, int off, int len);
+
/**
* Writes a <code>boolean</code> value to this output stream. If the argument <code>v</code> is <code>true</code>,
* the value <code>(byte)1</code> is written; if <code>v</code> is <code>false</code>, the value
@@ -150,12 +195,11 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* @param offset to write boolean
* @param v the boolean to be written.
*/
-
void writeBoolean(long offset, boolean v);
/**
* Writes two bytes to the output stream to represent the value of the argument. The byte values to be written, in
- * the order shown for big endian machines and the opposite for little endian, are: <p>
+ * the order shown for big endian machines and the opposite for little endian, are:
* <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 8))
* (byte)(0xff &amp; v)
@@ -170,7 +214,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes two bytes to the output stream to represent the value of the argument. The byte values to be written, in
- * the order shown for big endian machines and the opposite for little endian, are: <p>
+ * the order shown for big endian machines and the opposite for little endian, are:
* <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 8))
* (byte)(0xff &amp; v)
@@ -185,7 +229,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes two bytes to the output stream to represent the value of the argument. The byte values to be written, in
- * the order shown for big endian machines and the opposite for little endian, are: <p>
+ * the order shown for big endian machines and the opposite for little endian, are:
* <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 8))
* (byte)(0xff &amp; v)
@@ -199,7 +243,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes two bytes to the output stream to represent the value of the argument. The byte values to be written, in
- * the order shown for big endian machines and the opposite for little endian, are: <p>
+ * the order shown for big endian machines and the opposite for little endian, are:
* <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 8))
* (byte)(0xff &amp; v)
@@ -216,8 +260,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Writes one or three bytes as follows; Short.MIN_VALUE =&gt; Byte.MIN_VALUE, Short.MAX_VALUE =&gt; Byte.MAX_VALUE,
* Short.MIN_VALUE+2 to Short.MAX_VALUE-1 =&gt; writeByte(x), default =&gt; writeByte(Byte.MIN_VALUE+1;
* writeShort(x)
- * <p/>
- * The bytes written by this method may be read by the <code>readCompactShort</code> method of interface
+ *
+ * <p>The bytes written by this method may be read by the <code>readCompactShort</code> method of interface
* <code>RandomDataInput</code> , which will then return a <code>short</code> equal to <code>(short)v</code>.
*
* @param v the <code>short</code> value to be written.
@@ -226,8 +270,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes one or three bytes as follows; 0 to 254 =&gt; writeByte(x); otherwise writeByte(255); writeByteShort(x);
- * <p/>
- * The bytes written by this method may be read by the <code>readCompactUnsignedShort</code> method of interface
+ *
+ * <p>The bytes written by this method may be read by the <code>readCompactUnsignedShort</code> method of interface
* <code>RandomDataInput</code> , which will then return a <code>short</code> equal to <code>v &amp; 0xFFFF</code>.
*
* @param v the unsigned <code>short</code> value to be written.
@@ -237,7 +281,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes a <code>char</code> value, which is comprised of two bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 8))
* (byte)(0xff &amp; v)
* </code></pre><p>
@@ -252,7 +296,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes a <code>char</code> value, which is comprised of two bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 8))
* (byte)(0xff &amp; v)
* </code></pre><p>
@@ -267,7 +311,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes an <code>int</code> value, which is comprised of three bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 16))
* (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
* (byte)(0xff &amp; v)
@@ -282,7 +326,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes an <code>int</code> value, which is comprised of three bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 16))
* (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
* (byte)(0xff &amp; v)
@@ -298,7 +342,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes an <code>int</code> value, which is comprised of four bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 24))
* (byte)(0xff &amp; (v &gt;&gt; 16))
* (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
@@ -315,7 +359,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes an <code>int</code> value, which is comprised of four bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 24))
* (byte)(0xff &amp; (v &gt;&gt; 16))
* (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
@@ -332,7 +376,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes an <code>int</code> value, which is comprised of four bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 24))
* (byte)(0xff &amp; (v &gt;&gt; 16))
* (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
@@ -349,7 +393,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes an <code>int</code> value, which is comprised of four bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 24))
* (byte)(0xff &amp; (v &gt;&gt; 16))
* (byte)(0xff &amp; (v &gt;&gt; &#32; &#32;8))
@@ -368,8 +412,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Writes two or six bytes as follows; Integer.MIN_VALUE =&gt; Short.MIN_VALUE, Integer.MAX_VALUE =&gt;
* Short.MAX_VALUE, Short.MIN_VALUE+2 to Short.MAX_VALUE-1 =&gt; writeShort(x), default =&gt;
* writeShort(Short.MIN_VALUE+1; writeInt(x)
- * <p/>
- * The bytes written by this method may be read by the <code>readCompactInt</code> method of interface
+ *
+ * <p>The bytes written by this method may be read by the <code>readCompactInt</code> method of interface
* <code>RandomDataInput</code> , which will then return a <code>int</code> equal to <code>v</code>.
*
* @param v the <code>int</code> value to be written.
@@ -379,8 +423,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes two or six bytes as follows; 0 to (1 &lt;&lt; 16) - 2 =&gt; writeInt(x), otherwise writeShort(-1);
* writeInt(x)
- * <p/>
- * The bytes written by this method may be read by the <code>readCompactUnsignedInt</code> method of interface
+ *
+ * <p>The bytes written by this method may be read by the <code>readCompactUnsignedInt</code> method of interface
* <code>RandomDataInput</code> , which will then return a <code>int</code> equal to <code>v &amp;
* 0xFFFFFFFF</code>.
*
@@ -392,8 +436,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Same as writeInt but include an ordered write barrier. This means all writes will be visible on a read barrier
* if this write is visible. This might not be visible to be same thread for some clock cycles so an immediate read
* could see an old value
- * <p/>
- * This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
+ *
+ * <p>This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
* same time.
*
* @param v value to write
@@ -404,8 +448,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Same as writeInt but include an ordered write barrier. This means all writes will be visible on a read barrier
* if this write is visible. This might not be visible to be same thread for some clock cycles so an immediate read
* could see an old value
- * <p/>
- * This is much faster than <code>writeVolatileInt</code> as the volatile write stalls the pipeline. The data is
+ *
+ * <p>This is much faster than <code>writeVolatileInt</code> as the volatile write stalls the pipeline. The data is
* visible to other threads at the same time.
*
* @param offset to write to
@@ -445,7 +489,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes a <code>long</code> value, which is comprised of eight bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 40))
* (byte)(0xff &amp; (v &gt;&gt; 32))
* (byte)(0xff &amp; (v &gt;&gt; 24))
@@ -454,7 +498,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* (byte)(0xff &amp; v)
* </code></pre><p>
* The bytes written by this method may be read by the <code>readInt48</code> method of interface
- * <code>RandomDataInput</code> , which will then return a <code>long</code> equal to <code>v &amp; ((1L &lt;&lt 48)
+ * <code>RandomDataInput</code> , which will then return a <code>long</code> equal to <code>v &amp; ((1L &lt;&lt; 48)
* - 1)</code>.
*
* @param v the <code>long</code> value to be written.
@@ -464,7 +508,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes a <code>long</code> value, which is comprised of eight bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 40))
* (byte)(0xff &amp; (v &gt;&gt; 32))
* (byte)(0xff &amp; (v &gt;&gt; 24))
@@ -473,7 +517,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* (byte)(0xff &amp; v)
* </code></pre><p>
* The bytes written by this method may be read by the <code>readInt48</code> method of interface
- * <code>RandomDataInput</code> , which will then return a <code>long</code> equal to <code>v &amp; ((1L &lt;&lt 48)
+ * <code>RandomDataInput</code> , which will then return a <code>long</code> equal to <code>v &amp; ((1L &lt;&lt; 48)
* - 1)</code>.
*
* @param offset to be written to
@@ -484,7 +528,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes a <code>long</code> value, which is comprised of eight bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 56))
* (byte)(0xff &amp; (v &gt;&gt; 48))
* (byte)(0xff &amp; (v &gt;&gt; 40))
@@ -505,7 +549,7 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Writes a <code>long</code> value, which is comprised of eight bytes, to the output stream. The byte values to be
* written, in the order shown for big endian machines and the opposite for little endian, are:
- * <p><pre><code>
+ * <pre><code>
* (byte)(0xff &amp; (v &gt;&gt; 56))
* (byte)(0xff &amp; (v &gt;&gt; 48))
* (byte)(0xff &amp; (v &gt;&gt; 40))
@@ -527,8 +571,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Writes four or twelve bytes as follows Long.MIN_VALUE =&gt; Integer.MIN_VALUE, Long.MAX_VALUE =&gt;
* Integer.MAX_VALUE, Integer.MIN_VALUE+2 to Integer.MAX_VALUE-1 =&gt; writeInt(x), default =&gt;
* writeInt(Integer.MIN_VALUE+1; writeLong(x)
- * <p/>
- * The bytes written by this method may be read by the <code>readCompactLong</code> method of interface
+ *
+ * <p>The bytes written by this method may be read by the <code>readCompactLong</code> method of interface
* <code>RandomDataInput</code> , which will then return a <code>long</code> equal to <code>v</code>.
*
* @param v the <code>long</code> value to be written.
@@ -539,8 +583,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Same as writeLong but include an ordered write barrier. This means all writes will be visible on a read barrier
* if this write is visible. This might not be visible to be same thread for some clock cycles so an immediate read
* could see an old value
- * <p/>
- * This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
+ *
+ * <p>This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
* same time.
*
* @param v value to write
@@ -551,8 +595,8 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Same as writeLong but include an ordered write barrier. This means all writes will be visible on a read barrier
* if this write is visible. This might not be visible to be same thread for some clock cycles so an immediate read
* could see an old value
- * <p/>
- * This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
+ *
+ * <p>This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
* same time.
*
* @param offset to be written to
@@ -572,7 +616,21 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
boolean compareAndSwapLong(long offset, long expected, long x);
/**
- * Stop bit encoding numbers. This will write the same number of bytes whether you used a byte, short or int.
+ * Perform a compare and set operation. The value is set to <code>x</code> provided the <code>expected</code> value
+ * is set already. This operation is atomic.
+ *
+ * @param offset to write to.
+ * @param expected to expect
+ * @param x to set if expected was found
+ * @return true if set, false if the value was not expected
+ */
+ boolean compareAndSwapDouble(long offset, double expected, double x);
+
+ /**
+ * Stop bit encoding numbers. This will write the same number of bytes
+ * whether you used a byte, short or int.
+ *
+ * @param n the number to write
*/
void writeStopBit(long n);
@@ -604,11 +662,12 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Same as writeFloat but include an ordered write barrier. This means all writes will be visible on a read barrier
* if this write is visible. This might not be visible to be same thread for some clock cycles so an immediate read
* could see an old value
- * <p/>
- * This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
+ *
+ * <p>This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
* same time.
*
- * @param v value to write
+ * @param offset to write to
+ * @param v value to write
*/
void writeOrderedFloat(long offset, float v);
@@ -639,15 +698,16 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
void writeDouble(long offset, double v);
/**
+ * <p>
* Writes four or twelve bytes as follow;
- * <p><pre><code>
+ * </p><pre><code>
* if ((float) d == d) {
* writeFloat((float) d);
* } else {
* writeFloat(Float.NaN);
* writeDouble(d);
* }
- * <p/>
+ * </code></pre>
* The bytes written by this method may be read by the <code>readCompactDouble</code> method of interface
* <code>RandomDataInput</code> , which will then return a <code>double</code> equal to <code>v</code>.
*
@@ -659,11 +719,12 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* Same as writeDouble but include an ordered write barrier. This means all writes will be visible on a read
* barrier if this write is visible. This might not be visible to be same thread for some clock cycles so an
* immediate read could see an old value
- * <p/>
- * This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
+ *
+ * <p>This is much faster than a volatile write which stalls the pipeline. The data is visible to other threads at the
* same time.
*
- * @param v value to write
+ * @param offset to write to
+ * @param v value to write
*/
void writeOrderedDouble(long offset, double v);
@@ -688,27 +749,36 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* bytes are actually written, high-order byte first, in exactly the manner of the <code>writeChar</code> method.
*
* @param s the string value to be written. Cannot be null.
+ * @see #writeChars(CharSequence)
*/
@Override
void writeChars(@NotNull String s);
/**
+ * Writes chars of the given {@code CharSequence} to the bytes, without encoding.
+ *
+ * @param cs the {@code CharSequence} to be written. Cannot be null.
+ * @see #writeChars(String)
+ */
+ void writeChars(@NotNull CharSequence cs);
+
+ /**
* Writes two bytes of length information to the output stream, followed by the <a
* href="DataInput.html#modified-utf-8">modified UTF-8</a> representation of every character in the string
* <code>s</code>. If <code>s</code> is <code>null</code>, a <code>NullPointerException</code> is thrown. Each
* character in the string <code>s</code> is converted to a group of one, two, or three bytes, depending on the
* value of the character.<p> If a character <code>c</code> is in the range <code>&#92;u0001</code> through
- * <code>&#92;u007f</code>, it is represented by one byte:<p>
+ * <code>&#92;u007f</code>, it is represented by one byte:
* <pre>(byte)c </pre> <p>
* If a character <code>c</code> is <code>&#92;u0000</code> or is in the range <code>&#92;u0080</code> through
* <code>&#92;u07ff</code>, then it is represented by two bytes, to be written
- * in the order shown:<p> <pre><code>
+ * in the order shown:<pre><code>
* (byte)(0xc0 | (0x1f &amp; (c &gt;&gt; 6)))
* (byte)(0x80 | (0x3f &amp; c))
* </code></pre> <p> If a character
* <code>c</code> is in the range <code>&#92;u0800</code> through <code>uffff</code>, then it is represented by
* three bytes, to be written
- * in the order shown:<p> <pre><code>
+ * in the order shown:<pre><code>
* (byte)(0xe0 | (0x0f &amp; (c &gt;&gt; 12)))
* (byte)(0x80 | (0x3f &amp; (c &gt;&gt; 6)))
* (byte)(0x80 | (0x3f &amp; c))
@@ -730,9 +800,9 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* i.e. one byte longer for short strings, but is not limited in length. 2) The string can be null.
*
* @param s the string value to be written. Can be null.
+ * @throws IllegalArgumentException if there is not enough space left
*/
- void writeUTFΔ(@Nullable CharSequence s);
-
+ void writeUTFΔ(@Nullable CharSequence s) throws IllegalArgumentException;
/**
* Write the same encoding as <code>writeUTF</code> with the following changes. 1) The length is stop bit encoded
@@ -745,8 +815,29 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
*/
void writeUTFΔ(long offset, int maxSize, @Nullable CharSequence s) throws IllegalStateException;
+ void write8bitText(@Nullable CharSequence s);
/**
- * Copies the contents of a ByteBuffer from the potision ot the limit.
+ * Copies the contents of a ByteBuffer from the position to the limit.
+ *
+ * <p> This method transfers the bytes remaining in the given source
+ * buffer into this buffer. If there are more bytes remaining in the
+ * source buffer than in this buffer, that is, if
+ * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+ * then no bytes are transferred and a {@link
+ * java.nio.BufferOverflowException} is thrown.
+ *
+ * <p> Otherwise, this method copies
+ * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> bytes from the given
+ * buffer into this buffer, starting at each buffer's current position.
+ * The positions of both buffers are then incremented by <i>n</i>.
+ *
+ * <p> In other words, an invocation of this method of the form
+ * <tt>dst.write(src)</tt> has exactly the same effect as the loop
+ *
+ * <pre>
+ * while (src.hasRemaining())
+ * dst.writeByte(src.get());
+ * </pre>
*
* @param bb to copy.
*/
@@ -766,10 +857,11 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
/**
* Write an ordered collection of "enumerable objects" (See writeEnum). This writes the stop bit encoded length,
* followed by multiple calls to <code>writeEnum</code> All the elements must be of the same type.
- * <p/>
- * This can be read by the <code>readList</code> method of <code>RandomInputStream</code> and the reader must know
+ *
+ * <p>This can be read by the <code>readList</code> method of <code>RandomInputStream</code> and the reader must know
* the type of each element. You can send the class first by using <code>writeEnum</code> of the element class
*
+ * @param <E> the class of the list elements
* @param list to be written
*/
<E> void writeList(@NotNull Collection<E> list);
@@ -779,9 +871,10 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
* length, followed by multiple calls to <code>writeEnum</code> for each key and value. All the keys must be of the
* same type. All values must be of the same type.
*
+ * @param <K> the class of the map keys
+ * @param <V> the class of the map values
* @param map to write out
*/
-
<K, V> void writeMap(@NotNull Map<K, V> map);
// ObjectOutput
@@ -797,6 +890,15 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
void writeObject(@Nullable Object object);
/**
+ * Write an object with the assumption that the objClass will be provided when the class is read.
+ *
+ * @param <OBJ> the class of the object to write
+ * @param objClass class to write
+ * @param obj to write
+ */
+ <OBJ> void writeInstance(@NotNull Class<OBJ> objClass, @NotNull OBJ obj);
+
+ /**
* Copy data from an Object from bytes start to end.
*
* @param object to copy from
@@ -806,6 +908,32 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
void writeObject(Object object, int start, int end);
/**
+ * fill the Bytes with zeros, and clear the position.
+ *
+ * @return this
+ */
+ Bytes zeroOut();
+
+ /**
+ * fill the Bytes with zeros.
+ *
+ * @param start first byte to zero out
+ * @param end the first byte after the last to zero out (exclusive bound)
+ * @return this
+ */
+ Bytes zeroOut(long start, long end);
+
+ /**
+ * fill the Bytes with zeros, and clear the position, avoiding touching pages unnecessarily
+ *
+ * @param start first byte to zero out
+ * @param end the first byte after the last to zero out (exclusive bound)
+ * @param ifNotZero only set to zero after checking the value is not zero.
+ * @return this
+ */
+ Bytes zeroOut(long start, long end, boolean ifNotZero);
+
+ /**
* Check the end of the stream has not overflowed. Otherwise this doesn't do anything.
*/
@Override
@@ -816,4 +944,6 @@ public interface RandomDataOutput extends ObjectOutput, RandomAccess, BytesCommo
*/
@Override
void close();
+
+ void writeEnum(long offset, int len, Object object);
}
diff --git a/lang/src/main/java/net/openhft/lang/io/RandomDataUpdate.java b/lang/src/main/java/net/openhft/lang/io/RandomDataUpdate.java
index c019276..686cd69 100644
--- a/lang/src/main/java/net/openhft/lang/io/RandomDataUpdate.java
+++ b/lang/src/main/java/net/openhft/lang/io/RandomDataUpdate.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -90,9 +90,25 @@ public interface RandomDataUpdate {
void unlockInt(long offset) throws IllegalMonitorStateException;
/**
+ * Lock which uses 4 bytes. Reset forces the lock to be cleared. Use this only when the program believes the
+ * locked thread is dead.
+ *
+ * @param offset of the start of the 4-byte lock
+ */
+ void resetLockInt(long offset);
+
+ /**
+ * Lock which uses 4 bytes. This returns the lower bytes which contain the threadId.
+ *
+ * @param offset of the start of the 4-byte lock
+ * @return the threadId or 0 if no thread holds the lock.
+ */
+ int threadIdForLockInt(long offset);
+
+ /**
* Lock across processes
- * <p/>
- * Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
+ *
+ * <p>Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
* means if you create more than 16 million threads you can get a collision, and if you try to re-enter 65535 times
* you will get an ISE
*
@@ -103,8 +119,8 @@ public interface RandomDataUpdate {
/**
* Lock across processes
- * <p/>
- * Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
+ *
+ * <p>Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
* means if you create more than 16 million threads you can get a collision, and if you try to re-enter 65535 times
* you will get an ISE
*
@@ -116,8 +132,8 @@ public interface RandomDataUpdate {
/**
* Lock across processes
- * <p/>
- * Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
+ *
+ * <p>Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
* means if you create more than 16 million threads you can get a collision, and if you try to re-enter 65535 times
* you will get an ISE
*
@@ -129,8 +145,8 @@ public interface RandomDataUpdate {
/**
* Lock across processes
- * <p/>
- * Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
+ *
+ * <p>Lock which uses 8 bytes. It store the lower 32 bits of the Thread Id, 16 bits are the process id and the re-entrant count as 16 bit. This
* means if you create more than 16 million threads you can get a collision, and if you try to re-enter 65535 times
* you will get an ISE
*
@@ -138,4 +154,60 @@ public interface RandomDataUpdate {
* @throws IllegalMonitorStateException if this thread doesn't hold the lock
*/
void unlockLong(long offset) throws IllegalMonitorStateException;
+
+ /**
+ * Lock which uses 8 bytes. Reset forces the lock to be cleared. Use this only when the program believes the
+ * locked thread is dead.
+ *
+ * @param offset of the start of the 8-byte lock
+ */
+ void resetLockLong(long offset);
+
+ /**
+ * Lock which uses 8 bytes. This returns the lower bytes which contain the threadId.
+ *
+ * @param offset of the start of the 8-byte lock
+ * @return the threadId or 0 if no thread holds the lock.
+ */
+ long threadIdForLockLong(long offset);
+
+ /**
+ * Uses the 64-bit long at the offset as a non-reentrant read/write lock.
+ * There can be up to 2^20-1 threads reading, or waiting to read on a lock.
+ *
+ * @param offset of the long monitor
+ * @param timeOutNS length of time to busy wait for the lock.
+ * @return if the lock could be obtained in time.
+ * @throws java.lang.IllegalStateException if the monitor is in an illegal state
+ */
+ boolean tryRWReadLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException;
+
+ /**
+ * Uses the 64-bit long at the offset as a non-reentrant read/write lock.
+ * There can be up to 2^20-1 threads reading, or waiting to read on a lock.
+ *
+ * @param offset of the long monitor
+ * @param timeOutNS length of time to busy wait for the lock.
+ * @return if the lock could be obtained in time.
+ * @throws java.lang.IllegalStateException if the monitor is in an illegal state
+ */
+ boolean tryRWWriteLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException;
+
+ /**
+ * Uses the 64-bit long at the offset as a non-reentrant read/write lock.
+ * There can be up to 2^20-1 threads reading, or waiting to read on a lock.
+ *
+ * @param offset of the long monitor
+ * @throws java.lang.IllegalStateException if the monitor is in an illegal state
+ */
+ void unlockRWReadLock(long offset) throws IllegalStateException;
+
+ /**
+ * Uses the 64-bit long at the offset as a non-reentrant read/write lock.
+ * There can be up to 2^20-1 threads reading, or waiting to read on a lock.
+ *
+ * @param offset of the long monitor
+ * @throws java.lang.IllegalStateException if the monitor is in an illegal state
+ */
+ void unlockRWWriteLock(long offset) throws IllegalStateException;
}
diff --git a/lang/src/main/java/net/openhft/lang/io/ResizeableMappedStore.java b/lang/src/main/java/net/openhft/lang/io/ResizeableMappedStore.java
new file mode 100644
index 0000000..6580b51
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/ResizeableMappedStore.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.BytesMarshallableSerializer;
+import net.openhft.lang.io.serialization.JDKZObjectSerializer;
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+public final class ResizeableMappedStore extends AbstractMappedStore {
+ public ResizeableMappedStore(File file, FileChannel.MapMode mode, long size)
+ throws IOException {
+ this(file, mode, size, BytesMarshallableSerializer.create(
+ new VanillaBytesMarshallerFactory(), JDKZObjectSerializer.INSTANCE));
+ }
+
+ public ResizeableMappedStore(File file, FileChannel.MapMode mode, long size,
+ ObjectSerializer objectSerializer) throws IOException {
+ super(new MmapInfoHolder(), file, mode, 0L, size, objectSerializer);
+ }
+
+ /**
+ * Resizes the underlying file and re-maps it. Warning! After this call
+ * instances of {@link Bytes} obtained through {@link #bytes()} or
+ * {@link #bytes(long, long)} are invalid and using them can lead to reading
+ * arbitrary data or JVM crash! It is the callers responsibility to ensure
+ * that these instances are not used after the method call.
+ *
+ * @param newSize
+ * @throws IOException
+ */
+ public void resize(long newSize) throws IOException {
+ validateSize(newSize);
+ unmapAndSyncToDisk();
+ resizeIfNeeded(0L, newSize);
+ this.mmapInfoHolder.setSize(newSize);
+ map(0L);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/Reuses.java b/lang/src/main/java/net/openhft/lang/io/Reuses.java
new file mode 100644
index 0000000..7740fb3
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/Reuses.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+class Reuses {
+ static final ClassLoader MAGIC_CLASS_LOADER = findMagicClassLoader();
+
+ private static ClassLoader findMagicClassLoader() {
+ try {
+ Class<?> clazz = Class.forName("sun.reflect.ConstructorAccessor");
+ ClassLoader cl = clazz.getClassLoader();
+ if (cl == null) {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ return cl;
+ } catch (Throwable ignore) {
+ }
+ return null;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/SettableAtt.java b/lang/src/main/java/net/openhft/lang/io/SettableAtt.java
new file mode 100644
index 0000000..1adb5f4
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/SettableAtt.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+final class SettableAtt {
+ Object att;
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/StopCharTester.java b/lang/src/main/java/net/openhft/lang/io/StopCharTester.java
index 8f965e3..52c5c21 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/StopCharTester.java
+++ b/lang/src/main/java/net/openhft/lang/io/StopCharTester.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -22,10 +22,10 @@ package net.openhft.lang.io;
public interface StopCharTester {
/**
* Detect which byte stops the string to be parsed
- * <p/>
- * This should be changed to support char instead.
- * <p/>
- * Note: for safety reasons, you should stop on a 0 byte or throw an IllegalStateException.
+ *
+ * <p>This should be changed to support char instead.
+ *
+ * <p>Note: for safety reasons, you should stop on a 0 byte or throw an IllegalStateException.
*
* @param ch to test, 0 should return true or throw an exception.
* @return if this byte is a stop character.
diff --git a/lang/src/main/java/net/openhft/lang/io/StopCharTesters.java b/lang/src/main/java/net/openhft/lang/io/StopCharTesters.java
index f711706..f463222 100755..100644
--- a/lang/src/main/java/net/openhft/lang/io/StopCharTesters.java
+++ b/lang/src/main/java/net/openhft/lang/io/StopCharTesters.java
@@ -1,22 +1,22 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
/**
* @author peter.lawrey
@@ -50,6 +50,12 @@ public enum StopCharTesters implements StopCharTester {
public boolean isStopChar(int ch) {
return ch <= 1;
}
+ },
+ ALL {
+ @Override
+ public boolean isStopChar(int ch) {
+ return ch < 0;
+ }
};
@NotNull
@@ -60,7 +66,7 @@ public enum StopCharTesters implements StopCharTester {
}
@NotNull
- public static StopCharTester forChar(char ch) {
+ private static StopCharTester forChar(char ch) {
return new CharCSTester(ch);
}
diff --git a/lang/src/main/java/net/openhft/lang/io/StringBuilderUtils.java b/lang/src/main/java/net/openhft/lang/io/StringBuilderUtils.java
new file mode 100644
index 0000000..f11ed90
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/StringBuilderUtils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+
+import static java.lang.Character.toLowerCase;
+
+/**
+ * Created by Rob Austin
+ */
+public enum StringBuilderUtils {
+ ;
+
+ private static final Field SB_VALUE, SB_COUNT;
+
+ static {
+ try {
+ SB_VALUE = Class.forName("java.lang.AbstractStringBuilder").getDeclaredField("value");
+ SB_VALUE.setAccessible(true);
+ SB_COUNT = Class.forName("java.lang.AbstractStringBuilder").getDeclaredField("count");
+ SB_COUNT.setAccessible(true);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static boolean endsWith(@NotNull final CharSequence source,
+ @NotNull final String endsWith) {
+ for (int i = 1; i <= endsWith.length(); i++) {
+ if (toLowerCase(source.charAt(source.length() - i)) !=
+ toLowerCase(endsWith.charAt(endsWith.length() - i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isEqual(CharSequence s, CharSequence cs) {
+ if (s == null) return false;
+ if (s.length() != cs.length()) return false;
+ for (int i = 0; i < cs.length(); i++)
+ if (s.charAt(i) != cs.charAt(i))
+ return false;
+ return true;
+ }
+
+ public static String toString(Object o) {
+ return o == null ? null : o.toString();
+ }
+
+ public static char[] extractChars(StringBuilder sb) {
+ try {
+ return (char[]) SB_VALUE.get(sb);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static void setCount(StringBuilder sb, int count) {
+ try {
+ SB_COUNT.setInt(sb, count);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaBytesHash.java b/lang/src/main/java/net/openhft/lang/io/VanillaBytesHash.java
new file mode 100755
index 0000000..493ae2b
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaBytesHash.java
@@ -0,0 +1,89 @@
+package net.openhft.lang.io;
+
+import java.nio.ByteOrder;
+
+public enum VanillaBytesHash implements BytesHasher {
+ INSTANCE;
+
+ public static final int K0 = 0x6d0f27bd;
+ public static final int K1 = 0xc1f3bfc9;
+ public static final int K2 = 0x6b192397;
+ public static final int K3 = 0x6b915657;
+ public static final int M0 = 0x5bc80bad;
+ public static final int M1 = 0xea7585d7;
+ public static final int M2 = 0x7a646e19;
+ public static final int M3 = 0x855dd4db;
+ private static final int HI_BYTES = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? 4 : 0;
+
+ public static long agitate(long l) {
+ l += l >>> 22;
+ l ^= Long.rotateRight(l, 17);
+ return l;
+ }
+
+ @Override
+ public long hash(Bytes bytes, long offset, long limit) {
+ long start = offset;
+ int remaining = (int) (limit - offset);
+ // use two hashes so that when they are combined the 64-bit hash is more random.
+ long h0 = (long) remaining * K0;
+ long h1 = 0, h2 = 0, h3 = 0;
+ int i;
+ // optimise chunks of 32 bytes but this is the same as the next loop.
+ for (i = 0; i < remaining - 31; i += 32) {
+ if (i > 0) {
+ h0 *= K0;
+ h1 *= K1;
+ h2 *= K2;
+ h3 *= K3;
+ }
+ long addrI = start + i;
+ long l0 = bytes.readLong(addrI);
+ int l0a = bytes.readInt(addrI + HI_BYTES);
+ long l1 = bytes.readLong(addrI + 8);
+ int l1a = bytes.readInt(addrI + 8 + HI_BYTES);
+ long l2 = bytes.readLong(addrI + 16);
+ int l2a = bytes.readInt(addrI + 16 + HI_BYTES);
+ long l3 = bytes.readLong(addrI + 24);
+ int l3a = bytes.readInt(addrI + 24 + HI_BYTES);
+
+ h0 += (l0 + l1a - l2a) * M0;
+ h1 += (l1 + l2a - l3a) * M1;
+ h2 += (l2 + l3a - l0a) * M2;
+ h3 += (l3 + l0a - l1a) * M3;
+ }
+
+ // perform a hash of the end.
+ int left = remaining - i;
+ if (left > 0) {
+ if (i > 0) {
+ h0 *= K0;
+ h1 *= K1;
+ h2 *= K2;
+ h3 *= K3;
+ }
+
+ long addrI = start + i;
+ long l0 = bytes.readIncompleteLong(addrI);
+ int l0a = (int) (l0 >> 32);
+ long l1 = bytes.readIncompleteLong(addrI + 8);
+ int l1a = (int) (l1 >> 32);
+ long l2 = bytes.readIncompleteLong(addrI + 16);
+ int l2a = (int) (l2 >> 32);
+ long l3 = bytes.readIncompleteLong(addrI + 24);
+ int l3a = (int) (l3 >> 32);
+
+ h0 += (l0 + l1a - l2a) * M0;
+ h1 += (l1 + l2a - l3a) * M1;
+ h2 += (l2 + l3a - l0a) * M2;
+ h3 += (l3 + l0a - l1a) * M3;
+ }
+ return agitate(h0) ^ agitate(h1)
+ ^ agitate(h2) ^ agitate(h3);
+ }
+
+ @Override
+ public long hash(Bytes bytes) {
+ return hash(bytes, bytes.position(), bytes.limit());
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaBytesHasher.java b/lang/src/main/java/net/openhft/lang/io/VanillaBytesHasher.java
new file mode 100644
index 0000000..774fc1a
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaBytesHasher.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.Maths;
+
+public enum VanillaBytesHasher implements BytesHasher {
+ INSTANCE;
+ private static final long LONG_LEVEL_PRIME_MULTIPLE = 0x9ddfea08eb382d69L;
+ private static final short SHORT_LEVEL_PRIME_MULTIPLE = 0x404f;
+ private static final byte BYTE_LEVEL_PRIME_MULTIPLE = 0x57;
+
+ public long hash(Bytes bytes) {
+ return hash(bytes, bytes.position(), bytes.limit());
+ }
+
+ public long hash(Bytes bytes, long offset, long limit) {
+ return Maths.hash(limit - offset == 8 ? bytes.readLong(offset) : hash0(bytes, offset, limit));
+ }
+
+ private long hash0(Bytes bytes, long offset, long limit) {
+ long h = 0;
+ long i = offset;
+ for (; i < limit - 7; i += 8)
+ h = LONG_LEVEL_PRIME_MULTIPLE * h + bytes.readLong(i);
+ for (; i < limit - 1; i += 2)
+ h = SHORT_LEVEL_PRIME_MULTIPLE * h + bytes.readShort(i);
+ if (i < limit)
+ h = BYTE_LEVEL_PRIME_MULTIPLE * h + bytes.readByte(i);
+ return h;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaMappedBlocks.java b/lang/src/main/java/net/openhft/lang/io/VanillaMappedBlocks.java
new file mode 100755
index 0000000..1cdd254
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaMappedBlocks.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class VanillaMappedBlocks implements VanillaMappedResource {
+ private final VanillaMappedFile mappedFile;
+ private final List<VanillaMappedBytes> bytes;
+ private final long blockSize;
+ private final FileLifecycleListener fileLifecycleListener;
+
+ private VanillaMappedBytes mb0;
+ private VanillaMappedBytes mb1;
+
+ public VanillaMappedBlocks(final File path, VanillaMappedMode mode, long blockSize, long overlapSize) throws IOException {
+ this(path, mode, blockSize + overlapSize, null);
+ }
+
+ public VanillaMappedBlocks(final File path, VanillaMappedMode mode, long blockSize,
+ FileLifecycleListener fileLifecycleListener) throws IOException {
+ this.fileLifecycleListener = fileLifecycleListener;
+ this.mappedFile = new VanillaMappedFile(path, mode, -1, fileLifecycleListener);
+ this.bytes = new ArrayList<VanillaMappedBytes>();
+ this.blockSize = blockSize;
+ this.mb0 = null;
+ this.mb1 = null;
+ }
+
+ public synchronized VanillaMappedBytes acquire(long index) throws IOException {
+ if (this.mb0 != null && this.mb0.index() == index) {
+ this.mb0.reserve();
+ return this.mb0;
+ }
+
+ if (this.mb1 != null && this.mb1.index() == index) {
+ this.mb1.reserve();
+ return this.mb1;
+ }
+
+ return acquire0(index);
+ }
+
+ protected VanillaMappedBytes acquire0(long index) throws IOException {
+
+ if (this.mb1 != null) {
+ this.mb1.release();
+ }
+
+ this.mb1 = this.mb0;
+ this.mb0 = this.mappedFile.bytes(index * this.blockSize, this.blockSize, index);
+ this.mb0.reserve();
+
+ bytes.add(this.mb0);
+
+ for (int i = bytes.size() - 1; i >= 0; i--) {
+ if (bytes.get(i).unmapped()) {
+ bytes.remove(i);
+ }
+ }
+
+ return this.mb0;
+ }
+
+ @Override
+ public String path() {
+ return this.mappedFile.path();
+ }
+
+ @Override
+ public synchronized long size() {
+ return this.mappedFile.size();
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (this.mb0 != null && !this.mb0.unmapped()) {
+ this.mb0.release();
+ this.mb0 = null;
+ }
+
+ if (this.mb1 != null && !this.mb1.unmapped()) {
+ this.mb1.release();
+ this.mb1 = null;
+ }
+
+ for (int i = bytes.size() - 1; i >= 0; i--) {
+ bytes.get(i).cleanup();
+ }
+
+ this.bytes.clear();
+ this.mappedFile.close();
+ }
+
+ public static VanillaMappedBlocks readWrite(final File path, long size) throws IOException {
+ return readWrite(path, size, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public static VanillaMappedBlocks readOnly(final File path, long size) throws IOException {
+ return readOnly(path, size, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public static VanillaMappedBlocks readWrite(final File path, long size,
+ FileLifecycleListener listener) throws IOException {
+ return new VanillaMappedBlocks(path, VanillaMappedMode.RW, size, listener);
+ }
+
+ public static VanillaMappedBlocks readOnly(final File path, long size,
+ FileLifecycleListener listener) throws IOException {
+ return new VanillaMappedBlocks(path, VanillaMappedMode.RO, size, listener);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaMappedBytes.java b/lang/src/main/java/net/openhft/lang/io/VanillaMappedBytes.java
new file mode 100644
index 0000000..6f8191f
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaMappedBytes.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import sun.misc.Cleaner;
+import sun.nio.ch.DirectBuffer;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+public class VanillaMappedBytes extends NativeBytes {
+ private final File path;
+ private final MappedByteBuffer buffer;
+ private final FileChannel channel;
+ private final FileLifecycleListener fileLifecycleListener;
+ private final long index;
+ private boolean unmapped;
+
+ public VanillaMappedBytes(final File path, final MappedByteBuffer buffer) {
+ this(path, buffer, -1, null, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public VanillaMappedBytes(final File path, final MappedByteBuffer buffer, FileLifecycleListener fileLifecycleListener) {
+ this(path, buffer, -1, null, fileLifecycleListener);
+ }
+
+ public VanillaMappedBytes(final File path, final MappedByteBuffer buffer, long index) {
+ this(path, buffer, index, null, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public VanillaMappedBytes(final File path, final MappedByteBuffer buffer, long index, FileLifecycleListener fileLifecycleListener) {
+ this(path, buffer, index, null, fileLifecycleListener);
+ }
+
+ protected VanillaMappedBytes(final File path, final MappedByteBuffer buffer, long index, final FileChannel channel) {
+ this(path, buffer, index, channel, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ protected VanillaMappedBytes(
+ final File path,
+ final MappedByteBuffer buffer,
+ long index,
+ final FileChannel channel,
+ final FileLifecycleListener fileLifecycleListener) {
+
+ super(
+ buffer.capacity() == 0 ? NO_PAGE : ((DirectBuffer) buffer).address(),
+ buffer.capacity() == 0 ? NO_PAGE : ((DirectBuffer) buffer).address() + buffer.capacity()
+ );
+
+ this.buffer = buffer;
+ this.path = path;
+ this.channel = channel;
+ this.unmapped = false;
+ this.index = index;
+ this.fileLifecycleListener = fileLifecycleListener;
+ }
+
+ public long index() {
+ return this.index;
+ }
+
+ public synchronized boolean unmapped() {
+ return this.unmapped;
+ }
+
+ @Override
+ public boolean release() {
+ if(!unmapped()) {
+ return super.release();
+ }
+
+ return false;
+ }
+
+ @Override
+ protected synchronized void cleanup() {
+ if(!this.unmapped) {
+ Cleaner cl = ((DirectBuffer)this.buffer).cleaner();
+ if (cl != null) {
+ long start = System.nanoTime();
+ cl.clean();
+
+ fileLifecycleListener.onEvent(
+ FileLifecycleListener.EventType.UNMAP,
+ this.path,
+ System.nanoTime() - start
+ );
+
+ }
+
+ try {
+ if (this.channel != null && this.channel.isOpen()) {
+ this.channel.close();
+ }
+ } catch(IOException e) {
+ throw new AssertionError(e);
+ }
+
+ this.unmapped = true;
+ }
+
+ super.cleanup();
+ }
+
+ public void force() {
+ long start = System.nanoTime();
+ this.buffer.force();
+
+ fileLifecycleListener.onEvent(
+ FileLifecycleListener.EventType.SYNC,
+ this.path,
+ System.nanoTime() - start
+ );
+ }
+
+ @Override
+ public ByteBuffer sliceAsByteBuffer(ByteBuffer toReuse) {
+ return sliceAsByteBuffer(toReuse, buffer);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaMappedCache.java b/lang/src/main/java/net/openhft/lang/io/VanillaMappedCache.java
new file mode 100755
index 0000000..4aa0511
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaMappedCache.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class VanillaMappedCache<T> implements Closeable {
+ private final boolean cleanOnClose;
+ private final Map<T,VanillaMappedBytes> cache;
+ private final FileLifecycleListener fileLifecycleListener;
+
+ public VanillaMappedCache() {
+ this(new LinkedHashMap<T, VanillaMappedBytes>(), false, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public VanillaMappedCache(final boolean cleanOnClose) {
+ this(new LinkedHashMap<T, VanillaMappedBytes>(), cleanOnClose, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public VanillaMappedCache(final int maximumCacheSize, boolean releaseOnRemove) {
+ this(maximumCacheSize, releaseOnRemove, false);
+ }
+ public VanillaMappedCache(final int maximumCacheSize, final boolean releaseOnRemove, final boolean cleanOnClose) {
+ this(maximumCacheSize, releaseOnRemove, cleanOnClose, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ /**
+ *
+ * @param maximumCacheSize the maximum number of VanillaMappedBytes to cache
+ * @param releaseOnRemove release the VanillaMappedBytes when evicted from cache
+ * @param cleanOnClose clean the VanillaMappedBytes when evicted from cache
+ * @param fileLifecycleListener the file lifecycle
+ */
+ public VanillaMappedCache(
+ final int maximumCacheSize,
+ final boolean releaseOnRemove,
+ final boolean cleanOnClose,
+ FileLifecycleListener fileLifecycleListener) {
+
+ this(new LinkedHashMap<T, VanillaMappedBytes>(maximumCacheSize,1.0f,true) {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<T, VanillaMappedBytes> eldest) {
+ boolean removed = size() >= maximumCacheSize;
+ if (removed && releaseOnRemove) {
+ eldest.getValue().release();
+ }
+
+ return removed;
+ }
+ },
+ cleanOnClose,
+ fileLifecycleListener);
+ }
+
+ private VanillaMappedCache(final Map<T, VanillaMappedBytes> cache, final boolean cleanOnClose, FileLifecycleListener fileLifecycleListener) {
+ this.cache = cache;
+ this.cleanOnClose = cleanOnClose;
+ this.fileLifecycleListener = fileLifecycleListener;
+ }
+
+ public VanillaMappedBytes get(T key) {
+ return this.cache.get(key);
+ }
+
+ public VanillaMappedBytes put(T key, File path, long size) throws IOException {
+ return put(key,path,size,-1);
+ }
+
+ public VanillaMappedBytes put(T key, File path, long size, long index) throws IOException {
+ VanillaMappedBytes data = this.cache.get(key);
+
+ if(data != null) {
+ if (!data.unmapped()) {
+ data.cleanup();
+
+ throw new IllegalStateException(
+ "Buffer at " + data.index() + " has a count of " + + data.refCount()
+ );
+ }
+ }
+
+ data = VanillaMappedFile.readWriteBytes(path, size, index, fileLifecycleListener);
+ this.cache.put(key,data);
+
+ return data;
+ }
+
+ public int size() {
+ return this.cache.size();
+ }
+
+ @Override
+ public void close() {
+ final Iterator<Map.Entry<T,VanillaMappedBytes>> it = this.cache.entrySet().iterator();
+ while(it.hasNext()) {
+ Map.Entry<T,VanillaMappedBytes> entry = it.next();
+ entry.getValue().release();
+
+ if(this.cleanOnClose && !entry.getValue().unmapped()) {
+ entry.getValue().cleanup();
+ entry.getValue().close();
+ it.remove();
+
+ } else if(entry.getValue().unmapped()) {
+ entry.getValue().close();
+ it.remove();
+ }
+ }
+
+ this.cache.clear();
+ }
+
+ public synchronized void checkCounts(int min, int max) {
+ for(VanillaMappedBytes data : this.cache.values()) {
+ if (data.refCount() < min || data.refCount() > max) {
+ throw new IllegalStateException(
+ "Buffer at " + data.index() + " has a count of " + + data.refCount()
+ );
+ }
+ }
+ }
+}
+
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaMappedFile.java b/lang/src/main/java/net/openhft/lang/io/VanillaMappedFile.java
new file mode 100755
index 0000000..5562311
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaMappedFile.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.FileLifecycleListener.EventType;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+/*
+ * Merge memory mapped files:
+ * - net.openhft.lang.io.MappedFile
+ * - net.openhft.lang.io.MappedStore
+ * - net.openhft.chronicle.VanillaFile
+ */
+public class VanillaMappedFile implements VanillaMappedResource {
+
+ private final File path;
+ private final FileChannel fileChannel;
+ private final VanillaMappedMode mode;
+ private final long size;
+ private final FileLifecycleListener fileLifecycleListener;
+
+ public VanillaMappedFile(final File path, VanillaMappedMode mode) throws IOException {
+ this(path, mode, -1, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public VanillaMappedFile(final File path, VanillaMappedMode mode, long size,
+ FileLifecycleListener fileLifecycleListener) throws IOException {
+ this.path = path;
+ this.mode = mode;
+ this.size = size;
+ this.fileChannel = fileChannel(path, mode, this.size, fileLifecycleListener);
+ this.fileLifecycleListener = fileLifecycleListener;
+ }
+
+ public VanillaMappedBytes bytes(long address, long size) throws IOException {
+ return new VanillaMappedBytes(this.path, map(address, size), -1, null, this.fileLifecycleListener);
+ }
+
+ public VanillaMappedBytes bytes(long address, long size, long index) throws IOException {
+ return new VanillaMappedBytes(this.path, map(address,size), index, null, this.fileLifecycleListener);
+ }
+
+ @Override
+ public String path() {
+ return this.path.getAbsolutePath();
+ }
+
+ @Override
+ public long size() {
+ try {
+ return this.fileChannel.size();
+ } catch (IOException e) {
+ return 0;
+ }
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if(this.fileChannel.isOpen()) {
+ long start = System.nanoTime();
+ this.fileChannel.close();
+ this.fileLifecycleListener.onEvent(EventType.CLOSE, this.path, System.nanoTime() - start);
+ }
+ }
+
+ // *************************************************************************
+ // Helpers
+ // *************************************************************************
+
+ private synchronized MappedByteBuffer map(long address, long size) throws IOException {
+ long start = System.nanoTime();
+ MappedByteBuffer buffer = this.fileChannel.map(this.mode.mapValue(),address,size);
+ buffer.order(ByteOrder.nativeOrder());
+ fileLifecycleListener.onEvent(EventType.MMAP, path, System.nanoTime() - start);
+ return buffer;
+ }
+
+ private static FileChannel fileChannel(final File path, VanillaMappedMode mapMode, long size, FileLifecycleListener fileLifecycleListener) throws IOException {
+ long start = System.nanoTime();
+ FileChannel fileChannel = null;
+ try {
+ final RandomAccessFile raf = new RandomAccessFile(path, mapMode.stringValue());
+ if (size > 0 && raf.length() != size) {
+ if (mapMode.mapValue() != FileChannel.MapMode.READ_WRITE) {
+ throw new IOException("Cannot resize file to " + size + " as mode is not READ_WRITE");
+ }
+
+ raf.setLength(size);
+ }
+
+ fileChannel = raf.getChannel();
+ } catch (Exception e) {
+ throw wrap(e);
+ }
+
+ fileLifecycleListener.onEvent(EventType.NEW, path, System.nanoTime() - start);
+ return fileChannel;
+ }
+
+ private static IOException wrap(Throwable throwable) {
+ if(throwable instanceof InvocationTargetException) {
+ throwable = throwable.getCause();
+
+ } else if(throwable instanceof IOException) {
+ return (IOException)throwable;
+ }
+
+ return new IOException(throwable);
+ }
+
+ public static VanillaMappedFile readWrite(final File path) throws IOException {
+ return new VanillaMappedFile(path,VanillaMappedMode.RW);
+ }
+
+ public static VanillaMappedFile readWrite(final File path, long size) throws IOException {
+ return new VanillaMappedFile(path, VanillaMappedMode.RW, size,
+ FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public static VanillaMappedFile readOnly(final File path) throws IOException {
+ return new VanillaMappedFile(path,VanillaMappedMode.RO);
+ }
+
+ public static VanillaMappedFile readOnly(final File path, long size) throws IOException {
+ return new VanillaMappedFile(path, VanillaMappedMode.RO, size,
+ FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public static VanillaMappedBytes readWriteBytes(final File path, long size) throws IOException {
+ return readWriteBytes(path, size, -1);
+ }
+
+ public static VanillaMappedBytes readWriteBytes(final File path, long size, long index) throws IOException {
+ return readWriteBytes(path, size, index, FileLifecycleListener.FileLifecycleListeners.IGNORE);
+ }
+
+ public static VanillaMappedBytes readWriteBytes(final File path, long size, long index, FileLifecycleListener fileLifecycleListener) throws IOException {
+ VanillaMappedFile vmf = new VanillaMappedFile(path, VanillaMappedMode.RW, -1, fileLifecycleListener);
+ return new VanillaMappedBytes(path, vmf.map(0,size), index, vmf.fileChannel, fileLifecycleListener);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaMappedMode.java b/lang/src/main/java/net/openhft/lang/io/VanillaMappedMode.java
new file mode 100644
index 0000000..2fb6926
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaMappedMode.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import java.nio.channels.FileChannel;
+
+/**
+ * Helper wrapper for mapeed access mode
+ */
+public enum VanillaMappedMode {
+ RO("r" ,0, FileChannel.MapMode.READ_ONLY),
+ RW("rw",1,FileChannel.MapMode.READ_WRITE)
+ ;
+
+ private static final VanillaMappedMode[] VALUES = values();
+
+ private String stringValue;
+ private int intValue;
+ private FileChannel.MapMode mapValue;
+
+ VanillaMappedMode(String stringValue, int intValue, FileChannel.MapMode mapValue) {
+ this.stringValue = stringValue;
+ this.intValue = intValue;
+ this.mapValue = mapValue;
+ }
+
+ public int intValue() {
+ return this.intValue;
+ }
+
+ public String stringValue() {
+ return this.stringValue;
+ }
+
+ public FileChannel.MapMode mapValue() {
+ return this.mapValue;
+ }
+
+ public static VanillaMappedMode defaultMode() {
+ return VanillaMappedMode.RO;
+ }
+
+ public static VanillaMappedMode fromValue(int value) {
+ for(VanillaMappedMode mode : VALUES) {
+ if(mode.intValue() == value) {
+ return mode;
+ }
+ }
+
+ return defaultMode();
+ }
+
+ public static VanillaMappedMode fromValue(String value) {
+ for(VanillaMappedMode mode : VALUES) {
+ if(mode.stringValue().equalsIgnoreCase(value)) {
+ return mode;
+ }
+ }
+
+ return defaultMode();
+ }
+
+ public static VanillaMappedMode fromValue(FileChannel.MapMode value) {
+ for(VanillaMappedMode mode : VALUES) {
+ if(mode.mapValue() == value) {
+ return mode;
+ }
+ }
+
+ return defaultMode();
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/VanillaMappedResource.java b/lang/src/main/java/net/openhft/lang/io/VanillaMappedResource.java
new file mode 100644
index 0000000..e0a584a
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/VanillaMappedResource.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import java.io.IOException;
+
+public interface VanillaMappedResource {
+ String path();
+
+ long size();
+
+ void close() throws IOException;
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/WrappedBytes.java b/lang/src/main/java/net/openhft/lang/io/WrappedBytes.java
new file mode 100755
index 0000000..1176cea
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/WrappedBytes.java
@@ -0,0 +1,1056 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.io.serialization.ObjectSerializer;
+import net.openhft.lang.model.Byteable;
+import net.openhft.lang.model.constraints.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StreamCorruptedException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A super class for those which wrap bytes.
+ */
+public abstract class WrappedBytes<B extends Bytes> implements Bytes {
+ protected B wrapped;
+
+ protected WrappedBytes(B wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ @Override
+ public void clearThreadAssociation() {
+ wrapped.clearThreadAssociation();
+ }
+
+ public ByteBuffer sliceAsByteBuffer(@org.jetbrains.annotations.Nullable ByteBuffer toReuse) {
+ return wrapped.sliceAsByteBuffer(toReuse);
+ }
+
+ public void readMarshallable(@NotNull Bytes in) throws IllegalStateException {
+ wrapped.readMarshallable(in);
+ }
+
+ @Override
+ public String toDebugString(long limit) {
+ return wrapped.toDebugString(limit);
+ }
+
+ @Override
+ public String toHexString(long limit) {
+ return wrapped.toHexString(limit);
+ }
+
+ @Override
+ public boolean compare(long offset, RandomDataInput input, long inputOffset, long len) {
+ return wrapped.compare(offset, input, inputOffset, len);
+ }
+
+ public long readCompactLong() {
+ return wrapped.readCompactLong();
+ }
+
+ public boolean tryLockNanosInt(long offset, long nanos) {
+ return wrapped.tryLockNanosInt(offset, nanos);
+ }
+
+ public void writeMarshallable(@NotNull Bytes out) {
+ wrapped.writeMarshallable(out);
+ }
+
+ public int readInt24() {
+ return wrapped.readInt24();
+ }
+
+ public void flush() {
+ wrapped.flush();
+ }
+
+ public void writeDouble(long offset, double v) {
+ wrapped.writeDouble(offset, v);
+ }
+
+ public long limit() {
+ return wrapped.limit();
+ }
+
+ @NotNull
+ public ByteStringAppender appendTimeMillis(long timeInMS) {
+ return wrapped.appendTimeMillis(timeInMS);
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public <E extends Enum<E>> E parseEnum(@NotNull Class<E> eClass, @NotNull StopCharTester tester) throws BufferUnderflowException {
+ return wrapped.parseEnum(eClass, tester);
+ }
+
+ public int refCount() {
+ return wrapped.refCount();
+ }
+
+ public void writeShort(long offset, int v) {
+ wrapped.writeShort(offset, v);
+ }
+
+ public <E> void writeEnum(@org.jetbrains.annotations.Nullable E e) {
+ wrapped.writeEnum(e);
+ }
+
+ @NotNull
+ public <E> ByteStringAppender append(@NotNull Iterable<E> list, @NotNull CharSequence separator) {
+ return wrapped.append(list, separator);
+ }
+
+ public void writeCompactUnsignedShort(int v) {
+ wrapped.writeCompactUnsignedShort(v);
+ }
+
+ public long readVolatileLong() {
+ return wrapped.readVolatileLong();
+ }
+
+ public void write(RandomDataInput in, long position, long length) {
+ wrapped.write(in, position, length);
+ }
+
+ public void write(Byteable byteable) {
+ wrapped.write(byteable);
+ }
+
+ public void writeOrderedInt(int v) {
+ wrapped.writeOrderedInt(v);
+ }
+
+ public boolean readUTFΔ(@NotNull StringBuilder stringBuilder) {
+ return wrapped.readUTFΔ(stringBuilder);
+ }
+
+ public void writeInt48(long offset, long v) {
+ wrapped.writeInt48(offset, v);
+ }
+
+ public long readLong() {
+ return wrapped.readLong();
+ }
+
+ public long readIncompleteLong(long offset) {
+ return wrapped.readIncompleteLong(offset);
+ }
+
+ public void writeLong(long v) {
+ wrapped.writeLong(v);
+ }
+
+ @NotNull
+ public ByteStringAppender appendDateTimeMillis(long timeInMS) {
+ return wrapped.appendDateTimeMillis(timeInMS);
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public <E> E readEnum(@NotNull Class<E> eClass) {
+ return wrapped.readEnum(eClass);
+ }
+
+ public void write(RandomDataInput in) {
+ wrapped.write(in);
+ }
+
+ @NotNull
+ public ByteStringAppender append(double d) {
+ return wrapped.append(d);
+ }
+
+ @NotNull
+ public String toDebugString() {
+ return wrapped.toDebugString();
+ }
+
+ public boolean isFinished() {
+ return wrapped.isFinished();
+ }
+
+ public void writeCompactUnsignedInt(long v) {
+ wrapped.writeCompactUnsignedInt(v);
+ }
+
+ @NotNull
+ public ByteStringAppender append(double d, int precision) {
+ return wrapped.append(d, precision);
+ }
+
+ public int readUnsignedByteOrThrow() throws BufferUnderflowException {
+ return wrapped.readUnsignedByteOrThrow();
+ }
+
+ public Bytes zeroOut(long start, long end) {
+ wrapped.zeroOut(start, end);
+ return this;
+ }
+
+ @Override
+ public Bytes zeroOut(long start, long end, boolean ifNotZero) {
+ wrapped.zeroOut(start, end, ifNotZero);
+ return this;
+ }
+
+ public void writeShort(int v) {
+ wrapped.writeShort(v);
+ }
+
+ public short addShort(long offset, short s) {
+ return wrapped.addShort(offset, s);
+ }
+
+ public void writeUnsignedInt(long v) {
+ wrapped.writeUnsignedInt(v);
+ }
+
+ public void free() {
+ wrapped.free();
+ }
+
+ public int readUnsignedShort() {
+ return wrapped.readUnsignedShort();
+ }
+
+ public void writeStopBit(long n) {
+ wrapped.writeStopBit(n);
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public <T> T readObject(Class<T> tClass) throws IllegalStateException {
+ return wrapped.readObject(tClass);
+ }
+
+ public void writeCompactInt(int v) {
+ wrapped.writeCompactInt(v);
+ }
+
+ public void writeOrderedLong(long v) {
+ wrapped.writeOrderedLong(v);
+ }
+
+ public byte addByte(long offset, byte b) {
+ return wrapped.addByte(offset, b);
+ }
+
+ public int readVolatileInt() {
+ return wrapped.readVolatileInt();
+ }
+
+ public void close() {
+ wrapped.close();
+ }
+
+ public void read(@NotNull ByteBuffer bb) {
+ wrapped.read(bb);
+ }
+
+ public void read(@NotNull ByteBuffer bb, int length) {
+ wrapped.read(bb, length);
+ }
+
+ @NotNull
+ public ByteStringAppender append(long l, int base) {
+ return wrapped.append(l, base);
+ }
+
+ public long skip(long n) {
+ return wrapped.skip(n);
+ }
+
+ public boolean selfTerminating() {
+ return wrapped.selfTerminating();
+ }
+
+ public void writeBytes(@NotNull String s) {
+ wrapped.writeBytes(s);
+ }
+
+ public long size() {
+ return wrapped.size();
+ }
+
+ public int readCompactUnsignedShort() {
+ return wrapped.readCompactUnsignedShort();
+ }
+
+ @NotNull
+ public ByteStringAppender append(@NotNull CharSequence s, int start, int end) {
+ return wrapped.append(s, start, end);
+ }
+
+ public void writeCompactLong(long v) {
+ wrapped.writeCompactLong(v);
+ }
+
+ public double readCompactDouble() {
+ return wrapped.readCompactDouble();
+ }
+
+ public void writeOrderedInt(long offset, int v) {
+ wrapped.writeOrderedInt(offset, v);
+ }
+
+ public void writeObject(Object object, int start, int end) {
+ wrapped.writeObject(object, start, end);
+ }
+
+ public CharSequence asString() {
+ return wrapped.asString();
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public String readUTFΔ() {
+ return wrapped.readUTFΔ();
+ }
+
+ public Bytes flip() {
+ return wrapped.flip();
+ }
+
+ public int addInt(long offset, int i) {
+ return wrapped.addInt(offset, i);
+ }
+
+ public long readUnsignedInt(long offset) {
+ return wrapped.readUnsignedInt(offset);
+ }
+
+ public void writeByte(int v) {
+ wrapped.writeByte(v);
+ }
+
+ public void writeUnsignedInt(long offset, long v) {
+ wrapped.writeUnsignedInt(offset, v);
+ }
+
+ public void writeInt(int v) {
+ wrapped.writeInt(v);
+ }
+
+ public short readShort() {
+ return wrapped.readShort();
+ }
+
+ public void writeUnsignedByte(long offset, int v) {
+ wrapped.writeUnsignedByte(offset, v);
+ }
+
+ public void asString(Appendable appendable) {
+ wrapped.asString(appendable);
+ }
+
+ public long readInt48(long offset) {
+ return wrapped.readInt48(offset);
+ }
+
+ public void unlockRWReadLock(long offset) throws IllegalStateException {
+ wrapped.unlockRWReadLock(offset);
+ }
+
+ @NotNull
+ public String readUTF() {
+ return wrapped.readUTF();
+ }
+
+ public void writeUnsignedShort(long offset, int v) {
+ wrapped.writeUnsignedShort(offset, v);
+ }
+
+ public void readFully(@NotNull char[] data) {
+ wrapped.readFully(data);
+ }
+
+ public void writeInt24(long offset, int v) {
+ wrapped.writeInt24(offset, v);
+ }
+
+ public void writeChars(@NotNull CharSequence cs) {
+ wrapped.writeChars(cs);
+ }
+
+ public float readFloat(long offset) {
+ return wrapped.readFloat(offset);
+ }
+
+ public long capacity() {
+ return wrapped.capacity();
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ return wrapped.subSequence(start, end);
+ }
+
+ public Bytes clear() {
+ return wrapped.clear();
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public String readUTFΔ(long offset) throws IllegalStateException {
+ return wrapped.readUTFΔ(offset);
+ }
+
+ @NotNull
+ public ObjectSerializer objectSerializer() {
+ return wrapped.objectSerializer();
+ }
+
+ public void writeOrderedLong(long offset, long v) {
+ wrapped.writeOrderedLong(offset, v);
+ }
+
+ public long addAtomicLong(long offset, long l) {
+ return wrapped.addAtomicLong(offset, l);
+ }
+
+ @NotNull
+ public ByteStringAppender append(char c) {
+ return wrapped.append(c);
+ }
+
+ public void busyLockInt(long offset) throws InterruptedException, IllegalStateException {
+ wrapped.busyLockInt(offset);
+ }
+
+ public void resetLockInt(long offset) {
+ wrapped.resetLockInt(offset);
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public String readLine() {
+ return wrapped.readLine();
+ }
+
+ public char readChar(long offset) {
+ return wrapped.readChar(offset);
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public <T> T readInstance(@NotNull Class<T> objClass, T obj) {
+ return wrapped.readInstance(objClass, obj);
+ }
+
+ @NotNull
+ public ByteStringAppender append(boolean b) {
+ return wrapped.append(b);
+ }
+
+ public int addUnsignedByte(long offset, int i) {
+ return wrapped.addUnsignedByte(offset, i);
+ }
+
+ public void readFully(@NotNull byte[] byteArray, int off, int len) {
+ wrapped.readFully(byteArray, off, len);
+ }
+
+ public void readFully(@NotNull char[] data, int off, int len) {
+ wrapped.readFully(data, off, len);
+ }
+
+ public int addAndGetInt(long offset, int delta) {
+ return wrapped.addAndGetInt(offset, delta);
+ }
+
+ public long addUnsignedInt(long offset, long i) {
+ return wrapped.addUnsignedInt(offset, i);
+ }
+
+ public void writeInt48(long v) {
+ wrapped.writeInt48(v);
+ }
+
+ @NotNull
+ public ByteStringAppender append(@NotNull MutableDecimal md) {
+ return wrapped.append(md);
+ }
+
+ public <K, V> Map<K, V> readMap(@NotNull Map<K, V> map, @NotNull Class<K> kClass, @NotNull Class<V> vClass) {
+ return wrapped.readMap(map, kClass, vClass);
+ }
+
+ public char charAt(int index) {
+ return wrapped.charAt(index);
+ }
+
+ public void writeOrderedFloat(long offset, float v) {
+ wrapped.writeOrderedFloat(offset, v);
+ }
+
+ public void unlockRWWriteLock(long offset) throws IllegalStateException {
+ wrapped.unlockRWWriteLock(offset);
+ }
+
+ public void parseUtf8(@NotNull StringBuilder builder, @NotNull StopCharTester tester) throws BufferUnderflowException {
+ wrapped.parseUtf8(builder, tester);
+ }
+
+ @NotNull
+ public InputStream inputStream() {
+ return wrapped.inputStream();
+ }
+
+ public long remaining() {
+ return wrapped.remaining();
+ }
+
+ public void writeByte(long offset, int b) {
+ wrapped.writeByte(offset, b);
+ }
+
+ public double readDouble() {
+ return wrapped.readDouble();
+ }
+
+ public int readCompactInt() {
+ return wrapped.readCompactInt();
+ }
+
+ public boolean release() {
+ return wrapped.release();
+ }
+
+ public boolean readBoolean(long offset) {
+ return wrapped.readBoolean(offset);
+ }
+
+ public void writeBoolean(boolean v) {
+ wrapped.writeBoolean(v);
+ }
+
+ public int read(@NotNull byte[] byteArray) {
+ return wrapped.read(byteArray);
+ }
+
+ public void writeChars(@NotNull String s) {
+ wrapped.writeChars(s);
+ }
+
+ public Bytes slice() {
+ return wrapped.slice();
+ }
+
+ public Bytes zeroOut() {
+ return wrapped.zeroOut();
+ }
+
+ public void toString(Appendable sb, long start, long position, long end) {
+ wrapped.toString(sb, start, position, end);
+ }
+
+ public void writeOrderedDouble(long offset, double v) {
+ wrapped.writeOrderedDouble(offset, v);
+ }
+
+ public long readStopBit() {
+ return wrapped.readStopBit();
+ }
+
+ public void busyLockLong(long offset) throws InterruptedException, IllegalStateException {
+ wrapped.busyLockLong(offset);
+ }
+
+ public void writeDouble(double v) {
+ wrapped.writeDouble(v);
+ }
+
+ public double readDouble(long offset) {
+ return wrapped.readDouble(offset);
+ }
+
+ public float addFloat(long offset, float f) {
+ return wrapped.addFloat(offset, f);
+ }
+
+ public boolean skipTo(@NotNull StopCharTester tester) {
+ return wrapped.skipTo(tester);
+ }
+
+ public void writeChar(int v) {
+ wrapped.writeChar(v);
+ }
+
+ public void writeInt(long offset, int v) {
+ wrapped.writeInt(offset, v);
+ }
+
+ @NotNull
+ public OutputStream outputStream() {
+ return wrapped.outputStream();
+ }
+
+ public boolean compareAndSwapDouble(long offset, double expected, double x) {
+ return wrapped.compareAndSwapDouble(offset, expected, x);
+ }
+
+ public File file() {
+ return wrapped.file();
+ }
+
+ public <E> void readList(@NotNull Collection<E> list, @NotNull Class<E> eClass) {
+ wrapped.readList(list, eClass);
+ }
+
+ public void writeUnsignedByte(int v) {
+ wrapped.writeUnsignedByte(v);
+ }
+
+ public int readInt24(long offset) {
+ return wrapped.readInt24(offset);
+ }
+
+ public long readInt48() {
+ return wrapped.readInt48();
+ }
+
+ public void write(@NotNull char[] data) {
+ wrapped.write(data);
+ }
+
+ @org.jetbrains.annotations.Nullable
+ public Object readObject() throws IllegalStateException {
+ return wrapped.readObject();
+ }
+
+ @NotNull
+ public ByteStringAppender append(@net.openhft.lang.model.constraints.Nullable Enum value) {
+ return wrapped.append(value);
+ }
+
+ @NotNull
+ public String parseUtf8(@NotNull StopCharTester tester) throws BufferUnderflowException {
+ return wrapped.parseUtf8(tester);
+ }
+
+ public int readInt() {
+ return wrapped.readInt();
+ }
+
+ public void write(@NotNull char[] data, int off, int len) {
+ wrapped.write(data, off, len);
+ }
+
+ public int addUnsignedShort(long offset, int i) {
+ return wrapped.addUnsignedShort(offset, i);
+ }
+
+ public float readFloat() {
+ return wrapped.readFloat();
+ }
+
+ public int available() {
+ return wrapped.available();
+ }
+
+ public long position() {
+ return wrapped.position();
+ }
+
+ public double addDouble(long offset, double d) {
+ return wrapped.addDouble(offset, d);
+ }
+
+ public void write(int b) {
+ wrapped.write(b);
+ }
+
+ public int skipBytes(int n) {
+ return wrapped.skipBytes(n);
+ }
+
+ public short readCompactShort() {
+ return wrapped.readCompactShort();
+ }
+
+ public void write(long offset, byte[] byteArray) {
+ wrapped.write(offset, byteArray);
+ }
+
+ public <E> void writeList(@NotNull Collection<E> list) {
+ wrapped.writeList(list);
+ }
+
+ public int read(@NotNull byte[] byteArray, int off, int len) {
+ return wrapped.read(byteArray, off, len);
+ }
+
+ public int readInt(long offset) {
+ return wrapped.readInt(offset);
+ }
+
+ public void writeFloat(long offset, float v) {
+ wrapped.writeFloat(offset, v);
+ }
+
+ public long parseLong() throws BufferUnderflowException {
+ return wrapped.parseLong();
+ }
+
+ public int readUnsignedByte(long offset) {
+ return wrapped.readUnsignedByte(offset);
+ }
+
+ public Bytes slice(long offset, long length) {
+ return wrapped.slice(offset, length);
+ }
+
+ public void writeObject(@org.jetbrains.annotations.Nullable Object object) {
+ wrapped.writeObject(object);
+ }
+
+ public int length() {
+ return wrapped.length();
+ }
+
+ public char readChar() {
+ return wrapped.readChar();
+ }
+
+ public int read() {
+ return wrapped.read();
+ }
+
+ public void writeBoolean(long offset, boolean v) {
+ wrapped.writeBoolean(offset, v);
+ }
+
+ public double parseDouble() throws BufferUnderflowException {
+ return wrapped.parseDouble();
+ }
+
+ public void writeCompactDouble(double v) {
+ wrapped.writeCompactDouble(v);
+ }
+
+ public float addAtomicFloat(long offset, float f) {
+ return wrapped.addAtomicFloat(offset, f);
+ }
+
+ public void selfTerminating(boolean selfTerminate) {
+ wrapped.selfTerminating(selfTerminate);
+ }
+
+ public long readCompactUnsignedInt() {
+ return wrapped.readCompactUnsignedInt();
+ }
+
+ public double readVolatileDouble(long offset) {
+ return wrapped.readVolatileDouble(offset);
+ }
+
+ public long addLong(long offset, long i) {
+ return wrapped.addLong(offset, i);
+ }
+
+ public long readLong(long offset) {
+ return wrapped.readLong(offset);
+ }
+
+ public boolean compareAndSwapInt(long offset, int expected, int x) {
+ return wrapped.compareAndSwapInt(offset, expected, x);
+ }
+
+ @NotNull
+ public ByteStringAppender append(@NotNull CharSequence s) {
+ return wrapped.append(s);
+ }
+
+ @NotNull
+ public ByteStringAppender append(int i) {
+ return wrapped.append(i);
+ }
+
+ public <K, V> void writeMap(@NotNull Map<K, V> map) {
+ wrapped.writeMap(map);
+ }
+
+ public Boolean parseBoolean(@NotNull StopCharTester tester) throws BufferUnderflowException {
+ return wrapped.parseBoolean(tester);
+ }
+
+ public boolean tryRWReadLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ return wrapped.tryRWReadLock(offset, timeOutNS);
+ }
+
+ public int readUnsignedShort(long offset) {
+ return wrapped.readUnsignedShort(offset);
+ }
+
+ public void writeUTFΔ(long offset, int maxSize, @org.jetbrains.annotations.Nullable CharSequence s) throws IllegalStateException {
+ wrapped.writeUTFΔ(offset, maxSize, s);
+ }
+
+ public byte readByte(long offset) {
+ return wrapped.readByte(offset);
+ }
+
+ @NotNull
+ public ByteStringAppender append(long l) {
+ return wrapped.append(l);
+ }
+
+ public void writeUTFΔ(@org.jetbrains.annotations.Nullable CharSequence s) {
+ wrapped.writeUTFΔ(s);
+ }
+
+ public boolean compareAndSwapLong(long offset, long expected, long x) {
+ return wrapped.compareAndSwapLong(offset, expected, x);
+ }
+
+ public void writeCompactShort(int v) {
+ wrapped.writeCompactShort(v);
+ }
+
+ public Bytes bytes() {
+ return wrapped.bytes();
+ }
+
+ public void write(byte[] byteArray) {
+ wrapped.write(byteArray);
+ }
+
+ public void unlockInt(long offset) throws IllegalMonitorStateException {
+ wrapped.unlockInt(offset);
+ }
+
+ public boolean tryLockLong(long offset) {
+ return wrapped.tryLockLong(offset);
+ }
+
+ public byte readByte() {
+ return wrapped.readByte();
+ }
+
+ public boolean tryRWWriteLock(long offset, long timeOutNS) throws IllegalStateException, InterruptedException {
+ return wrapped.tryRWWriteLock(offset, timeOutNS);
+ }
+
+ public void write(byte[] byteArray, int off, int len) {
+ wrapped.write(byteArray, off, len);
+ }
+
+ public void writeUTF(@NotNull String s) {
+ wrapped.writeUTF(s);
+ }
+
+ public Bytes load() {
+ return wrapped.load();
+ }
+
+ public int getAndAdd(long offset, int delta) {
+ return wrapped.getAndAdd(offset, delta);
+ }
+
+ public short readShort(long offset) {
+ return wrapped.readShort(offset);
+ }
+
+ public boolean stepBackAndSkipTo(@NotNull StopCharTester tester) {
+ return wrapped.stepBackAndSkipTo(tester);
+ }
+
+ public void resetLockLong(long offset) {
+ wrapped.resetLockLong(offset);
+ }
+
+ public int readVolatileInt(long offset) {
+ return wrapped.readVolatileInt(offset);
+ }
+
+ @NotNull
+ public ByteOrder byteOrder() {
+ return wrapped.byteOrder();
+ }
+
+ public Bytes bytes(long offset, long length) {
+ return wrapped.bytes(offset, length);
+ }
+
+ public void alignPositionAddr(int alignment) {
+ wrapped.alignPositionAddr(alignment);
+ }
+
+ public void writeUnsignedShort(int v) {
+ wrapped.writeUnsignedShort(v);
+ }
+
+ public long parseLong(int base) throws BufferUnderflowException {
+ return wrapped.parseLong(base);
+ }
+
+ public boolean readBoolean() {
+ return wrapped.readBoolean();
+ }
+
+ public void checkEndOfBuffer() throws IndexOutOfBoundsException {
+ wrapped.checkEndOfBuffer();
+ }
+
+ public float readVolatileFloat(long offset) {
+ return wrapped.readVolatileFloat(offset);
+ }
+
+ @NotNull
+ public MutableDecimal parseDecimal(@NotNull MutableDecimal decimal) throws BufferUnderflowException {
+ return wrapped.parseDecimal(decimal);
+ }
+
+ public double addAtomicDouble(long offset, double d) {
+ return wrapped.addAtomicDouble(offset, d);
+ }
+
+ public void unlockLong(long offset) throws IllegalMonitorStateException {
+ wrapped.unlockLong(offset);
+ }
+
+ public void writeFloat(float v) {
+ wrapped.writeFloat(v);
+ }
+
+ public void reserve() {
+ wrapped.reserve();
+ }
+
+ public void write(@NotNull ByteBuffer bb) {
+ wrapped.write(bb);
+ }
+
+ public long threadIdForLockLong(long offset) {
+ return wrapped.threadIdForLockLong(offset);
+ }
+
+ public void writeChar(long offset, int v) {
+ wrapped.writeChar(offset, v);
+ }
+
+ public boolean tryLockNanosLong(long offset, long nanos) {
+ return wrapped.tryLockNanosLong(offset, nanos);
+ }
+
+ public int addAtomicInt(long offset, int i) {
+ return wrapped.addAtomicInt(offset, i);
+ }
+
+ public <OBJ> void writeInstance(@NotNull Class<OBJ> objClass, @NotNull OBJ obj) {
+ wrapped.writeInstance(objClass, obj);
+ }
+
+ public void readFully(@NotNull byte[] byteArray) {
+ wrapped.readFully(byteArray);
+ }
+
+ public Bytes position(long position) {
+ return wrapped.position(position);
+ }
+
+ public void writeLong(long offset, long v) {
+ wrapped.writeLong(offset, v);
+ }
+
+ public void readObject(Object object, int start, int end) {
+ wrapped.readObject(object, start, end);
+ }
+
+ public int threadIdForLockInt(long offset) {
+ return wrapped.threadIdForLockInt(offset);
+ }
+
+ @NotNull
+ public ByteStringAppender appendDateMillis(long timeInMS) {
+ return wrapped.appendDateMillis(timeInMS);
+ }
+
+ public void writeInt24(int v) {
+ wrapped.writeInt24(v);
+ }
+
+ public boolean startsWith(RandomDataInput keyBytes) {
+ return wrapped.startsWith(keyBytes);
+ }
+
+ public long readUnsignedInt() {
+ return wrapped.readUnsignedInt();
+ }
+
+ public Bytes limit(long limit) {
+ return wrapped.limit(limit);
+ }
+
+ public void finish() {
+ wrapped.finish();
+ }
+
+ public long address() {
+ return wrapped.address();
+ }
+
+ public boolean tryLockInt(long offset) {
+ return wrapped.tryLockInt(offset);
+ }
+
+ public long readVolatileLong(long offset) {
+ return wrapped.readVolatileLong(offset);
+ }
+
+ public int readUnsignedByte() {
+ return wrapped.readUnsignedByte();
+ }
+
+ @Override
+ public void readFully(long offset, @org.jetbrains.annotations.NotNull byte[] byteArray, int off, int len) {
+ wrapped.readFully(offset, byteArray, off, len);
+ }
+
+ @Override
+ public void write(long offset, byte[] byteArray, int off, int len) {
+ wrapped.write(offset, byteArray, off, len);
+ }
+
+ @Override
+ public void write(long offset, Bytes bytes) {
+ wrapped.write(offset, bytes);
+ }
+
+ @Override
+ public boolean read8bitText(@org.jetbrains.annotations.NotNull StringBuilder stringBuilder) throws StreamCorruptedException {
+ return wrapped.read8bitText(stringBuilder);
+ }
+
+ @Override
+ public <E> E readEnum(long offset, int maxSize, Class<E> eClass) {
+ return wrapped.readEnum(offset, maxSize, eClass);
+ }
+
+ @Override
+ public void write8bitText(@Nullable CharSequence s) {
+ wrapped.write8bitText(s);
+ }
+
+ @Override
+ public void writeEnum(long offset, int len, Object object) {
+ wrapped.writeEnum(offset, len, object);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java
index a92b316..5ac643e 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallable.java
@@ -1,23 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
import net.openhft.lang.io.Bytes;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
/**
* Integrated marshaller for objects.
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java
new file mode 100644
index 0000000..d68e355
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallableSerializer.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import net.openhft.lang.io.AbstractBytes;
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.NativeBytes;
+import net.openhft.lang.io.serialization.impl.NoMarshaller;
+import net.openhft.lang.io.serialization.impl.StringBuilderPool;
+import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.pool.EnumInterner;
+
+import java.io.Externalizable;
+import java.io.IOException;
+
+/**
+ * An extension of built-in Java serialization, featuring special treatment of {@link
+ * BytesMarshallable} objects, compact {@link String} encoding and support of pluggable custom
+ * serializers for arbitrary classes.
+ *
+ * <p>{@code BytesMarshallableSerializer} could benefit if objects (either top-level serialized or
+ * nested fields) implement {@link BytesMarshallable} interface the same way as built-in
+ * serialization benefit if objects implement {@link Externalizable} (of cause, {@code
+ * BytesMarshallableSerializer} supports {@code Externalizable} too).
+ *
+ * <p>{@link CharSequence}s, including {@code String}s (either top-level serialized or nested
+ * fields) are serialized in UTF-8 encoding.
+ *
+ * <p>Custom per-class serializers are held by {@link BytesMarshallerFactory}, which could be
+ * passed via constructor or static factory {@link #create create()} method.
+ *
+ * @see #create(BytesMarshallerFactory, ObjectSerializer)
+ */
+public class BytesMarshallableSerializer implements ObjectSerializer {
+ private static final long serialVersionUID = 0L;
+
+ private static final byte NULL = 'N';
+ private static final byte ENUMED = 'E';
+ private static final byte SERIALIZED = 'S';
+ private static final StringBuilderPool SBP = new StringBuilderPool();
+
+ private final BytesMarshallerFactory bytesMarshallerFactory;
+ private final ObjectSerializer objectSerializer;
+
+ protected BytesMarshallableSerializer(BytesMarshallerFactory bytesMarshallerFactory, ObjectSerializer objectSerializer) {
+ this.bytesMarshallerFactory = bytesMarshallerFactory;
+ this.objectSerializer = objectSerializer;
+ }
+
+ @Override
+ public void writeSerializable(Bytes bytes, Object object, Class expectedClass) throws IOException {
+ if (object == null) {
+ bytes.writeByte(NULL);
+ return;
+ }
+ if (expectedClass != null) {
+ if (BytesMarshallable.class.isAssignableFrom(expectedClass)) {
+ ((BytesMarshallable) object).writeMarshallable(bytes);
+ return;
+
+ } else if (Externalizable.class.isAssignableFrom(expectedClass)) {
+ ((Externalizable) object).writeExternal(bytes);
+ return;
+
+ } else if (CharSequence.class.isAssignableFrom(expectedClass)) {
+ bytes.writeUTFΔ((CharSequence) object);
+ return;
+
+ } else if (Enum.class.isAssignableFrom(expectedClass)) {
+ bytes.write8bitText(object.toString());
+ return;
+ }
+ }
+ writeSerializable2(bytes, object);
+ }
+
+ private void writeSerializable2(Bytes bytes, Object object) throws IOException {
+ Class<?> clazz = object.getClass();
+ BytesMarshaller em = bytesMarshallerFactory.acquireMarshaller(clazz, false);
+ if (em == NoMarshaller.INSTANCE && autoGenerateMarshaller(object))
+ em = bytesMarshallerFactory.acquireMarshaller(clazz, true);
+
+ if (em != NoMarshaller.INSTANCE) {
+ if (em instanceof CompactBytesMarshaller) {
+ bytes.writeByte(((CompactBytesMarshaller) em).code());
+ em.write(bytes, object);
+ return;
+ }
+ bytes.writeByte(ENUMED);
+ this.writeSerializable(bytes, clazz, Class.class);
+ em.write(bytes, object);
+ return;
+ }
+ bytes.writeByte(SERIALIZED);
+ // TODO this is the lame implementation, but it works.
+ objectSerializer.writeSerializable(bytes, object, null);
+ }
+
+ static boolean autoGenerateMarshaller(Object obj) {
+ return (obj instanceof Comparable && obj.getClass().getPackage().getName().startsWith("java"))
+ || obj instanceof Externalizable
+ || obj instanceof BytesMarshallable;
+ }
+
+ @Override
+ public <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException {
+ if (expectedClass != null) {
+ try {
+ if (BytesMarshallable.class.isAssignableFrom(expectedClass)) {
+ return readBytesMarshallable(bytes, expectedClass, object);
+
+ } else if (Externalizable.class.isAssignableFrom(expectedClass)) {
+ return readExternalizable(bytes, expectedClass, object);
+
+ } else if (CharSequence.class.isAssignableFrom(expectedClass)) {
+ return readCharSequence(bytes, object);
+
+ } else if (Enum.class.isAssignableFrom(expectedClass)) {
+ StringBuilder sb = SBP.acquireStringBuilder();
+ bytes.read8bitText(sb);
+ return (T) EnumInterner.intern((Class<Enum>) expectedClass, sb);
+ }
+ } catch (InstantiationException e) {
+ throw new IOException("Unable to create " + expectedClass, e);
+ }
+ }
+ int type = bytes.readUnsignedByteOrThrow();
+ switch (type) {
+ case AbstractBytes.END_OF_BUFFER:
+ case NULL:
+ return null;
+ case ENUMED: {
+ Class clazz = this.readSerializable(bytes, Class.class, null);
+ assert clazz != null;
+ return (T) bytesMarshallerFactory.acquireMarshaller(clazz, true).read(bytes, object);
+ }
+
+ case SERIALIZED: {
+ return objectSerializer.readSerializable(bytes, expectedClass, object);
+ }
+
+ default:
+ BytesMarshaller<Object> m = bytesMarshallerFactory.getMarshaller((byte) type);
+ if (m == null)
+ throw new IllegalStateException("Unknown type " + (char) type);
+ return (T) m.read(bytes);
+ }
+ }
+
+ private <T> T readCharSequence(Bytes bytes, T object) {
+ if (object instanceof StringBuilder) {
+ bytes.readUTFΔ(((StringBuilder) object));
+ return object;
+
+ } else {
+ return (T) bytes.readUTFΔ();
+ }
+ }
+
+ private <T> T readExternalizable(Bytes bytes, Class<T> expectedClass, T object) throws InstantiationException, IOException, ClassNotFoundException {
+ if (object == null)
+ object = (T) NativeBytes.UNSAFE.allocateInstance(expectedClass);
+ ((Externalizable) object).readExternal(bytes);
+ return object;
+ }
+
+ private <T> T readBytesMarshallable(Bytes bytes, Class<T> expectedClass, T object) throws InstantiationException {
+ if (object == null)
+ object = (T) NativeBytes.UNSAFE.allocateInstance(expectedClass);
+ ((BytesMarshallable) object).readMarshallable(bytes);
+ return object;
+ }
+
+ public static ObjectSerializer create() {
+ return create(new VanillaBytesMarshallerFactory(), JDKZObjectSerializer.INSTANCE);
+ }
+
+ public static ObjectSerializer create(BytesMarshallerFactory bytesMarshallerFactory, ObjectSerializer instance) {
+ return bytesMarshallerFactory == null ? instance : new BytesMarshallableSerializer(bytesMarshallerFactory, instance);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java
index d9a4fa2..d2593aa 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshaller.java
@@ -1,45 +1,60 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
import net.openhft.lang.io.Bytes;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.io.Serializable;
/**
- * External marshaller for classes.
+ * External marshaller for classes. From design patterns point of view, this interface
+ * is marshalling <i>strategy</i>.
*
* @author peter.lawrey
* @see BytesMarshallable
*/
-public interface BytesMarshaller<E> {
+public interface BytesMarshaller<E> extends Serializable {
+
/**
- * write the object out as bytes.
+ * Write the object out to the {@code bytes}.
*
* @param bytes to write to
- * @param e to write
+ * @param e the object to write
*/
void write(Bytes bytes, E e);
/**
- * Read bytes and obtain an object
+ * Reads and returns an object from {@code bytes}.
*
* @param bytes to read
- * @return the object
+ * @return the read object
*/
@Nullable
E read(Bytes bytes);
+
+ /**
+ * Reads and returns an object from {@code bytes}, reusing the given object, if possible.
+ *
+ * @param bytes to read
+ * @param e an object to reuse, if possible. {@code null} could be passed, in this case
+ * a new object should be allocated anyway.
+ * @return the read object
+ */
+ @Nullable
+ E read(Bytes bytes, @Nullable E e);
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java
index 87218b7..6814fe8 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/BytesMarshallerFactory.java
@@ -1,27 +1,29 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
+
+import java.io.Serializable;
/**
* @author peter.lawrey
*/
-public interface BytesMarshallerFactory {
+public interface BytesMarshallerFactory extends Serializable {
@NotNull
<E> BytesMarshaller<E> acquireMarshaller(@NotNull Class<E> eClass, boolean create);
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java
index 6ee1f87..5b8ef29 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/CompactBytesMarshaller.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
@@ -20,8 +20,21 @@ package net.openhft.lang.io.serialization;
* A BytesMarshaller with a byte code for the class.
*/
public interface CompactBytesMarshaller<E> extends BytesMarshaller<E> {
+ byte BYTE_BUFFER_CODE = 'B' & 31;
+ byte CLASS_CODE = 'C' & 31;
+ byte INT_CODE = 'I' & 31;
+ byte LONG_CODE = 'L' & 31;
+ byte DOUBLE_CODE = 'D' & 31;
+ byte DATE_CODE = 'T' & 31;
+ byte STRING_CODE = 'S' & 31;
+ byte STRINGZ_MAP_CODE = 'Y' & 31; // compressed string.
+ byte STRINGZ_CODE = 'Z' & 31; // compressed string.
+ byte LIST_CODE = '[';
+ byte SET_CODE = '[' & 31;
+ byte MAP_CODE = '{';
+
/**
- * the code for this marshaller
+ * @return the code for this marshaller
*/
byte code();
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java
new file mode 100644
index 0000000..30557fe
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/JDKObjectSerializer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.model.constraints.NotNull;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+public enum JDKObjectSerializer implements ObjectSerializer {
+ INSTANCE;
+
+ @Override
+ public void writeSerializable(Bytes bytes, Object object, Class expectedClass) throws IOException {
+ new ObjectOutputStream(bytes.outputStream()).writeObject(object);
+ }
+
+ @Override
+ public <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException {
+ return (T) new ObjectInputStream(bytes.inputStream()).readObject();
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java
new file mode 100644
index 0000000..784e7a9
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/JDKZObjectSerializer.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.model.constraints.NotNull;
+
+import java.io.*;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+public enum JDKZObjectSerializer implements ObjectSerializer {
+ INSTANCE;
+
+ @Override
+ public void writeSerializable(Bytes bytes, Object object, Class expectedClass) throws IOException {
+ // reset the finished flag and append
+ long position = bytes.position();
+ bytes.clear();
+ bytes.position(position + 4);
+ OutputStream out = bytes.outputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(new DeflaterOutputStream(out));
+ oos.writeObject(object);
+ oos.close();
+ long length = bytes.position() - position - 4;
+ bytes.writeUnsignedInt(position, length);
+ }
+
+ @Override
+ public <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException {
+ long length = bytes.readUnsignedInt();
+ if (length < 8 || length > Integer.MAX_VALUE)
+ throw new StreamCorruptedException("length = " + Long.toHexString(length));
+ long end = bytes.position() + length;
+ long lim = bytes.limit();
+ bytes.limit(end);
+ int magic = bytes.readUnsignedShort(bytes.position());
+ InputStream in = bytes.inputStream();
+ switch (magic) {
+ case 0xEDAC:
+ break;
+
+ case 0x9c78:
+ in = new InflaterInputStream(in);
+ break;
+ default:
+ throw new StreamCorruptedException("Unknown magic number " + Integer.toHexString(magic));
+ }
+ T t = (T) new ObjectInputStream(in).readObject();
+ bytes.limit(lim);
+ if (end != bytes.position()) {
+ System.out.println("diff: " + (end - bytes.position()));
+ bytes.position(end);
+ }
+ return t;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java
new file mode 100644
index 0000000..40dea33
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import java.io.Serializable;
+
+public interface ObjectFactory<E> extends Serializable {
+ E create() throws InstantiationException, IllegalAccessException;
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java
new file mode 100644
index 0000000..7683862
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/ObjectSerializer.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.model.constraints.NotNull;
+
+import java.io.*;
+
+/**
+ * Abstracts serialization implementation, which at least should be able to serialize objects that
+ * Java built-in serialization is able serialize. In other words, {@code ObjectSerializer} abstracts
+ * Java serialization re-implementations and extensions. {@link Bytes} is used as core IO interface
+ * instead of {@link InputStream} + {@link OutputStream} pair, which Java built-in serialization
+ * use. However, note that {@code Bytes} could always be converted to these old interfaces by
+ * {@link Bytes#inputStream()} and {@link Bytes#outputStream()}, if needed.
+ *
+ * <p>The default fallback implementation is Java built-in serialization itself:
+ * {@link JDKObjectSerializer}.
+ *
+ * <p>Another provided implementation is {@link BytesMarshallableSerializer}, which basically
+ * extends built-in serialization with some improvements. For example, it could benefit if objects
+ * implement {@link BytesMarshallable} interface the same way as built-in serialization benefit
+ * if objects implement {@link Externalizable}. See {@link BytesMarshallableSerializer} docs for
+ * more information.
+ *
+ * <p>This interface is supposed to be implemented to plug such third-party serialization
+ * re-implementations, as Kryo, fast-serialization, etc.
+ */
+public interface ObjectSerializer extends Serializable {
+ /**
+ * write an object
+ *
+ * @param bytes to write to
+ * @param object object to write
+ * @param expectedClass which will be provided on read, can be null
+ */
+ void writeSerializable(@NotNull Bytes bytes, Object object, Class expectedClass) throws IOException;
+
+ /**
+ * Read an object
+ *
+ * @param bytes to read
+ * @param expectedClass proved when writing, can be null
+ * @param object to populate, can be null
+ * @return object read.
+ * @throws IOException if it not possible to serialize the object
+ * @throws ClassNotFoundException if the expectedClass can not be created
+ */
+ <T> T readSerializable(@NotNull Bytes bytes, Class<T> expectedClass, T object) throws IOException, ClassNotFoundException;
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java
deleted file mode 100644
index c6b5b2e..0000000
--- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilter.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.openhft.lang.io.serialization.direct;
-
-import java.lang.reflect.Field;
-import java.util.*;
-
-import static net.openhft.lang.io.serialization.direct.FieldMetadata.*;
-
-public final class DirectSerializationFilter {
- public static List<Field> stopAtFirstIneligibleField(List<Field> fields) {
- ArrayList<Field> eligibleFields = new ArrayList<Field>();
- for (Field f : fields) {
- if (checkEligible(f)) {
- eligibleFields.add(f);
- } else {
- break;
- }
- }
-
- return eligibleFields.isEmpty() ?
- Collections.<Field>emptyList() :
- eligibleFields;
- }
-
- private static boolean checkEligible(Field f) {
- return isPrimitive(f) &&
- !isStatic(f) &&
- !isTransient(f);
- }
-} \ No newline at end of file
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java b/lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java
deleted file mode 100644
index d186c77..0000000
--- a/lang/src/main/java/net/openhft/lang/io/serialization/direct/FieldMetadata.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.openhft.lang.io.serialization.direct;
-
-import java.lang.reflect.*;
-
-public final class FieldMetadata {
- public static boolean isPrimitive(Field f) {
- return f.getType().isPrimitive();
- }
-
- public static boolean isPrimitiveArray(Field f) {
- Class<?> clazz = f.getType();
- return clazz.isArray() && clazz.getComponentType().isPrimitive();
- }
-
- public static boolean isStatic(Field f) {
- return Modifier.isStatic(f.getModifiers());
- }
-
- public static boolean isTransient(Field f) {
- return Modifier.isTransient(f.getModifiers());
- }
-}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java
new file mode 100644
index 0000000..70ac6f7
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/AllocateInstanceObjectFactory.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.NativeBytes;
+import net.openhft.lang.io.serialization.ObjectFactory;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Object factory which creates an object by means of {@code Unsafe.allocateInstance()} call,
+ * i. e. without calling constructor.
+ *
+ * @param <E> type of created objects
+ */
+public final class AllocateInstanceObjectFactory<E> implements ObjectFactory<E> {
+ private static final long serialVersionUID = 0L;
+
+ private final Class<E> eClass;
+
+ public AllocateInstanceObjectFactory(Class<E> eClass) {
+ if (eClass.isInterface() || Modifier.isAbstract(eClass.getModifiers()) ||
+ eClass.isEnum()) {
+ throw new IllegalArgumentException(eClass + " should be a non-abstract non-enum class");
+ }
+ this.eClass = eClass;
+ }
+
+ public Class<E> allocatedClass() {
+ return eClass;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public E create() throws InstantiationException {
+ return (E) NativeBytes.UNSAFE.allocateInstance(eClass);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && obj.getClass() == getClass() &&
+ ((AllocateInstanceObjectFactory) obj).eClass == eClass;
+ }
+
+ @Override
+ public int hashCode() {
+ return eClass.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{eClass=" + eClass + "}";
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java
new file mode 100644
index 0000000..ac4051f
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferMarshaller.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.nio.ByteBuffer;
+
+public enum ByteBufferMarshaller implements CompactBytesMarshaller<ByteBuffer> {
+ INSTANCE;
+
+ @Override
+ public byte code() {
+ return BYTE_BUFFER_CODE;
+ }
+
+ @Override
+ public void write(Bytes bytes, ByteBuffer byteBuffer) {
+ int position = byteBuffer.position();
+ bytes.writeStopBit(byteBuffer.remaining());
+ bytes.write(byteBuffer);
+
+ // reset the position back as we found it
+ byteBuffer.position(position);
+ }
+
+ @Override
+ public ByteBuffer read(Bytes bytes) {
+ return read(bytes, null);
+ }
+
+ @Override
+ public ByteBuffer read(Bytes bytes, @Nullable ByteBuffer byteBuffer) {
+ long length = bytes.readStopBit();
+ assert length <= Integer.MAX_VALUE;
+ if (length < 0 || length > Integer.MAX_VALUE) {
+ throw new IllegalStateException("Invalid length: " + length);
+ }
+ if (byteBuffer == null || byteBuffer.capacity() < length) {
+ byteBuffer = newByteBuffer((int) length);
+
+ } else {
+ byteBuffer.position(0);
+ byteBuffer.limit((int) length);
+ }
+
+ bytes.read(byteBuffer);
+ byteBuffer.flip();
+ return byteBuffer;
+ }
+
+ protected ByteBuffer newByteBuffer(int length) {
+ return ByteBuffer.allocate(length);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java
new file mode 100644
index 0000000..fe648e9
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ByteBufferZMarshaller.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+public enum ByteBufferZMarshaller implements CompactBytesMarshaller<ByteBuffer> {
+ INSTANCE;
+
+ @Override
+ public byte code() {
+ return BYTE_BUFFER_CODE;
+ }
+
+ @Override
+ public void write(Bytes bytes, ByteBuffer byteBuffer) {
+ bytes.writeStopBit(byteBuffer.remaining());
+ long position = bytes.position();
+ bytes.clear();
+ bytes.position(position + 4);
+ DataOutputStream dos = new DataOutputStream(new DeflaterOutputStream(bytes.outputStream()));
+ try {
+ while (byteBuffer.remaining() >= 8)
+ dos.writeLong(byteBuffer.getLong());
+ while (byteBuffer.remaining() > 0)
+ dos.write(byteBuffer.get());
+ dos.close();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ bytes.writeUnsignedInt(position, bytes.position() - position - 4);
+
+ bytes.write(byteBuffer);
+ }
+
+ @Override
+ public ByteBuffer read(Bytes bytes) {
+ return read(bytes, null);
+ }
+
+ @Override
+ public ByteBuffer read(Bytes bytes, @Nullable ByteBuffer byteBuffer) {
+ long length = bytes.readStopBit();
+ if (length < 0 || length > Integer.MAX_VALUE) {
+ throw new IllegalStateException("Invalid length: " + length);
+ }
+ if (byteBuffer == null || byteBuffer.capacity() < length) {
+ byteBuffer = newByteBuffer((int) length);
+
+ } else {
+ byteBuffer.clear();
+ }
+ byteBuffer.limit((int) length);
+
+ long position = bytes.position();
+ long end = position + length;
+
+ long limit = bytes.limit();
+ bytes.limit(end);
+
+ DataInputStream dis = new DataInputStream(new InflaterInputStream(bytes.inputStream()));
+ try {
+ while (byteBuffer.remaining() >= 8)
+ byteBuffer.putLong(dis.readLong());
+ while (byteBuffer.remaining() >= 0)
+ byteBuffer.put(dis.readByte());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ bytes.position(end);
+ bytes.limit(limit);
+
+ byteBuffer.flip();
+ return byteBuffer;
+ }
+
+ protected ByteBuffer newByteBuffer(int length) {
+ return ByteBuffer.allocate(length);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java
index ebcb95f..59ea161 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/BytesMarshallableMarshaller.java
@@ -1,31 +1,34 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.NativeBytes;
import net.openhft.lang.io.serialization.BytesMarshallable;
import net.openhft.lang.io.serialization.BytesMarshaller;
-import net.openhft.lang.io.NativeBytes;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
/**
* @author peter.lawrey
*/
-public class BytesMarshallableMarshaller<E extends BytesMarshallable> implements BytesMarshaller<E> {
+public class BytesMarshallableMarshaller<E extends BytesMarshallable>
+ implements BytesMarshaller<E> {
+ private static final long serialVersionUID = 0L;
@NotNull
private final Class<E> classMarshaled;
@@ -33,6 +36,10 @@ public class BytesMarshallableMarshaller<E extends BytesMarshallable> implements
this.classMarshaled = classMarshaled;
}
+ public final Class<E> marshaledClass() {
+ return classMarshaled;
+ }
+
@Override
public void write(@NotNull Bytes bytes, @NotNull E e) {
e.writeMarshallable(bytes);
@@ -40,13 +47,42 @@ public class BytesMarshallableMarshaller<E extends BytesMarshallable> implements
@Override
public E read(@NotNull Bytes bytes) {
- E e;
- try {
- e = (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled);
- } catch (Exception e2) {
- throw new IllegalStateException(e2);
+ return read(bytes, null);
+ }
+
+ @Nullable
+ @Override
+ public E read(Bytes bytes, @Nullable E e) {
+ if (e == null) {
+ try {
+ e = getInstance();
+ } catch (Exception e2) {
+ throw new IllegalStateException(e2);
+ }
}
e.readMarshallable(bytes);
return e;
}
+
+ @SuppressWarnings("unchecked")
+ @NotNull
+ protected E getInstance() throws Exception {
+ return (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && obj.getClass() == getClass() &&
+ ((BytesMarshallableMarshaller) obj).classMarshaled == classMarshaled;
+ }
+
+ @Override
+ public int hashCode() {
+ return classMarshaled.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{classMarshaled=" + classMarshaled + "}";
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java
index db36c37..92be9bd 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ClassMarshaller.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
@@ -19,8 +19,9 @@ package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.Compare;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.CompactBytesMarshaller;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
+import net.openhft.lang.pool.StringInterner;
import java.lang.ref.WeakReference;
import java.math.BigDecimal;
@@ -32,7 +33,8 @@ import java.util.Map;
/**
* @author peter.lawrey
*/
-public class ClassMarshaller implements CompactBytesMarshaller<Class> {
+public class ClassMarshaller extends ImmutableMarshaller<Class>
+ implements CompactBytesMarshaller<Class> {
private static final int CACHE_SIZE = 1019;
private static final Map<String, Class> SC_SHORT_NAME = new LinkedHashMap<String, Class>();
private static final Map<Class, String> CS_SHORT_NAME = new LinkedHashMap<Class, String>();
@@ -48,7 +50,7 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> {
}
private final ClassLoader classLoader;
- private final StringBuilder className = new StringBuilder(40);
+ private static final StringBuilderPool sbp = new StringBuilderPool();
@Nullable
@SuppressWarnings("unchecked")
private WeakReference<Class>[] classWeakReference = null;
@@ -68,9 +70,9 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> {
@Nullable
@Override
public Class read(@NotNull Bytes bytes) {
- className.setLength(0);
- bytes.readUTFΔ(className);
- return load(className);
+ StringBuilder sb = sbp.acquireStringBuilder();
+ bytes.readUTFΔ(sb);
+ return load(sb);
}
@Nullable
@@ -82,15 +84,16 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> {
WeakReference<Class> ref = classWeakReference[hash];
if (ref != null) {
Class clazz = ref.get();
- if (clazz != null && clazz.getName().equals(name))
+ if (clazz != null && StringInterner.isEqual(clazz.getName(), name))
return clazz;
}
try {
- Class<?> clazz = SC_SHORT_NAME.get(name.toString());
+ String className = name.toString();
+ Class<?> clazz = SC_SHORT_NAME.get(className);
if (clazz != null)
return clazz;
- clazz = classLoader.loadClass(name.toString());
+ clazz = classLoader.loadClass(className);
classWeakReference[hash] = new WeakReference<Class>(clazz);
return clazz;
} catch (ClassNotFoundException e) {
@@ -100,6 +103,7 @@ public class ClassMarshaller implements CompactBytesMarshaller<Class> {
@Override
public byte code() {
- return 'C' & 31; // control C
+ return CLASS_CODE; // control C
}
}
+ \ No newline at end of file
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java
new file mode 100644
index 0000000..dbf8f53
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CollectionMarshaller.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.util.Collection;
+
+abstract class CollectionMarshaller<E, C extends Collection<E>> {
+
+ public static final int NULL_LENGTH = -1;
+ final BytesMarshaller<E> eBytesMarshaller;
+
+ protected CollectionMarshaller(BytesMarshaller<E> eBytesMarshaller) {
+ this.eBytesMarshaller = eBytesMarshaller;
+ }
+
+ public void write(Bytes bytes, C c) {
+ if (c == null) {
+ bytes.writeStopBit(NULL_LENGTH);
+ return;
+ }
+ bytes.writeStopBit(c.size());
+ for (E e : c) {
+ eBytesMarshaller.write(bytes, e);
+ }
+ }
+
+ public C read(Bytes bytes) {
+ return read(bytes, null);
+ }
+
+ abstract C newCollection();
+
+ public C read(Bytes bytes, @Nullable C c) {
+ long length = bytes.readStopBit();
+
+ if (length == 0 && c != null) {
+ c.clear();
+ return c;
+ }
+
+ if (length < NULL_LENGTH || length > Integer.MAX_VALUE)
+ throw new IllegalStateException("Invalid length: " + length);
+
+ if (length == NULL_LENGTH)
+ return null;
+
+ if (c == null)
+ c = newCollection();
+
+ return readCollection(bytes, c, (int) length);
+ }
+
+ abstract C readCollection(Bytes bytes, C c, int length);
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java
index 08f66e4..676c86c 100644..100755
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/CompactEnumBytesMarshaller.java
@@ -1,26 +1,26 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.serialization.CompactBytesMarshaller;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
/**
- * Created with IntelliJ IDEA. User: peter Date: 09/12/13 Time: 17:05 To change this template use File | Settings | File
+ * Created with IntelliJ IDEA. User: peter.lawrey Date: 09/12/13 Time: 17:05
* Templates.
*/
public class CompactEnumBytesMarshaller<E> extends GenericEnumMarshaller<E> implements CompactBytesMarshaller<E> {
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java
index 03f6bb1..1e949c5 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/DateMarshaller.java
@@ -1,25 +1,25 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.CompactBytesMarshaller;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
import java.util.Date;
@@ -27,8 +27,8 @@ import java.util.Date;
* @author peter.lawrey
*/
public class DateMarshaller implements CompactBytesMarshaller<Date> {
- final int size1;
- private final StringBuilder sb = new StringBuilder();
+ private final int size1;
+ private static final StringBuilderPool sbp = new StringBuilderPool();
@Nullable
private Date[] interner = null;
@@ -65,12 +65,25 @@ public class DateMarshaller implements CompactBytesMarshaller<Date> {
@Nullable
@Override
public Date read(@NotNull Bytes bytes) {
+ StringBuilder sb = sbp.acquireStringBuilder();
bytes.readUTFΔ(sb);
long time = parseLong(sb);
return lookupDate(time);
}
@Nullable
+ @Override
+ public Date read(Bytes bytes, @Nullable Date date) {
+ if (date == null)
+ return read(bytes);
+ StringBuilder sb = sbp.acquireStringBuilder();
+ bytes.readUTFΔ(sb);
+ long time = parseLong(sb);
+ date.setTime(time);
+ return date;
+ }
+
+ @Nullable
private Date lookupDate(long time) {
int idx = hashFor(time);
if (interner == null)
@@ -90,6 +103,6 @@ public class DateMarshaller implements CompactBytesMarshaller<Date> {
@Override
public byte code() {
- return 'T' & 31; // Control T.
+ return DATE_CODE; // Control T.
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java
index 11f060b..189f7f5 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/EnumBytesMarshaller.java
@@ -1,25 +1,25 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshaller;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
import java.util.BitSet;
import java.util.LinkedHashMap;
@@ -28,19 +28,17 @@ import java.util.Map;
/**
* @author peter.lawrey
*/
-public class EnumBytesMarshaller<E extends Enum<E>> implements BytesMarshaller<E> {
- @NotNull
- private final Class<E> classMarshaled;
+public class EnumBytesMarshaller<E extends Enum<E>> extends ImmutableMarshaller<E>
+ implements BytesMarshaller<E> {
@SuppressWarnings("unchecked")
private final E[] interner = (E[]) new Enum[1024];
private final BitSet internerDup = new BitSet(1024);
- private final Map<String, E> map = new LinkedHashMap<String, E>();
+ private final Map<String, E> map = new LinkedHashMap<String, E>(64);
private final E defaultValue;
private final int mask;
- private final StringBuilder reader = new StringBuilder();
+ private static final StringBuilderPool sbp = new StringBuilderPool();
public EnumBytesMarshaller(@NotNull Class<E> classMarshaled, E defaultValue) {
- this.classMarshaled = classMarshaled;
this.defaultValue = defaultValue;
mask = interner.length - 1;
@@ -52,6 +50,7 @@ public class EnumBytesMarshaller<E extends Enum<E>> implements BytesMarshaller<E
//noinspection UnqualifiedFieldAccess,AssignmentToNull
interner[idx] = null;
internerDup.set(idx);
+
} else {
interner[idx] = e;
}
@@ -77,17 +76,18 @@ public class EnumBytesMarshaller<E extends Enum<E>> implements BytesMarshaller<E
@Override
public E read(@NotNull Bytes bytes) {
- bytes.readUTFΔ(reader);
- return builderToEnum();
+ StringBuilder sb = sbp.acquireStringBuilder();
+ bytes.readUTFΔ(sb);
+ return builderToEnum(sb);
}
- private E builderToEnum() {
- int num = hashFor(reader);
+ private E builderToEnum(StringBuilder sb) {
+ int num = hashFor(sb);
int idx = num & mask;
E e = interner[idx];
if (e != null) return e;
if (!internerDup.get(idx)) return defaultValue;
- e = map.get(reader.toString());
+ e = map.get(sb.toString());
return e == null ? defaultValue : e;
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java
index 05f5390..4e9b82c 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ExternalizableMarshaller.java
@@ -1,25 +1,26 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
-import net.openhft.lang.io.serialization.BytesMarshaller;
import net.openhft.lang.io.NativeBytes;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
import java.io.Externalizable;
import java.io.IOException;
@@ -28,6 +29,8 @@ import java.io.IOException;
* @author peter.lawrey
*/
public class ExternalizableMarshaller<E extends Externalizable> implements BytesMarshaller<E> {
+ private static final long serialVersionUID = 0L;
+
@NotNull
private final Class<E> classMarshaled;
@@ -35,6 +38,10 @@ public class ExternalizableMarshaller<E extends Externalizable> implements Bytes
this.classMarshaled = classMarshaled;
}
+ public final Class<E> marshaledClass() {
+ return classMarshaled;
+ }
+
@Override
public void write(Bytes bytes, @NotNull E e) {
try {
@@ -46,13 +53,41 @@ public class ExternalizableMarshaller<E extends Externalizable> implements Bytes
@Override
public E read(Bytes bytes) {
- E e;
+ return read(bytes, null);
+ }
+
+ @Nullable
+ @Override
+ public E read(Bytes bytes, @Nullable E e) {
try {
- e = (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled);
+ if (e == null)
+ e = getInstance();
e.readExternal(bytes);
+ return e;
} catch (Exception e2) {
throw new IllegalStateException(e2);
}
- return e;
+ }
+
+ @SuppressWarnings("unchecked")
+ @NotNull
+ protected E getInstance() throws Exception {
+ return (E) NativeBytes.UNSAFE.allocateInstance(classMarshaled);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && obj.getClass() == getClass() &&
+ ((ExternalizableMarshaller) obj).classMarshaled == classMarshaled;
+ }
+
+ @Override
+ public int hashCode() {
+ return classMarshaled.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{marshaledClass=" + classMarshaled + "}";
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java
index 8a1b52d..8ed4590 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/GenericEnumMarshaller.java
@@ -1,25 +1,25 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshaller;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -30,17 +30,20 @@ import java.util.Map;
* @author peter.lawrey
*/
public class GenericEnumMarshaller<E> implements BytesMarshaller<E> {
- @NotNull
- private final Class<E> classMarshaled;
+ private final int capacity;
@Nullable
- private final Constructor<E> constructor;
+ private transient final Constructor<E> constructor;
@Nullable
- private final Method valueOf;
+ private transient final Method valueOf;
@NotNull
private final Map<String, E> map;
+ //used by the read resolve method
+ private final Class<E> classMarshaled;
+
public GenericEnumMarshaller(@NotNull Class<E> classMarshaled, final int capacity) {
this.classMarshaled = classMarshaled;
+ this.capacity = capacity;
Constructor<E> constructor = null;
Method valueOf = null;
try {
@@ -48,6 +51,7 @@ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> {
} catch (NoSuchMethodException e) {
try {
constructor = classMarshaled.getConstructor(String.class);
+ constructor.setAccessible(true);
} catch (NoSuchMethodException e1) {
throw new IllegalArgumentException(classMarshaled + " doesn't have a valueOf(String) or a Constructor(String)");
}
@@ -62,6 +66,10 @@ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> {
};
}
+ private Object readResolve() {
+ return new GenericEnumMarshaller(classMarshaled, capacity);
+ }
+
@Override
public void write(@NotNull Bytes bytes, @Nullable E e) {
bytes.writeUTFΔ(e == null ? null : e.toString());
@@ -74,19 +82,26 @@ public class GenericEnumMarshaller<E> implements BytesMarshaller<E> {
return s == null ? null : valueOf(s);
}
+ @Nullable
+ @Override
+ public E read(Bytes bytes, @Nullable E e) {
+ return read(bytes);
+ }
+
private E valueOf(String s) {
E e = map.get(s);
if (e == null)
try {
if (constructor != null) {
map.put(s, e = constructor.newInstance(s));
+
} else {
@SuppressWarnings("unchecked")
E invoke = (E) valueOf.invoke(null, s);
map.put(s, e = invoke);
}
} catch (Exception t) {
- throw new AssertionError(t.getCause());
+ throw new AssertionError(t);
}
return e;
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java
new file mode 100644
index 0000000..de55a9c
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ImmutableMarshaller.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+
+abstract class ImmutableMarshaller<E> implements BytesMarshaller<E> {
+ @Nullable
+ @Override
+ public final E read(Bytes bytes, @Nullable E e) {
+ return read(bytes);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java
new file mode 100644
index 0000000..cc9b592
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/ListMarshaller.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListMarshaller<E> extends CollectionMarshaller<E, List<E>> implements CompactBytesMarshaller<List<E>> {
+
+ ListMarshaller(BytesMarshaller<E> eBytesMarshaller) {
+ super(eBytesMarshaller);
+ }
+
+ public static <E> BytesMarshaller<List<E>> of(BytesMarshaller<E> eBytesMarshaller) {
+ return new ListMarshaller<E>(eBytesMarshaller);
+ }
+
+ @Override
+ public byte code() {
+ return LIST_CODE;
+ }
+
+ @Override
+ List<E> newCollection() {
+ return new ArrayList<E>();
+ }
+
+ @Override
+ List<E> readCollection(Bytes bytes, List<E> es, int length) {
+ List<E> ret = es;
+ ret.clear();
+
+ for (int i = 0; i < length; i++) {
+ ret.add(eBytesMarshaller.read(bytes));
+ }
+
+ return ret;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java
new file mode 100755
index 0000000..195d96d
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/MapMarshaller.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Created by peter.lawrey on 24/10/14.
+ */
+public class MapMarshaller<K, V> implements CompactBytesMarshaller<Map<K, V>> {
+ private final BytesMarshaller<K> kBytesMarshaller;
+ private final BytesMarshaller<V> vBytesMarshaller;
+
+ MapMarshaller(BytesMarshaller<K> kBytesMarshaller, BytesMarshaller<V> vBytesMarshaller) {
+ this.kBytesMarshaller = kBytesMarshaller;
+ this.vBytesMarshaller = vBytesMarshaller;
+ }
+
+ @Override
+ public byte code() {
+ return MAP_CODE;
+ }
+
+ @Override
+ public void write(Bytes bytes, Map<K, V> kvMap) {
+ bytes.writeInt(kvMap.size());
+ for (Map.Entry<K, V> entry : kvMap.entrySet()) {
+ kBytesMarshaller.write(bytes, entry.getKey());
+ vBytesMarshaller.write(bytes, entry.getValue());
+ }
+ }
+
+ @Override
+ public Map<K, V> read(Bytes bytes) {
+ return read(bytes, null);
+ }
+
+ @Override
+ public Map<K, V> read(Bytes bytes, @Nullable Map<K, V> kvMap) {
+ if (kvMap == null) {
+ kvMap = new LinkedHashMap<K, V>();
+
+ } else {
+ kvMap.clear();
+ }
+ int size = bytes.readInt();
+ for (int i = 0; i < size; i++)
+ kvMap.put(kBytesMarshaller.read(bytes), vBytesMarshaller.read(bytes));
+ return kvMap;
+ }
+
+ public static <K, V> BytesMarshaller<Map<K, V>> of(BytesMarshaller<K> keyMarshaller, BytesMarshaller<V> valueMarshaller) {
+ return new MapMarshaller<K, V>(keyMarshaller, valueMarshaller);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java
new file mode 100644
index 0000000..0fba720
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NewInstanceObjectFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.serialization.ObjectFactory;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Object factory which creates an object by means of {@link Class#newInstance()} call,
+ * i. e. with calling the default no-arg constructor of the class.
+ *
+ * @param <E> type of created objects
+ */
+public final class NewInstanceObjectFactory<E> implements ObjectFactory<E> {
+ private static final long serialVersionUID = 0L;
+
+ private final Class<E> eClass;
+
+ public NewInstanceObjectFactory(Class<E> eClass) {
+ if (eClass.isInterface() || Modifier.isAbstract(eClass.getModifiers()) ||
+ eClass.isEnum()) {
+ throw new IllegalArgumentException(eClass + " should be a non-abstract non-enum class");
+ }
+ this.eClass = eClass;
+ }
+
+ @Override
+ public E create() throws IllegalAccessException, InstantiationException {
+ return eClass.newInstance();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && obj.getClass() == getClass() &&
+ ((NewInstanceObjectFactory) obj).eClass == eClass;
+ }
+
+ @Override
+ public int hashCode() {
+ return eClass.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{eClass=" + eClass + "}";
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java
index 1369c4a..c76054c 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoMarshaller.java
@@ -1,23 +1,24 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
/**
* Created with IntelliJ IDEA. User: peter.lawrey Date: 19/09/13 Time: 18:26 To change this template use File | Settings | File
@@ -35,4 +36,10 @@ public enum NoMarshaller implements BytesMarshaller<Void> {
public Void read(Bytes bytes) {
throw new UnsupportedOperationException();
}
+
+ @Nullable
+ @Override
+ public Void read(Bytes bytes, @Nullable Void aVoid) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java
new file mode 100644
index 0000000..c3e061f
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NoObjectFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.serialization.ObjectFactory;
+
+/**
+ * Placeholder object factory which always throws {@code UnsupportedOperationException}.
+ */
+public enum NoObjectFactory implements ObjectFactory {
+ INSTANCE;
+
+ /**
+ * Always throws {@code UnsupportedOperationException}.
+ *
+ * @return nothing
+ * @throws UnsupportedOperationException always
+ */
+ @Override
+ public Object create() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java
new file mode 100644
index 0000000..af76bc7
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/NullObjectFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.serialization.ObjectFactory;
+
+/**
+ * Object factory which always returns {@code null}.
+ */
+public enum NullObjectFactory implements ObjectFactory {
+ INSTANCE;
+
+ public static <E> ObjectFactory<E> of() {
+ return INSTANCE;
+ }
+
+ /**
+ * Always returns {@code null}.
+ *
+ * @return {@code null}
+ */
+ @Override
+ public Object create() {
+ return null;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java
new file mode 100644
index 0000000..e401722
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SetMarshaller.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.BytesMarshaller;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class SetMarshaller<E> extends CollectionMarshaller<E, Set<E>> implements CompactBytesMarshaller<Set<E>> {
+ SetMarshaller(BytesMarshaller<E> eBytesMarshaller) {
+ super(eBytesMarshaller);
+ }
+
+ public static <E> BytesMarshaller<Set<E>> of(BytesMarshaller<E> eBytesMarshaller) {
+ return new SetMarshaller<E>(eBytesMarshaller);
+ }
+
+ @Override
+ public byte code() {
+ return SET_CODE;
+ }
+
+ @Override
+ Set<E> newCollection() {
+ return new LinkedHashSet<E>();
+ }
+
+ @Override
+ Set<E> readCollection(Bytes bytes, Set<E> es, int length) {
+ es.clear();
+
+ for (int i = 0; i < length; i++) {
+ es.add(eBytesMarshaller.read(bytes));
+ }
+
+ return es;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java
new file mode 100755
index 0000000..14ff64f
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshaller.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+import org.xerial.snappy.Snappy;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.ByteBuffer;
+
+/**
+ * Created by peter.lawrey on 24/10/14.
+ */
+public enum SnappyStringMarshaller implements CompactBytesMarshaller<CharSequence> {
+ INSTANCE;
+ private static final StringFactory STRING_FACTORY = getStringFactory();
+
+ private static final int NULL_LENGTH = -1;
+
+ private static StringFactory getStringFactory() {
+ try {
+ return new StringFactory17();
+ } catch (Exception e) {
+ // do nothing
+ }
+
+ try {
+ return new StringFactory16();
+ } catch (Exception e) {
+ // no more alternatives
+ throw new AssertionError(e);
+ }
+ }
+
+ private static final ThreadLocal<ThreadLocals> THREAD_LOCALS = new ThreadLocal<ThreadLocals>();
+
+ static class ThreadLocals {
+ ByteBuffer decompressedByteBuffer = ByteBuffer.allocateDirect(32 * 1024);
+ Bytes decompressedBytes = ByteBufferBytes.wrap(decompressedByteBuffer);
+ ByteBuffer compressedByteBuffer = ByteBuffer.allocateDirect(0);
+
+ public void clear() {
+ decompressedByteBuffer.clear();
+ decompressedBytes.clear();
+ compressedByteBuffer.clear();
+ }
+ }
+
+ @Override
+ public byte code() {
+ return STRINGZ_CODE;
+ }
+
+ public ThreadLocals acquireThreadLocals() {
+ ThreadLocals threadLocals = THREAD_LOCALS.get();
+ if (threadLocals == null)
+ THREAD_LOCALS.set(threadLocals = new ThreadLocals());
+ threadLocals.clear();
+ return threadLocals;
+ }
+
+ @Override
+ public void write(Bytes bytes, CharSequence s) {
+ if (s == null) {
+ bytes.writeStopBit(NULL_LENGTH);
+ return;
+
+ } else if (s.length() == 0) {
+ bytes.writeStopBit(0);
+ return;
+ }
+ // write the total length.
+ int length = s.length();
+ bytes.writeStopBit(length);
+
+ ThreadLocals threadLocals = acquireThreadLocals();
+ // stream the portions of the string.
+ Bytes db = threadLocals.decompressedBytes;
+ ByteBuffer dbb = threadLocals.decompressedByteBuffer;
+ ByteBuffer cbb = bytes.sliceAsByteBuffer(threadLocals.compressedByteBuffer);
+
+ int position = 0;
+ while (position < length) {
+ // 3 is the longest encoding.
+ while (position < length && db.remaining() >= 3)
+ db.writeStopBit(s.charAt(position++));
+ dbb.position(0);
+ dbb.limit((int) db.position());
+ // portion copied now compress it.
+ int portionLengthPos = cbb.position();
+ cbb.putShort((short) 0);
+ int compressedLength;
+ try {
+ Snappy.compress(dbb, cbb);
+ compressedLength = cbb.remaining();
+ if (compressedLength >= 1 << 16)
+ throw new AssertionError();
+ // unflip.
+ cbb.position(cbb.limit());
+ cbb.limit(cbb.capacity());
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ cbb.putShort(portionLengthPos, (short) compressedLength);
+ db.clear();
+ }
+ // the end.
+ cbb.putShort((short) 0);
+ bytes.position(bytes.position() + cbb.position());
+ }
+
+ @Override
+ public String read(Bytes bytes) {
+ return read(bytes, null);
+ }
+
+ @Override
+ public String read(Bytes bytes, @Nullable CharSequence ignored) {
+ long size = bytes.readStopBit();
+ if (size == NULL_LENGTH)
+ return null;
+ if (size < 0 || size > Integer.MAX_VALUE)
+ throw new IllegalStateException("Invalid length: " + size);
+ if (size == 0)
+ return "";
+ ThreadLocals threadLocals = acquireThreadLocals();
+ // stream the portions of the string.
+ Bytes db = threadLocals.decompressedBytes;
+ ByteBuffer dbb = threadLocals.decompressedByteBuffer;
+ ByteBuffer cbb = bytes.sliceAsByteBuffer(threadLocals.compressedByteBuffer);
+
+ char[] chars = new char[(int) size];
+ int pos = 0;
+ for (int chunkLen; (chunkLen = cbb.getShort() & 0xFFFF) > 0; ) {
+ cbb.limit(cbb.position() + chunkLen);
+ dbb.clear();
+ try {
+ Snappy.uncompress(cbb, dbb);
+ cbb.position(cbb.limit());
+ cbb.limit(cbb.capacity());
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ db.position(0);
+ db.limit(dbb.limit());
+ while (db.remaining() > 0)
+ chars[pos++] = (char) db.readStopBit();
+ }
+ bytes.position(bytes.position() + cbb.position());
+ try {
+ return STRING_FACTORY.fromChars(chars);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private static abstract class StringFactory {
+ abstract String fromChars(char[] chars) throws IllegalAccessException, InvocationTargetException, InstantiationException;
+ }
+
+ private static final class StringFactory16 extends StringFactory {
+ private final Constructor<String> constructor;
+
+ private StringFactory16() throws NoSuchMethodException {
+ constructor = String.class.getDeclaredConstructor(int.class,
+ int.class, char[].class);
+ constructor.setAccessible(true);
+ }
+
+ @Override
+ String fromChars(char[] chars) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ return constructor.newInstance(0, chars.length, chars);
+ }
+ }
+
+ private static final class StringFactory17 extends StringFactory {
+ private final Constructor<String> constructor;
+
+ private StringFactory17() throws NoSuchMethodException {
+ constructor = String.class.getDeclaredConstructor(char[].class, boolean.class);
+ constructor.setAccessible(true);
+ }
+
+ @Override
+ String fromChars(char[] chars) throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ return constructor.newInstance(chars, true);
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java
new file mode 100755
index 0000000..d7ca469
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringBuilderPool.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+/**
+ * Created by peter.lawrey on 29/10/14.
+ */
+public class StringBuilderPool {
+ final ThreadLocal<StringBuilder> sbtl = new ThreadLocal<StringBuilder>();
+
+ public StringBuilder acquireStringBuilder() {
+ StringBuilder sb = sbtl.get();
+ if (sb == null) {
+ sbtl.set(sb = new StringBuilder(128));
+ }
+ sb.setLength(0);
+ return sb;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java
index 2fb2ee5..67843ae 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringMarshaller.java
@@ -1,34 +1,35 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
import net.openhft.lang.pool.StringInterner;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* @author peter.lawrey
*/
-public class StringMarshaller implements CompactBytesMarshaller<String> {
+public class StringMarshaller extends ImmutableMarshaller<String>
+ implements CompactBytesMarshaller<String> {
private final int size;
- private final StringBuilder reader = new StringBuilder();
- private StringInterner interner;
+ private static final StringBuilderPool sbp = new StringBuilderPool();
+ private transient StringInterner interner;
public StringMarshaller(int size) {
this.size = size;
@@ -42,19 +43,22 @@ public class StringMarshaller implements CompactBytesMarshaller<String> {
@Nullable
@Override
public String read(@NotNull Bytes bytes) {
- if (bytes.readUTFΔ(reader))
- return builderToString();
+ StringBuilder sb = sbp.acquireStringBuilder();
+ if (bytes.readUTFΔ(sb))
+ return builderToString(sb);
return null;
}
-
- private String builderToString() {
- if (interner == null)
+ private String builderToString(StringBuilder reader) {
+ if (interner == null) {
+ if (size == 0)
+ return reader.toString();
interner = new StringInterner(size);
+ }
return interner.intern(reader);
}
public byte code() {
- return 'S' & 31;
+ return STRING_CODE;
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java
new file mode 100755
index 0000000..efec05e
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/StringZMapMarshaller.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.CompactBytesMarshaller;
+import net.openhft.lang.model.constraints.Nullable;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.StreamCorruptedException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * Created by peter.lawrey on 24/10/14.
+ */
+public enum StringZMapMarshaller implements CompactBytesMarshaller<Map<String, String>> {
+ FAST(Deflater.BEST_SPEED),
+ COMPACT(Deflater.BEST_COMPRESSION),
+ INSTANCE(Deflater.DEFAULT_STRATEGY);
+
+ private final int level;
+
+ private static final long NULL_SIZE = -1;
+
+ StringZMapMarshaller(int level) {
+ this.level = level;
+ }
+
+ @Override
+ public byte code() {
+ return STRINGZ_MAP_CODE;
+ }
+
+ @Override
+ public void write(Bytes bytes, Map<String, String> kvMap) {
+ if (kvMap == null) {
+ bytes.writeStopBit(NULL_SIZE);
+ return;
+ }
+
+ bytes.writeStopBit(kvMap.size());
+ long position = bytes.position();
+ bytes.clear();
+ bytes.position(position + 4);
+ DataOutputStream dos = new DataOutputStream(
+ new DeflaterOutputStream(bytes.outputStream(), new Deflater(level)));
+ try {
+ for (Map.Entry<String, String> entry : kvMap.entrySet()) {
+ dos.writeUTF(entry.getKey());
+ dos.writeUTF(entry.getValue());
+ }
+ dos.close();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ bytes.writeUnsignedInt(position, bytes.position() - position - 4);
+ }
+
+ @Override
+ public Map<String, String> read(Bytes bytes) {
+ return read(bytes, null);
+ }
+
+ @Override
+ public Map<String, String> read(Bytes bytes, @Nullable Map<String, String> kvMap) {
+ long size = bytes.readStopBit();
+ if (size == NULL_SIZE)
+ return null;
+ if (size < 0 || size > Integer.MAX_VALUE)
+ throw new IllegalStateException("Invalid length: " + size);
+
+ long length = bytes.readUnsignedInt();
+ if (length < 0 || length > Integer.MAX_VALUE)
+ throw new IllegalStateException(new StreamCorruptedException());
+ long position = bytes.position();
+ long end = position + length;
+
+ long limit = bytes.limit();
+ bytes.limit(end);
+
+ DataInputStream dis = new DataInputStream(new InflaterInputStream(bytes.inputStream()));
+ if (kvMap == null) {
+ kvMap = new LinkedHashMap<String, String>();
+
+ } else {
+ kvMap.clear();
+ }
+ try {
+ for (int i = 0; i < size; i++) {
+ String key = dis.readUTF();
+ String value = dis.readUTF();
+ kvMap.put(key, value);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ bytes.position(end);
+ bytes.limit(limit);
+ return kvMap;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java b/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java
index 6fc66ee..3e8d94a 100644
--- a/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java
+++ b/lang/src/main/java/net/openhft/lang/io/serialization/impl/VanillaBytesMarshallerFactory.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization.impl;
@@ -20,63 +20,92 @@ import net.openhft.lang.io.serialization.BytesMarshallable;
import net.openhft.lang.io.serialization.BytesMarshaller;
import net.openhft.lang.io.serialization.BytesMarshallerFactory;
import net.openhft.lang.io.serialization.CompactBytesMarshaller;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
import java.io.Externalizable;
+import java.nio.ByteBuffer;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
+import static net.openhft.lang.io.serialization.CompactBytesMarshaller.*;
+
/**
* @author peter.lawrey
*/
-public class VanillaBytesMarshallerFactory implements BytesMarshallerFactory {
+public final class VanillaBytesMarshallerFactory implements BytesMarshallerFactory {
+ private static final long serialVersionUID = 1L;
+
+ private transient Map<Class<?>, BytesMarshaller<?>> marshallerMap;
+ private transient BytesMarshaller<?>[] compactMarshallerMap;
- private final Map<Class, BytesMarshaller> marshallerMap = new LinkedHashMap<Class, BytesMarshaller>();
- private final BytesMarshaller[] compactMarshallerMap = new BytesMarshaller[256];
+ private void init() {
+ marshallerMap = new LinkedHashMap<Class<?>, BytesMarshaller<?>>();
+ compactMarshallerMap = new BytesMarshaller[256];
- // private final Map<Class, BytesMarshaller> marshallerTextMap = new LinkedHashMap<Class, BytesMarshaller>();
- {
- BytesMarshaller stringMarshaller = new StringMarshaller(16 * 1024);
+ BytesMarshaller<String> stringMarshaller = new StringMarshaller(16 * 1024);
addMarshaller(String.class, stringMarshaller);
- addMarshaller(CharSequence.class, stringMarshaller);
+ addMarshaller(CharSequence.class, (BytesMarshaller)stringMarshaller);
addMarshaller(Class.class, new ClassMarshaller(Thread.currentThread().getContextClassLoader()));
addMarshaller(Date.class, new DateMarshaller(10191));
- addMarshaller(Integer.class, new CompactEnumBytesMarshaller<Integer>(Integer.class, 10191, (byte) ('I' & 31)));
- addMarshaller(Long.class, new CompactEnumBytesMarshaller<Long>(Long.class, 10191, (byte) ('L' & 31)));
- addMarshaller(Double.class, new CompactEnumBytesMarshaller<Double>(Double.class, 10191, (byte) ('D' & 31)));
+ addMarshaller(Integer.class, new CompactEnumBytesMarshaller<Integer>(Integer.class, 10191, INT_CODE));
+ addMarshaller(Long.class, new CompactEnumBytesMarshaller<Long>(Long.class, 10191, LONG_CODE));
+ addMarshaller(Double.class, new CompactEnumBytesMarshaller<Double>(Double.class, 10191, DOUBLE_CODE));
+ addMarshaller(ByteBuffer.class, ByteBufferMarshaller.INSTANCE);
}
@NotNull
@SuppressWarnings("unchecked")
@Override
public <E> BytesMarshaller<E> acquireMarshaller(@NotNull Class<E> eClass, boolean create) {
+ if (marshallerMap == null) {
+ init();
+ }
+
BytesMarshaller em = marshallerMap.get(eClass);
- if (em == null)
- if (eClass.isEnum())
+ if (em == null) {
+ if (eClass.isEnum()) {
marshallerMap.put(eClass, em = new EnumBytesMarshaller(eClass, null));
- else if (BytesMarshallable.class.isAssignableFrom(eClass))
+
+ } else if (BytesMarshallable.class.isAssignableFrom(eClass)) {
marshallerMap.put(eClass, em = new BytesMarshallableMarshaller((Class) eClass));
- else if (Externalizable.class.isAssignableFrom(eClass))
+
+ } else if (Externalizable.class.isAssignableFrom(eClass)) {
marshallerMap.put(eClass, em = new ExternalizableMarshaller((Class) eClass));
- else {
+
+ } else if (Throwable.class.isAssignableFrom(eClass)) {
+ marshallerMap.put(eClass, em = NoMarshaller.INSTANCE);
+
+ } else {
try {
marshallerMap.put(eClass, em = new GenericEnumMarshaller<E>(eClass, 1000));
} catch (Exception e) {
marshallerMap.put(eClass, em = NoMarshaller.INSTANCE);
}
}
+ }
+
return em;
}
@Override
+ @SuppressWarnings("unchecked")
public <E> BytesMarshaller<E> getMarshaller(byte code) {
- return compactMarshallerMap[code & 0xFF];
+ if (marshallerMap == null) {
+ init();
+ }
+
+ return (BytesMarshaller<E>) compactMarshallerMap[code & 0xFF];
}
public <E> void addMarshaller(Class<E> eClass, BytesMarshaller<E> marshaller) {
+ if (marshallerMap == null) {
+ init();
+ }
+
marshallerMap.put(eClass, marshaller);
- if (marshaller instanceof CompactBytesMarshaller)
+ if (marshaller instanceof CompactBytesMarshaller) {
compactMarshallerMap[((CompactBytesMarshaller) marshaller).code()] = marshaller;
+ }
}
}
diff --git a/lang/src/main/java/net/openhft/lang/io/view/BytesInputStream.java b/lang/src/main/java/net/openhft/lang/io/view/BytesInputStream.java
new file mode 100644
index 0000000..4896026
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/view/BytesInputStream.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.view;
+
+import net.openhft.lang.io.Bytes;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.InputStream;
+
+/**
+ * {@code InputStream} view of {@link Bytes}. Reading bytes from this stream pushes {@linkplain
+ * Bytes#position() position} of the underlying {@code Bytes}. When {@linkplain Bytes#limit() limit}
+ * is reached, {@code BytesInputStream} behaves as there is no more input.
+ *
+ * <p>This {@code InputStream} implementation supports {@link #mark(int)} and {@link #reset()}
+ * methods.
+ *
+ * <p>{@code BytesInputStream} objects are reusable, see {@link #bytes(Bytes)} method.
+ *
+ * @see Bytes#inputStream()
+ * @see BytesOutputStream
+ */
+public class BytesInputStream extends InputStream {
+ private Bytes bytes;
+ private long mark = 0;
+
+ /**
+ * Constructs a {@code BytesInputStream} backed by the given {@code bytes}.
+ *
+ * @param bytes the {@code Bytes} backing the constructed {@code BytesInputStream}
+ */
+ public BytesInputStream(Bytes bytes) {
+ this.bytes = bytes;
+ }
+
+ /**
+ * Constructs a {@code BytesInputStream} without backing {@code Bytes}, {@link #bytes(Bytes)}
+ * method must be called before first actual use of the constructed {@code BytesInputStream}
+ * instance.
+ */
+ public BytesInputStream() {}
+
+ /**
+ * Reassigns the underlying {@code Bytes} of this input stream.
+ *
+ * @param bytes new {@code Bytes} backing this {@code BytesInputStream}
+ * @return this {@code BytesInputStream} object back
+ */
+ public BytesInputStream bytes(Bytes bytes) {
+ this.bytes = bytes;
+ mark = 0;
+ return this;
+ }
+
+ @Override
+ public int available() {
+ return bytes.available();
+ }
+
+ @Override
+ public void close() {
+ bytes.finish();
+ }
+
+ @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod")
+ @Override
+ public void mark(int readLimit) {
+ mark = bytes.position();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public int read(@NotNull byte[] b, int off, int len) {
+ if (b == null) {
+ throw new NullPointerException();
+
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+
+ } else if (len == 0) {
+ return 0;
+ }
+ return bytes.read(b, off, len);
+ }
+
+ @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod")
+ @Override
+ public void reset() {
+ bytes.position(mark);
+ }
+
+ @Override
+ public long skip(long n) {
+ return bytes.skip(n);
+ }
+
+ @Override
+ public int read() {
+ return bytes.read();
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/io/view/BytesOutputStream.java b/lang/src/main/java/net/openhft/lang/io/view/BytesOutputStream.java
new file mode 100644
index 0000000..a05402f
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/io/view/BytesOutputStream.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.view;
+
+import net.openhft.lang.io.Bytes;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * {@code OutputStream} view of {@link Bytes}. Writing data to this stream pushes {@linkplain
+ * Bytes#position() position} of the underlying {@code Bytes}. On attempt of writing bytes beyond
+ * backing {@code Bytes}' {@linkplain Bytes#limit() limit} {@link IOException} is thrown.
+ *
+ * <p>{@code BytesOutputStream} are reusable, see {@link #bytes(Bytes)} method.
+ *
+ * @see Bytes#outputStream()
+ * @see BytesInputStream
+ */
+public class BytesOutputStream extends OutputStream {
+ private Bytes bytes;
+
+ /**
+ * Constructs a {@code BytesOutputStream} backed by the given {@code bytes}.
+ *
+ * @param bytes the {@code Bytes} backing the constructed {@code BytesOutputStream}
+ */
+ public BytesOutputStream(Bytes bytes) {
+ this.bytes = bytes;
+ }
+
+ /**
+ * Constructs a {@code BytesOutputStream} without backing {@code Bytes}, {@link #bytes(Bytes)}
+ * method must be called before first actual use of the constructed {@code BytesOutputStream}
+ * instance.
+ */
+ public BytesOutputStream() {}
+
+ /**
+ * Reassigns the underlying {@code Bytes} of this output stream.
+ *
+ * @param bytes new {@code Bytes} backing this {@code BytesOutputStream}
+ * @return this {@code BytesOutputStream} object back
+ */
+ public BytesOutputStream bytes(Bytes bytes) {
+ this.bytes = bytes;
+ return this;
+ }
+
+ @Override
+ public void close() {
+ try {
+ super.close();
+ } catch (IOException e) {
+ // never happens.
+ throw new AssertionError(e);
+ }
+ // Don't close as we may want to continue'
+ }
+
+ private void checkNotClosed() throws IOException {
+ if (bytes.isFinished())
+ throw new IOException("Underlying bytes is closed");
+ }
+
+ private void checkAvailable(int n) throws IOException {
+ if (n > bytes.remaining())
+ throw new IOException("Not enough available space for writing " + n + " bytes");
+ }
+
+ @Override
+ public void write(@NotNull byte[] b, int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+
+ } else if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+
+ } else if (len == 0) {
+ return;
+ }
+ checkNotClosed();
+ checkAvailable(len);
+ bytes.write(b, off, len);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ checkNotClosed();
+ checkAvailable(1);
+ bytes.writeUnsignedByte(b);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockState.java b/lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockState.java
new file mode 100644
index 0000000..6fc8ae0
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockState.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public abstract class AbstractReadWriteLockState implements ReadWriteLockState {
+
+ @Override
+ public boolean tryLock() {
+ return tryWriteLock();
+ }
+
+ @Override
+ public void unlock() {
+ writeUnlock();
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockingStrategy.java
new file mode 100644
index 0000000..2c4fd2a
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/AbstractReadWriteLockingStrategy.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public abstract class AbstractReadWriteLockingStrategy implements ReadWriteLockingStrategy {
+
+ @Override
+ public <T> boolean tryLock(NativeAtomicAccess<T> access, T t, long offset) {
+ return tryWriteLock(access, t, offset);
+ }
+
+ @Override
+ public <T> void unlock(NativeAtomicAccess<T> access, T t, long offset) {
+ writeUnlock(access, t, offset);
+ }
+
+ @Override
+ public boolean isReadLocked(long state) {
+ return readLockCount(state) > 0;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategies.java b/lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategies.java
new file mode 100644
index 0000000..7a1c234
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategies.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+import java.util.concurrent.TimeUnit;
+
+public final class AcquisitionStrategies {
+
+ private static class SpinLoopAcquisitionStrategy<S extends LockingStrategy>
+ implements AcquisitionStrategy<S, RuntimeException> {
+ private final long durationNanos;
+
+ private SpinLoopAcquisitionStrategy(long duration, TimeUnit unit) {
+ durationNanos = unit.toNanos(duration);
+ }
+
+ @Override
+ public <T> boolean acquire(TryAcquireOperation<? super S> operation, S strategy,
+ NativeAtomicAccess<T> access, T t, long offset) {
+ if (operation.tryAcquire(strategy, access, t, offset))
+ return true;
+ long deadLine = System.currentTimeMillis() + durationNanos;
+ beforeLoop(strategy, access, t, offset);
+ do {
+ if (operation.tryAcquire(strategy, access, t, offset))
+ return true;
+ } while (deadLine - System.currentTimeMillis() >= 0L); // overflow-cautious
+ afterLoop(strategy, access, t, offset);
+ return end();
+ }
+
+ <T> void beforeLoop(S strategy, NativeAtomicAccess<T> access, T t, long offset) {
+ }
+
+ <T> void afterLoop(S strategy, NativeAtomicAccess<T> access, T t, long offset) {
+ }
+
+ boolean end() {
+ return false;
+ }
+ }
+
+ public static AcquisitionStrategy<LockingStrategy, RuntimeException> spinLoop(
+ long duration, TimeUnit unit) {
+ return new SpinLoopAcquisitionStrategy<LockingStrategy>(duration, unit);
+ }
+
+ private static class SpinLoopOrFailAcquisitionStrategy<S extends LockingStrategy>
+ extends SpinLoopAcquisitionStrategy<S> {
+
+ private SpinLoopOrFailAcquisitionStrategy(long duration, TimeUnit unit) {
+ super(duration, unit);
+ }
+
+ @Override
+ boolean end() {
+ throw new RuntimeException("Failed to acquire the lock");
+ }
+ }
+
+ public static AcquisitionStrategy<LockingStrategy, RuntimeException> spinLoopOrFail(
+ long duration, TimeUnit unit) {
+ return new SpinLoopOrFailAcquisitionStrategy<LockingStrategy>(duration, unit);
+ }
+
+ private static class SpinLoopWriteWithWaitsAcquisitionStrategy
+ extends SpinLoopOrFailAcquisitionStrategy<ReadWriteWithWaitsLockingStrategy> {
+
+ private SpinLoopWriteWithWaitsAcquisitionStrategy(long duration, TimeUnit unit) {
+ super(duration, unit);
+ }
+
+ @Override
+ <T> void beforeLoop(ReadWriteWithWaitsLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T t, long offset) {
+ strategy.registerWait(access, t, offset);
+ }
+
+ @Override
+ <T> void afterLoop(ReadWriteWithWaitsLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T t, long offset) {
+ strategy.deregisterWait(access, t, offset);
+ }
+ }
+
+ public static AcquisitionStrategy<ReadWriteWithWaitsLockingStrategy, RuntimeException>
+ spinLoopRegisteringWaitOrFail(long duration, TimeUnit unit) {
+ return new SpinLoopWriteWithWaitsAcquisitionStrategy(duration, unit);
+ }
+
+ private AcquisitionStrategies() {}
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategy.java b/lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategy.java
new file mode 100644
index 0000000..5a62cd5
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/AcquisitionStrategy.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface AcquisitionStrategy<S extends LockingStrategy, E extends Exception> {
+
+ <T> boolean acquire(
+ TryAcquireOperation<? super S> operation, S strategy,
+ NativeAtomicAccess<T> access, T t, long offset) throws E;
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/BytesAtomicAccess.java b/lang/src/main/java/net/openhft/lang/locks/BytesAtomicAccess.java
new file mode 100644
index 0000000..c0bee33
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/BytesAtomicAccess.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+import net.openhft.lang.io.Bytes;
+
+import static java.nio.ByteOrder.nativeOrder;
+
+final class BytesAtomicAccess extends NativeAtomicAccess<Bytes> {
+ static final BytesAtomicAccess INSTANCE = new BytesAtomicAccess();
+
+ @Override
+ public long getLongVolatile(Bytes bytes, long offset) {
+ long value = bytes.readVolatileLong(offset);
+ if (bytes.byteOrder() != nativeOrder())
+ value = Long.reverseBytes(value);
+ return value;
+ }
+
+ @Override
+ public void putOrderedLong(Bytes bytes, long offset, long value) {
+ if (bytes.byteOrder() != nativeOrder())
+ value = Long.reverseBytes(value);
+ bytes.writeOrderedLong(offset, value);
+ }
+
+ @Override
+ public boolean compareAndSwapLong(Bytes bytes, long offset, long expected, long x) {
+ if (bytes.byteOrder() != nativeOrder()) {
+ expected = Long.reverseBytes(expected);
+ x = Long.reverseBytes(x);
+ }
+ return bytes.compareAndSwapLong(offset, expected, x);
+ }
+
+ @Override
+ public int getIntVolatile(Bytes bytes, long offset) {
+ int value = bytes.readVolatileInt(offset);
+ if (bytes.byteOrder() != nativeOrder())
+ value = Integer.reverseBytes(value);
+ return value;
+ }
+
+ @Override
+ public void putOrderedInt(Bytes bytes, long offset, int value) {
+ if (bytes.byteOrder() != nativeOrder())
+ value = Integer.reverseBytes(value);
+ bytes.writeOrderedInt(offset, value);
+ }
+
+ @Override
+ public boolean compareAndSwapInt(Bytes bytes, long offset, int expected, int x) {
+ if (bytes.byteOrder() != nativeOrder()) {
+ expected = Integer.reverseBytes(expected);
+ x = Integer.reverseBytes(x);
+ }
+ return bytes.compareAndSwapInt(offset, expected, x);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/LockState.java b/lang/src/main/java/net/openhft/lang/locks/LockState.java
new file mode 100644
index 0000000..a6706df
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/LockState.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface LockState {
+
+ boolean tryLock();
+
+ void unlock();
+
+ void reset();
+
+ long getState();
+
+ LockingStrategy lockingStrategy();
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/LockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/LockingStrategy.java
new file mode 100644
index 0000000..ce502bb
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/LockingStrategy.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface LockingStrategy {
+
+ <T> boolean tryLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void unlock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void reset(NativeAtomicAccess<T> access, T t, long offset);
+
+ long resetState();
+
+ <T> long getState(NativeAtomicAccess<T> access, T t, long offset);
+
+ boolean isLocked(long state);
+
+ int lockCount(long state);
+
+ String toString(long state);
+
+ int sizeInBytes();
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/NativeAtomicAccess.java b/lang/src/main/java/net/openhft/lang/locks/NativeAtomicAccess.java
new file mode 100644
index 0000000..0b47ea6
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/NativeAtomicAccess.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+import net.openhft.lang.io.Bytes;
+
+public abstract class NativeAtomicAccess<T> {
+
+ public static <T> NativeAtomicAccess<T> unsafe() {
+ return UnsafeAtomicAccess.INSTANCE;
+ }
+
+ public static NativeAtomicAccess<Bytes> toBytes() {
+ return BytesAtomicAccess.INSTANCE;
+ }
+
+ protected NativeAtomicAccess() {}
+
+ public abstract long getLongVolatile(T t, long offset);
+
+ public abstract void putOrderedLong(T t, long offset, long value);
+
+ public abstract boolean compareAndSwapLong(T t, long offset, long expected, long x);
+
+ public abstract int getIntVolatile(T t, long offset);
+
+ public abstract void putOrderedInt(T t, long offset, int value);
+
+ public abstract boolean compareAndSwapInt(T t, long offset, int expected, int x);
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteLockState.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteLockState.java
new file mode 100644
index 0000000..fe3127a
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteLockState.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteLockState extends LockState {
+
+ boolean tryReadLock();
+
+ boolean tryWriteLock();
+
+ boolean tryUpgradeReadToWriteLock();
+
+ void readUnlock();
+
+ void writeUnlock();
+
+ void downgradeWriteToReadLock();
+
+ @Override
+ ReadWriteLockingStrategy lockingStrategy();
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteLockingStrategy.java
new file mode 100644
index 0000000..bb6179d
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteLockingStrategy.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteLockingStrategy extends LockingStrategy {
+
+ <T> boolean tryReadLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> boolean tryWriteLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> boolean tryUpgradeReadToWriteLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void readUnlock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void writeUnlock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void downgradeWriteToReadLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ boolean isReadLocked(long state);
+
+ boolean isWriteLocked(long state);
+
+ int readLockCount(long state);
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockState.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockState.java
new file mode 100644
index 0000000..584ab1d
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockState.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteUpdateLockState extends ReadWriteLockState {
+
+ boolean tryUpdateLock();
+
+ boolean tryUpgradeReadToUpdateLock();
+
+ boolean tryUpgradeUpdateToWriteLock();
+
+ void updateUnlock();
+
+ void downgradeUpdateToReadLock();
+
+ void downgradeWriteToUpdateLock();
+
+ @Override
+ ReadWriteUpdateLockingStrategy lockingStrategy();
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockingStrategy.java
new file mode 100644
index 0000000..55bab01
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateLockingStrategy.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+/**
+ * Logic of read-write-update lock state transitions.
+ *
+ * Read lock - could be several at the same time.
+ * Update lock - doesn't block reads, but couldn't be several update locks at the same time
+ * Write lock - exclusive
+ */
+public interface ReadWriteUpdateLockingStrategy extends ReadWriteLockingStrategy {
+
+ <T> boolean tryUpdateLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> boolean tryUpgradeReadToUpdateLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> boolean tryUpgradeUpdateToWriteLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void updateUnlock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void downgradeUpdateToReadLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void downgradeWriteToUpdateLock(NativeAtomicAccess<T> access, T t, long offset);
+
+ boolean isUpdateLocked(long state);
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockState.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockState.java
new file mode 100644
index 0000000..ad5cf05
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockState.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteUpdateWithWaitsLockState
+ extends ReadWriteUpdateLockState, ReadWriteWithWaitsLockState {
+
+ boolean tryUpgradeUpdateToWriteLockAndDeregisterWait();
+
+ @Override
+ ReadWriteUpdateWithWaitsLockingStrategy lockingStrategy();
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockingStrategy.java
new file mode 100644
index 0000000..aa58ef7
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteUpdateWithWaitsLockingStrategy.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteUpdateWithWaitsLockingStrategy
+ extends ReadWriteUpdateLockingStrategy, ReadWriteWithWaitsLockingStrategy {
+
+ <T> boolean tryUpgradeUpdateToWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset);
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockState.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockState.java
new file mode 100644
index 0000000..d95d33a
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteWithWaitsLockState extends ReadWriteLockState {
+
+ void registerWait();
+
+ void deregisterWait();
+
+ boolean tryWriteLockAndDeregisterWait();
+
+ boolean tryUpgradeReadToWriteLockAndDeregisterWait();
+
+ void resetKeepingWaits();
+
+ @Override
+ ReadWriteWithWaitsLockingStrategy lockingStrategy();
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockingStrategy.java
new file mode 100644
index 0000000..8db8b9d
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/ReadWriteWithWaitsLockingStrategy.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface ReadWriteWithWaitsLockingStrategy extends ReadWriteLockingStrategy {
+
+ <T> void registerWait(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void deregisterWait(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> boolean tryWriteLockAndDeregisterWait(NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> boolean tryUpgradeReadToWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset);
+
+ <T> void resetKeepingWaits(NativeAtomicAccess<T> access, T t, long offset);
+
+ int waitCount(long state);
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/TryAcquireOperation.java b/lang/src/main/java/net/openhft/lang/locks/TryAcquireOperation.java
new file mode 100644
index 0000000..78a9e49
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/TryAcquireOperation.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public interface TryAcquireOperation<S extends LockingStrategy> {
+
+ <T> boolean tryAcquire(S strategy, NativeAtomicAccess<T> access, T t, long offset);
+} \ No newline at end of file
diff --git a/lang/src/main/java/net/openhft/lang/locks/TryAcquireOperations.java b/lang/src/main/java/net/openhft/lang/locks/TryAcquireOperations.java
new file mode 100644
index 0000000..5d7f391
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/TryAcquireOperations.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public final class TryAcquireOperations {
+
+ private static final TryAcquireOperation<LockingStrategy> LOCK =
+ new TryAcquireOperation<LockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(LockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<LockingStrategy> lock() {
+ return LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteLockingStrategy> READ_LOCK =
+ new TryAcquireOperation<ReadWriteLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryReadLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteLockingStrategy> readLock() {
+ return READ_LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteLockingStrategy> UPGRADE_READ_TO_WRITE_LOCK =
+ new TryAcquireOperation<ReadWriteLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryUpgradeReadToWriteLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteLockingStrategy> upgradeReadToWriteLock() {
+ return UPGRADE_READ_TO_WRITE_LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteLockingStrategy> WRITE_LOCK =
+ new TryAcquireOperation<ReadWriteLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryWriteLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteLockingStrategy> writeLock() {
+ return WRITE_LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteWithWaitsLockingStrategy>
+ UPGRADE_READ_TO_WRITE_LOCK_AND_DEREGISTER_WAIT =
+ new TryAcquireOperation<ReadWriteWithWaitsLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteWithWaitsLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryUpgradeReadToWriteLockAndDeregisterWait(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteWithWaitsLockingStrategy>
+ upgradeReadToWriteLockAndDeregisterWait() {
+ return UPGRADE_READ_TO_WRITE_LOCK_AND_DEREGISTER_WAIT;
+ }
+
+ private static final TryAcquireOperation<ReadWriteWithWaitsLockingStrategy>
+ WRITE_LOCK_AND_DEREGISTER_WAIT =
+ new TryAcquireOperation<ReadWriteWithWaitsLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteWithWaitsLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryWriteLockAndDeregisterWait(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteWithWaitsLockingStrategy>
+ writeLockAndDeregisterWait() {
+ return WRITE_LOCK_AND_DEREGISTER_WAIT;
+ }
+
+ private static final TryAcquireOperation<ReadWriteUpdateLockingStrategy> UPDATE_LOCK =
+ new TryAcquireOperation<ReadWriteUpdateLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteUpdateLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryUpdateLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteUpdateLockingStrategy> updateLock() {
+ return UPDATE_LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteUpdateLockingStrategy>
+ UPGRADE_READ_TO_UPDATE_LOCK =
+ new TryAcquireOperation<ReadWriteUpdateLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteUpdateLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryUpgradeReadToUpdateLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteUpdateLockingStrategy> upgradeReadToUpdateLock() {
+ return UPGRADE_READ_TO_UPDATE_LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteUpdateLockingStrategy>
+ UPGRADE_UPDATE_TO_WRITE_LOCK =
+ new TryAcquireOperation<ReadWriteUpdateLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteUpdateLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryUpgradeUpdateToWriteLock(access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteUpdateLockingStrategy> upgradeUpdateToWriteLock() {
+ return UPGRADE_UPDATE_TO_WRITE_LOCK;
+ }
+
+ private static final TryAcquireOperation<ReadWriteUpdateWithWaitsLockingStrategy>
+ UPGRADE_UPDATE_TO_WRITE_LOCK_AND_DEREGISTER_WAIT =
+ new TryAcquireOperation<ReadWriteUpdateWithWaitsLockingStrategy>() {
+ @Override
+ public <T> boolean tryAcquire(ReadWriteUpdateWithWaitsLockingStrategy strategy,
+ NativeAtomicAccess<T> access, T obj, long offset) {
+ return strategy.tryUpgradeUpdateToWriteLockAndDeregisterWait(
+ access, obj, offset);
+ }
+ };
+ public static TryAcquireOperation<ReadWriteUpdateWithWaitsLockingStrategy>
+ upgradeUpdateToWriteLockAndDeregisterWait() {
+ return UPGRADE_UPDATE_TO_WRITE_LOCK_AND_DEREGISTER_WAIT;
+ }
+
+ private TryAcquireOperations() {}
+}
+
diff --git a/lang/src/main/java/net/openhft/lang/locks/UnsafeAtomicAccess.java b/lang/src/main/java/net/openhft/lang/locks/UnsafeAtomicAccess.java
new file mode 100644
index 0000000..17c52f2
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/UnsafeAtomicAccess.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+import static net.openhft.lang.io.NativeBytes.UNSAFE;
+
+final class UnsafeAtomicAccess extends NativeAtomicAccess {
+ static final UnsafeAtomicAccess INSTANCE = new UnsafeAtomicAccess();
+
+ @Override
+ public long getLongVolatile(Object o, long offset) {
+ return UNSAFE.getLongVolatile(o, offset);
+ }
+
+ @Override
+ public void putOrderedLong(Object o, long offset, long value) {
+ UNSAFE.putOrderedLong(o, offset, value);
+ }
+
+ @Override
+ public boolean compareAndSwapLong(Object o, long offset, long expected, long x) {
+ return UNSAFE.compareAndSwapLong(o, offset, expected, x);
+ }
+
+ @Override
+ public int getIntVolatile(Object o, long offset) {
+ return UNSAFE.getInt(o, offset);
+ }
+
+ @Override
+ public void putOrderedInt(Object o, long offset, int value) {
+ UNSAFE.putOrderedInt(o, offset, value);
+ }
+
+ @Override
+ public boolean compareAndSwapInt(Object o, long offset, int expected, int x) {
+ return UNSAFE.compareAndSwapInt(o, offset, expected, x);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteUpdateWithWaitsLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteUpdateWithWaitsLockingStrategy.java
new file mode 100644
index 0000000..b1979e8
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteUpdateWithWaitsLockingStrategy.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+import static java.nio.ByteOrder.LITTLE_ENDIAN;
+import static java.nio.ByteOrder.nativeOrder;
+import static net.openhft.lang.io.AbstractBytes.UNSIGNED_INT_MASK;
+
+public final class VanillaReadWriteUpdateWithWaitsLockingStrategy
+ extends AbstractReadWriteLockingStrategy
+ implements ReadWriteUpdateWithWaitsLockingStrategy {
+
+ private static final ReadWriteUpdateWithWaitsLockingStrategy INSTANCE =
+ new VanillaReadWriteUpdateWithWaitsLockingStrategy();
+
+ public static ReadWriteUpdateWithWaitsLockingStrategy instance() {
+ return INSTANCE;
+ }
+
+ private VanillaReadWriteUpdateWithWaitsLockingStrategy() {}
+
+ static final long COUNT_WORD_OFFSET = 0L;
+ static final long WAIT_WORD_OFFSET = COUNT_WORD_OFFSET + 4L;
+
+ static final int COUNT_WORD_SHIFT = nativeOrder() == LITTLE_ENDIAN ? 0 : 32;
+ static final int WAIT_WORD_SHIFT = nativeOrder() == LITTLE_ENDIAN ? 32 : 0;
+
+ static final int READ_BITS = 30;
+ static final int MAX_READ = (1 << READ_BITS) - 1;
+ static final int READ_MASK = MAX_READ;
+ static final int READ_PARTY = 1;
+
+ static final int UPDATE_PARTY = 1 << READ_BITS;
+ static final int WRITE_LOCKED_COUNT_WORD = UPDATE_PARTY << 1;
+
+ static final int MAX_WAIT = Integer.MAX_VALUE;
+ static final int WAIT_PARTY = 1;
+
+ private static <T> long getLockWord(NativeAtomicAccess<T> access, T t, long offset) {
+ return access.getLongVolatile(t, offset);
+ }
+
+ private static <T> boolean casLockWord(
+ NativeAtomicAccess<T> access, T t, long offset, long expected, long x) {
+ return access.compareAndSwapLong(t, offset, expected, x);
+ }
+
+ private static int countWord(long lockWord) {
+ return (int) (lockWord >> COUNT_WORD_SHIFT);
+ }
+
+ private static int waitWord(long lockWord) {
+ return (int) (lockWord >> WAIT_WORD_SHIFT);
+ }
+
+ private static long lockWord(int countWord, int waitWord) {
+ return ((((long) countWord) & UNSIGNED_INT_MASK) << COUNT_WORD_SHIFT) |
+ ((((long) waitWord) & UNSIGNED_INT_MASK) << WAIT_WORD_SHIFT);
+ }
+
+ private static <T> int getCountWord(NativeAtomicAccess<T> access, T t, long offset) {
+ return access.getIntVolatile(t, offset + COUNT_WORD_OFFSET);
+ }
+
+ private static <T> boolean casCountWord(
+ NativeAtomicAccess<T> access, T t, long offset, int expected, int x) {
+ return access.compareAndSwapInt(t, offset + COUNT_WORD_OFFSET, expected, x);
+ }
+
+ private static <T> void putCountWord(
+ NativeAtomicAccess<T> access, T t, long offset, int countWord) {
+ access.putOrderedInt(t, offset + COUNT_WORD_OFFSET, countWord);
+ }
+
+ private static boolean writeLocked(int countWord) {
+ return countWord == WRITE_LOCKED_COUNT_WORD;
+ }
+
+ private static void checkWriteLocked(int countWord) {
+ if (countWord != WRITE_LOCKED_COUNT_WORD)
+ throw new IllegalMonitorStateException("Expected write lock");
+ }
+
+ private static boolean updateLocked(int countWord) {
+ return (countWord & UPDATE_PARTY) != 0;
+ }
+
+ private static void checkUpdateLocked(int countWord) {
+ if (!updateLocked(countWord))
+ throw new IllegalMonitorStateException("Expected update lock");
+ }
+
+ private static int readCount(int countWord) {
+ return countWord & READ_MASK;
+ }
+
+ private static void checkReadLocked(int countWord) {
+ if (readCount(countWord) <= 0)
+ throw new IllegalMonitorStateException("Expected read lock");
+ }
+
+ private static void checkReadCountForIncrement(int countWord) {
+ if (readCount(countWord) == MAX_READ) {
+ throw new IllegalMonitorStateException(
+ "Lock count reached the limit of " + MAX_READ);
+ }
+ }
+
+ private static <T> int getWaitWord(NativeAtomicAccess<T> access, T t, long offset) {
+ return access.getIntVolatile(t, offset + WAIT_WORD_OFFSET);
+ }
+
+ private static <T> boolean casWaitWord(
+ NativeAtomicAccess<T> access, T t, long offset, int expected, int x) {
+ return access.compareAndSwapInt(t, offset + WAIT_WORD_OFFSET, expected, x);
+ }
+
+ private static void checkWaitWordForIncrement(int waitWord) {
+ if (waitWord == MAX_WAIT) {
+ throw new IllegalMonitorStateException(
+ "Wait count reached the limit of " + MAX_WAIT);
+ }
+ }
+
+ private static void checkWaitWordForDecrement(int waitWord) {
+ if (waitWord == 0) {
+ throw new IllegalMonitorStateException(
+ "Wait count underflowed");
+ }
+ }
+
+ @Override
+ public long resetState() {
+ return 0L;
+ }
+
+ @Override
+ public <T> void reset(NativeAtomicAccess<T> access, T t, long offset) {
+ access.putOrderedLong(t, offset, 0L);
+ }
+
+ @Override
+ public <T> void resetKeepingWaits(NativeAtomicAccess<T> access, T t, long offset) {
+ putCountWord(access, t, offset, 0);
+ }
+
+ @Override
+ public <T> boolean tryReadLock(NativeAtomicAccess<T> access, T t, long offset) {
+ long lockWord = getLockWord(access, t, offset);
+ int countWord = countWord(lockWord);
+ if (!writeLocked(countWord) && waitWord(lockWord) == 0) {
+ checkReadCountForIncrement(countWord);
+ if (casCountWord(access, t, offset, countWord, countWord + READ_PARTY))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public <T> boolean tryUpgradeReadToUpdateLock(NativeAtomicAccess<T> access, T t, long offset) {
+ int countWord = getCountWord(access, t, offset);
+ checkReadLocked(countWord);
+ return !updateLocked(countWord) &&
+ casCountWord(access, t, offset, countWord, countWord - READ_PARTY + UPDATE_PARTY);
+ }
+
+ @Override
+ public <T> boolean tryUpgradeReadToWriteLock(NativeAtomicAccess<T> access, T t, long offset) {
+ int countWord = getCountWord(access, t, offset);
+ checkReadLocked(countWord);
+ return countWord == READ_PARTY &&
+ casCountWord(access, t, offset, READ_PARTY, WRITE_LOCKED_COUNT_WORD);
+ }
+
+ @Override
+ public <T> boolean tryUpgradeReadToWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset) {
+ long lockWord = getLockWord(access, t, offset);
+ int countWord = countWord(lockWord);
+ checkReadLocked(countWord);
+ return countWord == READ_PARTY &&
+ tryWriteLockAndDeregisterWait0(access, t, offset, lockWord);
+ }
+
+ private static <T> boolean tryWriteLockAndDeregisterWait0(
+ NativeAtomicAccess<T> access, T t, long offset, long lockWord) {
+ int waitWord = waitWord(lockWord);
+ checkWaitWordForDecrement(waitWord);
+ return casLockWord(access, t, offset, lockWord,
+ lockWord(WRITE_LOCKED_COUNT_WORD, waitWord - WAIT_PARTY));
+ }
+
+ @Override
+ public <T> boolean tryUpdateLock(NativeAtomicAccess<T> access, T t, long offset) {
+ long lockWord = getLockWord(access, t, offset);
+ int countWord = countWord(lockWord);
+ if (!updateLocked(countWord) && !writeLocked(countWord) && waitWord(lockWord) == 0) {
+ if (casCountWord(access, t, offset, countWord, countWord + UPDATE_PARTY))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public <T> boolean tryWriteLock(NativeAtomicAccess<T> access, T t, long offset) {
+ return getCountWord(access, t, offset) == 0 &&
+ casCountWord(access, t, offset, 0, WRITE_LOCKED_COUNT_WORD);
+ }
+
+ @Override
+ public <T> boolean tryWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset) {
+ long lockWord = getLockWord(access, t, offset);
+ int countWord = countWord(lockWord);
+ return countWord == 0 && tryWriteLockAndDeregisterWait0(access, t, offset, lockWord);
+ }
+
+ @Override
+ public <T> void registerWait(NativeAtomicAccess<T> access, T t, long offset) {
+ while (true) {
+ int waitWord = getWaitWord(access, t, offset);
+ checkWaitWordForIncrement(waitWord);
+ if (casWaitWord(access, t, offset, waitWord, waitWord + WAIT_PARTY))
+ return;
+ }
+ }
+
+ @Override
+ public <T> void deregisterWait(NativeAtomicAccess<T> access, T t, long offset) {
+ while (true) {
+ int waitWord = getWaitWord(access, t, offset);
+ checkWaitWordForDecrement(waitWord);
+ if (casWaitWord(access, t, offset, waitWord, waitWord - WAIT_PARTY))
+ return;
+ }
+ }
+
+ @Override
+ public <T> boolean tryUpgradeUpdateToWriteLock(NativeAtomicAccess<T> access, T t, long offset) {
+ int countWord = getCountWord(access, t, offset);
+ return checkExclusiveUpdateLocked(countWord) &&
+ casCountWord(access, t, offset, countWord, WRITE_LOCKED_COUNT_WORD);
+ }
+
+ private static boolean checkExclusiveUpdateLocked(int countWord) {
+ checkUpdateLocked(countWord);
+ return countWord == UPDATE_PARTY;
+ }
+
+ @Override
+ public <T> boolean tryUpgradeUpdateToWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset) {
+ long lockWord = getLockWord(access, t, offset);
+ int countWord = countWord(lockWord);
+ return checkExclusiveUpdateLocked(countWord) &&
+ tryWriteLockAndDeregisterWait0(access, t, offset, lockWord);
+ }
+
+ @Override
+ public <T> void readUnlock(NativeAtomicAccess<T> access, T t, long offset) {
+ while (true) {
+ int countWord = getCountWord(access, t, offset);
+ checkReadLocked(countWord);
+ if (casCountWord(access, t, offset, countWord, countWord - READ_PARTY))
+ return;
+ }
+ }
+
+ @Override
+ public <T> void updateUnlock(NativeAtomicAccess<T> access, T t, long offset) {
+ while (true) {
+ int countWord = getCountWord(access, t, offset);
+ checkUpdateLocked(countWord);
+ if (casCountWord(access, t, offset, countWord, countWord - UPDATE_PARTY)) {
+ return;
+ }
+ }
+ }
+
+ @Override
+ public <T> void downgradeUpdateToReadLock(NativeAtomicAccess<T> access, T t, long offset) {
+ while (true) {
+ int countWord = getCountWord(access, t, offset);
+ checkUpdateLocked(countWord);
+ checkReadCountForIncrement(countWord);
+ if (casCountWord(access, t, offset, countWord, countWord - UPDATE_PARTY + READ_PARTY)) {
+ return;
+ }
+ }
+ }
+
+ @Override
+ public <T> void writeUnlock(NativeAtomicAccess<T> access, T t, long offset) {
+ checkWriteLockedAndPut(access, t, offset, 0);
+ }
+
+ private static <T> void checkWriteLockedAndPut(
+ NativeAtomicAccess<T> access, T t, long offset, int countWord) {
+ checkWriteLocked(getCountWord(access, t, offset));
+ putCountWord(access, t, offset, countWord);
+ }
+
+ @Override
+ public <T> void downgradeWriteToUpdateLock(NativeAtomicAccess<T> access, T t, long offset) {
+ checkWriteLockedAndPut(access, t, offset, UPDATE_PARTY);
+ }
+
+ @Override
+ public boolean isUpdateLocked(long state) {
+ return updateLocked(countWord(state));
+ }
+
+ @Override
+ public <T> void downgradeWriteToReadLock(NativeAtomicAccess<T> access, T t, long offset) {
+ checkWriteLockedAndPut(access, t, offset, READ_PARTY);
+ }
+
+ @Override
+ public <T> long getState(NativeAtomicAccess<T> access, T t, long offset) {
+ return getLockWord(access, t, offset);
+ }
+
+ @Override
+ public int readLockCount(long state) {
+ return readCount(countWord(state));
+ }
+
+ @Override
+ public boolean isWriteLocked(long state) {
+ return writeLocked(countWord(state));
+ }
+
+ @Override
+ public int waitCount(long state) {
+ return waitWord(state);
+ }
+
+ @Override
+ public boolean isLocked(long state) {
+ return countWord(state) != 0;
+ }
+
+ @Override
+ public int lockCount(long state) {
+ int countWord = countWord(state);
+ int lockCount = readCount(countWord);
+ if (lockCount > 0) {
+ return lockCount + (updateLocked(countWord) ? 1 : 0);
+
+ } else {
+ return writeLocked(countWord) ? 1 : 0;
+ }
+ }
+
+ @Override
+ public String toString(long state) {
+ return "[read locks = " + readLockCount(state) +
+ ", update locked = " + isUpdateLocked(state) +
+ ", write locked = " + isWriteLocked(state) +
+ ", waits = " + waitCount(state) + "]";
+ }
+
+ @Override
+ public int sizeInBytes() {
+ return 8;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteWithWaitsLockingStrategy.java b/lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteWithWaitsLockingStrategy.java
new file mode 100644
index 0000000..37993ac
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/locks/VanillaReadWriteWithWaitsLockingStrategy.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+public final class VanillaReadWriteWithWaitsLockingStrategy extends AbstractReadWriteLockingStrategy
+ implements ReadWriteWithWaitsLockingStrategy {
+
+ private static final ReadWriteWithWaitsLockingStrategy INSTANCE =
+ new VanillaReadWriteWithWaitsLockingStrategy();
+
+ public static ReadWriteWithWaitsLockingStrategy instance() {
+ return INSTANCE;
+ }
+
+ private VanillaReadWriteWithWaitsLockingStrategy() {}
+
+ static final int RW_LOCK_LIMIT = 30;
+ static final long RW_READ_LOCKED = 1L;
+ static final long RW_WRITE_WAITING = 1L << RW_LOCK_LIMIT;
+ static final long RW_WRITE_LOCKED = 1L << 2 * RW_LOCK_LIMIT;
+ static final int RW_LOCK_MASK = (1 << RW_LOCK_LIMIT) - 1;
+
+ static int rwReadLocked(long lock) {
+ return (int) (lock & RW_LOCK_MASK);
+ }
+
+ static int rwWriteWaiting(long lock) {
+ return (int) ((lock >>> RW_LOCK_LIMIT) & RW_LOCK_MASK);
+ }
+
+ static int rwWriteLocked(long lock) {
+ return (int) (lock >>> (2 * RW_LOCK_LIMIT));
+ }
+
+ static <T> long read(NativeAtomicAccess<T> access, T t, long offset) {
+ return access.getLongVolatile(t, offset);
+ }
+
+ static <T> boolean cas(NativeAtomicAccess<T> access, T t, long offset, long expected, long x) {
+ return access.compareAndSwapLong(t, offset, expected, x);
+ }
+
+ @Override
+ public <T> boolean tryReadLock(NativeAtomicAccess<T> access, T t, long offset) {
+ long lock = read(access, t, offset);
+ int writersWaiting = rwWriteWaiting(lock);
+ int writersLocked = rwWriteLocked(lock);
+ // readers wait for waiting writers
+ if (writersLocked <= 0 && writersWaiting <= 0) {
+ // increment readers locked.
+ int readersLocked = rwReadLocked(lock);
+ if (readersLocked >= RW_LOCK_MASK)
+ throw new IllegalMonitorStateException("readersLocked has reached a limit of " +
+ readersLocked);
+ if (cas(access, t, offset, lock, lock + RW_READ_LOCKED))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public <T> boolean tryWriteLock(NativeAtomicAccess<T> access, T t, long offset) {
+ long lock = read(access, t, offset);
+ int readersLocked = rwReadLocked(lock);
+ int writersLocked = rwWriteLocked(lock);
+ // writers don't wait for waiting readers.
+ if (readersLocked <= 0 && writersLocked <= 0) {
+ if (cas(access, t, offset, lock, lock + RW_WRITE_LOCKED))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public <T> boolean tryUpgradeReadToWriteLock(NativeAtomicAccess<T> access, T t, long offset) {
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public <T> void readUnlock(NativeAtomicAccess<T> access, T t, long offset) {
+ for (; ; ) {
+ long lock = read(access, t, offset);
+ int readersLocked = rwReadLocked(lock);
+ if (readersLocked <= 0)
+ throw new IllegalMonitorStateException("readerLock underflow");
+ if (cas(access, t, offset, lock, lock - RW_READ_LOCKED))
+ return;
+ }
+ }
+
+ @Override
+ public <T> void writeUnlock(NativeAtomicAccess<T> access, T t, long offset) {
+ for (; ; ) {
+ long lock = read(access, t, offset);
+ int writersLocked = rwWriteLocked(lock);
+ if (writersLocked != 1)
+ throw new IllegalMonitorStateException("writersLock underflow " + writersLocked);
+ if (cas(access, t, offset, lock, lock - RW_WRITE_LOCKED))
+ return;
+ }
+ }
+
+ @Override
+ public <T> void downgradeWriteToReadLock(NativeAtomicAccess<T> access, T t, long offset) {
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public boolean isWriteLocked(long state) {
+ return rwWriteLocked(state) > 0;
+ }
+
+ @Override
+ public int readLockCount(long state) {
+ return rwReadLocked(state);
+ }
+
+ @Override
+ public <T> void reset(NativeAtomicAccess<T> access, T t, long offset) {
+ access.putOrderedLong(t, offset, 0L);
+ }
+
+ @Override
+ public <T> void resetKeepingWaits(NativeAtomicAccess<T> access, T t, long offset) {
+ while (true) {
+ long lock = read(access, t, offset);
+ long onlyWaits = lock & ((long) RW_LOCK_MASK) << RW_LOCK_LIMIT;
+ if (cas(access, t, offset, lock, onlyWaits))
+ return;
+ }
+ }
+
+ @Override
+ public <T> void registerWait(NativeAtomicAccess<T> access, T t, long offset) {
+ for (; ; ) {
+ long lock = read(access, t, offset);
+ int writersWaiting = rwWriteWaiting(lock);
+ if (writersWaiting >= RW_LOCK_MASK)
+ throw new IllegalMonitorStateException("writersWaiting has reached a limit of " +
+ writersWaiting);
+ if (cas(access, t, offset, lock, lock + RW_WRITE_WAITING))
+ break;
+ }
+ }
+
+ @Override
+ public <T> void deregisterWait(NativeAtomicAccess<T> access, T t, long offset) {
+ for (; ; ) {
+ long lock = read(access, t, offset);
+ int writersWaiting = rwWriteWaiting(lock);
+ if (writersWaiting <= 0)
+ throw new IllegalMonitorStateException("writersWaiting has underflowed");
+ if (cas(access, t, offset, lock, lock - RW_WRITE_WAITING))
+ break;
+ }
+ }
+
+ @Override
+ public <T> boolean tryWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset) {
+ long lock = read(access, t, offset);
+ int readersLocked = rwReadLocked(lock);
+ int writersWaiting = rwWriteWaiting(lock);
+ int writersLocked = rwWriteLocked(lock);
+ if (readersLocked <= 0 && writersLocked <= 0) {
+ // increment readers locked.
+ if (writersWaiting <= 0)
+ throw new IllegalMonitorStateException("writersWaiting has underflowed");
+ // add to the readLock count and decrease the readWaiting count.
+ if (cas(access, t, offset, lock, lock + RW_WRITE_LOCKED - RW_WRITE_WAITING))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public <T> boolean tryUpgradeReadToWriteLockAndDeregisterWait(
+ NativeAtomicAccess<T> access, T t, long offset) {
+ throw new UnsupportedOperationException("not implemented yet");
+ }
+
+ @Override
+ public long resetState() {
+ return 0L;
+ }
+
+ @Override
+ public <T> long getState(NativeAtomicAccess<T> access, T t, long offset) {
+ return read(access, t, offset);
+ }
+
+ @Override
+ public int waitCount(long state) {
+ return rwWriteWaiting(state);
+ }
+
+ @Override
+ public boolean isLocked(long state) {
+ return isReadLocked(state) || isWriteLocked(state);
+ }
+
+ @Override
+ public int lockCount(long state) {
+ return rwReadLocked(state) + rwWriteLocked(state);
+ }
+
+ @Override
+ public String toString(long state) {
+ return "[read locks = " + readLockCount(state) +
+ ", write locked = " + isWriteLocked(state) +
+ ", waits = " + waitCount(state) + "]";
+ }
+
+ @Override
+ public int sizeInBytes() {
+ return 8;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/Byteable.java b/lang/src/main/java/net/openhft/lang/model/Byteable.java
index a6c1a54..5349319 100644
--- a/lang/src/main/java/net/openhft/lang/model/Byteable.java
+++ b/lang/src/main/java/net/openhft/lang/model/Byteable.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
@@ -24,11 +24,11 @@ import net.openhft.lang.io.Bytes;
* Time: 21:38
*/
public interface Byteable {
- void bytes(Bytes bytes);
-
void bytes(Bytes bytes, long offset);
Bytes bytes();
+ long offset();
+
int maxSize();
} \ No newline at end of file
diff --git a/lang/src/main/java/net/openhft/lang/model/CodeGenerator.java b/lang/src/main/java/net/openhft/lang/model/CodeGenerator.java
index d1df93c..ddbba95 100644
--- a/lang/src/main/java/net/openhft/lang/model/CodeGenerator.java
+++ b/lang/src/main/java/net/openhft/lang/model/CodeGenerator.java
@@ -1,20 +1,20 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
-public interface CodeGenerator {
+interface CodeGenerator {
}
diff --git a/lang/src/main/java/net/openhft/lang/model/Copyable.java b/lang/src/main/java/net/openhft/lang/model/Copyable.java
index 79baf90..8c9f2dd 100644
--- a/lang/src/main/java/net/openhft/lang/model/Copyable.java
+++ b/lang/src/main/java/net/openhft/lang/model/Copyable.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueClassCache.java b/lang/src/main/java/net/openhft/lang/model/DataValueClassCache.java
new file mode 100644
index 0000000..1b15925
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/model/DataValueClassCache.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+/**
+ * This is cache for the generated classes for a ClassLoader.
+ */
+class DataValueClassCache {
+ private final DataValueGenerator dvg = new DataValueGenerator();
+
+ public <T> T newInstance(Class<T> interfaceClass) {
+ try {
+ //noinspection ClassNewInstance
+ return heapClassFor(interfaceClass).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public <T> T newDirectReference(Class<T> interfaceClass) {
+ try {
+ //noinspection ClassNewInstance
+ return directClassFor(interfaceClass).newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public synchronized <T> Class<T> heapClassFor(Class<T> interfaceClass) {
+ return dvg.acquireHeapClass(interfaceClass);
+ }
+
+ public synchronized <T> Class<T> directClassFor(Class<T> interfaceClass) {
+ return dvg.acquireNativeClass(interfaceClass);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueClasses.java b/lang/src/main/java/net/openhft/lang/model/DataValueClasses.java
new file mode 100644
index 0000000..d3ae332
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/model/DataValueClasses.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.lang.io.DirectStore;
+
+import java.util.WeakHashMap;
+
+/**
+ * This class is a central access point for loading generated on-heap and off heap collections.
+ */
+public enum DataValueClasses {
+ ;
+ // the weak hash map is required as the class loader could go away without notice e.g. in OSGi
+ private static final WeakHashMap<ClassLoader, DataValueClassCache> cacheMap = new WeakHashMap<ClassLoader, DataValueClassCache>();
+
+ public static <T> T newInstance(Class<T> interfaceClass) {
+ DataValueClassCache dataValueClassCache = acquireCache(interfaceClass);
+ return dataValueClassCache.newInstance(interfaceClass);
+ }
+
+ public static <T> T newDirectReference(Class<T> interfaceClass) {
+ DataValueClassCache dataValueClassCache = acquireCache(interfaceClass);
+ return dataValueClassCache.newDirectReference(interfaceClass);
+ }
+
+ public static <T> T newDirectInstance(Class<T> interfaceClass) {
+ T t = newDirectReference(interfaceClass);
+ Byteable b = (Byteable) t;
+ b.bytes(DirectStore.allocate(b.maxSize()).bytes(), 0);
+ return t;
+ }
+
+ public static <T> Class<T> heapClassFor(Class<T> interfaceClass) {
+ DataValueClassCache dataValueClassCache = acquireCache(interfaceClass);
+ return dataValueClassCache.heapClassFor(interfaceClass);
+ }
+
+ public static <T> Class<T> directClassFor(Class<T> interfaceClass) {
+ DataValueClassCache dataValueClassCache = acquireCache(interfaceClass);
+ return dataValueClassCache.directClassFor(interfaceClass);
+ }
+
+ private static <T> DataValueClassCache acquireCache(Class<T> interfaceClass) {
+ ClassLoader classLoader = interfaceClass.getClassLoader();
+ DataValueClassCache dataValueClassCache;
+ synchronized (cacheMap) {
+ dataValueClassCache = cacheMap.get(classLoader);
+ if (dataValueClassCache == null)
+ cacheMap.put(classLoader, dataValueClassCache = new DataValueClassCache());
+ }
+ return dataValueClassCache;
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueGenerator.java b/lang/src/main/java/net/openhft/lang/model/DataValueGenerator.java
index 97ff8fe..679d318 100644..100755
--- a/lang/src/main/java/net/openhft/lang/model/DataValueGenerator.java
+++ b/lang/src/main/java/net/openhft/lang/model/DataValueGenerator.java
@@ -1,26 +1,29 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
-import net.openhft.compiler.CachedCompiler;
+import net.openhft.compiler.CompilerUtils;
import net.openhft.lang.Compare;
import net.openhft.lang.Maths;
+import net.openhft.lang.MemoryUnit;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.serialization.BytesMarshallable;
+import net.openhft.lang.model.constraints.Group;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.ObjectInput;
@@ -28,68 +31,107 @@ import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Logger;
-/**
- * User: peter.lawrey
- * Date: 06/10/13
- * Time: 19:17
- */
+import static net.openhft.lang.MemoryUnit.BYTES;
+import static net.openhft.lang.model.DataValueModelImpl.heapSize;
+
public class DataValueGenerator {
- public static final Comparator<Class> COMPARATOR = new Comparator<Class>() {
+ private static final Comparator<Class> COMPARATOR = new Comparator<Class>() {
@Override
public int compare(Class o1, Class o2) {
return o1.getName().compareTo(o2.getName());
}
};
- public static final Comparator<Map.Entry<String, FieldModel>> COMPARE_BY_HEAP_SIZE = new Comparator<Map.Entry<String, FieldModel>>() {
+ private static final Comparator<Map.Entry<String, FieldModel>> COMPARE_BY_GROUP_THEN_HEAP_SIZE = new Comparator<Map.Entry<String, FieldModel>>() {
@Override
public int compare(Map.Entry<String, FieldModel> o1, Map.Entry<String, FieldModel> o2) {
// descending
- int cmp = -Maths.compare(o1.getValue().heapSize(), o2.getValue().heapSize());
- return cmp == 0 ? o1.getKey().compareTo(o2.getKey()) : cmp;
+ FieldModel model1 = o1.getValue();
+ FieldModel model2 = o2.getValue();
+
+ Group group1 = model1.group();
+ Group group2 = model2.group();
+
+ int group = Integer.compare(
+ group1 == null ? Integer.MIN_VALUE : model1.group().value(),
+ group2 == null ? Integer.MIN_VALUE : model2.group().value());
+
+ if (group != 0)
+ return group;
+
+ int cmp = -Maths.compare(model1.heapSize(), model2.heapSize());
+ if (cmp != 0)
+ return cmp;
+ Class firstPrimitiveFieldType1 = null;
+ if (!model1.type().isPrimitive() &&
+ !CharSequence.class.isAssignableFrom(model1.type())) {
+ firstPrimitiveFieldType1 = firstPrimitiveFieldType(model1.type());
+ }
+ Class firstPrimitiveFieldType2 = null;
+ if (!model2.type().isPrimitive() &&
+ !CharSequence.class.isAssignableFrom(model2.type())) {
+ firstPrimitiveFieldType2 = firstPrimitiveFieldType(model2.type());
+ }
+ if (firstPrimitiveFieldType1 != null && firstPrimitiveFieldType2 == null)
+ return -1;
+ if (firstPrimitiveFieldType1 == null && firstPrimitiveFieldType2 != null)
+ return 1;
+ if (firstPrimitiveFieldType1 != null && firstPrimitiveFieldType2 != null) {
+ return -Maths.compare(heapSize(firstPrimitiveFieldType1),
+ heapSize(firstPrimitiveFieldType2));
+ }
+ return o1.getKey().compareTo(o2.getKey());
}
};
- private static final Logger LOGGER = Logger.getLogger(DataValueGenerator.class.getName());
- final CachedCompiler cc = new CachedCompiler(null, null);
private final Map<Class, Class> heapClassMap = new ConcurrentHashMap<Class, Class>();
private final Map<Class, Class> nativeClassMap = new ConcurrentHashMap<Class, Class>();
- private boolean dumpCode = false;
+ private boolean dumpCode = Boolean.getBoolean("dvg.dumpCode");
- private static String bytesType(Class type) {
- if (type.isPrimitive())
- return Character.toUpperCase(type.getName().charAt(0)) + type.getName().substring(1);
- if (CharSequence.class.isAssignableFrom(type))
- return "UTFΔ";
- return "Object";
- }
-
- public <T> T heapInstance(Class<T> tClass) {
+ public static Class firstPrimitiveFieldType(Class valueClass) {
+ if (valueClass.getClassLoader() == null)
+ return null;
try {
- return (T) acquireHeapClass(tClass).newInstance();
+ DataValueModel valueModel;
+ if (valueClass.isInterface()) {
+ valueModel = DataValueModels.acquireModel(valueClass);
+
+ } else {
+ String valueClassName = valueClass.getName();
+ String $$Native = "$$Native";
+ if (valueClassName.endsWith($$Native)) {
+ valueClassName = valueClassName.substring(0,
+ valueClassName.length() - $$Native.length());
+ valueModel = DataValueModels.acquireModel(Class.forName(valueClassName));
+
+ } else {
+ return null;
+ }
+ }
+ Map.Entry<String, FieldModel>[] fields =
+ DataValueGenerator.heapSizeOrderedFieldsGrouped(valueModel);
+ if (fields.length == 0)
+ return null;
+ Class firstFieldType = fields[0].getValue().type();
+ if (firstFieldType.isPrimitive())
+ return firstFieldType;
+ return firstPrimitiveFieldType(firstFieldType);
} catch (Exception e) {
- throw new AssertionError(e);
+ return null;
}
}
- public <T> Class acquireHeapClass(Class<T> tClass) throws ClassNotFoundException {
- Class heapClass = heapClassMap.get(tClass);
- if (heapClass != null)
- return heapClass;
- String actual = new DataValueGenerator().generateHeapObject(tClass);
- if (dumpCode)
- LOGGER.info(actual);
- heapClass = cc.loadFromJava(tClass.getClassLoader(), tClass.getName() + "£heap", actual);
- heapClassMap.put(tClass, heapClass);
- return heapClass;
- }
-
- public String generateHeapObject(Class<?> tClass) {
- return generateHeapObject(DataValueModels.acquireModel(tClass));
+ public static String bytesType(Class type) {
+ if (type.isPrimitive())
+ return Character.toUpperCase(type.getName().charAt(0)) + type.getName().substring(1);
+ if (CharSequence.class.isAssignableFrom(type))
+ return "UTFΔ";
+ if (Enum.class.isAssignableFrom(type))
+ return "Enum";
+ return "Object";
}
- public String generateHeapObject(DataValueModel<?> dvmodel) {
- SortedSet<Class> imported = new TreeSet<Class>(COMPARATOR);
+ static String generateHeapObject(DataValueModel<?> dvmodel) {
+ SortedSet<Class> imported = newImported();
imported.add(BytesMarshallable.class);
imported.add(Bytes.class);
imported.add(IOException.class);
@@ -101,53 +143,88 @@ public class DataValueGenerator {
StringBuilder writeMarshal = new StringBuilder();
StringBuilder readMarshal = new StringBuilder();
StringBuilder copy = new StringBuilder();
- Map<String, ? extends FieldModel> fieldMap = dvmodel.fieldMap();
- Map.Entry<String, FieldModel>[] entries = fieldMap.entrySet().toArray(new Map.Entry[fieldMap.size()]);
- Arrays.sort(entries, COMPARE_BY_HEAP_SIZE);
+ Map.Entry<String, FieldModel>[] entries = heapSizeOrderedFieldsGrouped(dvmodel);
for (Map.Entry<String, ? extends FieldModel> entry : entries) {
String name = entry.getKey();
FieldModel model = entry.getValue();
Class type = model.type();
- if (!type.isPrimitive() && !type.getPackage().getName().equals("java.lang"))
+ if (shouldImport(type))
imported.add(type);
- fieldDeclarations.append(" private ").append(type.getName()).append(" _").append(name).append(";\n");
+ heapFieldDeclarations(fieldDeclarations, type, name, model);
+
+ Method setter = getSetter(model);
+ Method getter = getGetter(model);
+ Method getUsing = getUsing(model);
+
+ boolean bothVolatileAndPlain = false;
+
+ final Method orderedSetter = getOrderedSetter(model);
+ final Method volatileGetter = getVolatileGetter(model);
+
+ if (getter != null && volatileGetter != null) {
+ bothVolatileAndPlain = true;
+ }
+ if (setter == null && orderedSetter != null) {
+ setter = orderedSetter;
+ }
+ if (getter == null && volatileGetter != null) {
+ getter = volatileGetter;
+ }
- final Method setter = model.setter();
- final Method getter = model.getter();
if (setter == null) {
- copy.append(" ((Copyable) ").append(getter.getName()).append("()).copyFrom(from.").append(getter.getName()).append("());\n");
+ if (getter != null)
+ copy.append(" ((Copyable) ").append(getter.getName()).append("()).copyFrom(from.").append(getter.getName()).append("());\n");
+
} else {
- copy.append(" ").append(setter.getName()).append("(from.").append(getter.getName()).append("());\n");
- Class<?> setterType = setter.getParameterTypes()[0];
- getterSetters.append(" public void ").append(setter.getName()).append('(').append(setterType.getName()).append(" _) {\n");
- if (type == String.class && setterType != String.class)
- getterSetters.append(" _").append(name).append(" = _.toString();\n");
- else
- getterSetters.append(" _").append(name).append(" = _;\n");
- getterSetters.append(" }\n\n");
+ methodCopy(copy, getter, setter, model);
+ methodHeapSet(getterSetters, setter, name, type, model);
}
- getterSetters.append(" public ").append(type.getName()).append(' ').append(getter.getName()).append("() {\n");
- getterSetters.append(" return _").append(name).append(";\n");
- getterSetters.append(" }\n\n");
+ if (getter != null)
+ methodHeapGet(getterSetters, getter, name, type, model);
+
+ if (getUsing != null && type == String.class && !model.isArray()) {
+ methodHeapGetUsingWithStringBuilder(getterSetters, getUsing, name, type, model);
+
+ // we have to add in the getter method as its required for the equals() and hashCode()
+ if (getter == null && volatileGetter == null) {
+ String getterName = getterName(getUsing);
+ methodHeapGet(getterSetters, name, type, getterName);
+ }
+ }
+
+ //In the case where there are both volatile and plain gets and sets they need to be written here
+ //If there is just a volatile get and set it would have been written above.
+ if (bothVolatileAndPlain) {
+ methodHeapGet(getterSetters, volatileGetter, name, type, model);
+ methodHeapSet(getterSetters, orderedSetter, name, type, model);
+ }
+
Method adder = model.adder();
if (adder != null) {
- getterSetters.append(" public ").append(type.getName()).append(' ').append(adder.getName())
- .append("(").append(adder.getParameterTypes()[0].getName()).append(" _) {\n")
- .append(" return _").append(name).append(" += _;\n")
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(adder.getName())
+ .append("(").append(adder.getParameterTypes()[0].getName()).append(" $) {\n")
+ .append(" return _").append(name).append(" += $;\n")
.append(" }");
}
+ Method sizeOf = model.sizeOf();
+ if (sizeOf != null) {
+ getterSetters.append(" public int ").append(sizeOf.getName())
+ .append("() {\n")
+ .append(" return ").append(model.indexSize().value()).append(";\n")
+ .append(" }\n\n");
+ }
Method atomicAdder = model.atomicAdder();
if (atomicAdder != null) {
- getterSetters.append(" public synchronized ").append(type.getName()).append(' ').append(atomicAdder.getName())
- .append("(").append(adder.getParameterTypes()[0].getName()).append(" _) {\n")
- .append(" return _").append(name).append(" += _;\n")
- .append(" }");
+ getterSetters.append(" public synchronized ").append(normalize(type)).append(' ').append(atomicAdder.getName())
+ .append("(").append(atomicAdder.getParameterTypes()[0].getName()).append(" $) {\n")
+ .append(" return _").append(name).append(" += $;\n")
+ .append(" }\n\n");
}
Method cas = model.cas();
if (cas != null) {
getterSetters.append(" public synchronized boolean ").append(cas.getName()).append("(")
- .append(type.getName()).append(" _1, ")
- .append(type.getName()).append(" _2) {\n")
+ .append(normalize(type)).append(" _1, ")
+ .append(normalize(type)).append(" _2) {\n")
.append(" if (_").append(name).append(" == _1) {\n")
.append(" _").append(name).append(" = _2;\n")
.append(" return true;\n")
@@ -179,25 +256,23 @@ public class DataValueGenerator {
.append(" throw new UnsupportedOperationException();\n")
.append(" }");
}
- writeMarshal.append(" out.write").append(bytesType(type)).append("(_").append(name).append(");\n");
- readMarshal.append(" _").append(name).append(" = in.read").append(bytesType(type)).append("(");
- if ("Object".equals(bytesType(type)))
- readMarshal.append(type.getName()).append(".class");
- readMarshal.append(");\n");
+ methodWriteMarshall(writeMarshal, getter, setter, type, model);
+ methodHeapReadMarshall(readMarshal, name, type, model);
}
StringBuilder sb = new StringBuilder();
- sb.append("package ").append(dvmodel.type().getPackage().getName()).append(";\n\n");
+ appendPackage(dvmodel, sb);
sb.append("import static ").append(Compare.class.getName()).append(".*;\n");
for (Class aClass : imported) {
- sb.append("import ").append(aClass.getName()).append(";\n");
+ sb.append("import ").append(normalize(aClass)).append(";\n");
}
- sb.append("\npublic class ").append(dvmodel.type().getSimpleName())
- .append("£heap implements ").append(dvmodel.type().getSimpleName())
- .append(", BytesMarshallable, Copyable<").append(dvmodel.type().getName()).append("> {\n");
+ String className = simpleName(dvmodel.type());
+ sb.append("\npublic class ").append(className)
+ .append("$$Heap implements ").append(dvmodel.type().getSimpleName())
+ .append(", BytesMarshallable, Copyable<").append(normalize(dvmodel.type())).append("> {\n");
sb.append(fieldDeclarations).append('\n');
sb.append(getterSetters);
- sb.append(" @SuppressWarnings(\"unchecked\")\n" +
- " public void copyFrom(").append(dvmodel.type().getName()).append(" from) {\n");
+ sb.append(" @SuppressWarnings(\"unchecked\")\n" +
+ " public void copyFrom(").append(normalize(dvmodel.type())).append(" from) {\n");
sb.append(copy);
sb.append(" }\n\n");
sb.append(" public void writeMarshallable(Bytes out) {\n");
@@ -207,41 +282,80 @@ public class DataValueGenerator {
sb.append(readMarshal);
sb.append(" }\n");
if (Byteable.class.isAssignableFrom(dvmodel.type())) {
- sb.append(" public void bytes(Bytes bytes) {\n");
- sb.append(" throw new UnsupportedOperationException();\n");
- sb.append(" }\n");
sb.append(" public void bytes(Bytes bytes, long l) {\n");
sb.append(" throw new UnsupportedOperationException();\n");
sb.append(" }\n");
sb.append(" public Bytes bytes() {\n");
sb.append(" return null;\n");
sb.append(" }\n");
+ sb.append(" public long offset() {\n");
+ sb.append(" return 0L;\n");
+ sb.append(" }\n");
sb.append(" public int maxSize() {\n");
sb.append(" throw new UnsupportedOperationException();\n");
sb.append(" }\n");
}
- generateObjectMethods(sb, dvmodel, entries);
+ generateObjectMethods(sb, dvmodel, entries, false);
sb.append("}\n");
// System.out.println(sb);
return sb.toString();
}
- private static void generateObjectMethods(StringBuilder sb, DataValueModel<?> dvmodel, Map.Entry<String, FieldModel>[] entries) {
+ public static String simpleName(Class<?> type) {
+ String name = type.getName();
+ return name.substring(name.lastIndexOf('.') + 1);
+ }
+
+ public static CharSequence normalize(Class aClass) {
+ return aClass.getName().replace('$', '.');
+ }
+
+ private static void generateObjectMethods(StringBuilder sb, DataValueModel<?> dvmodel,
+ Map.Entry<String, FieldModel>[] entries,
+ boolean offHeap) {
int count = 0;
StringBuilder hashCode = new StringBuilder();
StringBuilder equals = new StringBuilder();
+ StringBuilder equalsGetUsing = new StringBuilder();
+ StringBuilder toStringGetUsing = new StringBuilder();
+ StringBuilder getUsingEquals = new StringBuilder();
StringBuilder toString = new StringBuilder();
for (Map.Entry<String, FieldModel> entry : entries) {
String name = entry.getKey();
FieldModel model = entry.getValue();
- Class type = model.type();
- if (count > 0)
- hashCode.append(") * 10191 +\n ");
- String getterName = model.getter().getName();
- hashCode.append("calcLongHashCode(").append(getterName).append("())");
- equals.append(" if(!isEqual(").append(getterName).append("(), that.").append(getterName).append("())) return false;\n");
- toString.append(" \", ").append(name).append("= \" + ").append(getterName).append("() +\n");
- count++;
+ Method getter = getGetter(model);
+ Method getUsing = getUsing(model);
+
+ if (getter == null) getter = getVolatileGetter(model);
+
+ if (getter != null || getUsing != null) {
+ String getterName = (getter == null) ? getterName(getUsing) : getter.getName();
+ methodLongHashCode(hashCode, getterName, model, count);
+
+ if (getter != null) {
+ methodEquals(equals, getterName, model, simpleName(dvmodel.type()));
+ methodToString(toString, getterName, name, model);
+
+ } else {
+ methodEqualsGetUsing(getUsingEquals, getUsing.getName());
+ methodToStringGetUsing(toStringGetUsing, getUsing.getName(), name, model);
+ }
+ count++;
+ }
+
+ Bytes b;
+
+ if (model.isArray()) {
+ String nameWithUpper = Character.toUpperCase(name.charAt(0)) + name.substring(1);
+ if (model.isVolatile()) nameWithUpper = "Volatile" + nameWithUpper;
+ sb.append("\n public long longHashCode_" + name + "() {\n" +
+ " long hc = 0;\n" +
+ " for (int i = 0; i < " + model.indexSize().value() + "; i++) {\n" +
+ " hc += calcLongHashCode(get" + nameWithUpper + "At(i));\n" +
+ " }\n" +
+ " return hc;\n" +
+ " }\n\n");
+ }
}
sb.append(" public int hashCode() {\n" +
" long lhc = longHashCode();\n" +
@@ -252,48 +366,465 @@ public class DataValueGenerator {
" return ");
for (int i = 1; i < count; i++)
sb.append('(');
+
sb.append(hashCode);
- String simpleName = dvmodel.type().getSimpleName();
+
+ CharSequence simpleName = simpleName(dvmodel.type()).replace('$', '.');
sb.append(";\n")
.append(" }\n")
- .append("\n")
- .append(" public boolean equals(Object o) {\n")
+ .append("\n");
+ sb.append(" public boolean equals(Object o) {\n")
.append(" if (this == o) return true;\n")
.append(" if (!(o instanceof ").append(simpleName).append(")) return false;\n")
.append(" ").append(simpleName).append(" that = (").append(simpleName).append(") o;\n")
.append("\n")
.append(equals)
- .append(" return true;\n" +
- " }\n" +
- "\n" +
- " public String toString() {\n" +
- " return \"").append(simpleName).append(" {\" +\n")
- .append(toString.substring(0, toString.length() - 3)).append(";\n")
- .append(" }");
+ .append(equalsGetUsing)
+ .append(" return true;\n")
+ .append(" }\n")
+ .append("\n");
+ sb.append(" public String toString() {\n")
+ .append(offHeap ? " if (_bytes == null) return \"bytes is null\";\n" : "")
+ .append(" StringBuilder sb = new StringBuilder();\n")
+ .append(" sb.append(\"").append(simpleName).append("{ \");\n")
+ .append(toString)
+ .append(toStringGetUsing)
+ .append(" sb.append(\" }\");\n")
+ .append(" return sb.toString();\n")
+ .append(" }\n");
+ }
+
+ private static Method getUsing(FieldModel model) {
+ Method getUsing = model.getUsing();
+ return getUsing;
+ }
+
+ public static Method getGetter(FieldModel model) {
+ Method getter = model.getter();
+ if (getter == null) getter = model.indexedGetter();
+ return getter;
+ }
+
+ public static Method getVolatileGetter(FieldModel model) {
+ Method getter = model.volatileGetter();
+ if (getter == null) getter = model.volatileIndexedGetter();
+ return getter;
+ }
+
+ public static Method getSetter(FieldModel model) {
+ Method setter = model.setter();
+ if (setter == null) setter = model.indexedSetter();
+
+ return setter;
+ }
+
+ public static Method getOrderedSetter(FieldModel model) {
+ Method setter = model.orderedSetter();
+ if (setter == null) setter = model.orderedIndexedSetter();
+
+ return setter;
+ }
+
+ private static void methodCopy(
+ StringBuilder copy, Method getter, Method setter, FieldModel model) {
+ if (!model.isArray()) {
+ if (model.setter() != null && getter != null) {
+ copy.append(" ").append(setter.getName());
+ copy.append("(from.").append(getter.getName()).append("());\n");
+ }
+ } else {
+ copy.append(" for (int i = 0; i < ").append(model.indexSize().value())
+ .append("; i++){");
+ copy.append("\n ").append(setter.getName()).append("(i, from.")
+ .append(getter.getName()).append("(i));\n");
+ copy.append(" }\n");
+ }
+ }
+
+ private static void methodWriteMarshall(StringBuilder writeMarshal, Method getter,
+ Method setter, Class type, FieldModel model) {
+ if (!model.isArray()) {
+ if (getter != null && setter != null) {
+ writeMarshal.append(" {\n");
+// saveCharSequencePosition(writeMarshal, type, "out");
+ writeMarshal.append(" out.write").append(bytesType(type)).append("(")
+ .append(getter.getName()).append("());\n");
+// zeroOutRemainingCharSequenceBytesAndUpdatePosition(
+// writeMarshal, model, type, "out");
+ writeMarshal.append(" }\n");
+ }
+ // otherwise skip.
+ } else {
+ writeMarshal.append(" for (int i = 0; i < ")
+ .append(model.indexSize().value()).append("; i++){\n");
+// saveCharSequencePosition(writeMarshal, type, "out");
+ writeMarshal.append(" out.write").append(bytesType(type)).append("(")
+ .append(getter.getName()).append("(i));\n");
+// zeroOutRemainingCharSequenceBytesAndUpdatePosition(
+// writeMarshal, model, type, "out");
+ writeMarshal.append(" }\n");
+ }
+ }
+
+ private static void saveCharSequencePosition(StringBuilder write, Class type, String bytes) {
+ if (CharSequence.class.isAssignableFrom(type))
+ write.append(" long pos = " + bytes + ".position();\n");
+ }
+
+ private static void zeroOutRemainingCharSequenceBytesAndUpdatePosition(
+ StringBuilder write, FieldModel model, Class type, String bytes) {
+ if (CharSequence.class.isAssignableFrom(type)) {
+ write.append(" long newPos = pos + ").append(fieldSize(model))
+ .append(";\n");
+ write.append(" " + bytes + ".zeroOut(" + bytes + ".position(), newPos);\n");
+ write.append(" " + bytes + ".position(newPos);\n");
+ }
+ }
+
+ private static void methodHeapReadMarshall(StringBuilder readMarshal, String name, Class type, FieldModel model) {
+
+ if(model.type() == Date.class){
+ readMarshal.append(" _").append(name).append(" = new Date(in.readLong());\n");
+ } else {
+ String str = bytesType(type);
+ if (!model.isArray()) {
+ readMarshal.append(" _").append(name).append(" = in.read").append(str).append("(");
+ if ("Object".equals(str) || "Enum".equals(str))
+ readMarshal.append(normalize(type)).append(".class");
+ readMarshal.append(");\n");
+
+ } else {
+ readMarshal.append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++){\n");
+ readMarshal.append(" _").append(name).append("[i] = in.read").append(str).append("(");
+ if ("Object".equals(str) || "Enum".equals(str))
+ readMarshal.append(normalize(type)).append(".class");
+ readMarshal.append(");\n");
+ readMarshal.append(" }\n");
+ }
+ }
+ }
+
+ private static void methodLongHashCode(StringBuilder hashCode, String getterName, FieldModel model, int count) {
+ if (count > 0)
+ hashCode.append(") * 10191 +\n ");
+
+ if (!model.isArray()) {
+ hashCode.append("calcLongHashCode(").append(getterName).append("())");
+
+ } else {
+ hashCode.append("longHashCode_").append(model.name()).append("()");
+ }
+ }
+
+ private static void methodEqualsGetUsing(StringBuilder equals, String getterName) {
+ equals.append(" if(!isEqual(").append(getterName).append("(new StringBuilder()).toString(), that.").append(getterName).append("new StringBuilder().toString())) return false;\n");
+ }
+
+ private static void methodEquals(StringBuilder equals, String getterName, FieldModel model, String className) {
+ if (!model.isArray()) {
+ equals.append(" if(!isEqual(").append(getterName).append("(), that.").append(getterName).append("())) return false;\n");
+
+ } else {
+ equals.append(" for (int i = 0; i <" + model.indexSize().value() + "; i++) {\n");
+ equals.append(" if(!isEqual(").append(getterName).append("(i), that.").append(getterName).append("(i))) return false;\n");
+ equals.append(" }\n");
+ }
+ }
+
+ private static void methodToStringGetUsing(StringBuilder toString, String getterName, String name, FieldModel model) {
+ toString.append(" sb.append(\"").append(name).append("= \").append(").append(getterName).append("(new StringBuilder()));\n");
+ }
+
+ private static void methodToString(StringBuilder toString, String getterName, String name, FieldModel model) {
+ if (toString.length() > 2)
+ toString.append("sb.append(\", \")\n;");
+ if (!model.isArray()) {
+ toString.append(" sb.append(\"").append(name).append("= \").append(").append(getterName).append("());\n");
+
+ } else {
+ toString
+ .append(" sb.append(\"").append(name).append("\").append(\"= [\");")
+ .append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++) {\n")
+ .append(" if (i > 0) sb.append(\", \") ;\n")
+ .append(" sb.append(").append(getterName).append("(i));\n")
+ .append(" }\n")
+ .append(" sb.append(\"]\");\n");
+ }
+ }
+
+ private static String nullAwareToString(String var) {
+ return "(" + var + " != null ? " + var + ".toString() : null)";
+ }
+
+ private static void methodHeapSet(StringBuilder getterSetters, Method setter, String name, Class type, FieldModel model) {
+ Class<?> setterType = setter.getParameterTypes()[setter.getParameterTypes().length - 1];
+ if (!model.isArray()) {
+ getterSetters.append(" public void ").append(setter.getName()).append('(').append(normalize(setterType)).append(" $) {\n");
+ if (type == String.class && setterType != String.class)
+ getterSetters.append(" _").append(name).append(" = " + nullAwareToString("$") + ";\n");
+ else
+ getterSetters.append(" _").append(name).append(" = $;\n");
+
+ } else {
+ getterSetters.append(" public void ").append(setter.getName()).append("(int i, ").append(normalize(setterType)).append(" $) {\n");
+ getterSetters.append(boundsCheck(model.indexSize().value()));
+ if (type == String.class && setterType != String.class)
+ getterSetters.append(" _").append(name).append("[i] = " + nullAwareToString("$") + ";\n");
+ else
+ getterSetters.append(" _").append(name).append("[i] = $;\n");
+ }
+ getterSetters.append(" }\n\n");
+ }
+
+ private static void methodHeapGet(StringBuilder getterSetters, Method getter, String name, Class type, FieldModel model) {
+ if (!model.isArray()) {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("() {\n");
+ getterSetters.append(" return _").append(name).append(";\n");
+
+ } else {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("(int i) {\n");
+ getterSetters.append(boundsCheck(model.indexSize().value()));
+ getterSetters.append(" return _").append(name).append("[i];\n");
+ }
+ getterSetters.append(" }\n\n");
+ }
+
+ private static void methodHeapGet(StringBuilder getterSetters, String name, Class type, String getterName) {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getterName).append("() {\n");
+ getterSetters.append(" return _").append(name).append(";\n");
+ getterSetters.append(" }\n\n");
+ }
+
+ private static void methodHeapGetUsingWithStringBuilder(StringBuilder result, Method method, String name, Class type, FieldModel model) {
+ final CharSequence returnType = method.getReturnType() == void.class ? "void" : normalize(method
+ .getReturnType());
+
+ if (!type.equals(String.class) || method.getParameterTypes().length != 1)
+ return;
+
+ if (!StringBuilder.class.equals(method.getParameterTypes()[0]))
+ return;
+
+ result.append(" public ").append(returnType).append(' ').append(method
+ .getName())
+ .append("(StringBuilder builder){\n");
+ result.append(" builder.append(_" + name + ");\n");
+ if (method.getReturnType() != void.class)
+ result.append(" return builder;\n");
+
+ result.append(" }\n\n");
+ }
+
+ private static void heapFieldDeclarations(StringBuilder fieldDeclarations, Class type, String name, FieldModel model) {
+ String vol = "";
+ if (model.isVolatile()) vol = "volatile ";
+
+ if (!model.isArray()) {
+ fieldDeclarations.append(" private ").append(vol).append(normalize(type)).append(" _").append(name).append(";\n");
+
+ } else {
+ fieldDeclarations.append(" private ").append(vol).append(normalize(type)).append("[] _").append(name)
+ .append(" = new ").append(normalize(type)).append("[").append(model.indexSize().value()).append("];\n");
+ if (!type.isPrimitive()) {
+ fieldDeclarations.append(" {\n")
+ .append(" for (int i = 0; i < _").append(name).append(".length; i++)\n")
+ .append(" _").append(name).append("[i] = new ").append(type.getName());
+
+ if (type.isInterface()) {
+ fieldDeclarations.append("$$Heap();\n");
+
+ } else {
+ fieldDeclarations.append("();\n");
+ }
+ fieldDeclarations.append(" }");
+ }
+ }
+ }
+
+ private static String boundsCheck(int check) {
+ return " if(i<0) throw new ArrayIndexOutOfBoundsException(i + \" must be greater than 0\");\n" +
+ " if(i>=" + check + ") throw new ArrayIndexOutOfBoundsException(i + \" must be less than " + check + "\");\n";
+ }
+
+ public static void appendImported(SortedSet<Class> imported, StringBuilder sb) {
+ for (Class aClass : imported) {
+ sb.append("import ").append(aClass.getName().replace('$', '.')).append(";\n");
+ }
+ }
+
+ public static void appendPackage(DataValueModel<?> dvmodel, StringBuilder sb) {
+ sb.append("package ").append(getPackage(dvmodel)).append(";\n\n");
+ }
+
+ public static String getPackage(DataValueModel<?> dvmodel) {
+ return dvmodel.type().getPackage().getName();
+ }
+
+ public static int fieldSize(FieldModel model) {
+ return computeOffset(
+ (int) BYTES.alignAndConvert((long) model.nativeSize(), MemoryUnit.BITS), model);
+ }
+
+ public static TreeSet<Class> newImported() {
+ return new TreeSet<Class>(COMPARATOR);
+ }
+
+ public static boolean shouldImport(Class type) {
+ return !type.isPrimitive() && !type.getPackage().getName().equals("java.lang");
+ }
+
+ public static Map.Entry<String, FieldModel>[] heapSizeOrderedFieldsGrouped(DataValueModel<?> dvmodel) {
+ Map<String, ? extends FieldModel> fieldMap = dvmodel.fieldMap();
+ Map.Entry<String, FieldModel>[] entries =
+ fieldMap.entrySet().toArray(new Map.Entry[fieldMap.size()]);
+ Arrays.sort(entries, COMPARE_BY_GROUP_THEN_HEAP_SIZE);
+ return entries;
+ }
+
+ /**
+ * gets the getter name based on the getUsing
+ */
+ private static String getterName(Method getUsingMethod) {
+ String name = getUsingMethod.getName();
+ if (!name.startsWith("getUsing"))
+ throw new IllegalArgumentException("expected the getUsingXX method to start with the text 'getUsing'.");
+ return "get" + name.substring("getUsing".length());
+ }
+
+ private static void methodGetUsingWithStringBuilder(StringBuilder result, Method method, Class type, boolean isVolatile, String name) {
+ String read = "read";
+ if (isVolatile) read = "readVolatile";
+
+ if (method.getParameterTypes().length != 1)
+ return;
+
+ if (!StringBuilder.class.equals(method.getParameterTypes()[0]))
+ return;
+
+ if (type != String.class)
+ return;
+
+ final CharSequence returnType = method.getReturnType() == void.class ? "void" : normalize(method
+ .getReturnType());
+
+ result.append(" public ").append(returnType).append(' ').append(method
+ .getName())
+ .append("(StringBuilder builder){\n");
+
+ result.append(" _bytes.position(_offset + ").append(name.toUpperCase()).append(");\n");
+ result.append(" _bytes.").append(read).append(bytesType(type)).append("(builder);\n");
+
+ if (method.getReturnType() != void.class) {
+ result.append(" return builder;\n");
+ }
+ result.append(" }\n\n");
+ }
+
+ public static int computeOffset(int offset, FieldModel model) {
+ if (model.indexSize() == null) {
+ return offset;
+
+ } else {
+ return model.indexSize().value() * offset;
+ }
+ }
+
+ public static int computeNonScalarOffset(DataValueModel dvmodel, Class type) {
+ int offset = 0;
+ DataValueModel dvmodel2 = dvmodel.nestedModel(type);
+ Map.Entry<String, FieldModel>[] entries2 = heapSizeOrderedFieldsGrouped(dvmodel2);
+ for (Map.Entry<String, ? extends FieldModel> entry2 : entries2) {
+ FieldModel model2 = entry2.getValue();
+ int add;
+ if (dvmodel2.isScalar(model2.type())) {
+ add = fieldSize(model2);
+
+ } else {
+ add = computeNonScalarOffset(dvmodel2, model2.type());
+ if (model2.isArray())
+ add *= model2.indexSize().value();
+ }
+ offset += add;
+ }
+ return offset;
+ }
+
+ public <T> T heapInstance(Class<T> tClass) {
+ try {
+ //noinspection ClassNewInstance
+ return (T) acquireHeapClass(tClass).newInstance();
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public <T> Class acquireHeapClass(Class<T> tClass) {
+ Class heapClass = heapClassMap.get(tClass);
+ if (heapClass != null)
+ return heapClass;
+ ClassLoader classLoader = tClass.getClassLoader();
+ String className = tClass.getName() + "$$Heap";
+ try {
+ heapClass = classLoader.loadClass(className);
+ } catch (ClassNotFoundException ignored) {
+ try {
+ String actual = generateHeapObject(tClass);
+ if (dumpCode)
+ LoggerFactory.getLogger(DataValueGenerator.class).info(actual);
+ heapClass = CompilerUtils.CACHED_COMPILER.loadFromJava(classLoader, className, actual);
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
+ heapClassMap.put(tClass, heapClass);
+ return heapClass;
+ }
+
+ String generateHeapObject(Class<?> tClass) {
+ DataValueModel<?> dvmodel = DataValueModels.acquireModel(tClass);
+ for (FieldModel fieldModel : dvmodel.fieldMap().values()) {
+ if (fieldModel.isArray() && !fieldModel.type().isPrimitive())
+ acquireHeapClass(fieldModel.type());
+ }
+ return generateHeapObject(dvmodel);
}
public <T> T nativeInstance(Class<T> tClass) {
try {
+ //noinspection ClassNewInstance
return (T) acquireNativeClass(tClass).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
}
- public <T> Class acquireNativeClass(Class<T> tClass) throws ClassNotFoundException {
+ public <T> Class acquireNativeClass(Class<T> tClass) {
+ if (!tClass.isInterface())
+ return tClass;
Class nativeClass = nativeClassMap.get(tClass);
if (nativeClass != null)
return nativeClass;
DataValueModel<T> dvmodel = DataValueModels.acquireModel(tClass);
for (Class clazz : dvmodel.nestedModels()) {
+ // touch them to make sure they are loaded.
Class clazz2 = acquireNativeClass(clazz);
}
String actual = new DataValueGenerator().generateNativeObject(dvmodel);
if (dumpCode)
- LOGGER.info(actual);
- nativeClass = cc.loadFromJava(tClass.getClassLoader(), tClass.getName() + "£native", actual);
+ LoggerFactory.getLogger(DataValueGenerator.class).info(actual);
+ ClassLoader classLoader = tClass.getClassLoader();
+ String className = tClass.getName() + "$$Native";
+ try {
+ nativeClass = classLoader.loadClass(className);
+ } catch (ClassNotFoundException ignored) {
+ try {
+ nativeClass = CompilerUtils.CACHED_COMPILER.loadFromJava(classLoader, className, actual);
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ }
+ }
nativeClassMap.put(tClass, nativeClass);
return nativeClass;
}
@@ -303,7 +834,7 @@ public class DataValueGenerator {
}
public String generateNativeObject(DataValueModel<?> dvmodel) {
- SortedSet<Class> imported = new TreeSet<Class>(COMPARATOR);
+ SortedSet<Class> imported = newImported();
imported.add(BytesMarshallable.class);
imported.add(ObjectOutput.class);
imported.add(ObjectInput.class);
@@ -319,51 +850,73 @@ public class DataValueGenerator {
StringBuilder readMarshal = new StringBuilder();
StringBuilder copy = new StringBuilder();
StringBuilder nestedBytes = new StringBuilder();
- Map<String, ? extends FieldModel> fieldMap = dvmodel.fieldMap();
- Map.Entry<String, FieldModel>[] entries = fieldMap.entrySet().toArray(new Map.Entry[fieldMap.size()]);
- Arrays.sort(entries, COMPARE_BY_HEAP_SIZE);
+
+ Map.Entry<String, FieldModel>[] entries = heapSizeOrderedFieldsGrouped(dvmodel);
int offset = 0;
for (Map.Entry<String, ? extends FieldModel> entry : entries) {
String name = entry.getKey();
FieldModel model = entry.getValue();
Class type = model.type();
- if (!type.isPrimitive() && !type.getPackage().getName().equals("java.lang"))
+ if (shouldImport(type))
imported.add(type);
String NAME = "_offset + " + name.toUpperCase();
- final Method setter = model.setter();
- final Method getter = model.getter();
+ final Method setter = getSetter(model);
+ final Method getter = getGetter(model);
+ final Method getUsing = getUsing(model);
+
+ final Method orderedSetter = getOrderedSetter(model);
+ final Method volatileGetter = getVolatileGetter(model);
+
+ final Method defaultSetter = setter != null ? setter : orderedSetter;
+ final Method defaultGetter = getter != null ? getter : volatileGetter;
+
if (dvmodel.isScalar(type)) {
staticFieldDeclarations.append(" private static final int ").append(name.toUpperCase()).append(" = ").append(offset).append(";\n");
- copy.append(" ").append(setter.getName()).append("(from.").append(getter.getName()).append("());\n");
- Class<?> setterType = setter.getParameterTypes()[0];
- getterSetters.append(" public void ").append(setter.getName()).append('(').append(setterType.getName()).append(" _) {\n");
- getterSetters.append(" _bytes.write").append(bytesType(type)).append("(").append(NAME).append(", ");
- if (CharSequence.class.isAssignableFrom(type))
- getterSetters.append(model.size().value()).append(", ");
- getterSetters.append("_);\n");
- getterSetters.append(" }\n\n");
- getterSetters.append(" public ").append(type.getName()).append(' ').append(getter.getName()).append("() {\n");
- getterSetters.append(" return _bytes.read").append(bytesType(type)).append("(").append(NAME).append(");\n");
- getterSetters.append(" }\n\n");
+ methodCopy(copy, defaultGetter, defaultSetter, model);
+ if (setter != null)
+ methodSet(getterSetters, setter, type, NAME, model, false);
+ if (getter != null)
+ methodGet(getterSetters, getter, type, NAME, model, false);
+ if (getUsing != null) {
+ methodGetUsingWithStringBuilder(getterSetters, getUsing, type, false, name);
+
+ // we have to add in the getter method as its required for the equals() and hashCode()
+ if (getter == null && volatileGetter == null) {
+ String getterName = getterName(getUsing);
+ methodGet(getterSetters, type, NAME, false, getterName);
+ }
+ }
+
+ if (orderedSetter != null)
+ methodSet(getterSetters, orderedSetter, type, NAME, model, true);
+ if (volatileGetter != null)
+ methodGet(getterSetters, volatileGetter, type, NAME, model, true);
+
Method adder = model.adder();
if (adder != null) {
- getterSetters.append(" public ").append(type.getName()).append(' ').append(adder.getName())
- .append("(").append(adder.getParameterTypes()[0].getName()).append(" _) {\n")
- .append(" return _bytes.add").append(bytesType(type)).append("(").append(NAME).append(", _);\n")
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(adder.getName())
+ .append("(").append(adder.getParameterTypes()[0].getName()).append(" $) {\n")
+ .append(" return _bytes.add").append(bytesType(type)).append("(").append(NAME).append(", $);\n")
.append(" }");
}
Method atomicAdder = model.atomicAdder();
if (atomicAdder != null) {
- getterSetters.append(" public ").append(type.getName()).append(' ').append(atomicAdder.getName())
- .append("(").append(adder.getParameterTypes()[0].getName()).append(" _) {\n")
- .append(" return _bytes.addAtomic").append(bytesType(type)).append("(").append(NAME).append(", _);\n")
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(atomicAdder.getName())
+ .append("(").append(atomicAdder.getParameterTypes()[0].getName()).append(" $) {\n")
+ .append(" return _bytes.addAtomic").append(bytesType(type)).append("(").append(NAME).append(", $);\n")
.append(" }");
}
+ Method sizeOf = model.sizeOf();
+ if (sizeOf != null) {
+ getterSetters.append(" public int ").append(sizeOf.getName())
+ .append("() {\n").append(" return ").append(model.indexSize().value()).append(";\n")
+ .append(" }\n\n");
+ }
Method cas = model.cas();
if (cas != null) {
getterSetters.append(" public boolean ").append(cas.getName()).append("(")
- .append(type.getName()).append(" _1, ")
- .append(type.getName()).append(" _2) {\n")
+ .append(normalize(type)).append(" _1, ")
+ .append(normalize(type)).append(" _2) {\n")
.append(" return _bytes.compareAndSwap").append(bytesType(type)).append('(').append(NAME).append(", _1, _2);\n")
.append(" }");
}
@@ -391,83 +944,77 @@ public class DataValueGenerator {
.append(" _bytes.busyLock").append(bytesType(type)).append('(').append(NAME).append(");\n")
.append(" }");
}
- writeMarshal.append(" out.write").append(bytesType(type)).append("(")
- .append(getter.getName()).append("());\n");
- readMarshal.append(" ").append(setter.getName()).append("(in.read").append(bytesType(type)).append("());\n");
- offset += (model.nativeSize() + 7) >> 3;
+ methodWriteMarshall(writeMarshal, defaultGetter, defaultSetter, type, model);
+ methodReadMarshall(readMarshal, defaultGetter, defaultSetter, type, model);
+
+ if(!Enum.class.isAssignableFrom(type))
+ offset += fieldSize(model);
+
} else {
staticFieldDeclarations.append(" private static final int ").append(name.toUpperCase()).append(" = ").append(offset).append(";\n");
- fieldDeclarations.append(" private final ").append(type.getName()).append("£native _").append(name).append(" = new ").append(type.getName()).append("£native();\n");
- if (setter == null) {
+ nonScalarFieldDeclaration(staticFieldDeclarations, type, name, model);
+ if (defaultSetter == null) {
copy.append(" _").append(name).append(".copyFrom(from.").append(getter.getName()).append("());\n");
+
} else {
- copy.append(" ").append(setter.getName()).append("(from.").append(getter.getName()).append("());\n");
- Class<?> setterType = setter.getParameterTypes()[0];
- getterSetters.append(" public void ").append(setter.getName()).append('(').append(setterType.getName()).append(" _) {\n");
- if (type == String.class && setterType != String.class)
- getterSetters.append(" _").append(name).append(" = _.toString();\n");
- else
- getterSetters.append(" _").append(name).append(".copyFrom(_);\n");
- getterSetters.append(" }\n\n");
+ methodCopy(copy, defaultGetter, defaultSetter, model);
+ methodNonScalarSet(getterSetters, defaultSetter, name, type, model);
}
- getterSetters.append(" public ").append(type.getName()).append(' ').append(getter.getName()).append("() {\n");
- getterSetters.append(" return _").append(name).append(";\n");
- getterSetters.append(" }\n\n");
-
- writeMarshal.append(" _").append(name).append(".writeMarshallable(out);\n");
- readMarshal.append(" _").append(name).append(".readMarshallable(in);\n");
-
- nestedBytes.append(" ((Byteable) _").append(name).append(").bytes(bytes, ").append(NAME).append(");\n");
- DataValueModel dvmodel2 = dvmodel.nestedModel(type);
- Map<String, ? extends FieldModel> fieldMap2 = dvmodel2.fieldMap();
- Map.Entry<String, FieldModel>[] entries2 = fieldMap2.entrySet().toArray(new Map.Entry[fieldMap2.size()]);
- Arrays.sort(entries2, COMPARE_BY_HEAP_SIZE);
- for (Map.Entry<String, ? extends FieldModel> entry2 : entries2) {
- FieldModel model2 = entry2.getValue();
- offset += (model2.nativeSize() + 7) >> 3;
- }
+ int size = computeNonScalarOffset(dvmodel, type);
+ methodNonScalarGet(getterSetters, getter, name, type, model);
+ methodNonScalarWriteMarshall(writeMarshal, name, model);
+ methodNonScalarReadMarshall(readMarshal, name, model);
+ methodNonScalarBytes(nestedBytes, name, NAME, size, model);
+
+ offset += computeOffset(size, model);
}
}
fieldDeclarations.append("\n")
.append(" private Bytes _bytes;\n")
.append(" private long _offset;\n");
StringBuilder sb = new StringBuilder();
- sb.append("package ").append(dvmodel.type().getPackage().getName()).append(";\n\n");
+ appendPackage(dvmodel, sb);
sb.append("import static ").append(Compare.class.getName()).append(".*;\n");
- for (Class aClass : imported) {
- sb.append("import ").append(aClass.getName()).append(";\n");
- }
- sb.append("\npublic class ").append(dvmodel.type().getSimpleName())
- .append("£native implements ").append(dvmodel.type().getSimpleName())
- .append(", BytesMarshallable, Byteable, Copyable<").append(dvmodel.type().getName()).append("> {\n");
+ appendImported(imported, sb);
+ sb.append("\npublic class ").append(simpleName(dvmodel.type()))
+ .append("$$Native implements ").append(simpleName(dvmodel.type()).replace('$', '.'))
+ .append(", BytesMarshallable, Byteable, Copyable<").append(normalize(dvmodel.type())).append("> {\n");
sb.append(staticFieldDeclarations).append('\n');
sb.append(fieldDeclarations).append('\n');
sb.append(getterSetters);
- sb.append(" public void copyFrom(").append(dvmodel.type().getName()).append(" from) {\n");
- sb.append(copy);
- sb.append(" }\n\n");
- sb.append(" public void writeMarshallable(Bytes out) {\n");
- sb.append(writeMarshal);
- sb.append(" }\n");
- sb.append(" public void readMarshallable(Bytes in) {\n");
- sb.append(readMarshal);
- sb.append(" }\n");
- sb.append(" public void bytes(Bytes bytes) {\n");
- sb.append(" bytes(bytes, 0L);\n");
- sb.append(" }\n");
- sb.append(" public void bytes(Bytes bytes, long offset) {\n");
- sb.append(" this._bytes = bytes;\n");
- sb.append(" this._offset = offset;\n");
- sb.append(nestedBytes);
- sb.append(" }\n");
- sb.append(" public Bytes bytes() {\n");
- sb.append(" return _bytes;\n");
- sb.append(" }\n");
- sb.append(" public int maxSize() {\n");
- sb.append(" return ").append(offset).append(";\n");
- sb.append(" }\n");
- generateObjectMethods(sb, dvmodel, entries);
+ sb.append(" @Override\n")
+ .append(" public void copyFrom(").append(normalize(dvmodel.type())).append(" from) {\n")
+ .append(copy)
+ .append(" }\n\n");
+ sb.append(" @Override\n")
+ .append(" public void writeMarshallable(Bytes out) {\n")
+ .append(writeMarshal)
+ .append(" }\n");
+ sb.append(" @Override\n")
+ .append(" public void readMarshallable(Bytes in) {\n")
+ .append(readMarshal)
+ .append(" }\n");
+ sb.append(" @Override\n")
+ .append(" public void bytes(Bytes bytes, long offset) {\n")
+ .append(" this._bytes = bytes;\n")
+ .append(" this._offset = offset;\n")
+ .append(nestedBytes)
+ .append(" }\n");
+ sb.append(" @Override\n")
+ .append(" public Bytes bytes() {\n")
+ .append(" return _bytes;\n")
+ .append(" }\n");
+ sb.append(" @Override\n")
+ .append(" public long offset() {\n")
+ .append(" return _offset;\n")
+ .append(" }\n");
+ sb.append(" @Override\n")
+ .append(" public int maxSize() {\n")
+ .append(" return ").append(offset).append(";\n")
+ .append(" }\n");
+
+ generateObjectMethods(sb, dvmodel, entries, true);
sb.append("}\n");
// System.out.println(sb);
return sb.toString();
@@ -480,4 +1027,167 @@ public class DataValueGenerator {
public void setDumpCode(boolean dumpCode) {
this.dumpCode = dumpCode;
}
+
+ private void methodSet(StringBuilder getterSetters, Method setter, Class type, String NAME, FieldModel model, boolean isVolatile) {
+ Class<?> setterType = setter.getParameterTypes()[setter.getParameterTypes().length - 1];
+ String write = "write";
+ if (isVolatile) write = "writeOrdered";
+ if (model.type() == Date.class) {
+ getterSetters.append("\n\n public void ").append(setter.getName()).append('(').append(normalize(setterType)).append(" $) {\n");
+ getterSetters.append(" _bytes.").append(write).append("Long").append("(").append(NAME).append(", ");
+ } else if(Enum.class.isAssignableFrom(type)){
+ getterSetters.append("\n\n public void ").append(setter.getName()).append('(').append(normalize(setterType)).append(" $) {\n");
+ getterSetters.append(" _bytes.").append(write).append("Enum").append("(");
+ } else if (!model.isArray()) {
+ getterSetters.append("\n\n public void ").append(setter.getName()).append('(').append(normalize(setterType)).append(" $) {\n");
+ getterSetters.append(" _bytes.").append(write).append(bytesType(type)).append("(").append(NAME).append(", ");
+
+ } else {
+ getterSetters.append(" public void ").append(setter.getName()).append("(int i, ");
+ getterSetters.append(normalize(setterType)).append(" $) {\n");
+ getterSetters.append(boundsCheck(model.indexSize().value()));
+ getterSetters.append(" _bytes.").append(write).append(bytesType(type)).append("(").append(NAME);
+ getterSetters.append(" + i * ").append((model.nativeSize() + 7) >> 3).append(", ");
+ }
+
+ if (CharSequence.class.isAssignableFrom(type))
+ getterSetters.append(model.size().value()).append(", ");
+
+ if (model.type() == Date.class) {
+ getterSetters.append("$.getTime());\n");
+ } else {
+ getterSetters.append("$);\n");
+ }
+ getterSetters.append(" }\n\n");
+ }
+ private void methodGet(StringBuilder getterSetters, Class type, String NAME, boolean isVolatile, String name) {
+ String read = "read";
+ if (isVolatile) read = "readVolatile";
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(name).append("() {\n");
+ getterSetters.append(" return _bytes.").append(read).append(bytesType(type)).append("(").append(NAME).append(");\n");
+ getterSetters.append(" }\n\n");
+ }
+
+ private void methodGet(StringBuilder getterSetters, Method getter, Class type, String NAME, FieldModel model, boolean isVolatile) {
+ String read = "read";
+ if (isVolatile) read = "readVolatile";
+
+ if(model.type() == Date.class){
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("() {\n");
+ getterSetters.append(" return new Date( _bytes.").append(read).append("Long").append("(").append(NAME).append("));\n");
+ } else if (Enum.class.isAssignableFrom(model.type())) {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("() {\n");
+ //getterSetters.append(" return _bytes.").append(read).append("Enum").append("(").append(NAME).append(");\n");
+ getterSetters.append(" return _bytes.").append(read).append("Enum").append("(").append(type.getName()).append(".class);\n");
+ } else if (!model.isArray()) {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("() {\n");
+ getterSetters.append(" return _bytes.").append(read).append(bytesType(type)).append("(").append(NAME).append(");\n");
+
+ } else {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("(int i) {\n");
+ getterSetters.append(boundsCheck(model.indexSize().value()));
+ getterSetters.append(" return _bytes.").append(read).append(bytesType(type)).append("(").append(NAME);
+ getterSetters.append(" + i * ").append((model.nativeSize() + 7) >> 3);
+ getterSetters.append(");\n");
+ }
+ getterSetters.append(" }\n\n");
+ }
+
+ private void methodNonScalarWriteMarshall(StringBuilder writeMarshal, String name, FieldModel model) {
+ if (!model.isArray()) {
+ writeMarshal.append(" _").append(name).append(".writeMarshallable(out);\n");
+
+ } else {
+ writeMarshal.append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++){\n");
+ writeMarshal.append(" _").append(name).append("[i].writeMarshallable(out);\n");
+ writeMarshal.append(" }\n");
+ }
+ }
+
+ private void methodReadMarshall(StringBuilder readMarshal, Method getter, Method setter, Class type, FieldModel model) {
+ if(model.type() == Date.class){
+ if (getter != null && setter != null)
+ readMarshal.append(" ").append(setter.getName()).append("((Date)in.read").append(bytesType(type)).append("());\n");
+ } else if (Enum.class.isAssignableFrom(model.type())) {
+ if (getter != null && setter != null)
+ readMarshal.append(" ").append(setter.getName()).append("(in.readEnum(" + model.type().getName() + ".class));\n");
+ } else if (!model.isArray()) {
+ if (getter != null && setter != null)
+ readMarshal.append(" ").append(setter.getName()).append("(in.read").append(bytesType(type)).append("());\n");
+
+ } else {
+ readMarshal.append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++){\n");
+ readMarshal.append(" ").append(setter.getName()).append("(i, in.read").append(bytesType(type)).append("());\n");
+ readMarshal.append(" }\n");
+ }
+ }
+
+ private void methodNonScalarReadMarshall(StringBuilder readMarshal, String name, FieldModel model) {
+ if (!model.isArray()) {
+ readMarshal.append(" _").append(name).append(".readMarshallable(in);\n");
+
+ } else {
+ readMarshal.append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++){\n");
+ readMarshal.append(" _").append(name).append("[i].readMarshallable(in);\n");
+ readMarshal.append(" }\n");
+ }
+ }
+
+ private void nonScalarFieldDeclaration(StringBuilder fieldDeclarations, Class type, String name, FieldModel model) {
+ fieldDeclarations.append(" private final ").append(type.getName()).append("$$Native _").append(name);
+ if (!model.isArray()) {
+ fieldDeclarations.append(" = new ").append(type.getName()).append("$$Native();\n");
+
+ } else {
+ fieldDeclarations.append("[] = new ").append(type.getName()).append("$$Native[").append(model.indexSize().value()).append("];\n");
+ fieldDeclarations.append(" {\n")
+ .append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++)\n")
+ .append(" _").append(name).append("[i] = new ").append(type.getName()).append("$$Native();\n")
+ .append(" }\n");
+ }
+ }
+
+ private void methodNonScalarSet(StringBuilder getterSetters, Method setter, String name, Class type, FieldModel model) {
+ Class<?> setterType = setter.getParameterTypes()[setter.getParameterTypes().length - 1];
+
+ if (!model.isArray()) {
+ getterSetters.append(" public void ").append(setter.getName()).append('(').append(normalize(setterType)).append(" $) {\n");
+ if (type == String.class && setterType != String.class)
+ getterSetters.append(" _").append(name).append(" = " + nullAwareToString("$") + ";\n");
+ else
+ getterSetters.append(" _").append(name).append(".copyFrom($);\n");
+
+ } else {
+ getterSetters.append(" public void ").append(setter.getName()).append("(int i, ").append(normalize(setterType)).append(" $) {\n");
+ if (type == String.class && setterType != String.class)
+ getterSetters.append(" _").append(name).append("[i] = " + nullAwareToString("$") + ";\n");
+ else
+ getterSetters.append(" _").append(name).append("[i].copyFrom($);\n");
+ }
+ getterSetters.append(" }\n\n");
+ }
+
+ private void methodNonScalarGet(StringBuilder getterSetters, Method getter, String name, Class type, FieldModel model) {
+ if (!model.isArray()) {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("() {\n");
+ getterSetters.append(" return _").append(name).append(";\n");
+
+ } else {
+ getterSetters.append(" public ").append(normalize(type)).append(' ').append(getter.getName()).append("(int i) {\n");
+ getterSetters.append(" return _").append(name).append("[i];\n");
+ }
+ getterSetters.append(" }\n\n");
+ }
+
+ private void methodNonScalarBytes(StringBuilder nestedBytes, String name, String NAME, int size, FieldModel model) {
+ if (!model.isArray()) {
+ nestedBytes.append(" ((Byteable) _").append(name).append(").bytes(bytes, ").append(NAME).append(");\n");
+
+ } else {
+ nestedBytes.append(" for (int i = 0; i < ").append(model.indexSize().value()).append("; i++){\n");
+ nestedBytes.append(" ((Byteable) _").append(name).append("[i]).bytes(bytes, ").append(NAME);
+ nestedBytes.append(" + (i * ").append(size).append("));\n");
+ nestedBytes.append(" }\n");
+ }
+ }
}
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueModel.java b/lang/src/main/java/net/openhft/lang/model/DataValueModel.java
index 23e1567..7528a73 100644
--- a/lang/src/main/java/net/openhft/lang/model/DataValueModel.java
+++ b/lang/src/main/java/net/openhft/lang/model/DataValueModel.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueModelImpl.java b/lang/src/main/java/net/openhft/lang/model/DataValueModelImpl.java
index bc5b03b..ad20852 100644..100755
--- a/lang/src/main/java/net/openhft/lang/model/DataValueModelImpl.java
+++ b/lang/src/main/java/net/openhft/lang/model/DataValueModelImpl.java
@@ -1,41 +1,43 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
import net.openhft.lang.io.serialization.BytesMarshallable;
import net.openhft.lang.model.constraints.Digits;
+import net.openhft.lang.model.constraints.Group;
import net.openhft.lang.model.constraints.MaxSize;
import net.openhft.lang.model.constraints.Range;
import java.io.Externalizable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+import static net.openhft.lang.MemoryUnit.BITS;
+import static net.openhft.lang.MemoryUnit.BYTES;
/**
- * User: peter.lawrey
- * Date: 06/10/13
- * Time: 17:23
+ * User: peter.lawrey Date: 06/10/13private static final int VALUE Time: 17:23
*/
public class DataValueModelImpl<T> implements DataValueModel<T> {
- static final Map<Class, Integer> HEAP_SIZE_MAP = new HashMap<Class, Integer>();
+ private static final Map<Class, Integer> HEAP_SIZE_MAP = new HashMap<Class, Integer>();
+ private static final String VOLATILE_GETTER_PREFIX = "volatile";
+ private static final java.lang.String ORDERED_SETTER_PREFIX = "ordered";
static {
HEAP_SIZE_MAP.put(boolean.class, 1);
@@ -46,6 +48,7 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
HEAP_SIZE_MAP.put(float.class, 32);
HEAP_SIZE_MAP.put(long.class, 64);
HEAP_SIZE_MAP.put(double.class, 64);
+ HEAP_SIZE_MAP.put(Date.class, 64);
}
private final Map<String, FieldModelImpl> fieldModelMap = new TreeMap<String, FieldModelImpl>();
@@ -54,6 +57,7 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
public DataValueModelImpl(Class<T> type) {
this.type = type;
+
if (!type.isInterface())
throw new IllegalArgumentException("type must be an interface, was " + type);
@@ -66,6 +70,11 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
|| declaringClass == Copyable.class
|| declaringClass == Byteable.class)
continue;
+
+ // ignore the default or static methods
+ if(isMethodDefaultOrStatic(method))
+ continue;
+
String name = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
final Class<?> returnType = method.getReturnType();
@@ -89,14 +98,38 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
fm.tryLock(method);
break;
}
+ String name6 = getSizeOf(name);
+ if (name6 != null && returnType == int.class) {
+ FieldModelImpl fm = acquireField(name6);
+ fm.sizeOf(method);
+ break;
+ }
if (returnType == void.class)
throw new IllegalArgumentException("void () not supported " + method);
+
String name2 = getGetter(name, returnType);
- FieldModelImpl fm = acquireField(name2);
- fm.getter(method);
+ if (isVolatileGetter(name2)) {
+ FieldModelImpl fm = acquireField(volatileGetterFieldName(name2));
+ fm.volatileGetter(method);
+ fm.setVolatile(true);
+
+ } else {
+ FieldModelImpl fm = acquireField(name2);
+ fm.getter(method);
+ }
+
break;
}
+
case 1: {
+
+ String name7 = getUsing(name, method);
+ if (name7 != null) {
+ FieldModelImpl fm = acquireField(name7);
+ fm.getUsing(method);
+ break;
+ }
+
String name5 = getTryLockNanos(name);
if (name5 != null && returnType == boolean.class) {
FieldModelImpl fm = acquireField(name5);
@@ -118,20 +151,35 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
break;
}
- String name6 = getGetter(name, returnType);
+ String name6 = getGetterAt(name, returnType);
if (name6 != null && parameterTypes[0] == int.class && returnType != void.class) {
- FieldModelImpl fm = acquireField(name6);
- fm.indexedGetter(method);
+ if (isVolatileGetter(name6)) {
+ FieldModelImpl fm = acquireField(volatileGetterFieldName(name6));
+ fm.volatileIndexedGetter(method);
+ fm.setVolatile(true);
+
+ } else {
+ FieldModelImpl fm = acquireField(name6);
+ fm.indexedGetter(method);
+ }
break;
}
if (returnType != void.class)
throw new IllegalArgumentException("setter must be void " + method);
+
String name2 = getSetter(name);
- FieldModelImpl fm = acquireField(name2);
- fm.setter(method);
+ if (isOrderedSetter(name2)) {
+ FieldModelImpl fm = acquireField(orderedSetterFieldName(name2));
+ fm.orderedSetter(method);
+
+ } else {
+ FieldModelImpl fm = acquireField(name2);
+ fm.setter(method);
+ }
break;
}
+
case 2: {
String name2 = getCAS(name);
if (name2 != null && returnType == boolean.class) {
@@ -139,29 +187,53 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
fm.cas(method);
break;
}
- String name3 = getSetter(name);
+ String name3 = getSetterAt(name);
if (name3 != null && parameterTypes[0] == int.class && returnType == void.class) {
- FieldModelImpl fm = acquireField(name3);
- fm.indexedSetter(method);
+ if (isOrderedSetter(name3)) {
+ FieldModelImpl fm = acquireField(orderedSetterFieldName(name3));
+ fm.orderedIndexedSetter(method);
+
+ } else {
+ FieldModelImpl fm = acquireField(name3);
+ fm.indexedSetter(method);
+ }
break;
}
}
+
default: {
throw new IllegalArgumentException("method not supported " + method);
}
}
}
+
for (Map.Entry<String, FieldModelImpl> entry : fieldModelMap.entrySet()) {
FieldModelImpl model = entry.getValue();
- if (model.getter() == null || (model.setter() == null && model.getter().getReturnType().isPrimitive()))
- if (model.indexedGetter() == null || (model.indexedSetter() == null && model.indexedGetter().getReturnType().isPrimitive()))
- throw new IllegalArgumentException("Field " + entry.getKey() + " must have a getter and setter.");
+ if ((model.getter() == null && model.getUsing() == null) || (model.setter() == null && model
+ .getter()
+ .getReturnType()
+ .isPrimitive()))
+ if (model.volatileGetter() == null || (model.orderedSetter() == null && model.volatileGetter().getReturnType().isPrimitive()))
+ if (model.indexedGetter() == null || (model.indexedSetter() == null && model.indexedGetter().getReturnType().isPrimitive()))
+ if (model.volatileIndexedGetter() == null || (model.orderedIndexedSetter() == null && model.volatileIndexedGetter().getReturnType().isPrimitive()))
+ if (model.busyLock() == null || model.unlock() == null)
+ throw new IllegalArgumentException("Field " + entry.getKey() + " must have a getter & setter, or getAt & setAt, or busyLock & unlock.");
+ if (model.indexedGetter() != null || model.indexedSetter() != null)
+ if (model.indexSize() == null)
+ throw new IllegalStateException("You must set a MaxSize for the range of the index for the getter or setter");
+
Class ftype = model.type();
if (!isScalar(ftype) && !nestedMap.containsKey(ftype))
nestedMap.put(ftype, new DataValueModelImpl(ftype));
}
}
+ public static int heapSize(Class primitiveType) {
+ if (!primitiveType.isPrimitive())
+ throw new IllegalArgumentException();
+ return (int) BYTES.alignAndConvert(HEAP_SIZE_MAP.get(primitiveType), BITS);
+ }
+
private static String getCAS(String name) {
final int len = 14;
if (name.length() > len && name.startsWith("compareAndSwap") && Character.isUpperCase(name.charAt(len)))
@@ -169,6 +241,13 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
return null;
}
+ private static String getSizeOf(String name) {
+ final int len = 6;
+ if (name.length() > len && name.startsWith("sizeOf") && Character.isUpperCase(name.charAt(len)))
+ return Character.toLowerCase(name.charAt(len)) + name.substring(len + 1);
+ return null;
+ }
+
private static String getAtomicAdder(String name) {
final int len = 9;
if (name.length() > len && name.startsWith("addAtomic") && Character.isUpperCase(name.charAt(len)))
@@ -190,6 +269,15 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
return name;
}
+ private static String getSetterAt(String name) {
+ final int len = 3;
+ final int len2 = 2;
+ if (name.length() > len + len2 && name.startsWith("set") && Character.isUpperCase(
+ name.charAt(len)) && name.endsWith("At"))
+ return Character.toLowerCase(name.charAt(len)) + name.substring(len + 1, name.length() - len2);
+ return name;
+ }
+
private static String getGetter(String name, Class returnType) {
if (name.length() > 3 && name.startsWith("get") && Character.isUpperCase(name.charAt(3)))
return Character.toLowerCase(name.charAt(3)) + name.substring(4);
@@ -199,34 +287,82 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
return name;
}
- private String getBusyLock(String name) {
+ private static String getUsing(String name, Method method) {
+ Class<?> returnType = method.getReturnType();
+ if (method.getParameterTypes().length != 1)
+ return null;
+
+ Class<?> parameter = method.getParameterTypes()[0];
+
+ if ((returnType == StringBuilder.class || returnType == void.class) && parameter ==
+ StringBuilder.class &&
+ name.length() > "getUsing".length() && name.startsWith
+ ("getUsing") && Character.isUpperCase(name.charAt("getUsing".length())))
+ return Character.toLowerCase(name.charAt("getUsing".length())) + name.substring("getUsing"
+ .length() + 1);
+ return null;
+ }
+
+ private static String getGetterAt(String name, Class returnType) {
+ final int len = 3;
+ final int len2 = 2;
+ if (name.length() > len + len2 && name.startsWith("get") && Character.isUpperCase(
+ name.charAt(len)) && name.endsWith("At"))
+ return Character.toLowerCase(name.charAt(len)) + name.substring(4, name.length() - len2);
+ return name;
+ }
+
+ private static String getBusyLock(String name) {
final int len = 8;
if (name.length() > len && name.startsWith("busyLock") && Character.isUpperCase(name.charAt(len)))
return Character.toLowerCase(name.charAt(len)) + name.substring(len + 1);
return null;
}
- private String getUnlock(String name) {
+ private static String getUnlock(String name) {
final int len = 6;
if (name.length() > len && name.startsWith("unlock") && Character.isUpperCase(name.charAt(len)))
return Character.toLowerCase(name.charAt(len)) + name.substring(len + 1);
return null;
}
- private String getTryLockNanos(String name) {
+ private static String getTryLockNanos(String name) {
final int len = 12;
if (name.length() > len && name.startsWith("tryLockNanos") && Character.isUpperCase(name.charAt(len)))
return Character.toLowerCase(name.charAt(len)) + name.substring(len + 1);
return null;
}
- private String getTryLock(String name) {
+ private static String getTryLock(String name) {
final int len = 7;
if (name.length() > len && name.startsWith("tryLock") && Character.isUpperCase(name.charAt(len)))
return Character.toLowerCase(name.charAt(len)) + name.substring(len + 1);
return null;
}
+ public boolean isMethodDefaultOrStatic(Method method) {
+ return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC)) ==
+ Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
+ }
+
+ private boolean isOrderedSetter(String name2) {
+ return name2.startsWith(ORDERED_SETTER_PREFIX) ? true : false;
+ }
+
+ private boolean isVolatileGetter(String name2) {
+ return name2.startsWith(VOLATILE_GETTER_PREFIX) ? true : false;
+ }
+
+ private String volatileGetterFieldName(String name) {
+ name = name.substring(VOLATILE_GETTER_PREFIX.length());
+ return Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ }
+
+ private String orderedSetterFieldName(String name) {
+ name = name.substring(ORDERED_SETTER_PREFIX.length());
+ return Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ }
+
private FieldModelImpl acquireField(String name) {
FieldModelImpl fieldModelImpl = fieldModelMap.get(name);
if (fieldModelImpl == null)
@@ -241,7 +377,7 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
}
public boolean isScalar(Class type) {
- return type.isPrimitive() || CharSequence.class.isAssignableFrom(type);
+ return type.isPrimitive() || CharSequence.class.isAssignableFrom(type) || Enum.class.isAssignableFrom(type) || Date.class == type;
}
@Override
@@ -265,19 +401,28 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
private final String name;
private Method getter, setter;
+ private Method volatileGetter;
+ private Method orderedSetter;
private Digits digits;
private Range range;
private MaxSize maxSize;
+ private Group group;
private MaxSize indexSize;
private Method adder;
private Method atomicAdder;
+ private Method getUsing;
private Method cas;
private Method tryLockNanos;
private Method tryLock;
private Method busyLock;
private Method unlock;
- private Method indexedGetter;
- private Method indexedSetter;
+ private Method getterAt;
+ private Method setterAt;
+ private Method volatileGetterAt;
+ private Method orderedSetterAt;
+ private Method sizeOf;
+ private boolean isArray = false;
+ private boolean isVolatile = false;
public FieldModelImpl(String name) {
this.name = name;
@@ -287,6 +432,20 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
return name;
}
+ public boolean isArray() {
+ return isArray;
+ }
+
+ @Override
+ public boolean isVolatile() {
+ return isVolatile;
+ }
+
+ @Override
+ public void setVolatile(boolean isVolatile) {
+ this.isVolatile = isVolatile;
+ }
+
public void getter(Method getter) {
this.getter = getter;
}
@@ -305,16 +464,54 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
if (a instanceof MaxSize)
maxSize = (MaxSize) a;
}
- }
+ for (Annotation a : setter.getAnnotations()) {
+ if (a instanceof Group)
+ group = (Group) a;
+ }
+ }
public Method setter() {
return setter;
}
+ public void volatileGetter(Method volatileGetter) {
+ this.volatileGetter = volatileGetter;
+ }
+
+ public Method volatileGetter() {
+ return volatileGetter;
+ }
+
+ public void orderedSetter(Method orderedSetter) {
+ this.orderedSetter = orderedSetter;
+ for (Annotation a : orderedSetter.getParameterAnnotations()[0]) {
+ if (a instanceof Digits)
+ digits = (Digits) a;
+ if (a instanceof Range)
+ range = (Range) a;
+ if (a instanceof MaxSize)
+ maxSize = (MaxSize) a;
+ }
+
+ for (Annotation a : orderedSetter.getAnnotations()) {
+ if (a instanceof Group)
+ group = (Group) a;
+ }
+ }
+
+ public Method orderedSetter() {
+ return orderedSetter;
+ }
+
@Override
public Class<T> type() {
return (Class<T>) (getter != null ? getter.getReturnType() :
- indexedGetter != null ? indexedGetter.getReturnType() : null);
+ volatileGetter != null ? volatileGetter.getReturnType() :
+ getterAt != null ? getterAt.getReturnType() :
+ volatileGetterAt != null ? volatileGetterAt.getReturnType() :
+ unlock != null ? int.class :
+ setter != null && setter.getParameterTypes().length == 1 ?
+ setter.getParameterTypes()[0] : null);
}
public void adder(Method method) {
@@ -338,10 +535,7 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
Integer size = HEAP_SIZE_MAP.get(type());
if (size != null)
return size;
- MaxSize maxSize2 = size();
- if (maxSize2 == null)
- throw new AssertionError(type() + " without a @MaxSize not supported for native types");
- return maxSize2.value() << 3;
+ return size().value() << 3;
}
@Override
@@ -356,19 +550,27 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
@Override
public MaxSize size() {
+ if (maxSize == null)
+ throw new IllegalStateException("Field " + name + " is missing @MaxSize on the setter");
return maxSize;
}
@Override
+ public Group group() {
+ return group;
+ }
+
+ @Override
public String toString() {
return "FieldModel{" +
"name='" + name + '\'' +
- ", getter=" + (indexedGetter != null ? indexedGetter : getter) +
- ", setter=" + (indexedSetter != null ? indexedSetter : setter) +
+ ", getter=" + (getterAt != null ? getterAt : getter) +
+ ", setter=" + (setterAt != null ? setterAt : setter) +
+ (unlock == null ? "" : ", busyLock=" + busyLock + ", tryLock=" + tryLock + ", unlock=" + unlock) +
(digits == null ? "" : ", digits= " + digits) +
(range == null ? "" : ", range= " + range) +
(maxSize == null ? "" : ", size= " + maxSize) +
- ((indexedGetter == null && indexedSetter == null) ? "" : ", indexSize= " + indexSize) +
+ ((getterAt == null && setterAt == null) ? "" : ", indexSize= " + indexSize.toString().replace("@net.openhft.lang.model.constraints.", "")) +
'}';
}
@@ -376,6 +578,10 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
atomicAdder = method;
}
+ public void getUsing(Method method) {
+ getUsing = method;
+ }
+
public Method atomicAdder() {
return atomicAdder;
}
@@ -388,6 +594,14 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
return cas;
}
+ public void sizeOf(Method method) {
+ sizeOf = method;
+ }
+
+ public Method sizeOf() {
+ return sizeOf;
+ }
+
public void tryLockNanos(Method method) {
tryLockNanos = method;
}
@@ -430,21 +644,28 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
}
public void indexedGetter(Method indexedGetter) {
- this.indexedGetter = indexedGetter;
+ isArray = true;
+ this.getterAt = indexedGetter;
indexAnnotations(indexedGetter);
}
public Method indexedGetter() {
- return indexedGetter;
+ return getterAt;
}
public void indexedSetter(Method indexedSetter) {
- this.indexedSetter = indexedSetter;
+ isArray = true;
+ this.setterAt = indexedSetter;
indexAnnotations(indexedSetter);
}
+ public Method indexedSetter() {
+ return setterAt;
+ }
+
public void indexAnnotations(Method method) {
- for (Annotation a : method.getParameterAnnotations()[0]) {
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ for (Annotation a : parameterAnnotations[0]) {
// if (a instanceof Digits)
// digits = (Digits) a;
// if (a instanceof Range)
@@ -452,10 +673,41 @@ public class DataValueModelImpl<T> implements DataValueModel<T> {
if (a instanceof MaxSize)
indexSize = (MaxSize) a;
}
+ if( parameterAnnotations.length > 1 ) {
+ for (Annotation a : parameterAnnotations[1]) {
+ if (a instanceof Digits)
+ digits = (Digits) a;
+ if (a instanceof Range)
+ range = (Range) a;
+ if (a instanceof MaxSize)
+ maxSize = (MaxSize) a;
+ }
+ }
}
- public Method indexedSetter() {
- return indexedSetter;
+ public void volatileIndexedGetter(Method volatileIndexedGetter) {
+ isArray = true;
+ this.volatileGetterAt = volatileIndexedGetter;
+ indexAnnotations(volatileIndexedGetter);
+ }
+
+ public Method volatileIndexedGetter() {
+ return volatileGetterAt;
+ }
+
+ public void orderedIndexedSetter(Method orderedIndexedSetter) {
+ isArray = true;
+ this.orderedSetterAt = orderedIndexedSetter;
+ indexAnnotations(orderedIndexedSetter);
+ }
+
+ public Method orderedIndexedSetter() {
+ return orderedSetterAt;
+ }
+
+ @Override
+ public Method getUsing() {
+ return getUsing;
}
}
}
diff --git a/lang/src/main/java/net/openhft/lang/model/DataValueModels.java b/lang/src/main/java/net/openhft/lang/model/DataValueModels.java
index bda9620..36c229b 100644..100755
--- a/lang/src/main/java/net/openhft/lang/model/DataValueModels.java
+++ b/lang/src/main/java/net/openhft/lang/model/DataValueModels.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
@@ -28,20 +28,22 @@ public enum DataValueModels {
;
private static final Map<Class, DataValueModel> MODEL_MAP = new WeakHashMap<Class, DataValueModel>();
- public static synchronized <T> DataValueModel<T> getModel(Class<T> tClass) {
+ private static synchronized <T> DataValueModel<T> getModel(Class<T> tClass) {
return MODEL_MAP.get(tClass);
}
- public static synchronized <T> void putModel(Class<T> tClass, DataValueModel<T> model) {
+ private static synchronized <T> void putModel(Class<T> tClass, DataValueModel<T> model) {
MODEL_MAP.put(tClass, model);
}
public static <T> DataValueModel<T> acquireModel(Class<T> tClass) {
+ if (!tClass.isInterface() || tClass.getClassLoader() == null)
+ throw new IllegalArgumentException(tClass + " not supported");
DataValueModel<T> model = getModel(tClass);
- if (model == null) {
- model = new DataValueModelImpl<T>(tClass);
- putModel(tClass, model);
- }
+ if (model == null) {
+ model = new DataValueModelImpl<T>(tClass);
+ putModel(tClass, model);
+ }
return model;
}
}
diff --git a/lang/src/main/java/net/openhft/lang/model/FieldModel.java b/lang/src/main/java/net/openhft/lang/model/FieldModel.java
index 33869d0..d5caec4 100644
--- a/lang/src/main/java/net/openhft/lang/model/FieldModel.java
+++ b/lang/src/main/java/net/openhft/lang/model/FieldModel.java
@@ -1,22 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
import net.openhft.lang.model.constraints.Digits;
+import net.openhft.lang.model.constraints.Group;
import net.openhft.lang.model.constraints.MaxSize;
import net.openhft.lang.model.constraints.Range;
@@ -34,6 +35,20 @@ public interface FieldModel<T> {
Method setter();
+ Method indexedGetter();
+
+ Method indexedSetter();
+
+ Method volatileGetter();
+
+ Method orderedSetter();
+
+ Method volatileIndexedGetter();
+
+ Method orderedIndexedSetter();
+
+ Method getUsing();
+
Method adder();
Method atomicAdder();
@@ -48,6 +63,8 @@ public interface FieldModel<T> {
Method unlock();
+ Method sizeOf();
+
Class<T> type();
int heapSize();
@@ -59,4 +76,14 @@ public interface FieldModel<T> {
Range range();
MaxSize size();
+
+ MaxSize indexSize();
+
+ boolean isArray();
+
+ boolean isVolatile();
+
+ void setVolatile(boolean isVolatile);
+
+ Group group();
}
diff --git a/lang/src/main/java/net/openhft/lang/model/HeapCodeGenerator.java b/lang/src/main/java/net/openhft/lang/model/HeapCodeGenerator.java
index 78886a4..b7cea1b 100644
--- a/lang/src/main/java/net/openhft/lang/model/HeapCodeGenerator.java
+++ b/lang/src/main/java/net/openhft/lang/model/HeapCodeGenerator.java
@@ -1,22 +1,22 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
-public enum HeapCodeGenerator implements CodeGenerator {
+enum HeapCodeGenerator implements CodeGenerator {
/* GET_VALUE {
public void addCode(CodeModel codeModel, Method method) {
StringBuilder sb = codeModel.acquireMethod()
diff --git a/lang/src/main/java/net/openhft/lang/model/Out.java b/lang/src/main/java/net/openhft/lang/model/Out.java
new file mode 100644
index 0000000..33db327
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/model/Out.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+/**
+ * The annotation indicates the argument can be mutated. In general, arguments should not be mutated.
+ */
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+@Documented
+@Retention(CLASS)
+@Target({PARAMETER})
+public @interface Out {
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/constraints/Digits.java b/lang/src/main/java/net/openhft/lang/model/constraints/Digits.java
index 4a1b1ee..4f76904 100644
--- a/lang/src/main/java/net/openhft/lang/model/constraints/Digits.java
+++ b/lang/src/main/java/net/openhft/lang/model/constraints/Digits.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model.constraints;
diff --git a/lang/src/main/java/net/openhft/lang/model/constraints/Group.java b/lang/src/main/java/net/openhft/lang/model/constraints/Group.java
new file mode 100644
index 0000000..caff68b
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/model/constraints/Group.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model.constraints;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Changes the serialization order fields.
+ * Multiple fields can be in the same group and these will be ordered with the smallest first.
+ * If you don't provided a group this is considered to be the top most group.
+ */
+@Target(METHOD)
+@Retention(RUNTIME)
+@Documented
+public @interface Group {
+ int value() default Integer.MIN_VALUE;
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/constraints/MaxSize.java b/lang/src/main/java/net/openhft/lang/model/constraints/MaxSize.java
index 4ca6c4a..9ec653f 100644
--- a/lang/src/main/java/net/openhft/lang/model/constraints/MaxSize.java
+++ b/lang/src/main/java/net/openhft/lang/model/constraints/MaxSize.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model.constraints;
diff --git a/lang/src/main/java/net/openhft/lang/model/constraints/NotNull.java b/lang/src/main/java/net/openhft/lang/model/constraints/NotNull.java
new file mode 100644
index 0000000..7706695
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/model/constraints/NotNull.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model.constraints;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+@Documented
+@Retention(CLASS)
+@Target({METHOD, FIELD, PARAMETER, LOCAL_VARIABLE})
+public @interface NotNull {
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/constraints/Nullable.java b/lang/src/main/java/net/openhft/lang/model/constraints/Nullable.java
new file mode 100644
index 0000000..e3dd1ed
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/model/constraints/Nullable.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model.constraints;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+@Documented
+@Retention(CLASS)
+@Target({METHOD, FIELD, PARAMETER, LOCAL_VARIABLE})
+public @interface Nullable {
+}
diff --git a/lang/src/main/java/net/openhft/lang/model/constraints/Range.java b/lang/src/main/java/net/openhft/lang/model/constraints/Range.java
index 2e99420..ddc2516 100644
--- a/lang/src/main/java/net/openhft/lang/model/constraints/Range.java
+++ b/lang/src/main/java/net/openhft/lang/model/constraints/Range.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model.constraints;
diff --git a/lang/src/main/java/net/openhft/lang/pool/CharSequenceInterner.java b/lang/src/main/java/net/openhft/lang/pool/CharSequenceInterner.java
new file mode 100644
index 0000000..9c159fa
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/pool/CharSequenceInterner.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.pool;
+
+import net.openhft.lang.model.constraints.NotNull;
+
+public interface CharSequenceInterner<S> {
+ @NotNull
+ S intern(@NotNull CharSequence cs);
+}
diff --git a/lang/src/main/java/net/openhft/lang/pool/EnumInterner.java b/lang/src/main/java/net/openhft/lang/pool/EnumInterner.java
new file mode 100644
index 0000000..88ae332
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/pool/EnumInterner.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.pool;
+
+import net.openhft.lang.Maths;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
+
+/**
+ * @author peter.lawrey
+ */
+public class EnumInterner<E extends Enum<E>> implements CharSequenceInterner<Enum<E>> {
+ private static final ClassValue<EnumInterner> internerForClass = new ClassValue<EnumInterner>() {
+ @Override
+ protected EnumInterner computeValue(Class<?> type) {
+ return new EnumInterner(type);
+ }
+ };
+ private final Enum<E>[] interner;
+ private final int mask;
+ private final Class<E> enumType;
+
+ private EnumInterner(Class<E> enumType) {
+ this.enumType = enumType;
+ int n = 128;
+ interner = (Enum<E>[]) new Enum[n];
+ mask = n - 1;
+ }
+
+ public static <T extends Enum<T>> T intern(Class<T> enumType, CharSequence cs) {
+ return (T) internerForClass.get(enumType).intern(cs);
+ }
+
+ public static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) {
+ if (s == null) return false;
+ if (s.length() != cs.length()) return false;
+ for (int i = 0; i < cs.length(); i++)
+ if (s.charAt(i) != cs.charAt(i))
+ return false;
+ return true;
+ }
+
+ @Override
+ @NotNull
+ public Enum<E> intern(@NotNull CharSequence cs) {
+ long hash = 0;
+ for (int i = 0; i < cs.length(); i++)
+ hash = 57 * hash + cs.charAt(i);
+ int h = (int) Maths.hash(hash) & mask;
+ Enum<E> e = interner[h];
+ if (e != null && isEqual(e.name(), cs))
+ return e;
+ String s2 = cs.toString();
+ return interner[h] = Enum.valueOf(enumType, s2);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/pool/StringInterner.java b/lang/src/main/java/net/openhft/lang/pool/StringInterner.java
index 3796bc0..b8e2501 100755..100644
--- a/lang/src/main/java/net/openhft/lang/pool/StringInterner.java
+++ b/lang/src/main/java/net/openhft/lang/pool/StringInterner.java
@@ -1,30 +1,29 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.pool;
import net.openhft.lang.Maths;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import net.openhft.lang.model.constraints.NotNull;
+import net.openhft.lang.model.constraints.Nullable;
/**
* @author peter.lawrey
*/
-public class StringInterner {
- @NotNull
+public class StringInterner implements CharSequenceInterner<String> {
private final String[] interner;
private final int mask;
@@ -34,7 +33,7 @@ public class StringInterner {
mask = n - 1;
}
- private static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) {
+ public static boolean isEqual(@Nullable CharSequence s, @NotNull CharSequence cs) {
if (s == null) return false;
if (s.length() != cs.length()) return false;
for (int i = 0; i < cs.length(); i++)
@@ -43,32 +42,13 @@ public class StringInterner {
return true;
}
-/* private static boolean isEqual(@Nullable CharSequence s, @NotNull byte[] bytes, int off, int len) {
- if (s == null) return false;
- if (s.length() != len) return false;
- for (int i = 0; i < len; i++)
- if (s.charAt(i) != (bytes[off + i] & 0xFF))
- return false;
- return true;
- }
-
- @NotNull
- public String intern(@NotNull byte[] bytes, int off, int len) {
- long hash = NativeBytes.longHash(bytes, off, len);
- int h = Maths.hash(hash) & mask;
- String s = interner[h];
- if (isEqual(s, bytes, off, len))
- return s;
- String s2 = new String(bytes, off, len, IOTools.ISO_8859_1);
- return interner[h] = s2;
- }*/
-
+ @Override
@NotNull
public String intern(@NotNull CharSequence cs) {
long hash = 0;
for (int i = 0; i < cs.length(); i++)
hash = 57 * hash + cs.charAt(i);
- int h = Maths.hash(hash) & mask;
+ int h = (int) Maths.hash(hash) & mask;
String s = interner[h];
if (isEqual(s, cs))
return s;
diff --git a/lang/src/main/java/net/openhft/lang/testing/Differencer.java b/lang/src/main/java/net/openhft/lang/testing/Differencer.java
index 29d44f1..5fcae8b 100644
--- a/lang/src/main/java/net/openhft/lang/testing/Differencer.java
+++ b/lang/src/main/java/net/openhft/lang/testing/Differencer.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.testing;
@@ -21,6 +21,6 @@ package net.openhft.lang.testing;
* Date: 05/08/13
* Time: 19:06
*/
-public interface Differencer {
+interface Differencer {
long sample(long startTime, long endTime);
}
diff --git a/lang/src/main/java/net/openhft/lang/testing/RunningMinimum.java b/lang/src/main/java/net/openhft/lang/testing/RunningMinimum.java
index 983f114..8b3e59b 100644
--- a/lang/src/main/java/net/openhft/lang/testing/RunningMinimum.java
+++ b/lang/src/main/java/net/openhft/lang/testing/RunningMinimum.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.testing;
@@ -31,7 +31,7 @@ public class RunningMinimum implements Differencer {
this(actualMinimum, 100 * 1000);
}
- public RunningMinimum(long actualMinimum, int drift) {
+ private RunningMinimum(long actualMinimum, int drift) {
this.actualMinimum = actualMinimum;
this.drift = drift;
}
diff --git a/lang/src/main/java/net/openhft/lang/testing/VanillaDifferencer.java b/lang/src/main/java/net/openhft/lang/testing/VanillaDifferencer.java
index 3853861..a14a934 100644
--- a/lang/src/main/java/net/openhft/lang/testing/VanillaDifferencer.java
+++ b/lang/src/main/java/net/openhft/lang/testing/VanillaDifferencer.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.testing;
diff --git a/lang/src/main/java/net/openhft/lang/thread/BusyPauser.java b/lang/src/main/java/net/openhft/lang/thread/BusyPauser.java
new file mode 100755
index 0000000..ad5872c
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/thread/BusyPauser.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.thread;
+
+/**
+ * Created by peter.lawrey on 11/12/14.
+ */
+public enum BusyPauser implements Pauser {
+ INSTANCE;
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void pause(long maxPauseNS) {
+ }
+
+ @Override
+ public void unpause() {
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/thread/LightPauser.java b/lang/src/main/java/net/openhft/lang/thread/LightPauser.java
new file mode 100755
index 0000000..ae6142d
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/thread/LightPauser.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.thread;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * Created by peter.lawrey on 11/12/14.
+ */
+public class LightPauser implements Pauser {
+ public static final long NO_BUSY_PERIOD = -1;
+ public static final long NO_PAUSE_PERIOD = -1;
+ private final AtomicBoolean pausing = new AtomicBoolean();
+ private final long busyPeriodNS;
+ private final long parkPeriodNS;
+ private int count;
+ private long pauseStart = 0;
+ private volatile Thread thread;
+
+ public LightPauser(long busyPeriodNS, long parkPeriodNS) {
+ this.busyPeriodNS = busyPeriodNS;
+ this.parkPeriodNS = parkPeriodNS;
+ }
+
+ @Override
+ public void reset() {
+ pauseStart = count = 0;
+ }
+
+ @Override
+ public void pause() {
+ pause(parkPeriodNS);
+ }
+
+ public void pause(long maxPauseNS) {
+ if (busyPeriodNS > 0) {
+ if (count++ < 1000)
+ return;
+ if (pauseStart == 0) {
+ pauseStart = System.nanoTime();
+ return;
+ }
+ if (System.nanoTime() < pauseStart + busyPeriodNS)
+ return;
+ }
+ if (maxPauseNS < 10000)
+ return;
+ thread = Thread.currentThread();
+ pausing.set(true);
+ doPause(maxPauseNS);
+ pausing.set(false);
+ reset();
+ }
+
+ protected void doPause(long maxPauseNS) {
+ LockSupport.parkNanos(Math.max(maxPauseNS, parkPeriodNS));
+ }
+
+ @Override
+ public void unpause() {
+ if (pausing.get())
+ LockSupport.unpark(thread);
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/thread/NamedThreadFactory.java b/lang/src/main/java/net/openhft/lang/thread/NamedThreadFactory.java
index fc9895e..5c8c7a7 100644
--- a/lang/src/main/java/net/openhft/lang/thread/NamedThreadFactory.java
+++ b/lang/src/main/java/net/openhft/lang/thread/NamedThreadFactory.java
@@ -1,22 +1,22 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.thread;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
diff --git a/lang/src/main/java/net/openhft/lang/thread/Pauser.java b/lang/src/main/java/net/openhft/lang/thread/Pauser.java
new file mode 100755
index 0000000..13f954c
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/thread/Pauser.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.thread;
+
+/**
+ * Created by peter.lawrey on 11/12/14.
+ */
+public interface Pauser {
+ void reset();
+
+ void pause();
+
+ void pause(long maxPauseNS);
+
+ void unpause();
+}
diff --git a/lang/src/main/java/net/openhft/lang/threadlocal/Provider.java b/lang/src/main/java/net/openhft/lang/threadlocal/Provider.java
new file mode 100644
index 0000000..ce9de09
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/threadlocal/Provider.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.threadlocal;
+
+public abstract class Provider<T> {
+
+ public static <T> Provider<T> of(Class<T> tClass) {
+ if (StatefulCopyable.class.isAssignableFrom(tClass)) {
+ return StatefulProvider.INSTANCE;
+ }
+ return StatelessProvider.INSTANCE;
+ }
+
+ public abstract T get(ThreadLocalCopies copies, T original);
+
+ public abstract ThreadLocalCopies getCopies(ThreadLocalCopies copies);
+
+ private static final class StatefulProvider<T extends StatefulCopyable<T>> extends Provider<T> {
+ private static final Provider INSTANCE = new StatefulProvider();
+
+ @Override
+ public ThreadLocalCopies getCopies(ThreadLocalCopies copies) {
+ if (copies != null)
+ return copies;
+ return ThreadLocalCopies.get();
+ }
+
+ @Override
+ public T get(ThreadLocalCopies copies, T original) {
+ return get(copies, original, true);
+ }
+
+ private T get(ThreadLocalCopies copies, T original, boolean syncPut) {
+ Object id = original.stateIdentity();
+ int m = copies.mask;
+ Object[] tab = copies.table;
+ int i = System.identityHashCode(id) & m;
+ while (true) {
+ Object idInTable = tab[i];
+ if (idInTable == id) {
+ return (T) tab[i + 1];
+
+ } else if (idInTable == null) {
+ if (syncPut) {
+ if (copies.currentlyAccessed.compareAndSet(false, true)) {
+ try {
+ return get(copies, original, false);
+ } finally {
+ copies.currentlyAccessed.set(false);
+ }
+ } else {
+ throw new IllegalStateException("Concurrent or recursive access " +
+ "to ThreadLocalCopies is not allowed");
+ }
+ } else {
+ // actual put
+ tab[i] = id;
+ T copy;
+ tab[i + 1] = copy = original.copy();
+ copies.postInsert();
+ return copy;
+ }
+ }
+ i = (i + 2) & m;
+ }
+ }
+ }
+
+ private static final class StatelessProvider<M> extends Provider<M> {
+ private static final Provider INSTANCE = new StatelessProvider();
+
+ @Override
+ public M get(ThreadLocalCopies copies, M original) {
+ return original;
+ }
+
+ @Override
+ public ThreadLocalCopies getCopies(ThreadLocalCopies copies) {
+ return copies;
+ }
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/threadlocal/StatefulCopyable.java b/lang/src/main/java/net/openhft/lang/threadlocal/StatefulCopyable.java
new file mode 100644
index 0000000..65f6371
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/threadlocal/StatefulCopyable.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.threadlocal;
+
+public interface StatefulCopyable<S extends StatefulCopyable<S>> {
+ Object stateIdentity();
+
+ S copy();
+}
diff --git a/lang/src/main/java/net/openhft/lang/threadlocal/ThreadLocalCopies.java b/lang/src/main/java/net/openhft/lang/threadlocal/ThreadLocalCopies.java
new file mode 100644
index 0000000..7d949ea
--- /dev/null
+++ b/lang/src/main/java/net/openhft/lang/threadlocal/ThreadLocalCopies.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.threadlocal;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public final class ThreadLocalCopies {
+
+ private static ThreadLocal<ThreadLocalCopies> states = new ThreadLocal<ThreadLocalCopies>() {
+ @Override
+ protected ThreadLocalCopies initialValue() {
+ return new ThreadLocalCopies();
+ }
+ };
+
+ public static ThreadLocalCopies get() {
+ return states.get();
+ }
+
+ final AtomicBoolean currentlyAccessed = new AtomicBoolean(false);
+ Object[] table;
+ int size = 0, sizeLimit, mask;
+
+ public ThreadLocalCopies() {
+ init(32); // 16 entries
+ }
+
+ void init(int doubledCapacity) {
+ table = new Object[doubledCapacity];
+ sizeLimit = doubledCapacity / 3; // 0.66 fullness
+ mask = (doubledCapacity - 1) & ~1;
+ }
+
+ void rehash() {
+ Object[] oldTab = this.table;
+ int oldCapacity = oldTab.length;
+ if (oldCapacity == (1 << 30))
+ throw new IllegalStateException("Hash is full");
+ init(oldCapacity << 1);
+ int m = mask;
+ Object[] tab = this.table;
+ for (int oldI = 0; oldI < oldCapacity; oldI += 2) {
+ Object id = oldTab[oldI];
+ if (id != null) {
+ int i = System.identityHashCode(id) & m;
+ while (tab[i] != null) {
+ i = (i + 2) & m;
+ }
+ tab[i] = id;
+ tab[i + 1] = oldTab[oldI + 1];
+ }
+ }
+ }
+
+ void postInsert() {
+ if (++size > sizeLimit)
+ rehash();
+ }
+}
diff --git a/lang/src/main/java/net/openhft/lang/values/BooleanValue.java b/lang/src/main/java/net/openhft/lang/values/BooleanValue.java
index 5af319c..13d42e3 100644
--- a/lang/src/main/java/net/openhft/lang/values/BooleanValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/BooleanValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/ByteValue.java b/lang/src/main/java/net/openhft/lang/values/ByteValue.java
index b0d1f62..c281ad5 100644
--- a/lang/src/main/java/net/openhft/lang/values/ByteValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/ByteValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/CharValue.java b/lang/src/main/java/net/openhft/lang/values/CharValue.java
index d798208..84cc59a 100644
--- a/lang/src/main/java/net/openhft/lang/values/CharValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/CharValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/DoubleValue.java b/lang/src/main/java/net/openhft/lang/values/DoubleValue.java
index 8954f73..61ca9d2 100644
--- a/lang/src/main/java/net/openhft/lang/values/DoubleValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/DoubleValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -26,6 +26,10 @@ public interface DoubleValue {
void setValue(double value);
+ double getVolatileValue();
+
+ void setOrderedValue(double value);
+
double addValue(double delta);
double addAtomicValue(double delta);
diff --git a/lang/src/main/java/net/openhft/lang/values/FloatValue.java b/lang/src/main/java/net/openhft/lang/values/FloatValue.java
index b56152b..1890b48 100644
--- a/lang/src/main/java/net/openhft/lang/values/FloatValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/FloatValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -26,6 +26,10 @@ public interface FloatValue {
void setValue(float value);
+ void setOrderedValue(float value);
+
+ float getVolatileValue();
+
float addValue(float delta);
float addAtomicValue(float delta);
diff --git a/lang/src/main/java/net/openhft/lang/values/Int24Value.java b/lang/src/main/java/net/openhft/lang/values/Int24Value.java
index 538ea42..21e1e6c 100644
--- a/lang/src/main/java/net/openhft/lang/values/Int24Value.java
+++ b/lang/src/main/java/net/openhft/lang/values/Int24Value.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/Int48Value.java b/lang/src/main/java/net/openhft/lang/values/Int48Value.java
index bb7482b..1a17216 100644
--- a/lang/src/main/java/net/openhft/lang/values/Int48Value.java
+++ b/lang/src/main/java/net/openhft/lang/values/Int48Value.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/IntValue.java b/lang/src/main/java/net/openhft/lang/values/IntValue.java
index 892d640..685c253 100644
--- a/lang/src/main/java/net/openhft/lang/values/IntValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/IntValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -26,6 +26,10 @@ public interface IntValue {
void setValue(int value);
+ int getVolatileValue();
+
+ void setOrderedValue(int value);
+
int addValue(int delta);
int addAtomicValue(int delta);
@@ -36,8 +40,7 @@ public interface IntValue {
boolean tryLockNanosValue(long nanos);
- void busyLockValue() throws InterruptedException, IllegalStateException;
+ void busyLockValue() throws IllegalStateException, InterruptedException;
void unlockValue() throws IllegalMonitorStateException;
-
}
diff --git a/lang/src/main/java/net/openhft/lang/values/LongValue.java b/lang/src/main/java/net/openhft/lang/values/LongValue.java
index b59b707..f015940 100644
--- a/lang/src/main/java/net/openhft/lang/values/LongValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/LongValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -26,6 +26,10 @@ public interface LongValue {
void setValue(long value);
+ long getVolatileValue();
+
+ void setOrderedValue(long value);
+
long addValue(long delta);
long addAtomicValue(long delta);
diff --git a/lang/src/main/java/net/openhft/lang/values/ShortValue.java b/lang/src/main/java/net/openhft/lang/values/ShortValue.java
index 4dd5547..1b859b3 100644
--- a/lang/src/main/java/net/openhft/lang/values/ShortValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/ShortValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/StringValue.java b/lang/src/main/java/net/openhft/lang/values/StringValue.java
index 2a0c587..e068730 100644
--- a/lang/src/main/java/net/openhft/lang/values/StringValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/StringValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -19,12 +19,18 @@ package net.openhft.lang.values;
import net.openhft.lang.model.constraints.MaxSize;
/**
- * User: peter.lawrey
- * Date: 10/10/13
- * Time: 07:13
+ * User: peter.lawrey Date: 10/10/13 Time: 07:13
*/
public interface StringValue {
+
String getValue();
void setValue(@MaxSize CharSequence value);
+
+ /**
+ * a getter for a String which takes a StringBuilder
+ * @param stringBuilder the builder to return
+ * @return a StringBuilder containing the value
+ */
+ StringBuilder getUsingValue(StringBuilder stringBuilder);
}
diff --git a/lang/src/main/java/net/openhft/lang/values/UnsignedByteValue.java b/lang/src/main/java/net/openhft/lang/values/UnsignedByteValue.java
index 7cc5007..8a61991 100644
--- a/lang/src/main/java/net/openhft/lang/values/UnsignedByteValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/UnsignedByteValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/main/java/net/openhft/lang/values/UnsignedIntValue.java b/lang/src/main/java/net/openhft/lang/values/UnsignedIntValue.java
index 8eae1a3..3b4d96f 100644
--- a/lang/src/main/java/net/openhft/lang/values/UnsignedIntValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/UnsignedIntValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -29,5 +29,4 @@ public interface UnsignedIntValue {
void setValue(@Range(min = 0, max = (1L << 32) - 1) long value);
long addValue(long delta);
-
}
diff --git a/lang/src/main/java/net/openhft/lang/values/UnsignedShortValue.java b/lang/src/main/java/net/openhft/lang/values/UnsignedShortValue.java
index b9d06d6..a82661b 100644
--- a/lang/src/main/java/net/openhft/lang/values/UnsignedShortValue.java
+++ b/lang/src/main/java/net/openhft/lang/values/UnsignedShortValue.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/test/java/DataValueGroupTest$BaseInterface$$Native.java b/lang/src/test/java/DataValueGroupTest$BaseInterface$$Native.java
new file mode 100644
index 0000000..29c7668
--- /dev/null
+++ b/lang/src/test/java/DataValueGroupTest$BaseInterface$$Native.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.serialization.BytesMarshallable;
+import net.openhft.lang.model.Byteable;
+import net.openhft.lang.model.Copyable;
+
+import static net.openhft.lang.Compare.calcLongHashCode;
+import static net.openhft.lang.Compare.isEqual;
+
+public class DataValueGroupTest$BaseInterface$$Native implements GroupTest.BaseInterface, BytesMarshallable, Byteable, Copyable<GroupTest.BaseInterface> {
+ private static final int INT = 0;
+ private static final int STR = 4;
+
+ private Bytes _bytes;
+ private long _offset;
+
+ public void setInt(int $) {
+ _bytes.writeInt(_offset + INT, $);
+ }
+
+ public int getInt() {
+ return _bytes.readInt(_offset + INT);
+ }
+
+ public void setStr(java.lang.String $) {
+ _bytes.writeUTFΔ(_offset + STR, 15, $);
+ }
+
+ public java.lang.String getStr() {
+ return _bytes.readUTFΔ(_offset + STR);
+ }
+
+ @Override
+ public void copyFrom(GroupTest.BaseInterface from) {
+ setInt(from.getInt());
+ setStr(from.getStr());
+ }
+
+ @Override
+ public void writeMarshallable(Bytes out) {
+ out.writeInt(getInt());
+ out.writeUTFΔ(getStr());
+ }
+ @Override
+ public void readMarshallable(Bytes in) {
+ setInt(in.readInt());
+ setStr(in.readUTFΔ());
+ }
+ @Override
+ public void bytes(Bytes bytes, long offset) {
+ this._bytes = bytes;
+ this._offset = offset;
+ }
+ @Override
+ public Bytes bytes() {
+ return _bytes;
+ }
+ @Override
+ public long offset() {
+ return _offset;
+ }
+ @Override
+ public int maxSize() {
+ return 19;
+ }
+ public int hashCode() {
+ long lhc = longHashCode();
+ return (int) ((lhc >>> 32) ^ lhc);
+ }
+
+ public long longHashCode() {
+ return (calcLongHashCode(getInt())) * 10191 +
+ calcLongHashCode(getStr());
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof GroupTest.BaseInterface)) return false;
+ GroupTest.BaseInterface that = (GroupTest.BaseInterface) o;
+
+ if(!isEqual(getInt(), that.getInt())) return false;
+ return isEqual(getStr(), that.getStr());
+ }
+
+ public String toString() {
+ if (_bytes == null) return "bytes is null";
+ StringBuilder sb = new StringBuilder();
+ sb.append("DataValueGroupTest.BaseInterface{ ");
+ sb.append("int= ").append(getInt());
+sb.append(", ")
+; sb.append("str= ").append(getStr());
+ sb.append(" }");
+ return sb.toString();
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/GroupTest.java b/lang/src/test/java/net/openhft/lang/GroupTest.java
new file mode 100644
index 0000000..10f0862
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/GroupTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang;
+
+import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.IByteBufferBytes;
+import net.openhft.lang.model.Byteable;
+import net.openhft.lang.model.DataValueClasses;
+import net.openhft.lang.model.constraints.Group;
+import net.openhft.lang.model.constraints.MaxSize;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Rob Austin
+ */
+public class GroupTest {
+
+ @Test
+ public void test() {
+ IByteBufferBytes byteBufferBytes = ByteBufferBytes.wrap(ByteBuffer.allocate(1024));
+
+ {
+ BaseInterface baseInterface = DataValueClasses.newDirectReference(BaseInterface.class);
+
+ ((Byteable) baseInterface).bytes(byteBufferBytes, 0);
+
+ baseInterface.setInt(1);
+ baseInterface.setStr("Hello World");
+
+ Assert.assertEquals(1, baseInterface.getInt());
+ Assert.assertEquals("Hello World", baseInterface.getStr());
+ }
+ {
+ ExtInterface extInterface = DataValueClasses.newDirectReference(ExtInterface.class);
+ byteBufferBytes.clear();
+ ((Byteable) extInterface).bytes(byteBufferBytes, 0);
+ extInterface.setInt2(43);
+
+ Assert.assertEquals(1, extInterface.getInt());
+ Assert.assertEquals(43, extInterface.getInt2());
+ Assert.assertEquals("Hello World", extInterface.getStr());
+ extInterface.setInt(2);
+
+ Assert.assertEquals(2, extInterface.getInt());
+ }
+ }
+
+ @Test
+ public void test2() {
+ IByteBufferBytes byteBufferBytes = ByteBufferBytes.wrap(ByteBuffer.allocate(1024));
+
+ {
+ ExtInterface extInterface = DataValueClasses.newDirectReference(ExtInterface.class);
+ byteBufferBytes.clear();
+ ((Byteable) extInterface).bytes(byteBufferBytes, 0);
+
+ extInterface.setInt(1);
+ extInterface.setInt2(2);
+ extInterface.setStr("Hello World");
+
+ Assert.assertEquals(1, extInterface.getInt());
+ Assert.assertEquals(1, extInterface.getInt());
+ Assert.assertEquals("Hello World", extInterface.getStr());
+ }
+
+ {
+ BaseInterface baseInterface = DataValueClasses.newDirectReference(BaseInterface.class);
+ byteBufferBytes.clear();
+ ((Byteable) baseInterface).bytes(byteBufferBytes, 0);
+
+ Assert.assertEquals(1, baseInterface.getInt());
+ Assert.assertEquals("Hello World", baseInterface.getStr());
+ }
+ }
+
+ public interface BaseInterface {
+
+ String getStr();
+
+ void setStr(@MaxSize(15) String str);
+
+ int getInt();
+
+ void setInt(int i);
+ }
+
+ public interface ExtInterface extends BaseInterface {
+
+ int getInt2();
+
+ @Group(1)
+ void setInt2(int i);
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/JvmTest.java b/lang/src/test/java/net/openhft/lang/JvmTest.java
index af3eae8..3ce24e7 100644
--- a/lang/src/test/java/net/openhft/lang/JvmTest.java
+++ b/lang/src/test/java/net/openhft/lang/JvmTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang;
diff --git a/lang/src/test/java/net/openhft/lang/MathsTest.java b/lang/src/test/java/net/openhft/lang/MathsTest.java
index ab96efb..d25152b 100644
--- a/lang/src/test/java/net/openhft/lang/MathsTest.java
+++ b/lang/src/test/java/net/openhft/lang/MathsTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang;
diff --git a/lang/src/test/java/net/openhft/lang/collection/DirectBitSetTest.java b/lang/src/test/java/net/openhft/lang/collection/DirectBitSetTest.java
new file mode 100644
index 0000000..438dcf9
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/collection/DirectBitSetTest.java
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.collection;
+
+import net.openhft.lang.io.ByteBufferBytes;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static net.openhft.lang.collection.DirectBitSet.Bits;
+import static org.junit.Assert.*;
+
+@RunWith(value = Parameterized.class)
+public class DirectBitSetTest {
+
+ private static final int[] INDICES = new int[]{0, 50, 100, 127, 128, 255};
+ private DirectBitSet bs;
+ private boolean singleThreaded;
+ private SingleThreadedDirectBitSet st;
+
+ public DirectBitSetTest(DirectBitSet bs) {
+ this.bs = bs;
+ singleThreaded = bs instanceof SingleThreadedDirectBitSet;
+ if (singleThreaded)
+ st = (SingleThreadedDirectBitSet) bs;
+ assertTrue(bs.size() >= 256);
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> data() {
+ int capacityInBytes = 256 / 8;
+ return Arrays.asList(new Object[][]{
+ {
+ ATSDirectBitSet.wrap(ByteBufferBytes.wrap(
+ ByteBuffer.allocate(capacityInBytes)))
+ },
+ {
+ new SingleThreadedDirectBitSet(ByteBufferBytes.wrap(
+ ByteBuffer.allocate(capacityInBytes)))
+ },
+ {
+ ATSDirectBitSet.wrap(ByteBufferBytes.wrap(
+ ByteBuffer.allocateDirect(capacityInBytes)))
+ },
+ {
+ new SingleThreadedDirectBitSet(ByteBufferBytes.wrap(
+ ByteBuffer.allocateDirect(capacityInBytes)))
+ }
+ });
+ }
+
+ private void setIndices() {
+ bs.clear();
+ for (int i : INDICES) {
+ bs.set(i);
+ }
+ }
+
+ private void setIndicesComplement() {
+ setIndices();
+ bs.flip(0, bs.size());
+ }
+
+ private void assertRangeIsClear(long from, long to) {
+ for (long i = from; i < to; i++) {
+ assertFalse(bs.get(i));
+ }
+ }
+
+ private void assertRangeIsClear(String message, long from, long to) {
+ for (long i = from; i < to; i++) {
+ assertFalse(message + ", bit: " + i, bs.get(i));
+ }
+ }
+
+ private void assertRangeIsSet(long from, long to) {
+ for (long i = from; i < to; i++) {
+ assertTrue(bs.get(i));
+ }
+ }
+
+ private void assertRangeIsSet(String message, long from, long to) {
+ for (long i = from; i < to; i++) {
+ assertTrue(message + ", bit: " + i, bs.get(i));
+ }
+ }
+
+ @Test
+ public void testGetSetClearAndCardinality() {
+ bs.clear();
+ assertEquals(0, bs.cardinality());
+ int c = 0;
+ for (int i : INDICES) {
+ c++;
+ assertFalse("At index " + i, bs.get(i));
+ assertFalse("At index " + i, bs.isSet(i));
+ assertTrue("At index " + i, bs.isClear(i));
+ bs.set(i);
+ assertTrue("At index " + i, bs.get(i));
+ assertTrue("At index " + i, bs.isSet(i));
+ assertFalse("At index " + i, bs.isClear(i));
+ assertEquals(c, bs.cardinality());
+ }
+
+ for (int i : INDICES) {
+ assertTrue("At index " + i, bs.get(i));
+ assertTrue("At index " + i, bs.isSet(i));
+ assertFalse("At index " + i, bs.isClear(i));
+ bs.clear(i);
+ assertFalse("At index " + i, bs.get(i));
+ assertFalse("At index " + i, bs.isSet(i));
+ assertTrue("At index " + i, bs.isClear(i));
+ }
+
+ for (int i : INDICES) {
+ assertEquals("At index " + i, true, bs.setIfClear(i));
+ assertEquals("At index " + i, false, bs.setIfClear(i));
+ }
+
+ for (int i : INDICES) {
+ assertEquals("At index " + i, true, bs.clearIfSet(i));
+ assertEquals("At index " + i, false, bs.clearIfSet(i));
+ }
+ }
+
+ @Test
+ public void testGetLong() {
+ setIndices();
+ long l0 = 1L | (1L << 50);
+ assertEquals(l0, bs.getLong(0));
+ long l1 = (1L << (100 - 64)) | (1L << (127 - 64));
+ assertEquals(l1, bs.getLong(1));
+ }
+
+ @Test
+ public void testFlip() {
+ bs.clear();
+ for (int i : INDICES) {
+ assertEquals("At index " + i, false, bs.get(i));
+ bs.flip(i);
+ assertEquals("At index " + i, true, bs.get(i));
+ bs.flip(i);
+ assertEquals("At index " + i, false, bs.get(i));
+ }
+ }
+
+ @Test
+ public void testNextSetBit() {
+ setIndices();
+ int order = 0;
+ for (long i = bs.nextSetBit(0L); i >= 0; i = bs.nextSetBit(i + 1)) {
+ assertEquals(INDICES[order], i);
+ order++;
+ }
+ assertEquals(-1, bs.nextSetBit(bs.size()));
+
+ bs.clear();
+ assertEquals(-1, bs.nextSetBit(0L));
+ }
+
+ @Test
+ public void testSetBitsIteration() {
+ setIndices();
+ int order = 0;
+ Bits bits = bs.setBits();
+ long i;
+ while ((i = bits.next()) >= 0) {
+ assertEquals(INDICES[order], i);
+ order++;
+ }
+ assertEquals(-1, bits.next());
+
+ bs.clear();
+ assertEquals(-1, bs.setBits().next());
+ }
+
+ @Test
+ public void testClearNextSetBit() {
+ setIndices();
+ long cardinality = bs.cardinality();
+ int order = 0;
+ for (long i = bs.clearNextSetBit(0L); i >= 0;
+ i = bs.clearNextSetBit(i + 1)) {
+ assertEquals(INDICES[order], i);
+ assertFalse(bs.get(i));
+ order++;
+ cardinality--;
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.clearNextSetBit(bs.size()));
+ assertEquals(0, bs.cardinality());
+ assertEquals(-1, bs.clearNextSetBit(0L));
+ }
+
+ @Test
+ public void testClearNext1SetBit() {
+ setIndices();
+ long cardinality = bs.cardinality();
+ int order = 0;
+ for (long i = bs.clearNextNContinuousSetBits(0L, 1); i >= 0;
+ i = bs.clearNextNContinuousSetBits(i + 1, 1)) {
+ assertEquals(INDICES[order], i);
+ assertFalse(bs.get(i));
+ order++;
+ cardinality--;
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.clearNextNContinuousSetBits(bs.size(), 1));
+ assertEquals(0, bs.cardinality());
+ assertEquals(-1, bs.clearNextNContinuousSetBits(0L, 1));
+ }
+
+ @Test
+ public void testNextSetLong() {
+ bs.clear();
+ bs.set(0);
+ bs.set(255);
+ long[] setLongs = {0, 3};
+ int order = 0;
+ for (long i = bs.nextSetLong(0L); i >= 0; i = bs.nextSetLong(i + 1)) {
+ assertEquals(setLongs[order], i);
+ order++;
+ }
+ assertEquals(-1, bs.nextSetLong(bs.size() / 64));
+
+ bs.clear();
+ assertEquals(-1, bs.nextSetLong(0L));
+ }
+
+ @Test
+ public void testNextClearBit() {
+ setIndicesComplement();
+ int order = 0;
+ for (long i = bs.nextClearBit(0L); i >= 0; i = bs.nextClearBit(i + 1)) {
+ assertEquals(INDICES[order], i);
+ order++;
+ }
+ assertEquals(-1, bs.nextClearBit(bs.size()));
+
+ bs.setAll();
+ assertEquals(-1, bs.nextClearBit(0L));
+ }
+
+ @Test
+ public void testSetNextClearBit() {
+ setIndicesComplement();
+ long cardinality = bs.cardinality();
+ int order = 0;
+ for (long i = bs.setNextClearBit(0L); i >= 0;
+ i = bs.setNextClearBit(i + 1)) {
+ assertEquals(INDICES[order], i);
+ assertTrue(bs.get(i));
+ order++;
+ cardinality++;
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.setNextClearBit(bs.size()));
+ assertEquals(bs.size(), bs.cardinality());
+ assertEquals(-1, bs.setNextClearBit(0L));
+ }
+
+ @Test
+ public void testSetNext1ClearBit() {
+ setIndicesComplement();
+ long cardinality = bs.cardinality();
+ int order = 0;
+ for (long i = bs.setNextNContinuousClearBits(0L, 1); i >= 0;
+ i = bs.setNextNContinuousClearBits(i + 1, 1)) {
+ assertEquals(INDICES[order], i);
+ assertTrue(bs.get(i));
+ order++;
+ cardinality++;
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.setNextNContinuousClearBits(bs.size(), 1));
+ assertEquals(bs.size(), bs.cardinality());
+ assertEquals(-1, bs.setNextNContinuousClearBits(0L, 1));
+ }
+
+ @Test
+ public void testNextClearLong() {
+ bs.setAll();
+ bs.clear(0);
+ bs.clear(255);
+ long[] clearLongs = {0, 3};
+ int order = 0;
+ for (long i = bs.nextClearLong(0L); i >= 0; i = bs.nextClearLong(i + 1)) {
+ assertEquals(clearLongs[order], i);
+ order++;
+ }
+ assertEquals(-1, bs.nextClearLong(bs.size() / 64));
+
+ bs.setAll();
+ assertEquals(-1, bs.nextClearLong(0L));
+ }
+
+ @Test
+ public void testPreviousSetBit() {
+ setIndices();
+ int order = INDICES.length;
+ for (long i = bs.size(); (i = bs.previousSetBit(i - 1)) >= 0; ) {
+ order--;
+ assertEquals(INDICES[order], i);
+ }
+ assertEquals(-1, bs.previousSetBit(-1));
+
+ bs.clear();
+ assertEquals(-1, bs.previousSetBit(bs.size()));
+ }
+
+ @Test
+ public void testClearPreviousSetBit() {
+ setIndices();
+ long cardinality = bs.cardinality();
+ int order = INDICES.length;
+ for (long i = bs.size(); (i = bs.clearPreviousSetBit(i - 1)) >= 0; ) {
+ order--;
+ cardinality--;
+ assertEquals(INDICES[order], i);
+ assertFalse(bs.get(i));
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.clearPreviousSetBit(-1));
+ assertEquals(0, bs.cardinality());
+ assertEquals(-1, bs.clearPreviousSetBit(bs.size()));
+ }
+
+ @Test
+ public void testClearPrevious1SetBit() {
+ setIndices();
+ long cardinality = bs.cardinality();
+ int order = INDICES.length;
+ for (long i = bs.size();
+ (i = bs.clearPreviousNContinuousSetBits(i - 1, 1)) >= 0; ) {
+ order--;
+ cardinality--;
+ assertEquals(INDICES[order], i);
+ assertFalse(bs.get(i));
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.clearPreviousNContinuousSetBits(-1, 1));
+ assertEquals(0, bs.cardinality());
+ assertEquals(-1, bs.clearPreviousNContinuousSetBits(bs.size(), 1));
+ }
+
+ @Test
+ public void testPreviousSetLong() {
+ bs.clear();
+ bs.set(0);
+ bs.set(255);
+ long[] setLongs = {0, 3};
+ int order = setLongs.length;
+ for (long i = bs.size() / 64; (i = bs.previousSetLong(i - 1)) >= 0; ) {
+ order--;
+ assertEquals(setLongs[order], i);
+ }
+ assertEquals(-1, bs.previousSetLong(-1));
+
+ bs.clear();
+ assertEquals(-1, bs.previousSetLong(bs.size() / 64));
+ }
+
+ @Test
+ public void testPreviousClearBit() {
+ setIndicesComplement();
+ int order = INDICES.length;
+ for (long i = bs.size(); (i = bs.previousClearBit(i - 1)) >= 0; ) {
+ order--;
+ assertEquals(INDICES[order], i);
+ }
+ assertEquals(-1, bs.previousClearBit(-1));
+
+ bs.setAll();
+ assertEquals(-1, bs.previousClearBit(bs.size()));
+ }
+
+ @Test
+ public void testSetPreviousClearBit() {
+ setIndicesComplement();
+ long cardinality = bs.cardinality();
+ int order = INDICES.length;
+ for (long i = bs.size(); (i = bs.setPreviousClearBit(i - 1)) >= 0; ) {
+ order--;
+ cardinality++;
+ assertEquals(INDICES[order], i);
+ assertTrue(bs.get(i));
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.setPreviousClearBit(-1));
+ assertEquals(bs.size(), bs.cardinality());
+ assertEquals(-1, bs.setPreviousClearBit(bs.size()));
+ }
+
+ @Test
+ public void testSetPrevious1ClearBit() {
+ setIndicesComplement();
+ long cardinality = bs.cardinality();
+ int order = INDICES.length;
+ for (long i = bs.size();
+ (i = bs.setPreviousNContinuousClearBits(i - 1, 1)) >= 0; ) {
+ order--;
+ cardinality++;
+ assertEquals(INDICES[order], i);
+ assertTrue(bs.get(i));
+ assertEquals(cardinality, bs.cardinality());
+ }
+ assertEquals(-1, bs.setPreviousNContinuousClearBits(-1, 1));
+ assertEquals(bs.size(), bs.cardinality());
+ assertEquals(-1, bs.setPreviousNContinuousClearBits(bs.size(), 1));
+ }
+
+ @Test
+ public void testPreviousClearLong() {
+ bs.setAll();
+ bs.clear(0);
+ bs.clear(255);
+ long[] clearLongs = {0, 3};
+ int order = clearLongs.length;
+ for (long i = bs.size() / 64; (i = bs.previousClearLong(i - 1)) >= 0; ) {
+ order--;
+ assertEquals(clearLongs[order], i);
+ }
+ assertEquals(-1, bs.previousClearLong(-1));
+
+ bs.setAll();
+ assertEquals(-1, bs.previousClearLong(bs.size() / 64));
+ }
+
+ @Test
+ public void testSetAll() {
+ bs.clear();
+ bs.setAll();
+ assertEquals(bs.size(), bs.cardinality());
+ }
+
+ @Test
+ public void testRangeOpsWithinLongCase() {
+ bs.clear();
+ if (singleThreaded) {
+ assertTrue(st.allClear(0, 0));
+ assertTrue(st.allClear(63, 63));
+ assertTrue(st.allSet(0, 0));
+ assertTrue(st.allSet(63, 63));
+ }
+
+ bs.flip(0, 0);
+ assertEquals(false, bs.get(0));
+ assertEquals(0, bs.cardinality());
+ bs.flip(0, 1);
+ assertEquals(true, bs.get(0));
+ assertEquals(1, bs.cardinality());
+ if (singleThreaded) {
+ assertTrue(st.allSet(0, 1));
+ assertFalse(st.allSet(0, 2));
+ assertFalse(st.allClear(0, 1));
+ }
+
+ bs.clear(0, 0);
+ assertEquals(true, bs.get(0));
+ assertEquals(1, bs.cardinality());
+ bs.clear(0, 1);
+ assertEquals(false, bs.get(0));
+ assertEquals(0, bs.cardinality());
+
+ bs.set(0, 0);
+ assertEquals(false, bs.get(0));
+ assertEquals(0, bs.cardinality());
+ bs.set(0, 1);
+ assertEquals(true, bs.get(0));
+ assertEquals(1, bs.cardinality());
+ }
+
+ @Test
+ public void testRangeOpsCrossLongCase() {
+ bs.clear();
+
+ bs.flip(63, 64);
+ assertEquals(true, bs.get(63));
+ assertEquals(false, bs.get(64));
+ assertEquals(1, bs.cardinality());
+ if (singleThreaded) {
+ assertFalse(st.allSet(63, 65));
+ assertFalse(st.allClear(63, 65));
+ }
+ bs.flip(63, 65);
+ assertEquals(false, bs.get(63));
+ assertEquals(true, bs.get(64));
+ assertEquals(1, bs.cardinality());
+ if (singleThreaded) {
+ assertFalse(st.allSet(63, 65));
+ assertFalse(st.allClear(63, 65));
+ }
+
+ bs.clear(64);
+ bs.set(63, 64);
+ assertEquals(true, bs.get(63));
+ assertEquals(false, bs.get(64));
+ assertEquals(1, bs.cardinality());
+
+ bs.set(64);
+ bs.clear(63, 64);
+ assertEquals(false, bs.get(63));
+ assertEquals(true, bs.get(64));
+ assertEquals(1, bs.cardinality());
+
+ bs.clear(64);
+ bs.set(63, 65);
+ assertEquals(true, bs.get(63));
+ assertEquals(true, bs.get(64));
+ assertEquals(2, bs.cardinality());
+ if (singleThreaded) {
+ assertTrue(st.allSet(63, 65));
+ assertFalse(st.allClear(63, 65));
+ }
+
+ bs.clear(63, 65);
+ assertEquals(false, bs.get(63));
+ assertEquals(false, bs.get(64));
+ assertEquals(0, bs.cardinality());
+ if (singleThreaded) {
+ assertFalse(st.allSet(63, 65));
+ assertTrue(st.allClear(63, 65));
+ }
+ }
+
+ @Test
+ public void testRangeOpsSpanLongCase() {
+ bs.clear();
+ if (singleThreaded) {
+ assertTrue(st.allClear(0, st.size()));
+ assertFalse(st.allSet(0, st.size()));
+ }
+
+ bs.set(0, bs.size());
+ assertEquals(bs.size(), bs.cardinality());
+ if (singleThreaded) {
+ assertFalse(st.allClear(0, st.size()));
+ assertTrue(st.allSet(0, st.size()));
+ }
+
+ bs.clear(0, bs.size());
+ assertEquals(0, bs.cardinality());
+
+ bs.flip(0, bs.size());
+ assertEquals(bs.size(), bs.cardinality());
+ }
+
+ private String m(int n) {
+ return "N: " + n + ", " + bs.getClass().getSimpleName();
+ }
+
+ @Test
+ public void testSetNextNContinuousClearBitsWithinLongCase() {
+ long size = (bs.size() + 63) / 64 * 64;
+ for (int n = 1; n <= 64; n *= 2) {
+ bs.clear();
+ for (int i = 0; i < size / n; i++) {
+ assertRangeIsClear(i * n, i * n + n);
+ assertEquals(m(n), i * n, bs.setNextNContinuousClearBits(0L, n));
+ assertRangeIsSet(i * n, i * n + n);
+ assertEquals(i * n + n, bs.cardinality());
+ }
+ }
+ for (int n = 2; n <= 64; n *= 2) {
+ bs.setAll();
+ bs.clear(size - n, size);
+ assertEquals(size - n, bs.setNextNContinuousClearBits(0L, n));
+ assertRangeIsSet(size - n, size);
+
+ long offset = (64 - n) / 2;
+ long from = size - n - offset;
+ long to = size - offset;
+ bs.clear(from, to);
+ assertEquals(from, bs.setNextNContinuousClearBits(from, n));
+ assertRangeIsSet(from, to);
+
+ bs.clear(from, to);
+ for (long i = from - 2; i >= 0; i -= 2) {
+ bs.clear(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.setNextNContinuousClearBits(0, n));
+ assertEquals(cardinality + n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testSetNextNContinuousClearBitsCrossLongCase() {
+ if (bs instanceof ATSDirectBitSet)
+ return;
+ long size = bs.size();
+ for (int n : new int[]{3, 7, 13, 31, 33, 63, 65, 100, 127, 128, 129, 254, 255}) {
+ bs.clear();
+ for (int i = 0; i < size / n; i++) {
+ assertRangeIsClear(i * n, i * n + n);
+ assertEquals(m(n), i * n, bs.setNextNContinuousClearBits(0L, n));
+ assertRangeIsSet(i * n, i * n + n);
+ assertEquals(i * n + n, bs.cardinality());
+ }
+ }
+ long lastBound = size - (size % 64 == 0 ? 64 : size % 64);
+ for (int n : new int[]{2, 3, 7, 13, 31, 33, 63, 64, 65, 100, 127, 128, 129}) {
+ bs.setAll();
+ long from = n <= 64 ? lastBound - (n / 2) : 30;
+ long to = from + n;
+ bs.clear(from, to);
+ assertEquals("" + n, from, bs.setNextNContinuousClearBits(0L, n));
+ assertRangeIsSet(from, to);
+
+ bs.clear(from, to);
+ for (long i = from - 2; i >= 0; i -= 2) {
+ bs.clear(i);
+ }
+ for (long i = to + 1; i < bs.size(); i += 2) {
+ bs.clear(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.setNextNContinuousClearBits(from, n));
+ assertEquals(cardinality + n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testClearNextNContinuousSetBitsWithinLongCase() {
+ long size = (bs.size() + 63) / 64 * 64;
+ for (int n = 1; n <= 64; n *= 2) {
+ bs.setAll();
+ long cardinality = bs.cardinality();
+ for (int i = 0; i < size / n; i++) {
+ assertRangeIsSet(i * n, i * n + n);
+ assertEquals(m(n), i * n, bs.clearNextNContinuousSetBits(0L, n));
+ assertRangeIsClear(i * n, i * n + n);
+ assertEquals(cardinality - (i * n + n), bs.cardinality());
+ }
+ }
+ for (int n = 2; n <= 64; n *= 2) {
+ bs.clear();
+ bs.set(size - n, size);
+ assertEquals(size - n, bs.clearNextNContinuousSetBits(0L, n));
+ assertRangeIsClear(size - n, size);
+
+ long offset = (64 - n) / 2;
+ long from = size - n - offset;
+ long to = size - offset;
+ bs.set(from, to);
+ assertEquals(from, bs.clearNextNContinuousSetBits(from, n));
+ assertRangeIsClear(from, to);
+
+ bs.set(from, to);
+ for (long i = from - 2; i >= 0; i -= 2) {
+ bs.set(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.clearNextNContinuousSetBits(0, n));
+ assertEquals(cardinality - n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testClearNextNContinuousSetBitsCrossLongCase() {
+ if (bs instanceof ATSDirectBitSet)
+ return;
+ long size = bs.size();
+ for (int n : new int[]{3, 7, 13, 31, 33, 63}) {
+ bs.setAll();
+ long cardinality = bs.cardinality();
+ for (int i = 0; i < size / n; i++) {
+ assertRangeIsSet(i * n, i * n + n);
+ assertEquals(m(n), i * n, bs.clearNextNContinuousSetBits(0L, n));
+ assertRangeIsClear(i * n, i * n + n);
+ assertEquals(cardinality -= n, bs.cardinality());
+ }
+ }
+ long lastBound = size - (size % 64 == 0 ? 64 : size % 64);
+ for (int n : new int[]{2, 3, 7, 13, 31, 33, 63, 64}) {
+ bs.clear();
+ long from = lastBound - (n / 2);
+ long to = from + n;
+ bs.set(from, to);
+ assertEquals(from, bs.clearNextNContinuousSetBits(0L, n));
+ assertRangeIsClear(from, to);
+
+ bs.set(from, to);
+ for (long i = from - 2; i >= 0; i -= 2) {
+ bs.set(i);
+ }
+ for (long i = to + 1; i < bs.size(); i += 2) {
+ bs.set(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.clearNextNContinuousSetBits(from, n));
+ assertEquals(cardinality - n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testSetPreviousNContinuousClearBitsWithinLongCase() {
+ long size = (bs.size() + 63) / 64 * 64;
+ for (int n = 1; n <= 64; n *= 2) {
+ bs.clear();
+ long cardinality = 0;
+ for (long i = size / n - 1; i >= 0; i--) {
+ assertRangeIsClear(i * n, i * n + n);
+ assertEquals(m(n), i * n, bs.setPreviousNContinuousClearBits(size, n));
+ assertRangeIsSet(i * n, i * n + n);
+ assertEquals(cardinality += n, bs.cardinality());
+ }
+ }
+ for (int n = 2; n <= 64; n *= 2) {
+ bs.setAll();
+ bs.clear(0, n);
+ assertEquals(0, bs.setPreviousNContinuousClearBits(bs.size(), n));
+ assertRangeIsSet(0, n);
+
+ long from = (64 - n) / 2;
+ long to = from + n;
+ bs.clear(from, to);
+ assertEquals(from, bs.setPreviousNContinuousClearBits(to - 1, n));
+ assertRangeIsSet(from, to);
+
+ bs.clear(from, to);
+ for (long i = to + 1; i < bs.size(); i += 2) {
+ bs.clear(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.setPreviousNContinuousClearBits(bs.size(), n));
+ assertEquals(cardinality + n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testSetPreviousNContinuousClearBitsCrossLongCase() {
+ if (bs instanceof ATSDirectBitSet)
+ return;
+ long size = bs.size();
+ for (int n : new int[]{3, 7, 13, 31, 33, 63}) {
+ bs.clear();
+ long cardinality = 0;
+ for (long from = size - n; from >= 0; from -= n) {
+ assertRangeIsClear(from, from + n);
+ assertEquals(m(n), from, bs.setPreviousNContinuousClearBits(size, n));
+ assertRangeIsSet(from, from + n);
+ assertEquals(cardinality += n, bs.cardinality());
+ }
+ }
+ for (int n : new int[]{2, 3, 7, 13, 31, 33, 63, 64}) {
+ bs.setAll();
+ long from = 64 - (n / 2);
+ long to = from + n;
+ bs.clear(from, to);
+ assertEquals(from, bs.setPreviousNContinuousClearBits(size, n));
+ assertRangeIsSet(from, to);
+
+ bs.clear(from, to);
+ for (long i = from - 2; i >= 0; i -= 2) {
+ bs.clear(i);
+ }
+ for (long i = to + 1; i < bs.size(); i += 2) {
+ bs.clear(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.setPreviousNContinuousClearBits(to - 1, n));
+ assertEquals(cardinality + n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testClearPreviousNContinuousSetBitsWithinLongCase() {
+ long size = (bs.size() + 63) / 64 * 64;
+ for (int n = 1; n <= 64; n *= 2) {
+ bs.setAll();
+ long cardinality = bs.cardinality();
+ for (long i = size / n - 1; i >= 0; i--) {
+ assertRangeIsSet(i * n, i * n + n);
+ assertEquals(m(n), i * n, bs.clearPreviousNContinuousSetBits(size, n));
+ assertRangeIsClear(m(n), i * n, i * n + n);
+ assertEquals(cardinality -= n, bs.cardinality());
+ }
+ }
+ for (int n = 2; n <= 64; n *= 2) {
+ bs.clear();
+ bs.set(0, n);
+ assertEquals(0, bs.clearPreviousNContinuousSetBits(bs.size(), n));
+ assertRangeIsClear(0, n);
+
+ long from = (64 - n) / 2;
+ long to = from + n;
+ bs.set(from, to);
+ assertEquals(from, bs.clearPreviousNContinuousSetBits(to - 1, n));
+ assertRangeIsClear(from, to);
+
+ bs.set(from, to);
+ for (long i = to + 1; i < bs.size(); i += 2) {
+ bs.set(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.clearPreviousNContinuousSetBits(bs.size(), n));
+ assertEquals(cardinality - n, bs.cardinality());
+ }
+ }
+
+ @Test
+ public void testClearPreviousNContinuousSetBitsCrossLongCase() {
+ if (bs instanceof ATSDirectBitSet)
+ return;
+ long size = bs.size();
+ for (int n : new int[]{3, 7, 13, 31, 33, 63}) {
+ bs.setAll();
+ long cardinality = bs.cardinality();
+ for (long from = size - n; from >= 0; from -= n) {
+ assertRangeIsSet(from, from + n);
+ assertEquals(m(n), from, bs.clearPreviousNContinuousSetBits(size, n));
+ assertRangeIsClear(from, from + n);
+ assertEquals(cardinality -= n, bs.cardinality());
+ }
+ }
+ for (int n : new int[]{2, 3, 7, 13, 31, 33, 63, 64}) {
+ bs.clear();
+ long from = 64 - (n / 2);
+ long to = from + n;
+ bs.set(from, to);
+ assertEquals(from, bs.clearPreviousNContinuousSetBits(size, n));
+ assertRangeIsClear(from, to);
+
+ bs.set(from, to);
+ for (long i = from - 2; i >= 0; i -= 2) {
+ bs.set(i);
+ }
+ for (long i = to + 1; i < bs.size(); i += 2) {
+ bs.set(i);
+ }
+ long cardinality = bs.cardinality();
+ assertEquals(from, bs.clearPreviousNContinuousSetBits(to - 1, n));
+ assertEquals(cardinality - n, bs.cardinality());
+ }
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeGetNegative() {
+ bs.get(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeGetOverCapacity() {
+ bs.get(bs.size());
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetNegative() {
+ bs.set(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetOverCapacity() {
+ bs.set(bs.size());
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetIfClearNegative() {
+ bs.setIfClear(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetIfClearOverCapacity() {
+ bs.setIfClear(bs.size());
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearIfSetNegative() {
+ bs.clearIfSet(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearIfSetOverCapacity() {
+ bs.clearIfSet(bs.size());
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeFlipNegative() {
+ bs.flip(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeFlipOverCapacity() {
+ bs.flip(bs.size());
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeGetLongNegative() {
+ bs.getLong(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeGetLongOverCapacity() {
+ bs.getLong((bs.size() + 63) / 64);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeNextSetBit() {
+ bs.nextSetBit(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeNextSetLong() {
+ bs.nextSetLong(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeNextClearBit() {
+ bs.nextClearBit(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeNextClearLong() {
+ bs.nextClearLong(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobePreviousSetBit() {
+ bs.previousSetBit(-2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobePreviousSetLong() {
+ bs.previousSetLong(-2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobePreviousClearBit() {
+ bs.previousClearBit(-2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobePreviousClearLong() {
+ bs.previousClearLong(-2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearNextSetBit() {
+ bs.clearNextSetBit(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearNextNContinuousSetBits() {
+ bs.clearNextNContinuousSetBits(-1, 2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetNextClearBit() {
+ bs.setNextClearBit(-1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetNextNContinuousClearBits() {
+ bs.setNextNContinuousClearBits(-1, 2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearPreviousSetBit() {
+ bs.clearPreviousSetBit(-2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearPreviousNContinuousSetBit() {
+ bs.clearPreviousNContinuousSetBits(-2, 2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetPreviousClearBit() {
+ bs.setPreviousClearBit(-2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetPreviousNContinuousClearBit() {
+ bs.setPreviousNContinuousClearBits(-2, 2);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetRangeFromNegative() {
+ bs.set(-1, 0);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetRangeFromOverTo() {
+ bs.set(1, 0);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeSetRangeToOverCapacity() {
+ bs.set(0, bs.size() + 1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearRangeFromNegative() {
+ bs.clear(-1, 0);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearRangeFromOverTo() {
+ bs.clear(1, 0);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeClearRangeToOverCapacity() {
+ bs.clear(0, bs.size() + 1);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeFlipRangeFromNegative() {
+ bs.flip(-1, 0);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeFlipRangeFromOverTo() {
+ bs.flip(1, 0);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testIoobeFlipRangeToOverCapacity() {
+ bs.flip(0, bs.size() + 1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIaeClearNextNContinuousSetBits() {
+ bs.clearNextNContinuousSetBits(0, 0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIaeSetNextNContinuousClearBits() {
+ bs.setNextNContinuousClearBits(0, 0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIaeClearPreviousNContinuousSetBits() {
+ bs.clearPreviousNContinuousSetBits(bs.size(), 0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIaeSetPreviousNContinuousClearBits() {
+ bs.setPreviousNContinuousClearBits(bs.size(), 0);
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/collection/HugeArrayTest.java b/lang/src/test/java/net/openhft/lang/collection/HugeArrayTest.java
index 0b10e01..ce227dc 100644
--- a/lang/src/test/java/net/openhft/lang/collection/HugeArrayTest.java
+++ b/lang/src/test/java/net/openhft/lang/collection/HugeArrayTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection;
@@ -32,52 +32,84 @@ public class HugeArrayTest {
org.junit.Assert.assertEquals(a, b);
}
+ /*
+ * Test proves that you can get more than one object from the array
+ * The first object is created at construction time to get the size of an element
+ * The second one is created on the fly due to freelist being empty.
+ * There was a bug where acquire() was creating a heap object on freelist miss
+ */
+ @Test
+ public void testGetTwoObjects() {
+ HugeArray<JavaBeanInterface> array =
+ HugeCollections.newArray(JavaBeanInterface.class, 2);
+ JavaBeanInterface obj1 = array.get(0);
+ JavaBeanInterface obj2 = array.get(1);
+/*
+Can't call recycle due to recycle using .equals checks on your model.
+Two unmodified objects are .equals().
+Recycle should use identity to know if it's putting the same object back in the list.
+
+ array.recycle(obj1);
+ array.recycle(obj2);
+*/
+ }
+
+ /*
+ With lock: false, average time to access a JavaBeanInterface was 71.9 ns
+ With lock: true, average time to access a JavaBeanInterface was 124.7 ns
+ */
@Test
public void testHugeArray() throws InterruptedException {
// runs with a maximum heap size of 32 MB.
int length = 10 * 1000 * 1000;
HugeArray<JavaBeanInterface> array =
HugeCollections.newArray(JavaBeanInterface.class, length);
- long start = System.nanoTime();
- for (int i = 0; i < array.length(); i++) {
- JavaBeanInterface jbi = array.get(i);
-// jbi.busyLockRecord();
-// try {
- jbi.setByte((byte) i);
- jbi.setChar((char) i);
- jbi.setShort((short) i);
- jbi.setInt(i);
- jbi.setFloat(i);
- jbi.setLong(i); // System.nanoTime());
- jbi.setDouble(i);
- jbi.setFlag((i & 3) == 0);
- jbi.setString("hello");
-// } finally {
-// jbi.unlockRecord();
-// }
- array.recycle(jbi);
- }
- for (int i = 0; i < array.length(); i++) {
- JavaBeanInterface jbi = array.get(i);
-// jbi.busyLockRecord();
-// try {
- assertEquals2((byte) i, jbi.getByte());
- assertEquals2((char) i, jbi.getChar());
- assertEquals2((short) i, jbi.getShort());
- assertEquals2(i, jbi.getInt());
- assertEquals(i, jbi.getFloat(), 0);
+ for (boolean withLock : new boolean[]{false, true}) {
+ long start = System.nanoTime();
+ for (int i = 0; i < array.length(); i++) {
+ JavaBeanInterface jbi = array.get(i);
+ if (withLock)
+ jbi.busyLockRecord();
+ try {
+ jbi.setByte((byte) i);
+ jbi.setChar((char) i);
+ jbi.setShort((short) i);
+ jbi.setInt(i);
+ jbi.setFloat(i);
+ jbi.setLong(i); // System.nanoTime());
+ jbi.setDouble(i);
+ jbi.setFlag((i & 3) == 0);
+ jbi.setString("hello");
+ } finally {
+ if (withLock)
+ jbi.unlockRecord();
+ }
+ array.recycle(jbi);
+ }
+ for (int i = 0; i < array.length(); i++) {
+ JavaBeanInterface jbi = array.get(i);
+ if (withLock)
+ jbi.busyLockRecord();
+ try {
+ assertEquals2((byte) i, jbi.getByte());
+ assertEquals2((char) i, jbi.getChar());
+ assertEquals2((short) i, jbi.getShort());
+ assertEquals2(i, jbi.getInt());
+ assertEquals(i, jbi.getFloat(), 0);
// long time = System.nanoTime() - jbi.getLong();
- assertEquals2(i, jbi.getLong());
- assertEquals(i, jbi.getDouble(), 0.0);
- assertEquals((i & 3) == 0, jbi.getFlag());
- assertEquals("hello", jbi.getString());
-// } finally {
-// jbi.unlockRecord();
-// }
- array.recycle(jbi);
+ assertEquals2(i, jbi.getLong());
+ assertEquals(i, jbi.getDouble(), 0.0);
+ assertEquals((i & 3) == 0, jbi.getFlag());
+ assertEquals("hello", jbi.getString());
+ } finally {
+ if (withLock)
+ jbi.unlockRecord();
+ }
+ array.recycle(jbi);
+ }
+ long time = System.nanoTime() - start;
+ double avg = time / 2.0 / length;
+ System.out.printf("With lock: %s, average time to access a JavaBeanInterface was %.1f ns%n", withLock, avg);
}
- long time = System.nanoTime() - start;
- double avg = time / 2.0 / length;
- System.out.printf("Average time to access a JavaBeanInterface was %.1f ns%n", avg);
}
}
diff --git a/lang/src/test/java/net/openhft/lang/collection/HugePricesMain.java b/lang/src/test/java/net/openhft/lang/collection/HugePricesMain.java
index 2613063..af3977f 100644
--- a/lang/src/test/java/net/openhft/lang/collection/HugePricesMain.java
+++ b/lang/src/test/java/net/openhft/lang/collection/HugePricesMain.java
@@ -1,23 +1,24 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection;
import net.openhft.lang.model.constraints.MaxSize;
import net.openhft.lang.model.constraints.Range;
+import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -63,7 +64,9 @@ interface TimedQuote extends Quote {
}
public class HugePricesMain {
- public static void main(String[] args) {
+
+ @Test
+ public void test() {
int length = 1000;
final HugeArray<Price> prices =
HugeCollections.newArray(Price.class, length);
@@ -72,7 +75,7 @@ public class HugePricesMain {
price.setInstrument("ID" + i);
price.getAsk().setPrice(100.1);
price.getAsk().setAmount(1000);
- price.getBid().setPrice(99.8);
+ price.getBid().setPrice(99.8123456789);
price.getBid().setAmount(2000);
prices.recycle(price);
}
@@ -81,7 +84,7 @@ public class HugePricesMain {
assertEquals("ID" + i, price.getInstrument());
assertEquals(100.1, price.getAsk().getPrice(), 0.0);
assertEquals(1000, price.getAsk().getAmount());
- assertEquals(99.8, price.getBid().getPrice(), 0.0);
+ assertEquals(99.8123456789, price.getBid().getPrice(), 0.0);
assertEquals(2000, price.getBid().getAmount());
prices.recycle(price);
}
diff --git a/lang/src/test/java/net/openhft/lang/collection/HugeQueueTest.java b/lang/src/test/java/net/openhft/lang/collection/HugeQueueTest.java
index 5c5d01c..b68f6b1 100644
--- a/lang/src/test/java/net/openhft/lang/collection/HugeQueueTest.java
+++ b/lang/src/test/java/net/openhft/lang/collection/HugeQueueTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.collection;
@@ -66,6 +66,5 @@ public class HugeQueueTest {
long time = System.nanoTime() - start;
double avg = time / 2.0 / tests;
System.out.printf("Average time to access a JavaBeanInterface was %.1f ns%n", avg);
-
}
}
diff --git a/lang/src/test/java/net/openhft/lang/example/CounterExampleMain.java b/lang/src/test/java/net/openhft/lang/example/CounterExampleMain.java
new file mode 100644
index 0000000..41135be
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/example/CounterExampleMain.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.example;
+
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.MappedStore;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+public class CounterExampleMain {
+ static volatile long id;
+
+ public static void main(String... ignored) throws IOException {
+ int counters = 128;
+ int repeats = 100000;
+
+ File file = new File(System.getProperty("java.io.tmpdir") + "/counters");
+ MappedStore ms = new MappedStore(file, FileChannel.MapMode.READ_WRITE, counters * 8);
+ DirectBytes slice = ms.bytes();
+
+ long start = System.nanoTime();
+ for (int j = 0; j < repeats; j++) {
+ for (int i = 0; i < counters; i++) {
+ id = slice.addAtomicLong(i * 8, 1);
+ }
+ }
+ long time = System.nanoTime() - start;
+ System.out.printf("Took %.3f second to increment %,d counters, %,d times, last id=%,d%n",
+ time / 1e9, counters, repeats, id);
+ ms.free();
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/AllocationRatesTest.java b/lang/src/test/java/net/openhft/lang/io/AllocationRatesTest.java
index da8696a..66cde7b 100644..100755
--- a/lang/src/test/java/net/openhft/lang/io/AllocationRatesTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/AllocationRatesTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -21,7 +21,7 @@ import org.junit.Test;
import java.nio.ByteBuffer;
/**
- * User: peter Date: 24/12/13 Time: 19:43
+ * User: peter.lawrey Date: 24/12/13 Time: 19:43
*/
/*
buffers 128 KB took an average of 18,441 ns for heap ByteBuffer, 33,683 ns for direct ByteBuffer and 1,761 for DirectStore
@@ -32,7 +32,7 @@ buffers 128 KB took an average of 8,739 ns for heap ByteBuffer, 22,684 ns for di
*/
public class AllocationRatesTest {
static final int BUFFER_SIZE = 128 * 1024;
- static final int ALLOCATIONS = 25000;
+ static final int ALLOCATIONS = 10000;
public static final int BATCH = 10;
@Test
diff --git a/lang/src/test/java/net/openhft/lang/io/BigDecimalVsDoubleMain.java b/lang/src/test/java/net/openhft/lang/io/BigDecimalVsDoubleMain.java
new file mode 100644
index 0000000..609bc03
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/BigDecimalVsDoubleMain.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import java.math.BigDecimal;
+import java.nio.ByteBuffer;
+
+public class BigDecimalVsDoubleMain {
+
+ public static final String[] NUMBER = {"1000000", "1.1", "1.23456", "12345.67890"};
+ public static final Bytes[] IN_BYTES = new Bytes[NUMBER.length];
+ public static final Bytes OUT_BYTES;
+
+ static {
+ DirectStore store = new DirectStore((NUMBER.length + 1) * 16);
+ for (int i = 0; i < NUMBER.length; i++) {
+ IN_BYTES[i] = store.bytes((i + 1) * 16, 16);
+ IN_BYTES[i].append(NUMBER[i]);
+ }
+ OUT_BYTES = store.bytes(0, 16);
+ }
+
+ static int count = 0;
+
+ public static void main(String[] args) throws InterruptedException {
+ Bytes x = ByteBufferBytes.wrap(ByteBuffer.allocateDirect(16));
+ x.writeUTFΔ("Hello World");
+ System.out.println(x);
+ int runs = 5000;
+
+ for (int t = 0; t < 5; t++) {
+ long timeD = 0;
+ long timeBD = 0;
+ long timeB = 0;
+ if (t == 0)
+ System.out.println("Warming up");
+ else if (t == 1)
+ System.out.println("Cold code");
+
+ int r = t == 0 ? 20000 : runs;
+ for (int i = 0; i < r; i += 3) {
+ count++;
+ if (count >= NUMBER.length) count = 0;
+
+ if (t > 0)
+ Thread.sleep(1);
+ timeB += testDoubleWithBytes();
+ timeBD += testBigDecimalWithString();
+ timeD += testDoubleWithString();
+ if (t > 0)
+ Thread.sleep(1);
+ timeD += testDoubleWithString();
+ timeB += testDoubleWithBytes();
+ timeBD += testBigDecimalWithString();
+ if (t > 0)
+ Thread.sleep(1);
+ timeBD += testBigDecimalWithString();
+ timeD += testDoubleWithString();
+ timeB += testDoubleWithBytes();
+ }
+ System.out.printf("double took %.1f us, BigDecimal took %.1f, double with Bytes took %.1f%n",
+ timeD / 1e3 / r, timeBD / 1e3 / r, timeB / 1e3 / r);
+ }
+ }
+
+ static volatile double saved;
+ static volatile String savedStr;
+
+ public static long testDoubleWithString() {
+ long start = System.nanoTime();
+ saved = Double.parseDouble(NUMBER[count]);
+ savedStr = Double.toString(saved);
+ return System.nanoTime() - start;
+ }
+
+ public static long testDoubleWithBytes() {
+ IN_BYTES[count].position(0);
+ OUT_BYTES.position(0);
+
+ long start = System.nanoTime();
+ saved = IN_BYTES[count].parseDouble();
+ OUT_BYTES.append(saved);
+ System.out.println(OUT_BYTES);
+
+ return System.nanoTime() - start;
+ }
+
+ static volatile BigDecimal savedBD;
+
+ public static long testBigDecimalWithString() {
+ long start = System.nanoTime();
+ savedBD = new BigDecimal(NUMBER[count]);
+ savedStr = savedBD.toString();
+ return System.nanoTime() - start;
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/ByteBufferBytesTest.java b/lang/src/test/java/net/openhft/lang/io/ByteBufferBytesTest.java
index 9c2ec03..8ba8b65 100644..100755
--- a/lang/src/test/java/net/openhft/lang/io/ByteBufferBytesTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/ByteBufferBytesTest.java
@@ -1,28 +1,32 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
import net.openhft.lang.Maths;
+import net.openhft.lang.io.serialization.BytesMarshallable;
+import net.openhft.lang.model.DataValueClasses;
+import net.openhft.lang.model.constraints.MaxSize;
import net.openhft.lang.thread.NamedThreadFactory;
import org.junit.Before;
import org.junit.Test;
import java.io.*;
import java.math.BigDecimal;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
@@ -31,27 +35,25 @@ import java.util.concurrent.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-import static net.openhft.lang.io.StopCharTesters.CONTROL_STOP;
-import static net.openhft.lang.io.StopCharTesters.SPACE_STOP;
+import static net.openhft.lang.io.StopCharTesters.*;
import static org.junit.Assert.*;
/**
- * Created with IntelliJ IDEA. User: peter.lawrey Date: 17/09/13 Time: 16:09 To change this template use File | Settings | File
- * Templates.
+ * User: peter.lawrey
*/
public class ByteBufferBytesTest {
public static final int SIZE = 128;
- private ByteBufferBytes bytes;
+ private Bytes bytes;
private ByteBuffer byteBuffer;
@Before
public void beforeTest() {
byteBuffer = ByteBuffer.allocate(SIZE).order(ByteOrder.nativeOrder());
- bytes = new ByteBufferBytes(byteBuffer);
+ bytes = ByteBufferBytes.wrap(byteBuffer);
}
@Test
- public void testLongHash() throws Exception {
+ public void testLongHash() {
byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8};
long h = NativeBytes.longHash(bytes, 0, bytes.length);
assertFalse(h == 0);
@@ -62,7 +64,14 @@ public class ByteBufferBytesTest {
}
@Test
- public void testRead() throws Exception {
+ public void testCAS() {
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(100));
+ bytes.compareAndSwapLong(0, 0L, 1L);
+ assertEquals(1L, bytes.readLong(0));
+ }
+
+ @Test
+ public void testRead() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.writeByte(i, i);
bytes.position(0);
@@ -71,11 +80,10 @@ public class ByteBufferBytesTest {
for (int i = (int) (bytes.capacity() - 1); i >= 0; i--) {
assertEquals((byte) i, bytes.readByte(i));
}
-
}
@Test
- public void testReadFully() throws Exception {
+ public void testReadFully() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.write(i);
bytes.position(0);
@@ -86,16 +94,15 @@ public class ByteBufferBytesTest {
}
@Test
- public void testCompareAndSetLong() throws Exception {
+ public void testCompareAndSetLong() {
assertTrue(bytes.compareAndSwapLong(0, 0, 1));
assertFalse(bytes.compareAndSwapLong(0, 0, 1));
assertTrue(bytes.compareAndSwapLong(8, 0, 1));
assertTrue(bytes.compareAndSwapLong(0, 1, 2));
-
}
@Test
- public void testPosition() throws Exception {
+ public void testPosition() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.write(i);
for (int i = (int) (bytes.capacity() - 1); i >= 0; i--) {
@@ -105,29 +112,23 @@ public class ByteBufferBytesTest {
}
@Test
- public void testCapacity() throws Exception {
- assertEquals(SIZE, bytes.capacity());
- assertEquals(10, new NativeBytes(0, 0, 10).capacity());
- }
-
- @Test
- public void testRemaining() throws Exception {
+ public void testRemaining() {
assertEquals(SIZE, bytes.remaining());
bytes.position(10);
assertEquals(SIZE - 10, bytes.remaining());
}
@Test
- public void testByteOrder() throws Exception {
+ public void testByteOrder() {
assertEquals(ByteOrder.nativeOrder(), bytes.byteOrder());
}
@Test
- public void testCheckEndOfBuffer() throws Exception {
+ public void testCheckEndOfBuffer() {
bytes.checkEndOfBuffer();
- bytes.position(SIZE + 2);
try {
+ bytes.position(SIZE + 2);
bytes.checkEndOfBuffer();
fail();
} catch (IndexOutOfBoundsException expected) {
@@ -146,11 +147,28 @@ public class ByteBufferBytesTest {
}
private void testAppendDouble0(double d) {
- bytes.position(0);
+ bytes.clear();
bytes.append(d).append(' ');
- bytes.position(0);
+ bytes.flip();
double d2 = bytes.parseDouble();
assertEquals(d, d2, 0);
+
+ bytes.selfTerminating(true);
+ bytes.clear();
+ bytes.append(d);
+ bytes.flip();
+ double d3 = bytes.parseDouble();
+ assertEquals(d, d3, 0);
+
+ bytes.selfTerminating(false);
+ bytes.clear();
+ bytes.append(d);
+ bytes.flip();
+ try {
+ fail("got " + bytes.parseDouble());
+ } catch (BufferUnderflowException expected) {
+ // expected
+ }
}
@Test
@@ -175,7 +193,7 @@ public class ByteBufferBytesTest {
bytes.position(0);
bytes.append(d, precision).append(' ');
bytes.position(0);
- String text = bytes.parseUTF(SPACE_STOP);
+ String text = bytes.parseUtf8(SPACE_STOP);
bytes.position(0);
assertEquals(0, bytes.position());
double d2 = bytes.parseDouble();
@@ -252,19 +270,19 @@ public class ByteBufferBytesTest {
bytes.append(word).append('\t');
}
bytes.append('\t');
- bytes.position(0);
+ bytes.flip();
for (String word : words) {
- assertEquals(word, bytes.parseUTF(CONTROL_STOP));
+ assertEquals(word, bytes.parseUtf8(CONTROL_STOP));
}
- assertEquals("", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("", bytes.parseUtf8(CONTROL_STOP));
bytes.position(0);
StringBuilder sb = new StringBuilder();
for (String word : words) {
- bytes.parseUTF(sb, CONTROL_STOP);
+ bytes.parseUtf8(sb, CONTROL_STOP);
assertEquals(word, sb.toString());
}
- bytes.parseUTF(sb, CONTROL_STOP);
+ bytes.parseUtf8(sb, CONTROL_STOP);
assertEquals("", sb.toString());
bytes.position(0);
@@ -272,10 +290,11 @@ public class ByteBufferBytesTest {
assertEquals(6, bytes.position());
bytes.skipTo(CONTROL_STOP);
assertEquals(13, bytes.position());
- bytes.skipTo(CONTROL_STOP);
- assertEquals(17, bytes.position());
- bytes.skipTo(CONTROL_STOP);
- assertEquals(18, bytes.position());
+ assertTrue(bytes.skipTo(CONTROL_STOP));
+ assertEquals(23, bytes.position());
+ assertTrue(bytes.skipTo(CONTROL_STOP));
+ assertEquals(24, bytes.position());
+ assertFalse(bytes.skipTo(CONTROL_STOP));
bytes.position(0);
bytes.stepBackAndSkipTo(CONTROL_STOP);
@@ -285,7 +304,6 @@ public class ByteBufferBytesTest {
bytes.position(10);
bytes.stepBackAndSkipTo(CONTROL_STOP);
assertEquals(13, bytes.position());
-
}
@Test
@@ -562,8 +580,8 @@ public class ByteBufferBytesTest {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd'T'HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String asStr = sdf.format(new Date(now));
- assertEquals(asStr, bytes.parseUTF(SPACE_STOP));
- assertEquals(asStr, bytes.parseUTF(SPACE_STOP));
+ assertEquals(asStr, bytes.parseUtf8(SPACE_STOP));
+ assertEquals(asStr, bytes.parseUtf8(SPACE_STOP));
}
@Test
@@ -636,7 +654,7 @@ public class ByteBufferBytesTest {
public void testAppendSubstring() {
bytes.append("Hello World", 2, 7).append("\n");
bytes.position(0);
- assertEquals("Hello World".substring(2, 7), bytes.parseUTF(CONTROL_STOP));
+ assertEquals("Hello World".substring(2, 7), bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -658,18 +676,51 @@ public class ByteBufferBytesTest {
bytes.append(1234).append(' ');
bytes.append(123456L).append(' ');
bytes.append(1.2345).append(' ');
+
bytes.append(1.5555, 3).append(' ');
bytes.position(0);
assertEquals(false, bytes.parseBoolean(SPACE_STOP));
assertEquals(true, bytes.parseBoolean(SPACE_STOP));
assertEquals(null, bytes.parseBoolean(SPACE_STOP));
- assertEquals("word£€", bytes.parseUTF(SPACE_STOP));
+ assertEquals("word£€", bytes.parseUtf8(SPACE_STOP));
assertEquals(BuySell.Buy, bytes.parseEnum(BuySell.class, SPACE_STOP));
assertEquals(1234, bytes.parseLong());
assertEquals(123456L, bytes.parseLong());
assertEquals(1.2345, bytes.parseDouble(), 0);
assertEquals(1.556, bytes.parseDouble(), 0);
+ }
+ @Test
+ public void testSelfTerminating() {
+ bytes.limit(0);
+ bytes.selfTerminating(true);
+ assertEquals(null, bytes.parseBoolean(ALL));
+ assertEquals(0L, bytes.parseLong());
+ assertEquals(0.0, bytes.parseDouble(), 0.0);
+ assertEquals("", bytes.parseUtf8(ALL));
+ assertEquals(null, bytes.parseEnum(StopCharTesters.class, ALL));
+
+ bytes.selfTerminating(false);
+ try {
+ fail("got " + bytes.parseBoolean(ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseLong());
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseDouble());
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseUtf8(ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseEnum(StopCharTesters.class, ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
}
@Test
@@ -690,7 +741,7 @@ public class ByteBufferBytesTest {
bytes.write("good bye\n".getBytes(), 4, 4);
bytes.write(4, "0 w".getBytes());
bytes.position(0);
- assertEquals("Hell0 worl bye", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("Hell0 worl bye", bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -698,7 +749,7 @@ public class ByteBufferBytesTest {
bytes.append(Arrays.asList(1, 2, 3, 4, 5), ";").append(' ');
bytes.append(new TreeSet<Integer>(Arrays.asList(21, 2, 13, 4, 5)), ";");
bytes.position(0);
- assertEquals("1;2;3;4;5 2;4;5;13;21", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("1;2;3;4;5 2;4;5;13;21", bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -723,14 +774,14 @@ public class ByteBufferBytesTest {
bytes.position(0);
bytes.parseDecimal(md2);
bytes.position(0);
- String text = bytes.parseUTF(CONTROL_STOP);
+ String text = bytes.parseUtf8(CONTROL_STOP);
if (!md.equals(md2))
assertEquals("n: " + n + ", s: " + j + " t: " + text, md, md2);
}
@Test
public void testStream() throws IOException {
- bytes = new ByteBufferBytes(ByteBuffer.allocate(1000));
+ bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(1000));
GZIPOutputStream out = new GZIPOutputStream(bytes.outputStream());
out.write("Hello world\n".getBytes());
out.close();
@@ -777,7 +828,7 @@ public class ByteBufferBytesTest {
@Test
public void testWriteObject() {
- for (Object o : new Object[]{10, 9.9, "string", new Date(), BigDecimal.valueOf(1.1)}) {
+ for (Object o : new Object[]{BigDecimal.valueOf(-1.234), 10, 9.9, "string", new Date(), BigDecimal.valueOf(1.1)}) {
bytes.position(0);
bytes.writeObject(o);
// System.out.println(o +" size: "+bytes.position());
@@ -795,7 +846,7 @@ public class ByteBufferBytesTest {
public void testWriteSerializable() {
int capacity = 16 * 1024;
byteBuffer = ByteBuffer.allocateDirect(capacity);
- bytes = new ByteBufferBytes(byteBuffer);
+ bytes = ByteBufferBytes.wrap(byteBuffer);
Calendar cal = Calendar.getInstance();
bytes.writeObject(cal);
Dummy d = new Dummy();
@@ -820,6 +871,50 @@ public class ByteBufferBytesTest {
assertEquals(11 * 11, bytes.readInt(4L));
}
+ @Test
+ public void testReadWriteMarshallable() {
+ // generate a class for this interface.
+ // you can use any hand written BytesMarshallable
+ MyMarshallable mm = DataValueClasses.newInstance(MyMarshallable.class);
+
+ mm.setNum(5);
+ mm.setBig(3.1415);
+ mm.setText("Hello World");
+
+ // write to a byte[]
+ ByteBuffer byteBuffer = ByteBuffer.allocate(128);
+ IByteBufferBytes bbb = ByteBufferBytes.wrap(byteBuffer);
+ mm.writeMarshallable(bbb);
+
+ // how much data was written.
+ int len = (int) bbb.position();
+ byte[] bytes = byteBuffer.array();
+
+ // deserialize from a byte[]
+ MyMarshallable mm2 = DataValueClasses.newInstance(MyMarshallable.class);
+ IByteBufferBytes bbb2 = ByteBufferBytes.wrap(ByteBuffer.wrap(bytes));
+ bbb2.limit(len);
+ mm2.readMarshallable(bbb2);
+
+ assertEquals(5, mm2.getNum());
+ assertEquals(3.1415, mm2.getBig(), 0.0);
+ assertEquals("Hello World", mm2.getText());
+ }
+
+ interface MyMarshallable extends BytesMarshallable {
+ int getNum();
+
+ void setNum(int num);
+
+ double getBig();
+
+ void setBig(double d);
+
+ String getText();
+
+ void setText(@MaxSize(16) String text);
+ }
+
enum BuySell {
Buy, Sell
}
@@ -853,7 +948,7 @@ public class ByteBufferBytesTest {
bytes.finish();
bytes.flush();
- bytes.reset();
+ bytes.clear();
assertEquals(0, bytes.position());
assertEquals(8, bytes.skip(8));
assertEquals(8, bytes.position());
@@ -865,15 +960,15 @@ public class ByteBufferBytesTest {
public void testWriteList() {
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
bytes.writeList(ints);
- bytes.reset();
+ bytes.clear();
List<Integer> ints2 = new ArrayList<Integer>();
bytes.readList(ints2, Integer.class);
assertEquals(ints, ints2);
- bytes.reset();
+ bytes.clear();
List<String> words = Arrays.asList("Hello word byte for now".split(" "));
bytes.writeList(words);
- bytes.reset();
+ bytes.clear();
List<String> words2 = new ArrayList<String>();
bytes.readList(words2, String.class);
}
@@ -892,7 +987,7 @@ public class ByteBufferBytesTest {
bytes.writeMap(map);
bytes.finish();
- bytes.reset();
+ bytes.clear();
Map<String, Integer> map2 = new LinkedHashMap<String, Integer>();
bytes.readMap(map2, String.class, Integer.class);
assertEquals(map, map2);
@@ -904,7 +999,7 @@ public class ByteBufferBytesTest {
ExecutorService es = Executors.newSingleThreadExecutor(new NamedThreadFactory("unloadFailed"));
Future<Void> future = es.submit(new Callable<Void>() {
@Override
- public Void call() throws Exception {
+ public Void call() {
bytes.unlockInt(0);
return null;
}
@@ -917,4 +1012,26 @@ public class ByteBufferBytesTest {
assertEquals(IllegalMonitorStateException.class, e.getCause().getClass());
}
}
+
+ @Test
+ public void testToString() {
+ NativeBytes bytes = new DirectStore(32).bytes();
+ assertEquals("[pos: 0, lim: 32, cap: 32 ] ٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(1);
+ assertEquals("[pos: 1, lim: 32, cap: 32 ] ⒈‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(2);
+ assertEquals("[pos: 2, lim: 32, cap: 32 ] ⒈⒉‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(3);
+ assertEquals("[pos: 3, lim: 32, cap: 32 ] ⒈⒉⒊‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(4);
+ assertEquals("[pos: 4, lim: 32, cap: 32 ] ⒈⒉⒊⒋‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(5);
+ assertEquals("[pos: 5, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(6);
+ assertEquals("[pos: 6, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(7);
+ assertEquals("[pos: 7, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍⒎‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(8);
+ assertEquals("[pos: 8, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍⒎⒏‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ }
}
diff --git a/lang/src/test/java/net/openhft/lang/io/BytesTest.java b/lang/src/test/java/net/openhft/lang/io/BytesTest.java
new file mode 100755
index 0000000..e44c110
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/BytesTest.java
@@ -0,0 +1,28 @@
+package net.openhft.lang.io;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Created by peter.lawrey on 06/08/2015.
+ */
+public class BytesTest {
+ @Test
+ public void testReadEnum() {
+ Bytes b = DirectStore.allocate(128).bytes();
+ b.writeEnum("Hello");
+ b.writeEnum("World");
+ b.flip();
+ String x = b.readEnum(String.class);
+ String y = b.readEnum(String.class);
+ assertNotSame(x, y);
+ b.position(0);
+ String x2 = b.readEnum(String.class);
+ String y2 = b.readEnum(String.class);
+ assertNotSame(x2, y2);
+ assertSame(x, x2);
+ assertSame(y, y2);
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/DirectByteBufferBytesTest.java b/lang/src/test/java/net/openhft/lang/io/DirectByteBufferBytesTest.java
index bba0933..c3d35b6 100644..100755
--- a/lang/src/test/java/net/openhft/lang/io/DirectByteBufferBytesTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/DirectByteBufferBytesTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -23,6 +23,7 @@ import org.junit.Test;
import java.io.*;
import java.math.BigDecimal;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
@@ -31,8 +32,7 @@ import java.util.concurrent.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-import static net.openhft.lang.io.StopCharTesters.CONTROL_STOP;
-import static net.openhft.lang.io.StopCharTesters.SPACE_STOP;
+import static net.openhft.lang.io.StopCharTesters.*;
import static org.junit.Assert.*;
/**
@@ -41,17 +41,17 @@ import static org.junit.Assert.*;
*/
public class DirectByteBufferBytesTest {
public static final int SIZE = 128;
- private ByteBufferBytes bytes;
+ private Bytes bytes;
private ByteBuffer byteBuffer;
@Before
public void beforeTest() {
byteBuffer = ByteBuffer.allocateDirect(SIZE).order(ByteOrder.nativeOrder());
- bytes = new ByteBufferBytes(byteBuffer);
+ bytes = ByteBufferBytes.wrap(byteBuffer);
}
@Test
- public void testLongHash() throws Exception {
+ public void testLongHash() {
byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8};
long h = NativeBytes.longHash(bytes, 0, bytes.length);
assertFalse(h == 0);
@@ -62,7 +62,7 @@ public class DirectByteBufferBytesTest {
}
@Test
- public void testRead() throws Exception {
+ public void testRead() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.writeByte(i, i);
bytes.position(0);
@@ -71,11 +71,10 @@ public class DirectByteBufferBytesTest {
for (int i = (int) (bytes.capacity() - 1); i >= 0; i--) {
assertEquals((byte) i, bytes.readByte(i));
}
-
}
@Test
- public void testReadFully() throws Exception {
+ public void testReadFully() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.write(i);
bytes.position(0);
@@ -86,16 +85,15 @@ public class DirectByteBufferBytesTest {
}
@Test
- public void testCompareAndSetLong() throws Exception {
+ public void testCompareAndSetLong() {
assertTrue(bytes.compareAndSwapLong(0, 0, 1));
assertFalse(bytes.compareAndSwapLong(0, 0, 1));
assertTrue(bytes.compareAndSwapLong(8, 0, 1));
assertTrue(bytes.compareAndSwapLong(0, 1, 2));
-
}
@Test
- public void testPosition() throws Exception {
+ public void testPosition() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.write(i);
for (int i = (int) (bytes.capacity() - 1); i >= 0; i--) {
@@ -105,29 +103,23 @@ public class DirectByteBufferBytesTest {
}
@Test
- public void testCapacity() throws Exception {
- assertEquals(SIZE, bytes.capacity());
- assertEquals(10, new NativeBytes(0, 0, 10).capacity());
- }
-
- @Test
- public void testRemaining() throws Exception {
+ public void testRemaining() {
assertEquals(SIZE, bytes.remaining());
bytes.position(10);
assertEquals(SIZE - 10, bytes.remaining());
}
@Test
- public void testByteOrder() throws Exception {
+ public void testByteOrder() {
assertEquals(ByteOrder.nativeOrder(), bytes.byteOrder());
}
@Test
- public void testCheckEndOfBuffer() throws Exception {
+ public void testCheckEndOfBuffer() {
bytes.checkEndOfBuffer();
- bytes.position(SIZE + 2);
try {
+ bytes.position(SIZE + 2);
bytes.checkEndOfBuffer();
fail();
} catch (IndexOutOfBoundsException expected) {
@@ -175,7 +167,7 @@ public class DirectByteBufferBytesTest {
bytes.position(0);
bytes.append(d, precision).append(' ');
bytes.position(0);
- String text = bytes.parseUTF(SPACE_STOP);
+ String text = bytes.parseUtf8(SPACE_STOP);
bytes.position(0);
assertEquals(0, bytes.position());
double d2 = bytes.parseDouble();
@@ -252,19 +244,19 @@ public class DirectByteBufferBytesTest {
bytes.append(word).append('\t');
}
bytes.append('\t');
- bytes.position(0);
+ bytes.flip();
for (String word : words) {
- assertEquals(word, bytes.parseUTF(CONTROL_STOP));
+ assertEquals(word, bytes.parseUtf8(CONTROL_STOP));
}
- assertEquals("", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("", bytes.parseUtf8(CONTROL_STOP));
bytes.position(0);
StringBuilder sb = new StringBuilder();
for (String word : words) {
- bytes.parseUTF(sb, CONTROL_STOP);
+ bytes.parseUtf8(sb, CONTROL_STOP);
assertEquals(word, sb.toString());
}
- bytes.parseUTF(sb, CONTROL_STOP);
+ bytes.parseUtf8(sb, CONTROL_STOP);
assertEquals("", sb.toString());
bytes.position(0);
@@ -272,10 +264,11 @@ public class DirectByteBufferBytesTest {
assertEquals(6, bytes.position());
bytes.skipTo(CONTROL_STOP);
assertEquals(13, bytes.position());
- bytes.skipTo(CONTROL_STOP);
- assertEquals(17, bytes.position());
- bytes.skipTo(CONTROL_STOP);
- assertEquals(18, bytes.position());
+ assertTrue(bytes.skipTo(CONTROL_STOP));
+ assertEquals(23, bytes.position());
+ assertTrue(bytes.skipTo(CONTROL_STOP));
+ assertEquals(24, bytes.position());
+ assertFalse(bytes.skipTo(CONTROL_STOP));
bytes.position(0);
bytes.stepBackAndSkipTo(CONTROL_STOP);
@@ -285,7 +278,6 @@ public class DirectByteBufferBytesTest {
bytes.position(10);
bytes.stepBackAndSkipTo(CONTROL_STOP);
assertEquals(13, bytes.position());
-
}
@Test
@@ -562,8 +554,8 @@ public class DirectByteBufferBytesTest {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd'T'HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String asStr = sdf.format(new Date(now));
- assertEquals(asStr, bytes.parseUTF(SPACE_STOP));
- assertEquals(asStr, bytes.parseUTF(SPACE_STOP));
+ assertEquals(asStr, bytes.parseUtf8(SPACE_STOP));
+ assertEquals(asStr, bytes.parseUtf8(SPACE_STOP));
}
@Test
@@ -636,7 +628,7 @@ public class DirectByteBufferBytesTest {
public void testAppendSubstring() {
bytes.append("Hello World", 2, 7).append("\n");
bytes.position(0);
- assertEquals("Hello World".substring(2, 7), bytes.parseUTF(CONTROL_STOP));
+ assertEquals("Hello World".substring(2, 7), bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -658,18 +650,96 @@ public class DirectByteBufferBytesTest {
bytes.append(1234).append(' ');
bytes.append(123456L).append(' ');
bytes.append(1.2345).append(' ');
- bytes.append(1.5555, 3).append(' ');
+
+ bytes.append(1.1234567891, 9).append(' ');
+ bytes.append(1.1234567).append(' ');
bytes.position(0);
assertEquals(false, bytes.parseBoolean(SPACE_STOP));
assertEquals(true, bytes.parseBoolean(SPACE_STOP));
assertEquals(null, bytes.parseBoolean(SPACE_STOP));
- assertEquals("word£€", bytes.parseUTF(SPACE_STOP));
+ assertEquals("word£€", bytes.parseUtf8(SPACE_STOP));
assertEquals(BuySell.Buy, bytes.parseEnum(BuySell.class, SPACE_STOP));
assertEquals(1234, bytes.parseLong());
assertEquals(123456L, bytes.parseLong());
assertEquals(1.2345, bytes.parseDouble(), 0);
- assertEquals(1.556, bytes.parseDouble(), 0);
+ assertEquals(1.123456789, bytes.parseDouble(), 0);
+ assertEquals(1.1234567, bytes.parseDouble(), 0);
+ }
+
+ @Test
+ public void testSelfTerminating() {
+ bytes.limit(0);
+ bytes.selfTerminating(true);
+ assertEquals(null, bytes.parseBoolean(ALL));
+ assertEquals(0L, bytes.parseLong());
+ assertEquals(0.0, bytes.parseDouble(), 0.0);
+ assertEquals("", bytes.parseUtf8(ALL));
+ assertEquals(null, bytes.parseEnum(StopCharTesters.class, ALL));
+
+ bytes.selfTerminating(false);
+ try {
+ fail("got " + bytes.parseBoolean(ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseLong());
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseDouble());
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseUtf8(ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseEnum(StopCharTesters.class, ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ }
+
+ @Test
+ public void testAppendParseDouble0() {
+ bytes.append(1.123456789234, 7).append(' ');
+ bytes.append(1.123456789234, 7).append(' ');
+ bytes.position(0);
+ assertEquals(1.1234568, bytes.parseDouble(), 0);
+ assertEquals(1.1234568, bytes.parseDouble(), 0);
+ }
+
+ @Test
+ public void testAppendParseDouble1() {
+ bytes.append(1.123456789);
+ bytes.position(0);
+ assertEquals(1.123456789, bytes.parseDouble(), 0);
+ }
+ @Test
+ public void testAppendParseDoubleWithPadding() {
+ bytes.append("qwertyuiop").append(' ');
+ bytes.append(1.123456789).append(' ');
+ bytes.append(123456L);
+ bytes.position(0);
+ assertEquals("qwertyuiop", bytes.parseUtf8(SPACE_STOP));
+ assertEquals(1.123456789, bytes.parseDouble(), 0);
+ assertEquals(123456, bytes.parseLong());
+ }
+
+ @Test
+ public void testAppendParseDoubleWithPadding2() {
+ bytes.append(1.2345, 3).append(' ');
+ bytes.append(2.1234567891, 9).append(' ');
+ bytes.position(0);
+ assertEquals(1.235, bytes.parseDouble(), 0);
+ assertEquals(2.123456789, bytes.parseDouble(), 0);
+ }
+
+ @Test
+ public void testAppendParseDouble2() {
+ bytes.append(1.1234).append(' ');
+ bytes.position(0);
+ assertEquals(1.1234, bytes.parseDouble(), 0);
}
@Test
@@ -690,7 +760,7 @@ public class DirectByteBufferBytesTest {
bytes.write("good bye\n".getBytes(), 4, 4);
bytes.write(4, "0 w".getBytes());
bytes.position(0);
- assertEquals("Hell0 worl bye", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("Hell0 worl bye", bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -698,7 +768,7 @@ public class DirectByteBufferBytesTest {
bytes.append(Arrays.asList(1, 2, 3, 4, 5), ";").append(' ');
bytes.append(new TreeSet<Integer>(Arrays.asList(21, 2, 13, 4, 5)), ";");
bytes.position(0);
- assertEquals("1;2;3;4;5 2;4;5;13;21", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("1;2;3;4;5 2;4;5;13;21", bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -723,14 +793,14 @@ public class DirectByteBufferBytesTest {
bytes.position(0);
bytes.parseDecimal(md2);
bytes.position(0);
- String text = bytes.parseUTF(CONTROL_STOP);
+ String text = bytes.parseUtf8(CONTROL_STOP);
if (!md.equals(md2))
assertEquals("n: " + n + ", s: " + j + " t: " + text, md, md2);
}
@Test
public void testStream() throws IOException {
- bytes = new ByteBufferBytes(ByteBuffer.allocateDirect(1000));
+ bytes = ByteBufferBytes.wrap(ByteBuffer.allocateDirect(1000));
GZIPOutputStream out = new GZIPOutputStream(bytes.outputStream());
out.write("Hello world\n".getBytes());
out.close();
@@ -795,7 +865,7 @@ public class DirectByteBufferBytesTest {
public void testWriteSerializable() {
int capacity = 16 * 1024;
byteBuffer = ByteBuffer.allocateDirect(capacity);
- bytes = new ByteBufferBytes(byteBuffer);
+ bytes = ByteBufferBytes.wrap(byteBuffer);
Calendar cal = Calendar.getInstance();
bytes.writeObject(cal);
Dummy d = new Dummy();
@@ -854,7 +924,7 @@ public class DirectByteBufferBytesTest {
bytes.finish();
bytes.flush();
- bytes.reset();
+ bytes.clear();
assertEquals(0, bytes.position());
assertEquals(8, bytes.skip(8));
assertEquals(8, bytes.position());
@@ -866,15 +936,15 @@ public class DirectByteBufferBytesTest {
public void testWriteList() {
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
bytes.writeList(ints);
- bytes.reset();
+ bytes.clear();
List<Integer> ints2 = new ArrayList<Integer>();
bytes.readList(ints2, Integer.class);
assertEquals(ints, ints2);
- bytes.reset();
+ bytes.clear();
List<String> words = Arrays.asList("Hello word byte for now".split(" "));
bytes.writeList(words);
- bytes.reset();
+ bytes.clear();
List<String> words2 = new ArrayList<String>();
bytes.readList(words2, String.class);
}
@@ -893,7 +963,7 @@ public class DirectByteBufferBytesTest {
bytes.writeMap(map);
bytes.finish();
- bytes.reset();
+ bytes.clear();
Map<String, Integer> map2 = new LinkedHashMap<String, Integer>();
bytes.readMap(map2, String.class, Integer.class);
assertEquals(map, map2);
@@ -905,7 +975,7 @@ public class DirectByteBufferBytesTest {
ExecutorService es = Executors.newSingleThreadExecutor(new NamedThreadFactory("unloadFailed"));
Future<Void> future = es.submit(new Callable<Void>() {
@Override
- public Void call() throws Exception {
+ public Void call() {
bytes.unlockInt(0);
return null;
}
@@ -918,4 +988,68 @@ public class DirectByteBufferBytesTest {
assertEquals(IllegalMonitorStateException.class, e.getCause().getClass());
}
}
+
+ @Test
+ public void testToString() {
+ NativeBytes bytes = new DirectStore(32).bytes();
+ assertEquals("[pos: 0, lim: 32, cap: 32 ] ٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(1);
+ assertEquals("[pos: 1, lim: 32, cap: 32 ] ⒈‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(2);
+ assertEquals("[pos: 2, lim: 32, cap: 32 ] ⒈⒉‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(3);
+ assertEquals("[pos: 3, lim: 32, cap: 32 ] ⒈⒉⒊‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(4);
+ assertEquals("[pos: 4, lim: 32, cap: 32 ] ⒈⒉⒊⒋‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(5);
+ assertEquals("[pos: 5, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(6);
+ assertEquals("[pos: 6, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(7);
+ assertEquals("[pos: 7, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍⒎‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(8);
+ assertEquals("[pos: 8, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍⒎⒏‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ }
+
+ @Test
+ public void testResizeKeepData() {
+ DirectByteBufferBytes buffer = new DirectByteBufferBytes(16);
+ for (int i = 1; buffer.position() < buffer.capacity(); i++) {
+ buffer.writeInt(i);
+ }
+
+ buffer.resize(32, true, true).position(0L);
+ for(int i=1;i <= 8; i++) {
+ if(i <= 4 ) {
+ assertEquals(i, buffer.readInt());
+
+ } else {
+ assertEquals(0, buffer.readInt());
+ }
+ }
+ }
+
+ @Test
+ public void testResizeDeleteData() {
+ DirectByteBufferBytes buffer = new DirectByteBufferBytes(16);
+ for (int i = 1; buffer.position() < buffer.capacity(); i++) {
+ buffer.writeInt(i);
+ }
+
+ buffer.resize(32, true, false).position(0L);
+
+ for(int i=1;i <= 8; i++) {
+ assertEquals(0, buffer.readInt());
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testResizeExceptionData() {
+ DirectByteBufferBytes buffer = new DirectByteBufferBytes(16);
+ for (int i = 1; buffer.position() < buffer.capacity(); i++) {
+ buffer.writeInt(i);
+ }
+
+ buffer.resize(4, true, true);
+ }
}
diff --git a/lang/src/test/java/net/openhft/lang/io/DirectBytesTest.java b/lang/src/test/java/net/openhft/lang/io/DirectBytesTest.java
index 090b0b5..6724309 100755..100644
--- a/lang/src/test/java/net/openhft/lang/io/DirectBytesTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/DirectBytesTest.java
@@ -1,22 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
+import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
@@ -25,33 +26,12 @@ import static org.junit.Assert.*;
* @author peter.lawrey
*/
public class DirectBytesTest {
- @Test
- public void testSimpleLock() {
- DirectBytes bytes = new DirectStore(64).createSlice();
- bytes.writeLong(0, -1L);
- assertFalse(bytes.tryLockLong(0));
- bytes.writeLong(0, 0L);
- assertTrue(bytes.tryLockLong(0));
- long val1 = bytes.readLong(0);
- assertTrue(bytes.tryLockLong(0));
- bytes.unlockLong(0);
- assertEquals(val1, bytes.readLong(0));
- bytes.unlockLong(0);
- assertEquals(0L, bytes.readLong(0));
- try {
- bytes.unlockLong(0);
- fail();
- } catch (IllegalMonitorStateException e) {
- // expected.
- }
- }
-
private static void manyToggles(@NotNull DirectStore store1, int lockCount, int from, int to) {
long id = Thread.currentThread().getId();
assertEquals(0, id >>> 24);
System.out.println("Thread " + id);
- DirectBytes slice1 = store1.createSlice();
+ DirectBytes slice1 = store1.bytes();
int records = 64;
for (int i = 0; i < lockCount; i += records) {
@@ -70,6 +50,7 @@ public class DirectBytesTest {
int toggle1 = slice1.readInt(4);
if (toggle1 == from) {
slice1.writeInt(4L, to);
+
} else {
// noinspection AssignmentToForLoopParameter,AssignmentToForLoopParameter
i--;
@@ -85,7 +66,7 @@ public class DirectBytesTest {
assertEquals(0, id >>> 32);
System.out.println("Thread " + id);
- DirectBytes slice1 = store1.createSlice();
+ DirectBytes slice1 = store1.bytes();
int records = 64;
for (int i = 0; i < lockCount; i += records) {
@@ -104,6 +85,7 @@ public class DirectBytesTest {
long toggle1 = slice1.readLong(8);
if (toggle1 == from) {
slice1.writeLong(8L, to);
+
} else {
// noinspection AssignmentToForLoopParameter,AssignmentToForLoopParameter
i--;
@@ -115,11 +97,32 @@ public class DirectBytesTest {
}
@Test
- public void testAllocate() throws Exception {
+ public void testSimpleLock() {
+ DirectBytes bytes = new DirectStore(64).bytes();
+ bytes.writeLong(0, -1L);
+ assertFalse(bytes.tryLockLong(0));
+ bytes.writeLong(0, 0L);
+ assertTrue(bytes.tryLockLong(0));
+ long val1 = bytes.readLong(0);
+ assertTrue(bytes.tryLockLong(0));
+ bytes.unlockLong(0);
+ assertEquals(val1, bytes.readLong(0));
+ bytes.unlockLong(0);
+ assertEquals(0L, bytes.readLong(0));
+ try {
+ bytes.unlockLong(0);
+ fail();
+ } catch (IllegalMonitorStateException e) {
+ // expected.
+ }
+ }
+
+ @Test
+ public void testAllocate() {
long size = 1L << 24; // 31; don't overload cloud-bees
DirectStore store = DirectStore.allocate(size);
assertEquals(size, store.size());
- DirectBytes slice = store.createSlice();
+ DirectBytes slice = store.bytes();
slice.positionAndSize(0, size);
slice.writeLong(0, size);
slice.writeLong(size - 8, size);
@@ -175,7 +178,7 @@ public class DirectBytesTest {
}
@Test
- public void testLocking2() throws Exception {
+ public void testLocking2() throws InterruptedException {
if (Runtime.getRuntime().availableProcessors() < 2) {
System.err.println("Test requires 2 CPUs, skipping");
return;
@@ -193,8 +196,8 @@ public class DirectBytesTest {
assertEquals(0, id >>> 24);
int expected = (1 << 24) | (int) id;
try {
- DirectBytes slice1 = store1.createSlice();
- DirectBytes slice2 = store2.createSlice();
+ DirectBytes slice1 = store1.bytes();
+ DirectBytes slice2 = store2.bytes();
for (int i = 0; i < lockCount; i += 2) {
slice1.busyLockInt(0);
@@ -210,6 +213,7 @@ public class DirectBytesTest {
slice1.writeInt(4, 0);
// if (i % 10000== 0)
// System.out.println("t: " + i);
+
} else {
// noinspection AssignmentToForLoopParameter
i--;
@@ -219,6 +223,7 @@ public class DirectBytesTest {
slice2.writeInt(4, 0);
// if (i % 10000== 0)
// System.out.println("t: " + i);
+
} else {
// noinspection AssignmentToForLoopParameter
i--;
@@ -249,8 +254,8 @@ public class DirectBytesTest {
int expected = (1 << 24) | (int) id;
System.out.println("Thread " + id);
- DirectBytes slice1 = store1.createSlice();
- DirectBytes slice2 = store2.createSlice();
+ DirectBytes slice1 = store1.bytes();
+ DirectBytes slice2 = store2.bytes();
for (int i = 0; i < lockCount; i += 2) {
slice1.busyLockInt(0);
slice2.busyLockInt(0);
@@ -265,6 +270,7 @@ public class DirectBytesTest {
slice1.writeInt(4, 1);
// if (i % 10000== 0)
// System.out.println("t: " + i);
+
} else {
// noinspection AssignmentToForLoopParameter
i--;
@@ -274,6 +280,7 @@ public class DirectBytesTest {
slice2.writeInt(4, 1);
// if (i % 10000== 0)
// System.out.println("t: " + i);
+
} else {
// noinspection AssignmentToForLoopParameter
i--;
@@ -297,4 +304,22 @@ public class DirectBytesTest {
store2.free();
}
+ @Test
+ @Ignore
+ public void benchmarkByteLargeArray() {
+ long length = 1L << 32;
+ long start = System.nanoTime();
+ DirectBytes array = DirectStore.allocateLazy(length).bytes();
+ System.out.println("Constructor time: " + (System.nanoTime() - start) / 1e9 + " sec");
+ int iters = 2;
+ byte one = 1;
+ start = System.nanoTime();
+ for (int it = 0; it < iters; it++) {
+ for (long i = 0; i < length; i++) {
+ array.writeByte(i, one);
+ array.writeByte(i, (byte) (array.readByte(i) + one));
+ }
+ }
+ System.out.println("Computation time: " + (System.nanoTime() - start) / 1e9 / iters + " sec");
+ }
}
diff --git a/lang/src/test/java/net/openhft/lang/io/IOToolsTest.java b/lang/src/test/java/net/openhft/lang/io/IOToolsTest.java
index 086749d..163c074 100644
--- a/lang/src/test/java/net/openhft/lang/io/IOToolsTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/IOToolsTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
diff --git a/lang/src/test/java/net/openhft/lang/io/LockingViaFileLockMain.java b/lang/src/test/java/net/openhft/lang/io/LockingViaFileLockMain.java
index 46abc86..93fe4b6 100644
--- a/lang/src/test/java/net/openhft/lang/io/LockingViaFileLockMain.java
+++ b/lang/src/test/java/net/openhft/lang/io/LockingViaFileLockMain.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -19,7 +19,6 @@ package net.openhft.lang.io;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
@@ -29,7 +28,7 @@ import java.nio.channels.FileLock;
* Date: 22/12/13
* Time: 11:05
*
- * Toggled 10,000,128 times with an average delay of 2,402 ns
+ * <p>Toggled 10,000,128 times with an average delay of 2,402 ns
*/
public class LockingViaFileLockMain {
static int RECORDS = Integer.getInteger("records", 128);
@@ -46,7 +45,7 @@ public class LockingViaFileLockMain {
File tmpFile = new File(System.getProperty("java.io.tmpdir"), "lock-test.dat");
FileChannel fc = new RandomAccessFile(tmpFile, "rw").getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, RECORDS * RECORD_SIZE);
- ByteBufferBytes bytes = new ByteBufferBytes(mbb.order(ByteOrder.nativeOrder()));
+ ByteBufferBytes bytes = new ByteBufferBytes(mbb);
long start = 0;
for (int i = -WARMUP / RECORDS; i < (RUNS + RECORDS - 1) / RECORDS; i++) {
@@ -61,6 +60,7 @@ public class LockingViaFileLockMain {
if (t == 0)
if (i >= 0) {
throw new AssertionError("Didn't toggle in time !??");
+
} else {
System.out.println("waiting");
t = 99999;
diff --git a/lang/src/test/java/net/openhft/lang/io/LockingViaMMapMain.java b/lang/src/test/java/net/openhft/lang/io/LockingViaMMapMain.java
index a1cddd1..7b57ff5 100644
--- a/lang/src/test/java/net/openhft/lang/io/LockingViaMMapMain.java
+++ b/lang/src/test/java/net/openhft/lang/io/LockingViaMMapMain.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -19,7 +19,6 @@ package net.openhft.lang.io;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
-import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
@@ -28,13 +27,13 @@ import java.nio.channels.FileChannel;
* Date: 22/12/13
* Time: 11:05
*
- * Toggled 10,000,128 times with an average delay of 28 ns
+ * <p>Toggled 100,000,000 times with an average delay of 49 ns
*/
public class LockingViaMMapMain {
static int RECORDS = Integer.getInteger("records", 128);
static int RECORD_SIZE = Integer.getInteger("record_size", 64); // cache line size
static int WARMUP = Integer.getInteger("warmup", RECORDS * 100);
- static int RUNS = Integer.getInteger("runs", 5 * 1000 * 1000);
+ static int RUNS = Integer.getInteger("runs", 50 * 1000 * 1000);
// offsets
static int LOCK = 0;
@@ -46,8 +45,7 @@ public class LockingViaMMapMain {
File tmpFile = new File(System.getProperty("java.io.tmpdir"), "lock-test.dat");
FileChannel fc = new RandomAccessFile(tmpFile, "rw").getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, RECORDS * RECORD_SIZE);
- ByteBufferBytes bytes = new ByteBufferBytes(mbb.order(ByteOrder.nativeOrder()));
- bytes.setCurrentThread();
+ Bytes bytes = ByteBufferBytes.wrap(mbb);
long start = 0;
for (int i = -WARMUP / RECORDS; i < (RUNS + RECORDS - 1) / RECORDS; i++) {
@@ -62,6 +60,7 @@ public class LockingViaMMapMain {
if (t == 0)
if (i >= 0) {
throw new AssertionError("Didn't toggle in time !??");
+
} else {
Thread.sleep(200);
}
@@ -90,7 +89,7 @@ public class LockingViaMMapMain {
long time = System.nanoTime() - start;
final int toggles = (RUNS + RECORDS - 1) / RECORDS * RECORDS * 2; // one for each of two processes.
System.out.printf("Toggled %,d times with an average delay of %,d ns%n",
- toggles, time / toggles);
+ toggles, 2 * time / toggles);
fc.close();
tmpFile.deleteOnExit();
}
diff --git a/lang/src/test/java/net/openhft/lang/io/MappedFileTest.java b/lang/src/test/java/net/openhft/lang/io/MappedFileTest.java
index 6456888..7b3a314 100644
--- a/lang/src/test/java/net/openhft/lang/io/MappedFileTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/MappedFileTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -34,7 +34,6 @@ public class MappedFileTest {
br.close();
throw ioe;
}
-
}
public static void delete(File file) throws IOException {
@@ -69,8 +68,9 @@ public class MappedFileTest {
fill(map1.buffer().force());
long free1 = dir.getFreeSpace();
- map1.release();
- map0.release();
+ mfile.release(map1);
+ mfile.release(map0);
+
mfile.close();
// printMappings();
@@ -85,8 +85,6 @@ public class MappedFileTest {
Thread.sleep(500);
}
assertTrue("free3-free1: " + (free3 - free1), free3 > free1);
-
-
}
private void fill(MappedByteBuffer buffer) {
diff --git a/lang/src/test/java/net/openhft/lang/io/MappedStoreTest.java b/lang/src/test/java/net/openhft/lang/io/MappedStoreTest.java
new file mode 100755
index 0000000..c93cc24
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/MappedStoreTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import net.openhft.lang.Jvm;
+import net.openhft.lang.io.serialization.JDKZObjectSerializer;
+import org.junit.After;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import static org.junit.Assert.assertEquals;
+
+public class MappedStoreTest {
+ //private static final long MS_SIZE = 3L << 30;
+ private static final long MS_SIZE = 1024;
+
+ static File getStoreFile(String fileName) {
+ File file = new File(System.getProperty("java.io.tmpdir"), fileName);
+ file.delete();
+ file.deleteOnExit();
+
+ return file;
+ }
+
+ @After
+ public void tearDown() {
+ System.gc();
+ }
+
+ @Test
+ public void testCreateSlice() throws IOException {
+ File file = new File(System.getProperty("java.io.tmpdir") + "/MappedStoreTest-testCreateSlice" + System.nanoTime() + ".tmp");
+ file.deleteOnExit();
+ long size = Jvm.is64Bit() ? 3L << 30 : 256 << 20;
+ MappedStore ms = new MappedStore(file, FileChannel.MapMode.READ_WRITE, size);
+ DirectBytes slice = ms.bytes();
+ assertEquals(1, slice.refCount());
+ assertEquals(0L, slice.readLong(0L));
+ assertEquals(0L, slice.readLong(ms.size() - 8));
+
+ slice.writeLong(0,1L);
+ assertEquals(1L,slice.readLong(0));
+
+ slice.release();
+
+ ms.close();
+ }
+
+ @Test
+ public void testOpenExistingFile() throws IOException {
+ File file = getStoreFile("mapped-store-2.tmp");
+
+ {
+ MappedStore ms1 = new MappedStore(file, FileChannel.MapMode.READ_WRITE, MS_SIZE);
+ DirectBytes slice1 = ms1.bytes();
+ assertEquals(1, slice1.refCount());
+
+ slice1.writeLong(1L);
+ slice1.writeLong(2L);
+ slice1.release();
+
+ ms1.close();
+ }
+
+ {
+ MappedStore ms2 = new MappedStore(file, FileChannel.MapMode.READ_WRITE, MS_SIZE);
+ DirectBytes slice2 = ms2.bytes();
+ assertEquals( 1, slice2.refCount());
+ assertEquals(1L, slice2.readLong());
+ assertEquals(2L, slice2.readLong());
+
+ slice2.release();
+
+ ms2.close();
+ }
+ }
+
+ /*
+ @Test
+ public void testSliceSize() {
+ File file = getStoreFile("mapped-store");
+
+ MappedStore ms = new MappedStore(file, FileChannel.MapMode.READ_WRITE, MS_SIZE);
+ DirectBytes slice = ms.bytes();
+
+ for(long i=0;i<MS_SIZE+1;i += 8) {
+ slice.writeLong(i);
+ }
+
+ slice.release();
+ ms.free();
+ }
+ */
+ // *************************************************************************
+ // Helpers
+ // *************************************************************************
+
+ @Test
+ public void testCreateMappedStoreWithOffset() throws IOException {
+ final int _64k = 64 * 1024, _128k = 128 * 1024;
+
+ File file = getStoreFile("mapped-store-3.tmp");
+ fill(file, _128k);
+
+ MappedStore ms = new MappedStore(file, FileChannel.MapMode.READ_WRITE,
+ _64k, _128k, JDKZObjectSerializer.INSTANCE);
+ Bytes bytes = ms.bytes();
+
+ assertEquals(1, bytes.readByte(1));
+ assertEquals(0, bytes.readByte(_64k));
+
+ bytes.release();
+ ms.close();
+ }
+
+ private void fill(File file, int expectedSize) throws IOException {
+ MappedStore ms = new MappedStore(file, FileChannel.MapMode.READ_WRITE, expectedSize);
+ Bytes bytes = ms.bytes();
+ for (int i = 0; i < expectedSize; ++i) {
+ bytes.writeUnsignedByte(i);
+ }
+ bytes.release();
+ ms.close();
+ }
+}
+
diff --git a/lang/src/test/java/net/openhft/lang/io/MutableDecimalTest.java b/lang/src/test/java/net/openhft/lang/io/MutableDecimalTest.java
index ba6796e..055a7b7 100644
--- a/lang/src/test/java/net/openhft/lang/io/MutableDecimalTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/MutableDecimalTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
@@ -36,7 +36,11 @@ public class MutableDecimalTest {
assertEquals(Long.MAX_VALUE / 1e10, md2.doubleValue(), 0);
assertEquals("922337203.6854775807", md2.toString());
- MutableDecimal md3 = new MutableDecimal(Math.PI, 6);
+ MutableDecimal md2b = new MutableDecimal((double) Long.MAX_VALUE, 10);
+ assertEquals(Long.MAX_VALUE / 1e10, md2b.doubleValue(), 0);
+ assertEquals("922337203.6854775807", md2b.toString());
+
+ MutableDecimal md3 = new MutableDecimal(Math.PI * Math.pow(10, 6), 6);
assertEquals(3.141593, md3.doubleValue(), 0);
assertEquals(3.141593f, md3.floatValue(), 0);
assertEquals(3, md3.intValue());
diff --git a/lang/src/test/java/net/openhft/lang/io/NativeBytesTest.java b/lang/src/test/java/net/openhft/lang/io/NativeBytesTest.java
index 2b50825..bcfa95b 100644..100755
--- a/lang/src/test/java/net/openhft/lang/io/NativeBytesTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/NativeBytesTest.java
@@ -1,22 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io;
import net.openhft.lang.Maths;
+import net.openhft.lang.model.Byteable;
import net.openhft.lang.thread.NamedThreadFactory;
import org.junit.Before;
import org.junit.Test;
@@ -24,6 +25,7 @@ import sun.nio.ch.DirectBuffer;
import java.io.*;
import java.math.BigDecimal;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
@@ -32,8 +34,9 @@ import java.util.concurrent.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-import static net.openhft.lang.io.StopCharTesters.CONTROL_STOP;
-import static net.openhft.lang.io.StopCharTesters.SPACE_STOP;
+import static net.openhft.lang.io.StopCharTesters.*;
+import static net.openhft.lang.model.DataValueClasses.newDirectInstance;
+import static net.openhft.lang.model.DataValueClasses.newDirectReference;
import static org.junit.Assert.*;
/**
@@ -49,11 +52,11 @@ public class NativeBytesTest {
public void beforeTest() {
byteBuffer = ByteBuffer.allocateDirect(SIZE);
long addr = ((DirectBuffer) byteBuffer).address();
- bytes = new NativeBytes(addr, addr, addr + SIZE);
+ bytes = new NativeBytes(addr, addr + SIZE);
}
@Test
- public void testLongHash() throws Exception {
+ public void testLongHash() {
byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8};
long h = NativeBytes.longHash(bytes, 0, bytes.length);
assertFalse(h == 0);
@@ -64,7 +67,7 @@ public class NativeBytesTest {
}
@Test
- public void testRead() throws Exception {
+ public void testRead() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.writeByte(i, i);
bytes.position(0);
@@ -73,11 +76,10 @@ public class NativeBytesTest {
for (int i = (int) (bytes.capacity() - 1); i >= 0; i--) {
assertEquals((byte) i, bytes.readByte(i));
}
-
}
@Test
- public void testReadFully() throws Exception {
+ public void testReadFully() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.write(i);
bytes.position(0);
@@ -88,16 +90,15 @@ public class NativeBytesTest {
}
@Test
- public void testCompareAndSetLong() throws Exception {
+ public void testCompareAndSetLong() {
assertTrue(bytes.compareAndSwapLong(0, 0, 1));
assertFalse(bytes.compareAndSwapLong(0, 0, 1));
assertTrue(bytes.compareAndSwapLong(8, 0, 1));
assertTrue(bytes.compareAndSwapLong(0, 1, 2));
-
}
@Test
- public void testPosition() throws Exception {
+ public void testPosition() {
for (int i = 0; i < bytes.capacity(); i++)
bytes.write(i);
for (int i = (int) (bytes.capacity() - 1); i >= 0; i--) {
@@ -107,31 +108,32 @@ public class NativeBytesTest {
}
@Test
- public void testCapacity() throws Exception {
+ public void testCapacity() {
assertEquals(SIZE, bytes.capacity());
- assertEquals(10, new NativeBytes(0, 0, 10).capacity());
+ assertEquals(10, new NativeBytes(100000, 100010).capacity());
}
@Test
- public void testRemaining() throws Exception {
+ public void testRemaining() {
assertEquals(SIZE, bytes.remaining());
bytes.position(10);
assertEquals(SIZE - 10, bytes.remaining());
}
@Test
- public void testByteOrder() throws Exception {
+ public void testByteOrder() {
assertEquals(ByteOrder.nativeOrder(), bytes.byteOrder());
}
@Test
- public void testCheckEndOfBuffer() throws Exception {
+ public void testCheckEndOfBuffer() {
bytes.checkEndOfBuffer();
- bytes.position(SIZE + 2);
try {
+ bytes.position(SIZE + 2);
bytes.checkEndOfBuffer();
fail();
+ } catch (IllegalArgumentException expected) {
} catch (IndexOutOfBoundsException expected) {
}
}
@@ -148,11 +150,28 @@ public class NativeBytesTest {
}
private void testAppendDouble0(double d) {
- bytes.position(0);
+ bytes.clear();
bytes.append(d).append(' ');
- bytes.position(0);
+ bytes.flip();
double d2 = bytes.parseDouble();
assertEquals(d, d2, 0);
+
+ bytes.selfTerminating(true);
+ bytes.clear();
+ bytes.append(d);
+ bytes.flip();
+ double d3 = bytes.parseDouble();
+ assertEquals(d, d3, 0);
+
+ bytes.selfTerminating(false);
+ bytes.clear();
+ bytes.append(d);
+ bytes.flip();
+ try {
+ fail("got " + bytes.parseDouble());
+ } catch (BufferUnderflowException expected) {
+ // expected
+ }
}
@Test
@@ -177,7 +196,7 @@ public class NativeBytesTest {
bytes.position(0);
bytes.append(d, precision).append(' ');
bytes.position(0);
- String text = bytes.parseUTF(SPACE_STOP);
+ String text = bytes.parseUtf8(SPACE_STOP);
bytes.position(0);
assertEquals(0, bytes.position());
double d2 = bytes.parseDouble();
@@ -199,7 +218,7 @@ public class NativeBytesTest {
this.bytes.write(22, bytes);
byte[] bytes3 = new byte[bytes.length];
- this.bytes.skipBytes((int) (22 - this.bytes.position()));
+ this.bytes.position(22);
assertEquals(bytes3.length, this.bytes.read(bytes3));
assertTrue(Arrays.equals(bytes, bytes3));
this.bytes.position(this.bytes.capacity());
@@ -254,19 +273,19 @@ public class NativeBytesTest {
bytes.append(word).append('\t');
}
bytes.append('\t');
- bytes.position(0);
+ bytes.flip();
for (String word : words) {
- assertEquals(word, bytes.parseUTF(CONTROL_STOP));
+ assertEquals(word, bytes.parseUtf8(CONTROL_STOP));
}
- assertEquals("", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("", bytes.parseUtf8(CONTROL_STOP));
bytes.position(0);
StringBuilder sb = new StringBuilder();
for (String word : words) {
- bytes.parseUTF(sb, CONTROL_STOP);
+ bytes.parseUtf8(sb, CONTROL_STOP);
assertEquals(word, sb.toString());
}
- bytes.parseUTF(sb, CONTROL_STOP);
+ bytes.parseUtf8(sb, CONTROL_STOP);
assertEquals("", sb.toString());
bytes.position(0);
@@ -274,10 +293,11 @@ public class NativeBytesTest {
assertEquals(6, bytes.position());
bytes.skipTo(CONTROL_STOP);
assertEquals(13, bytes.position());
- bytes.skipTo(CONTROL_STOP);
- assertEquals(17, bytes.position());
- bytes.skipTo(CONTROL_STOP);
- assertEquals(18, bytes.position());
+ assertTrue(bytes.skipTo(CONTROL_STOP));
+ assertEquals(23, bytes.position());
+ assertTrue(bytes.skipTo(CONTROL_STOP));
+ assertEquals(24, bytes.position());
+ assertFalse(bytes.skipTo(CONTROL_STOP));
bytes.position(0);
bytes.stepBackAndSkipTo(CONTROL_STOP);
@@ -287,7 +307,6 @@ public class NativeBytesTest {
bytes.position(10);
bytes.stepBackAndSkipTo(CONTROL_STOP);
assertEquals(13, bytes.position());
-
}
@Test
@@ -399,7 +418,7 @@ public class NativeBytesTest {
@Test
public void testReadWriteStop() {
- long[] longs = {Long.MIN_VALUE, Long.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE};
+ long[] longs = {Long.MIN_VALUE, Long.MAX_VALUE, 1<<14, (1<<14)-1, 1<<7, (1<<7)-1, Integer.MIN_VALUE, Integer.MAX_VALUE};
for (long i : longs) {
bytes.writeStopBit(i);
// System.out.println(i + " " + bytes.position());
@@ -409,6 +428,18 @@ public class NativeBytesTest {
bytes.position(0);
for (long i : longs)
assertEquals(i, bytes.readStopBit());
+
+ for(long l = 1; l > 0; l += l) {
+ bytes.clear();
+ bytes.writeStopBit(l-1);
+ bytes.writeStopBit(l);
+ bytes.writeStopBit(l+1);
+ bytes.flip();
+ assertEquals(l-1, bytes.readStopBit());
+ assertEquals(l, bytes.readStopBit());
+ assertEquals(l+1, bytes.readStopBit());
+ assertEquals(0, bytes.remaining());
+ }
}
@Test
@@ -564,8 +595,8 @@ public class NativeBytesTest {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd'T'HH:mm:ss.SSS");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String asStr = sdf.format(new Date(now));
- assertEquals(asStr, bytes.parseUTF(SPACE_STOP));
- assertEquals(asStr, bytes.parseUTF(SPACE_STOP));
+ assertEquals(asStr, bytes.parseUtf8(SPACE_STOP));
+ assertEquals(asStr, bytes.parseUtf8(SPACE_STOP));
}
@Test
@@ -638,7 +669,7 @@ public class NativeBytesTest {
public void testAppendSubstring() {
bytes.append("Hello World", 2, 7).append("\n");
bytes.position(0);
- assertEquals("Hello World".substring(2, 7), bytes.parseUTF(CONTROL_STOP));
+ assertEquals("Hello World".substring(2, 7), bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -665,13 +696,45 @@ public class NativeBytesTest {
assertEquals(false, bytes.parseBoolean(SPACE_STOP));
assertEquals(true, bytes.parseBoolean(SPACE_STOP));
assertEquals(null, bytes.parseBoolean(SPACE_STOP));
- assertEquals("word£€", bytes.parseUTF(SPACE_STOP));
+ assertEquals("word£€", bytes.parseUtf8(SPACE_STOP));
assertEquals(BuySell.Buy, bytes.parseEnum(BuySell.class, SPACE_STOP));
assertEquals(1234, bytes.parseLong());
assertEquals(123456L, bytes.parseLong());
assertEquals(1.2345, bytes.parseDouble(), 0);
assertEquals(1.556, bytes.parseDouble(), 0);
+ }
+ @Test
+ public void testSelfTerminating() {
+ bytes.limit(0);
+ bytes.selfTerminating(true);
+ assertEquals(null, bytes.parseBoolean(ALL));
+ assertEquals(0L, bytes.parseLong());
+ assertEquals(0.0, bytes.parseDouble(), 0.0);
+ assertEquals("", bytes.parseUtf8(ALL));
+ assertEquals(null, bytes.parseEnum(StopCharTesters.class, ALL));
+
+ bytes.selfTerminating(false);
+ try {
+ fail("got " + bytes.parseBoolean(ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseLong());
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseDouble());
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseUtf8(ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
+ try {
+ fail("got " + bytes.parseEnum(StopCharTesters.class, ALL));
+ } catch (BufferUnderflowException ignored) {
+ }
}
@Test
@@ -690,9 +753,10 @@ public class NativeBytesTest {
public void testWriteBytes() {
bytes.write("Hello World\n".getBytes(), 0, 10);
bytes.write("good bye\n".getBytes(), 4, 4);
- bytes.write(4, "0 w".getBytes());
+ bytes.write(4, "0".getBytes());
+ bytes.write(5, " w".getBytes(), 0, 2);
bytes.position(0);
- assertEquals("Hell0 worl bye", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("Hell0 worl bye", bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -700,7 +764,7 @@ public class NativeBytesTest {
bytes.append(Arrays.asList(1, 2, 3, 4, 5), ";").append(' ');
bytes.append(new TreeSet<Integer>(Arrays.asList(21, 2, 13, 4, 5)), ";");
bytes.position(0);
- assertEquals("1;2;3;4;5 2;4;5;13;21", bytes.parseUTF(CONTROL_STOP));
+ assertEquals("1;2;3;4;5 2;4;5;13;21", bytes.parseUtf8(CONTROL_STOP));
}
@Test
@@ -725,7 +789,7 @@ public class NativeBytesTest {
bytes.position(0);
bytes.parseDecimal(md2);
bytes.position(0);
- String text = bytes.parseUTF(CONTROL_STOP);
+ String text = bytes.parseUtf8(CONTROL_STOP);
if (!md.equals(md2))
assertEquals("n: " + n + ", s: " + j + " t: " + text, md, md2);
}
@@ -777,6 +841,43 @@ public class NativeBytesTest {
}
@Test
+ public void testWriteByteable() {
+ final DummyByteable db1w = newDirectInstance(DummyByteable.class);
+ final DummyByteable db2w = newDirectInstance(DummyByteable.class);
+ final DummyByteable db1r = newDirectReference(DummyByteable.class);
+ final DummyByteable db2r = newDirectReference(DummyByteable.class);
+
+ db1w.setField1(1);
+ db1w.setField2(2);
+ db1w.setField3(3);
+
+ db2w.setField1(4);
+ db2w.setField2(5);
+ db2w.setField3(6);
+
+ bytes.write(db1w);
+ bytes.write(db2w);
+
+ assertEquals(32, bytes.position());
+
+ db1r.bytes(bytes, 0);
+ db2r.bytes(bytes, db1w.maxSize());
+
+ assertEquals(1, db1r.getField1());
+ assertEquals(2, db1r.getField2());
+ assertEquals(3, db1r.getField3());
+ assertEquals(4, db2r.getField1());
+ assertEquals(5, db2r.getField2());
+ assertEquals(6, db2r.getField3());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWriteByteableException() {
+ DummyByteable byteable = newDirectReference(DummyByteable.class);
+ bytes.write(byteable);
+ }
+
+ @Test
public void testWriteObject() {
for (Object o : new Object[]{10, 9.9, "string", new Date(), BigDecimal.valueOf(1.1)}) {
bytes.position(0);
@@ -797,7 +898,7 @@ public class NativeBytesTest {
int capacity = 16 * 1024;
byteBuffer = ByteBuffer.allocateDirect(capacity);
long addr = ((DirectBuffer) byteBuffer).address();
- bytes = new NativeBytes(addr, addr, addr + capacity);
+ bytes = new NativeBytes(addr, addr + capacity);
Calendar cal = Calendar.getInstance();
bytes.writeObject(cal);
Dummy d = new Dummy();
@@ -833,13 +934,27 @@ public class NativeBytesTest {
}
}
+ interface DummyByteable extends Byteable {
+ void setField1(long field);
+
+ long getField1();
+
+ void setField2(int field);
+
+ int getField2();
+
+ void setField3(int field);
+
+ int getField3();
+ }
+
@Test
public void testErrors() {
int capacity = 1024;
byteBuffer = ByteBuffer.allocateDirect(capacity);
long addr = ((DirectBuffer) byteBuffer).address();
// it is actually much bigger than it believes
- bytes = new NativeBytes(addr, addr, addr + 16);
+ bytes = new NativeBytes(addr, addr + 16);
bytes.writeLong(8);
assertFalse(bytes.isFinished());
bytes.finish();
@@ -848,18 +963,14 @@ public class NativeBytesTest {
bytes.writeLong(16);
bytes.finish();
bytes.flush();
- bytes.writeLong(24);
try {
+ bytes.writeLong(24);
bytes.finish();
fail();
} catch (IndexOutOfBoundsException expected) {
}
- try {
- bytes.flush();
- fail();
- } catch (IndexOutOfBoundsException expected) {
- }
- bytes.reset();
+
+ bytes.clear();
assertEquals(0, bytes.position());
assertEquals(8, bytes.skip(8));
assertEquals(8, bytes.position());
@@ -871,15 +982,15 @@ public class NativeBytesTest {
public void testWriteList() {
List<Integer> ints = Arrays.asList(1, 2, 3, 4);
bytes.writeList(ints);
- bytes.reset();
+ bytes.clear();
List<Integer> ints2 = new ArrayList<Integer>();
bytes.readList(ints2, Integer.class);
assertEquals(ints, ints2);
- bytes.reset();
+ bytes.clear();
List<String> words = Arrays.asList("Hello word byte for now".split(" "));
bytes.writeList(words);
- bytes.reset();
+ bytes.clear();
List<String> words2 = new ArrayList<String>();
bytes.readList(words2, String.class);
}
@@ -898,7 +1009,7 @@ public class NativeBytesTest {
bytes.writeMap(map);
bytes.finish();
- bytes.reset();
+ bytes.clear();
Map<String, Integer> map2 = new LinkedHashMap<String, Integer>();
bytes.readMap(map2, String.class, Integer.class);
assertEquals(map, map2);
@@ -910,7 +1021,7 @@ public class NativeBytesTest {
ExecutorService es = Executors.newSingleThreadExecutor(new NamedThreadFactory("unloadFailed"));
Future<Void> future = es.submit(new Callable<Void>() {
@Override
- public Void call() throws Exception {
+ public Void call() {
bytes.unlockInt(0);
return null;
}
@@ -923,4 +1034,26 @@ public class NativeBytesTest {
assertEquals(IllegalMonitorStateException.class, e.getCause().getClass());
}
}
+
+ @Test
+ public void testToString() {
+ NativeBytes bytes = new DirectStore(32).bytes();
+ assertEquals("[pos: 0, lim: 32, cap: 32 ] ٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(1);
+ assertEquals("[pos: 1, lim: 32, cap: 32 ] ⒈‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(2);
+ assertEquals("[pos: 2, lim: 32, cap: 32 ] ⒈⒉‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(3);
+ assertEquals("[pos: 3, lim: 32, cap: 32 ] ⒈⒉⒊‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(4);
+ assertEquals("[pos: 4, lim: 32, cap: 32 ] ⒈⒉⒊⒋‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(5);
+ assertEquals("[pos: 5, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(6);
+ assertEquals("[pos: 6, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(7);
+ assertEquals("[pos: 7, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍⒎‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ bytes.writeByte(8);
+ assertEquals("[pos: 8, lim: 32, cap: 32 ] ⒈⒉⒊⒋⒌⒍⒎⒏‖٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString());
+ }
}
diff --git a/lang/src/test/java/net/openhft/lang/io/OptimisedBytesHashTest.java b/lang/src/test/java/net/openhft/lang/io/OptimisedBytesHashTest.java
new file mode 100755
index 0000000..6747330
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/OptimisedBytesHashTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * Created by peter on 28/06/15.
+ */
+public class OptimisedBytesHashTest {
+
+ /*
+ @Test
+ public void testApplyAsLong() {
+ Bytes b = DirectStore.allocate(128).bytes();
+ b.writeLong(0x0102030405060708L);
+ b.writeLong(0x1112131415161718L);
+ b.flip();
+ while (b.remaining() > 0) {
+ assertEquals("Rem: " + b.remaining(),
+ VanillaBytesStoreHash.INSTANCE.hash(b),
+ OptimisedBytesHash.INSTANCE.hash(b));
+ b.readSkip(1);
+ }
+ assertEquals(VanillaBytesStoreHash.INSTANCE.hash(b),
+ OptimisedBytesHash.INSTANCE.hash(b));
+ }
+*/
+/*
+ @Test
+ public void sizeMatch() {
+ Bytes nb = DirectStore.allocate(128).bytes();
+ for (int i = 1; i <= 64; i++)
+ nb.writeUnsignedByte(i);
+ nb.flip();
+ assertEquals(0L, applyAsLong1to7(nb, 0));
+ for (int i = 1; i <= 7; i++)
+ assertEquals(applyAsLong1to7(nb, i), applyAsLong9to16(nb, i));
+ assertEquals(applyAsLong8(nb), applyAsLong1to7(nb, 8));
+ assertEquals(applyAsLong8(nb), applyAsLong9to16(nb, 8));
+ for (int i = 1; i <= 16; i++)
+ assertEquals(applyAsLong9to16(nb, i), applyAsLong17to32(nb, i));
+ for (int i = 1; i <= 32; i++)
+ assertEquals(applyAsLong17to32(nb, i), applyAsLongAny(nb, i));
+ }
+*/
+ @Test
+ @Ignore("Long running, avg score = 6879")
+ public void testRandomness() {
+ long time = 0, timeCount = 0;
+ long scoreSum = 0;
+ for (int t = 0; t < 500; t++) {
+ long[] hashs = new long[8192];
+ byte[] init = new byte[hashs.length / 8];
+ Bytes b = DirectStore.allocate(init.length).bytes();
+ new SecureRandom().nextBytes(init);
+ for (int i = 0; i < hashs.length; i++) {
+ b.clear();
+ b.write(init);
+
+ b.writeLong(i >> 6 << 3, 1L << i);
+
+ b.position(0);
+ b.limit(init.length);
+ long start = System.nanoTime();
+ hashs[i] = VanillaBytesHash.INSTANCE.hash(b);
+
+ time += System.nanoTime() - start;
+ timeCount++;
+ }
+ long score = 0;
+ for (int i = 0; i < hashs.length - 1; i++)
+ for (int j = i + 1; j < hashs.length; j++) {
+ long diff = hashs[j] ^ hashs[i];
+ int diffBC = Long.bitCount(diff);
+ if (diffBC <= 17) {
+ long d = 1L << (17 - diffBC);
+ score += d;
+ }
+ }
+ scoreSum += score;
+ if (t % 50 == 0)
+ System.out.println(t + " - Score: " + score);
+ }
+ System.out.println("Average score: " + scoreSum / 500);
+ System.out.printf("Average time %.3f us%n", time / timeCount / 1e3);
+ }
+
+ @Test
+ @Ignore("Long running, avg score = 1594788, note lower is better")
+ public void testRandomnessOld() {
+ long time = 0, timeCount = 0;
+ long scoreSum = 0;
+ for (int t = 0; t < 500; t++) {
+ long[] hashs = new long[8192];
+ byte[] init = new byte[hashs.length / 8];
+ Bytes b = DirectStore.allocate(init.length).bytes();
+ new SecureRandom().nextBytes(init);
+ for (int i = 0; i < hashs.length; i++) {
+ b.clear();
+ b.write(init);
+
+ b.writeLong(i >> 6 << 3, 1L << i);
+
+ b.position(0);
+ b.limit(init.length);
+ long start = System.nanoTime();
+ hashs[i] = VanillaBytesHasher.INSTANCE.hash(b);
+
+ time += System.nanoTime() - start;
+ timeCount++;
+ }
+ long score = 0;
+ for (int i = 0; i < hashs.length - 1; i++)
+ for (int j = i + 1; j < hashs.length; j++) {
+ long diff = hashs[j] ^ hashs[i];
+ int diffBC = Long.bitCount(diff);
+ if (diffBC <= 17) {
+ long d = 1L << (17 - diffBC);
+ score += d;
+ }
+ }
+ scoreSum += score;
+ if (t % 50 == 0)
+ System.out.println(t + " - Score: " + score);
+ }
+ System.out.println("Average score: " + scoreSum / 500);
+ System.out.printf("Average time %.3f us%n", time / timeCount / 1e3);
+ }
+
+ @Test
+ @Ignore("Long running, avg score = 6823, avg time 0.027 us")
+ public void testSmallRandomness() {
+ long time = 0, timeCount = 0;
+ long scoreSum = 0;
+// StringBuilder sb = new StringBuilder();
+
+ for (int t = 0; t < 500; t++) {
+ long[] hashs = new long[8192];
+ Bytes b = DirectStore.allocate(hashs.length / 64).bytes();
+ for (int i = 0; i < hashs.length; i++) {
+ b.clear();
+ b.append(t);
+ b.append('-');
+ b.append(i);
+ long start = System.nanoTime();
+ hashs[i] = VanillaBytesHash.INSTANCE.hash(b);
+ time += System.nanoTime() - start;
+ timeCount++;
+
+/* if (true) {
+ sb.setLength(0);
+ sb.append(b);
+ assertEquals(hashs[i], Maths.longHash(sb));
+ }*/
+ }
+ long score = 0;
+ for (int i = 0; i < hashs.length - 1; i++)
+ for (int j = i + 1; j < hashs.length; j++) {
+ long diff = hashs[j] ^ hashs[i];
+ int diffBC = Long.bitCount(diff);
+ if (diffBC < 18) {
+ long d = 1L << (17 - diffBC);
+ score += d;
+ }
+ }
+ scoreSum += score;
+ if (t % 50 == 0)
+ System.out.println(t + " - Score: " + score);
+ }
+ System.out.println("Average score: " + scoreSum / 500);
+ System.out.printf("Average time %.3f us%n", time / timeCount / 1e3);
+ }
+
+ @Test
+ @Ignore("Only run for comparison, avg score = 6843")
+ public void testSecureRandomness() {
+ long scoreSum = 0;
+ for (int t = 0; t < 500; t++) {
+ Random rand = new SecureRandom();
+ long[] hashs = new long[8192];
+ for (int i = 0; i < hashs.length; i++) {
+ hashs[i] = rand.nextLong();
+ }
+ int score = 0;
+ for (int i = 0; i < hashs.length - 1; i++)
+ for (int j = i + 1; j < hashs.length; j++) {
+ long diff = hashs[j] ^ hashs[i];
+ int diffBC = Long.bitCount(diff);
+ if (diffBC < 18) {
+ int d = 1 << (17 - diffBC);
+ score += d;
+ }
+ }
+ scoreSum += score;
+ if (t % 50 == 0)
+ System.out.println(t + " - Score: " + score);
+ }
+ System.out.println("Average score: " + scoreSum / 500);
+ }
+
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/io/PingPongMain.java b/lang/src/test/java/net/openhft/lang/io/PingPongMain.java
new file mode 100755
index 0000000..1ebdc5a
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/PingPongMain.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+
+/**
+ * Created by peter.lawrey on 21/11/14.
+ */
+public class PingPongMain {
+ public static final int PORT = Integer.getInteger("port", 8181);
+ public static final int SIZE = Integer.getInteger("size", 128);
+
+ public static void main(String[] args) throws IOException {
+ if (args.length < 1)
+ startServer();
+ else
+ startClient(args[0]);
+ }
+
+ private static void startClient(String hostname) throws IOException {
+ int runs = 100000;
+ int[] times = new int[runs];
+ SocketChannel sc = SocketChannel.open(new InetSocketAddress(hostname, PORT));
+ System.out.println("Connected to " + hostname + ":" + PORT);
+ sc.configureBlocking(false);
+ ByteBuffer bb = ByteBuffer.allocateDirect(SIZE);
+ for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < runs; i++) {
+ long start = System.nanoTime();
+ bb.clear();
+ while (bb.remaining() > 0) {
+ int len = sc.write(bb);
+ if (len < 0)
+ throw new EOFException("write");
+ }
+ bb.clear();
+ while (bb.remaining() > 0) {
+ int len = sc.read(bb);
+ if (len < 0)
+ throw new EOFException("read");
+ }
+ times[i] = (int) (System.nanoTime() - start);
+ }
+ Arrays.sort(times);
+ System.out.printf("50/90/99/99.9 %%tile %,d / %,d / %,d / %,d%n",
+ times[runs / 2] / 1000,
+ times[runs - runs / 10] / 1000,
+ times[runs - runs / 100] / 1000,
+ times[runs - runs / 1000] / 1000
+ );
+ }
+ sc.close();
+ }
+
+ private static void startServer() throws IOException {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.socket().setReuseAddress(true);
+ ssc.socket().bind(new InetSocketAddress(PORT));
+
+ System.out.println("Listening for one connection on port " + PORT);
+ SocketChannel sc = ssc.accept();
+ sc.configureBlocking(false);
+ ByteBuffer bb = ByteBuffer.allocateDirect(16 * 1024);
+ bb.clear(); // Prepare buffer for use
+ while (sc.read(bb) >= 0 || bb.position() != 0) {
+ bb.flip();
+ sc.write(bb);
+ bb.compact(); // In case of partial write
+ }
+ sc.close();
+ ssc.close();
+ System.out.println("... finished");
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/ResizeableMappedStoreTest.java b/lang/src/test/java/net/openhft/lang/io/ResizeableMappedStoreTest.java
new file mode 100644
index 0000000..45b18f7
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/ResizeableMappedStoreTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import org.junit.After;
+import org.junit.Test;
+
+public final class ResizeableMappedStoreTest {
+ @After
+ public void tearDown() {
+ System.gc();
+ }
+
+ @Test
+ public void testResizableMappedStore() throws IOException {
+ File file = MappedStoreTest.getStoreFile("resizable-mapped-store.tmp");
+
+ final int smallSize = 1024, largeSize = 10 * smallSize;
+
+ {
+ ResizeableMappedStore ms = new ResizeableMappedStore(file, FileChannel.MapMode.READ_WRITE, smallSize);
+
+ DirectBytes slice1 = ms.bytes();
+ for (int i = 0; i < smallSize; ++i) {
+ slice1.writeByte(42);
+ }
+
+ ms.resize(largeSize);
+
+ DirectBytes slice2 = ms.bytes();
+ slice2.skipBytes(smallSize);
+ for (int i = smallSize; i < largeSize; ++i) {
+ slice2.writeByte(24);
+ }
+
+ ms.close();
+ }
+
+ assertEquals(largeSize, file.length());
+
+ {
+ ResizeableMappedStore ms = new ResizeableMappedStore(file, FileChannel.MapMode.READ_WRITE, file.length());
+ DirectBytes slice = ms.bytes();
+ assertEquals(42, slice.readByte(smallSize - 1));
+ assertEquals(24, slice.readByte(largeSize - 1));
+ slice.release();
+
+ ms.close();
+ }
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/VanillaMappedFileTest.java b/lang/src/test/java/net/openhft/lang/io/VanillaMappedFileTest.java
new file mode 100755
index 0000000..ca5087f
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/VanillaMappedFileTest.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package net.openhft.lang.io;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+
+import static org.junit.Assert.*;
+
+public class VanillaMappedFileTest {
+ public static String TMPDIR = System.getProperty("java.io.tmpdir");
+ public static String SEPARATOR = System.getProperty("file.separator");
+ public static String BASEPATH = TMPDIR + SEPARATOR + "vmf";
+
+ private static File newTempraryFile(String name) {
+ return newTempraryFile(name, true);
+ }
+
+ private static File newTempraryFile(String name, boolean delete) {
+ File file = new File(
+ BASEPATH,
+ name);
+
+ if (delete) {
+ file.delete();
+ file.deleteOnExit();
+ }
+
+ if(!file.getParentFile().exists()) {
+ file.getParentFile().mkdirs();
+ }
+
+ return file;
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ @Test
+ public void testCreate() throws IOException {
+ File f1 = newTempraryFile("vmf-create-1");
+ File f2 = newTempraryFile("vmf-create-2");
+
+ VanillaMappedFile vmf1 = VanillaMappedFile.readWrite(f1);
+ VanillaMappedFile vmf2 = VanillaMappedFile.readWrite(f2,128);
+
+ assertTrue(f1.exists());
+ assertTrue(f2.exists());
+
+ assertEquals(0, vmf1.size());
+ assertEquals(128, vmf2.size());
+
+ vmf1.close();
+ vmf2.close();
+ }
+
+ @Test
+ public void testAcquireBytes() throws IOException {
+ VanillaMappedFile vmf = VanillaMappedFile.readWrite(
+ newTempraryFile("vmf-acquire-buffer"));
+
+ assertTrue(new File(vmf.path()).exists());
+
+ VanillaMappedBytes buffer = vmf.bytes(0,128);
+ assertEquals(1, buffer.refCount());
+ assertEquals(0L, buffer.readLong(0L));
+ assertEquals(0L, buffer.readLong(1L));
+
+ buffer.writeLong(0, 1L);
+ assertEquals(1L, buffer.readLong(0));
+ assertEquals(128, buffer.size());
+
+ buffer.writeLong(2L);
+ assertEquals(2L, buffer.readLong(0));
+ assertEquals(120, buffer.remaining());
+
+ buffer.release();
+ vmf.close();
+ }
+
+ @Test
+ public void testAcquireBlocks1() throws IOException {
+ VanillaMappedBlocks blocks = VanillaMappedBlocks.readWrite(
+ newTempraryFile("vmf-acquire-blocks-1"),
+ 128);
+
+ assertTrue(new File(blocks.path()).exists());
+
+ VanillaMappedBytes b1 = blocks.acquire(0);
+ assertEquals(128, blocks.size());
+ assertEquals(2, b1.refCount());
+ assertEquals(128, b1.size());
+
+ VanillaMappedBytes b2 = blocks.acquire(1);
+ assertEquals(256, blocks.size());
+ assertEquals(2, b2.refCount());
+ assertEquals(128, b2.size());
+
+ VanillaMappedBytes b3 = blocks.acquire(1);
+ assertEquals(256, blocks.size());
+ assertEquals(3, b3.refCount());
+ assertEquals(128, b2.size());
+
+ assertNotEquals(b1.address(), b2.address());
+ assertNotEquals(b1.address(), b3.address());
+ assertEquals(b2.address(), b3.address());
+
+ b1.release();
+ b2.release();
+ b2.release();
+
+ blocks.close();
+ }
+
+ @Test
+ public void testAcquireBlocks2() throws IOException {
+ VanillaMappedBlocks blocks = VanillaMappedBlocks.readWrite(
+ newTempraryFile("vmf-acquire-blocks-2"),
+ 64);
+
+ assertTrue(new File(blocks.path()).exists());
+
+ final long nblocks = 10000;
+ for (long i = 0; i < nblocks; i++) {
+ VanillaMappedBytes b = blocks.acquire(i);
+ assertEquals(2, b.refCount());
+
+ b.release();
+
+ assertEquals(1, b.refCount());
+ assertFalse(b.unmapped());
+ }
+
+ blocks.close();
+ }
+
+ @Test
+ public void testAcquireOverlap() throws IOException {
+ File path = newTempraryFile("vmf-acquire-overlap");
+
+ VanillaMappedFile vmf = VanillaMappedFile.readWrite(path);
+ VanillaMappedBlocks blocks = VanillaMappedBlocks.readWrite(path,128);
+
+ VanillaMappedBytes b1 = blocks.acquire(0);
+ b1.writeLong(1);
+ b1.release();
+
+ assertEquals(1, b1.refCount());
+ assertFalse(b1.unmapped());
+
+ VanillaMappedBytes b2 = blocks.acquire(1);
+ b2.writeLong(2);
+ b2.release();
+
+ assertEquals(1, b2.refCount());
+ assertFalse(b1.unmapped());
+ assertFalse(b2.unmapped());
+
+ VanillaMappedBytes b3 = blocks.acquire(2);
+ b3.writeLong(3);
+ b3.release();
+
+ assertEquals(1, b3.refCount());
+ assertTrue(b1.unmapped());
+ assertFalse(b2.unmapped());
+ assertFalse(b3.unmapped());
+
+ VanillaMappedBytes b4 = vmf.bytes(0, 128 * 3);
+ assertEquals( 1, b4.refCount());
+ assertEquals(384, b4.size());
+ assertEquals( 1L, b4.readLong(0));
+ assertEquals( 2L, b4.readLong(128));
+ assertEquals( 3L, b4.readLong(256));
+
+ vmf.close();
+ blocks.close();
+ }
+
+ @Test
+ public void testReopen() throws IOException {
+ File file = newTempraryFile("vmf-reopen");
+
+ {
+ VanillaMappedFile vmf = VanillaMappedFile.readWrite(file);
+ VanillaMappedBytes buf = vmf.bytes(0,128);
+
+ buf.writeLong(0, 1L);
+
+ assertEquals(1L , buf.readLong(0));
+ assertEquals(128, vmf.size());
+
+ buf.release();
+ vmf.close();
+ }
+
+ {
+ VanillaMappedFile vmf = VanillaMappedFile.readWrite(file);
+ VanillaMappedBytes buf = vmf.bytes(0,128);
+
+ assertEquals(1L , buf.readLong(0));
+ assertEquals(128, vmf.size());
+
+ buf.release();
+ vmf.close();
+ }
+
+ assertEquals(128, file.length());
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ @Test
+ public void testMappedCache1() throws IOException {
+ VanillaMappedCache<Integer> cache = new VanillaMappedCache();
+
+ assertEquals(cache.size(),0);
+ assertNull(cache.get(1));
+
+ cache.put(1, newTempraryFile("vmc-1-v1"), 64);
+ cache.put(2, newTempraryFile("vmc-1-v2"), 128);
+
+ assertEquals(cache.size(),2);
+
+ assertNotNull(cache.get(1));
+ assertNotNull(cache.get(2));
+
+ VanillaMappedBytes b1 = cache.get(1);
+ assertEquals( 1, b1.refCount());
+ assertEquals( 64, b1.size());
+
+ VanillaMappedBytes b2 = cache.get(2);
+ assertEquals( 1, b2.refCount());
+ assertEquals(128, b2.size());
+
+ cache.close();
+ }
+
+ @Test
+ public void testMappedCache2() throws IOException {
+ final int size = 5;
+ VanillaMappedCache<Integer> cache = new VanillaMappedCache(size, true);
+ for(int i=0;i<10;i++) {
+ cache.put(i, newTempraryFile("vmc-2-v" + i), 8 * i, i);
+ if(i >= size) {
+ assertEquals(cache.size(), size - 1);
+ }
+ }
+
+ for(int i=10-1;i>=0;i--) {
+ if(i >= 6) {
+ assertNotNull(cache.get(i));
+ assertEquals(cache.get(i).index(),i);
+
+ } else {
+ assertNull(cache.get(i));
+ }
+ }
+
+ cache.close();
+ }
+
+ @Test
+ public void testMappedCache3() throws IOException {
+ VanillaMappedCache<Integer> cache = new VanillaMappedCache(32, false);
+ VanillaMappedBytes buffer = null;
+ File file = null;
+
+ for (int j = 0; j < 5; j++) {
+ long start = System.nanoTime();
+ int maxRuns = 10000, runs;
+ for (runs = 0; runs < maxRuns; runs++) {
+ file = newTempraryFile("vmc-3-v" + runs, false);
+
+ buffer = cache.put(runs, file, 256, runs);
+ buffer.writeLong(0, 0x12345678);
+
+ assertEquals(0x12345678L, buffer.readLong(0));
+ assertEquals(runs, buffer.index());
+
+ buffer.release();
+ buffer.close();
+
+ assertEquals(0, buffer.refCount());
+ assertTrue(file.delete());
+ if (System.nanoTime() - start > 1e9)
+ break;
+ }
+
+ long time = System.nanoTime() - start;
+ System.out.printf("The average time was %,d us%n", time / runs / 1000);
+ }
+
+ cache.close();
+ }
+
+ @Test
+ public void testMappedCache4() throws IOException {
+ VanillaMappedCache<Integer> cache = new VanillaMappedCache(10000, true);
+ VanillaMappedBytes buffer = cache.put(1, newTempraryFile("vmc-4"), 256, 1);
+
+ buffer.reserve();
+ assertEquals(2,buffer.refCount());
+
+ buffer.release();
+ assertEquals(1,buffer.refCount());
+
+ cache.close();
+ assertEquals(0,buffer.refCount());
+ }
+
+ // *************************************************************************
+ //
+ // *************************************************************************
+
+ @Test
+ public void testMessageKeySerialization() throws IOException {
+ File path = newTempraryFile("vmc-x");
+ VanillaMappedBytes bytes = VanillaMappedFile.readWriteBytes(path, 1024, 0,
+ FileLifecycleListener.FileLifecycleListeners.CONSOLE);
+
+ bytes.writeObject(new MessageKey("type", 123L));
+ bytes.flush();
+
+ bytes.position(0);
+ System.out.println("" + bytes.readObject(MessageKey.class));
+
+ bytes.close();
+ }
+
+ public static class MessageKey implements Serializable {
+ private String arg1;
+ private long arg2;
+ public MessageKey(String arg1, long arg2) {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+ @Override
+ public String toString() {
+ return "MessageKey{" + "arg1='" + arg1 + ", arg2=" + arg2 + "}";
+ }
+ }
+}
+
diff --git a/lang/src/test/java/net/openhft/lang/io/examples/MappedStroreExampleMain.java b/lang/src/test/java/net/openhft/lang/io/examples/MappedStroreExampleMain.java
new file mode 100755
index 0000000..f083dd7
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/examples/MappedStroreExampleMain.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.examples;
+
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.MappedStore;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+/**
+ * Created by peter.lawrey on 14/07/14.
+ */
+public class MappedStroreExampleMain {
+ public static void main(String[] args) throws IOException {
+ File deleteme = File.createTempFile("deleteme", ".tmp");
+ deleteme.deleteOnExit();
+ // 4 GB of memory.
+ long size = 4L << 30;
+ long start = System.currentTimeMillis();
+ MappedStore ms = new MappedStore(deleteme, FileChannel.MapMode.READ_WRITE, size);
+ DirectBytes bytes = ms.bytes();
+ for(long i = 0; i < size; i+= 4)
+ bytes.writeLong(i);
+ ms.free();
+ long time = System.currentTimeMillis() - start;
+ System.out.printf("Wrote %,d MB/s%n", size / 1000 / time);
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/examples/ParserExampleMain.java b/lang/src/test/java/net/openhft/lang/io/examples/ParserExampleMain.java
index c9ec1b5..53ca541 100644..100755
--- a/lang/src/test/java/net/openhft/lang/io/examples/ParserExampleMain.java
+++ b/lang/src/test/java/net/openhft/lang/io/examples/ParserExampleMain.java
@@ -1,22 +1,23 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.examples;
import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.StopCharTesters;
import java.nio.ByteBuffer;
@@ -25,24 +26,24 @@ import static org.junit.Assert.assertEquals;
/**
* Run with -verbosegc -Xmx32m
- * <p/>
- * Average time was 282 nano-seconds
+ *
+ * <p>Average time was 282 nano-seconds
*/
public class ParserExampleMain {
public static void main(String... ignored) {
ByteBuffer wrap = ByteBuffer.allocate(1024);
- ByteBufferBytes bufferBytes = new ByteBufferBytes(wrap);
+ Bytes bufferBytes = ByteBufferBytes.wrap(wrap);
byte[] bytes = "BAC,12.32,12.54,12.56,232443".getBytes();
int runs = 10000000;
long start = System.nanoTime();
for (int i = 0; i < runs; i++) {
- bufferBytes.reset();
+ bufferBytes.clear();
// read the next message.
bufferBytes.write(bytes);
bufferBytes.position(0);
// decode message
- String word = bufferBytes.parseUTF(StopCharTesters.COMMA_STOP);
+ String word = bufferBytes.parseUtf8(StopCharTesters.COMMA_STOP);
double low = bufferBytes.parseDouble();
double curr = bufferBytes.parseDouble();
double high = bufferBytes.parseDouble();
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/ByteMarshallableMarshallerTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/ByteMarshallableMarshallerTest.java
index 95df903..1db20f9 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/ByteMarshallableMarshallerTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/ByteMarshallableMarshallerTest.java
@@ -1,24 +1,24 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
import net.openhft.lang.io.Bytes;
import net.openhft.lang.io.NativeBytes;
-import org.jetbrains.annotations.NotNull;
+import net.openhft.lang.model.constraints.NotNull;
import org.junit.Test;
import sun.nio.ch.DirectBuffer;
@@ -37,12 +37,12 @@ public class ByteMarshallableMarshallerTest {
int capacity = 2 * 1024;
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
long addr = ((DirectBuffer) byteBuffer).address();
- NativeBytes nativeBytes = new NativeBytes(addr, addr, addr + capacity);
+ NativeBytes nativeBytes = new NativeBytes(addr, addr + capacity);
BytesMarshallable bm = new MockBytesMarshallable(12345678);
nativeBytes.writeObject(bm);
nativeBytes.finish();
- nativeBytes.reset();
+ nativeBytes.clear();
BytesMarshallable bm2 = nativeBytes.readObject(MockBytesMarshallable.class);
assertEquals(bm, bm2);
}
@@ -71,9 +71,8 @@ public class ByteMarshallableMarshallerTest {
MockBytesMarshallable that = (MockBytesMarshallable) o;
- if (number != that.number) return false;
+ return number == that.number;
- return true;
}
}
}
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/ExternalizableMarshallerTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/ExternalizableMarshallerTest.java
index 70bad3e..6e665b0 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/ExternalizableMarshallerTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/ExternalizableMarshallerTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
@@ -39,12 +39,12 @@ public class ExternalizableMarshallerTest {
int capacity = 2 * 1024;
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
long addr = ((DirectBuffer) byteBuffer).address();
- NativeBytes nativeBytes = new NativeBytes(addr, addr, addr + capacity);
+ NativeBytes nativeBytes = new NativeBytes(addr, addr + capacity);
Externalizable bm = new MockExternalizable(12345678);
nativeBytes.writeObject(bm);
nativeBytes.finish();
- nativeBytes.reset();
+ nativeBytes.clear();
Externalizable bm2 = nativeBytes.readObject(MockExternalizable.class);
assertEquals(bm, bm2);
}
@@ -73,9 +73,8 @@ public class ExternalizableMarshallerTest {
MockExternalizable that = (MockExternalizable) o;
- if (number != that.number) return false;
+ return number == that.number;
- return true;
}
}
}
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/JDKZObjectSerializerTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/JDKZObjectSerializerTest.java
new file mode 100644
index 0000000..73f5d29
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/JDKZObjectSerializerTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.DirectStore;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.zip.DeflaterOutputStream;
+
+import static org.junit.Assert.assertEquals;
+
+public class JDKZObjectSerializerTest {
+
+ @Test
+ public void testReadSerializable() throws IOException, ClassNotFoundException {
+ {
+ DirectBytes bytes = DirectStore.allocate(1024).bytes();
+ bytes.writeInt(0);
+ ObjectOutputStream oos = new ObjectOutputStream(bytes.outputStream());
+ oos.writeObject("hello");
+ oos.close();
+ bytes.writeUnsignedInt(0, bytes.position() - 4);
+
+ bytes.flip();
+ assertEquals("hello", JDKZObjectSerializer.INSTANCE.readSerializable(bytes, null, null));
+ bytes.release();
+ }
+ {
+ DirectBytes bytes = DirectStore.allocate(1024).bytes();
+ bytes.writeInt(0);
+ ObjectOutputStream oos = new ObjectOutputStream(new DeflaterOutputStream(bytes.outputStream()));
+ oos.writeObject("hello world");
+ oos.close();
+ bytes.writeUnsignedInt(0, bytes.position() - 4);
+
+ bytes.flip();
+ assertEquals("hello world", JDKZObjectSerializer.INSTANCE.readSerializable(bytes, null, null));
+ bytes.close();
+ }
+ }
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/JavaSerializationTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/JavaSerializationTest.java
new file mode 100644
index 0000000..d15fb51
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/JavaSerializationTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization;
+
+import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @author Rob Austin.
+ */
+public class JavaSerializationTest {
+
+ @Test
+ @Ignore
+ public void NullPointerException() {
+ final Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(1024).order
+ (ByteOrder.nativeOrder()));
+
+ NullPointerException expected = new NullPointerException("test");
+ bytes.writeObject(expected);
+
+ bytes.position(0);
+ NullPointerException actual = (NullPointerException)bytes.readObject();
+
+ Assert.assertEquals(expected, actual);
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/VanillaBytesMarshallerTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/VanillaBytesMarshallerTest.java
index b258e32..f6cb1a7 100644
--- a/lang/src/test/java/net/openhft/lang/io/serialization/VanillaBytesMarshallerTest.java
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/VanillaBytesMarshallerTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.io.serialization;
@@ -19,27 +19,36 @@ package net.openhft.lang.io.serialization;
import net.openhft.lang.io.DirectBytes;
import net.openhft.lang.io.DirectStore;
import net.openhft.lang.io.NativeBytes;
+import net.openhft.lang.io.serialization.impl.VanillaBytesMarshallerFactory;
import org.junit.Test;
import sun.nio.ch.DirectBuffer;
+import java.io.EOFException;
+import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicInteger;
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
/**
* User: peter.lawrey Date: 20/09/13 Time: 09:28
*/
public class VanillaBytesMarshallerTest {
+
+ enum BuySell {
+ BUY, SELL
+ }
+
@Test
public void testObjects() {
- DirectBytes bytes = new DirectStore(1024).createSlice();
+ DirectBytes bytes = new DirectStore(1024).bytes();
Object[] objects = {1, 1L, 1.0, "Hello"};
for (Object o : objects) {
long pos = bytes.position();
bytes.writeObject(o);
System.out.printf("%s used %,d bytes%n", o.getClass(), bytes.position() - pos);
}
- bytes.reset();
+ bytes.clear();
for (Object o : objects) {
Object o2 = bytes.readObject();
assertEquals(o, o2);
@@ -51,17 +60,62 @@ public class VanillaBytesMarshallerTest {
int capacity = 2 * 1024;
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
long addr = ((DirectBuffer) byteBuffer).address();
- NativeBytes nativeBytes = new NativeBytes(addr, addr, addr + capacity);
+ NativeBytes nativeBytes = new NativeBytes(addr, addr + capacity);
nativeBytes.writeObject(BuySell.BUY);
nativeBytes.writeObject(BuySell.SELL);
nativeBytes.finish();
- nativeBytes.reset();
+ nativeBytes.clear();
assertEquals(BuySell.BUY, nativeBytes.readObject());
assertEquals(BuySell.SELL, nativeBytes.readObject());
}
- enum BuySell {
- BUY, SELL
+ @Test
+ public void testExceptionWithoutCause() {
+ final int capacity = 2 * 1024;
+ final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
+ final long addr = ((DirectBuffer) byteBuffer).address();
+
+ final NativeBytes nativeBytes = new NativeBytes(
+ new VanillaBytesMarshallerFactory(), addr, addr + capacity, new AtomicInteger(1));
+
+ Throwable expected = new IOException("io-exception");
+
+ nativeBytes.writeObject(expected);
+ nativeBytes.finish();
+ nativeBytes.clear();
+
+ Throwable actual = nativeBytes.readObject(Throwable.class);
+ assertNotNull(actual);
+ assertNull(actual.getCause());
+
+ assertEquals(expected.getMessage(), actual.getMessage());
+ assertArrayEquals(expected.getStackTrace(), actual.getStackTrace());
+ }
+
+ @Test
+ public void testExceptionWithCause() {
+ final int capacity = 2 * 1024;
+ final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(capacity);
+ final long addr = ((DirectBuffer) byteBuffer).address();
+
+ final NativeBytes nativeBytes = new NativeBytes(
+ new VanillaBytesMarshallerFactory(), addr, addr + capacity, new AtomicInteger(1));
+
+ Throwable expected = new IOException(
+ "io-exception", new EOFException("eof-exception"));
+
+ nativeBytes.writeObject(expected);
+ nativeBytes.finish();
+ nativeBytes.clear();
+
+ Throwable actual = nativeBytes.readObject(Throwable.class);
+ assertNotNull(actual);
+ assertNotNull(actual.getCause());
+
+ assertEquals(expected.getMessage(), actual.getMessage());
+ assertEquals(expected.getCause().getMessage(), actual.getCause().getMessage());
+ assertArrayEquals(expected.getStackTrace(), actual.getStackTrace());
+ assertArrayEquals(expected.getCause().getStackTrace(), actual.getCause().getStackTrace());
}
}
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshallerTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshallerTest.java
new file mode 100644
index 0000000..f6c68b7
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/impl/SnappyStringMarshallerTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.DirectStore;
+import org.junit.Test;
+
+import java.nio.charset.Charset;
+import java.util.Random;
+
+import static org.junit.Assert.assertEquals;
+
+public class SnappyStringMarshallerTest {
+
+ @Test
+ public void testWriteRead() {
+ Bytes b = DirectStore.allocate(64 * 1024).bytes();
+ testWriteRead(b, "");
+ testWriteRead(b, null);
+ testWriteRead(b, "Hello World");
+ testWriteRead(b, new String(new char[1000000]));
+ byte[] bytes = new byte[64000];
+ Random random = new Random();
+ for (int i = 0; i < bytes.length; i++)
+ bytes[i] = (byte) ('A' + random.nextInt(26));
+ testWriteRead(b, new String(bytes, Charset.forName("ISO-8859-1")));
+ }
+
+ private void testWriteRead(Bytes b, String s) {
+ b.clear();
+ SnappyStringMarshaller.INSTANCE.write(b, s);
+ b.writeInt(0x12345678);
+ b.flip();
+ String s2 = SnappyStringMarshaller.INSTANCE.read(b);
+ assertEquals(0x12345678, b.readInt());
+ assertEquals(s, s2);
+ }
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/io/serialization/impl/StringZMapMarshallerTest.java b/lang/src/test/java/net/openhft/lang/io/serialization/impl/StringZMapMarshallerTest.java
new file mode 100644
index 0000000..a80b88a
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/io/serialization/impl/StringZMapMarshallerTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.io.serialization.impl;
+
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.io.DirectStore;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class StringZMapMarshallerTest {
+ static final Bytes b = DirectStore.allocate(1024).bytes();
+
+ @Test
+ public void testWriteRead() {
+ testWriteRead(null);
+ testWriteRead(Collections.<String, String>emptyMap());
+ testWriteRead(mapOf("Hello", "World", "aye", "alpha", "bee", "beta", "zed", "zeta"));
+ }
+
+ private void testWriteRead(Map<String, String> map) {
+ b.clear();
+ StringZMapMarshaller.INSTANCE.write(b, map);
+ b.writeInt(0x12345678);
+ b.flip();
+ Map<String, String> s2 = StringZMapMarshaller.INSTANCE.read(b);
+ assertEquals(map, s2);
+ assertEquals(0x12345678, b.readInt());
+ }
+
+ public static <K, V> Map<K, V> mapOf(K k, V v, Object... keysAndValues) {
+ Map<K, V> ret = new LinkedHashMap<K, V>();
+ ret.put(k, v);
+ for (int i = 0; i < keysAndValues.length - 1; i += 2) {
+ Object key = keysAndValues[i];
+ Object value = keysAndValues[i + 1];
+ ret.put((K) key, (V) value);
+ }
+ return ret;
+ }
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/locks/LockingStrategyTest.java b/lang/src/test/java/net/openhft/lang/locks/LockingStrategyTest.java
new file mode 100644
index 0000000..66537b7
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/locks/LockingStrategyTest.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.locks;
+
+import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import sun.nio.ch.DirectBuffer;
+
+import java.nio.ByteBuffer;
+import java.util.Collection;
+import java.util.concurrent.*;
+
+import static java.util.Arrays.asList;
+import static net.openhft.lang.locks.LockingStrategyTest.AccessMethod.ADDRESS;
+import static net.openhft.lang.locks.LockingStrategyTest.AccessMethod.BYTES_WITH_OFFSET;
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
+
+@RunWith(value = Parameterized.class)
+public class LockingStrategyTest {
+
+ enum AccessMethod {ADDRESS, BYTES_WITH_OFFSET}
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> data() {
+ return asList(new Object[][] {
+ {VanillaReadWriteUpdateWithWaitsLockingStrategy.instance(), ADDRESS},
+ {VanillaReadWriteUpdateWithWaitsLockingStrategy.instance(), BYTES_WITH_OFFSET},
+ {VanillaReadWriteWithWaitsLockingStrategy.instance(), ADDRESS},
+ {VanillaReadWriteWithWaitsLockingStrategy.instance(), BYTES_WITH_OFFSET},
+ });
+ }
+
+ ExecutorService e1, e2;
+ ByteBuffer buffer;
+ Bytes bytes;
+ long offset;
+ LockingStrategy lockingStrategy;
+ AccessMethod accessMethod;
+ NativeAtomicAccess access;
+ Object accessObj;
+
+ public LockingStrategyTest(LockingStrategy lockingStrategy, AccessMethod accessMethod) {
+ this.lockingStrategy = lockingStrategy;
+ this.accessMethod = accessMethod;
+ }
+
+ @Before
+ public void setUp() {
+ e1 = new ThreadPoolExecutor(0, 1, Integer.MAX_VALUE, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>());
+ e2 = new ThreadPoolExecutor(0, 1, Integer.MAX_VALUE, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<Runnable>());
+
+ buffer = ByteBuffer.allocateDirect(8);
+ bytes = new ByteBufferBytes(buffer);
+ offset = accessMethod == ADDRESS ? ((DirectBuffer) buffer).address() : 0L;
+ accessObj = accessMethod == BYTES_WITH_OFFSET ? bytes : null;
+ access = accessMethod == ADDRESS ? NativeAtomicAccess.unsafe() :
+ NativeAtomicAccess.toBytes();
+ rwls().reset();
+ }
+
+ @After
+ public void tearDown() {
+ e1.shutdown();
+ e2.shutdown();
+ }
+
+ Callable<Boolean> tryReadLockTask = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return rwls().tryReadLock();
+ }
+ };
+
+ class TestReadWriteLockState extends AbstractReadWriteLockState {
+
+ private ReadWriteLockingStrategy rwls() {
+ return (ReadWriteLockingStrategy) lockingStrategy;
+ }
+
+ @Override
+ public boolean tryReadLock() {
+ return rwls().tryReadLock(access, accessObj, offset);
+ }
+
+ @Override
+ public boolean tryWriteLock() {
+ return rwls().tryWriteLock(access, accessObj, offset);
+ }
+
+ @Override
+ public boolean tryUpgradeReadToWriteLock() {
+ return rwls().tryUpgradeReadToWriteLock(access, accessObj, offset);
+ }
+
+ @Override
+ public void readUnlock() {
+ rwls().readUnlock(access, accessObj, offset);
+ }
+
+ @Override
+ public void writeUnlock() {
+ rwls().writeUnlock(access, accessObj, offset);
+ }
+
+ @Override
+ public void downgradeWriteToReadLock() {
+ rwls().downgradeWriteToReadLock(access, accessObj, offset);
+ }
+
+ @Override
+ public void reset() {
+ rwls().reset(access, accessObj, offset);
+ }
+
+ @Override
+ public long getState() {
+ return rwls().getState(access, accessObj, offset);
+ }
+
+ @Override
+ public ReadWriteLockingStrategy lockingStrategy() {
+ return rwls();
+ }
+ }
+ TestReadWriteLockState rwLockState = new TestReadWriteLockState();
+
+ ReadWriteLockState rwls() {
+ return rwLockState;
+ }
+
+ class TestReadWriteUpdateLockState extends TestReadWriteLockState
+ implements ReadWriteUpdateLockState {
+
+ ReadWriteUpdateLockingStrategy rwuls() {
+ return (ReadWriteUpdateLockingStrategy) lockingStrategy;
+ }
+
+ @Override
+ public boolean tryUpdateLock() {
+ return rwuls().tryUpdateLock(access, accessObj, offset);
+ }
+
+ @Override
+ public boolean tryUpgradeReadToUpdateLock() {
+ return rwuls().tryUpgradeReadToUpdateLock(access, accessObj, offset);
+ }
+
+ @Override
+ public boolean tryUpgradeUpdateToWriteLock() {
+ return rwuls().tryUpgradeUpdateToWriteLock(access, accessObj, offset);
+ }
+
+ @Override
+ public void updateUnlock() {
+ rwuls().updateUnlock(access, accessObj, offset);
+ }
+
+ @Override
+ public void downgradeUpdateToReadLock() {
+ rwuls().downgradeUpdateToReadLock(access, accessObj, offset);
+ }
+
+ @Override
+ public void downgradeWriteToUpdateLock() {
+ rwuls().downgradeWriteToUpdateLock(access, accessObj, offset);
+ }
+
+ @Override
+ public ReadWriteUpdateLockingStrategy lockingStrategy() {
+ return rwuls();
+ }
+ }
+ TestReadWriteUpdateLockState rwuLockState = new TestReadWriteUpdateLockState();
+
+ Runnable readUnlockTask = new Runnable() {
+ @Override
+ public void run() {
+ rwls().readUnlock();
+ }
+ };
+
+ Callable<Boolean> tryUpdateLockTask = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return rwuls().tryUpdateLock();
+ }
+ };
+
+ ReadWriteUpdateLockState rwuls() {
+ return rwuLockState;
+ }
+
+ Runnable updateUnlockTask = new Runnable() {
+ @Override
+ public void run() {
+ rwuls().updateUnlock();
+ }
+ };
+
+ Callable<Boolean> tryWriteLockTask = new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return rwls().tryWriteLock();
+ }
+ };
+
+ Runnable writeUnlockTask = new Runnable() {
+ @Override
+ public void run() {
+ rwls().writeUnlock();
+ }
+ };
+
+ @Test
+ public void testUpdateLockIsExclusive() throws ExecutionException, InterruptedException {
+ assumeReadWriteUpdateLock();
+
+ // Acquire the update lock in thread 1...
+ assertTrue(e1.submit(tryUpdateLockTask).get());
+
+ // Try to acquire update lock in thread 2, should fail...
+ assertFalse(e2.submit(tryUpdateLockTask).get());
+
+ // Release the update lock in thread 1...
+ e1.submit(updateUnlockTask).get();
+
+ // Try to acquire update lock in thread 2 again, should succeed...
+ assertTrue(e2.submit(tryUpdateLockTask).get());
+
+ // Release the update lock in thread 2...
+ e2.submit(updateUnlockTask).get();
+ }
+
+ @Test
+ public void testUpdateLockAllowsOtherReaders() throws ExecutionException, InterruptedException {
+ assumeReadWriteUpdateLock();
+
+ // Acquire the update lock in thread 1...
+ assertTrue(e1.submit(tryUpdateLockTask).get());
+
+ // Try to acquire read lock in thread 2, should succeed...
+ assertTrue(e2.submit(tryReadLockTask).get());
+
+ // Release the update lock in thread 1...
+ e1.submit(updateUnlockTask).get();
+
+ // Release the read lock in thread 2...
+ e2.submit(readUnlockTask).get();
+ }
+
+ @Test
+ public void testUpdateLockBlocksOtherWriters() throws ExecutionException, InterruptedException {
+ assumeReadWriteUpdateLock();
+
+ // Acquire the update lock in thread 1...
+ assertTrue(e1.submit(tryUpdateLockTask).get());
+
+ // Try to acquire write lock in thread 2, should fail...
+ assertFalse(e2.submit(tryWriteLockTask).get());
+
+ // Release the update lock in thread 1...
+ e1.submit(updateUnlockTask).get();
+
+ // Try to acquire write lock in thread 2 again, should succeed...
+ assertTrue(e2.submit(tryWriteLockTask).get());
+
+ // Release the write lock in thread 2...
+ e2.submit(writeUnlockTask).get();
+ }
+
+ @Test
+ public void testWriteLockBlocksOtherReaders() throws ExecutionException, InterruptedException {
+ assumeReadWriteLock();
+
+ // Acquire the write lock in thread 1...
+ assertTrue(e1.submit(tryWriteLockTask).get());
+
+ // Try to acquire read lock in thread 2, should fail...
+ assertFalse(e2.submit(tryReadLockTask).get());
+
+ // Release the write lock in thread 1...
+ e1.submit(writeUnlockTask).get();
+
+ // Try to acquire read lock in thread 2 again, should succeed...
+ assertTrue(e2.submit(tryReadLockTask).get());
+
+ // Release the read lock in thread 2...
+ e2.submit(readUnlockTask).get();
+ }
+
+ @Test
+ public void testUpdateLockUpgradeToWriteLock() throws ExecutionException, InterruptedException {
+ assumeReadWriteUpdateLock();
+
+ // Acquire the update lock in thread 1...
+ assertTrue(e1.submit(tryUpdateLockTask).get());
+
+ // Try to acquire write lock in thread 1, should succeed...
+ assertTrue(e1.submit(new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return rwuls().tryUpgradeUpdateToWriteLock();
+ }
+ }).get());
+
+ // Release the write lock in thread 1...
+ e1.submit(new Runnable() {
+ @Override
+ public void run() {
+ rwuls().downgradeWriteToUpdateLock();
+ }
+ });
+
+ // Release the update lock in thread 1...
+ e1.submit(updateUnlockTask).get();
+ }
+
+ @Test
+ public void testReadWriteLockTransitions() {
+ assumeReadWriteLock();
+
+ // forbid upgrades/downgrades/unlocks when lock is not held
+ readUnlockForbidden();
+ writeUnlockForbidden();
+ upgradeReadToWriteLockForbidden();
+ downgradeWriteToReadLockForbidden();
+
+ // Read lock is held
+ assertTrue(rwls().tryReadLock());
+ writeUnlockForbidden();
+ downgradeWriteToReadLockForbidden();
+
+ // allow unlock
+ rwls().readUnlock();
+ assertTrue(rwls().tryReadLock());
+
+ // allow upgrade to write lock
+ try {
+ assertTrue(rwls().tryUpgradeReadToWriteLock());
+ } catch (UnsupportedOperationException tolerated) {
+ rwls().readUnlock();
+ assertTrue(rwls().tryWriteLock());
+ }
+
+ // write lock is held
+ readUnlockForbidden();
+ upgradeReadToWriteLockForbidden();
+
+ // allow unlock
+ rwls().writeUnlock();
+ assertTrue(rwls().tryWriteLock());
+
+ // allow downgrade to read lock
+ try {
+ rwls().downgradeWriteToReadLock();
+ } catch (UnsupportedOperationException tolerated) {}
+
+ rwls().reset();
+ }
+
+ void downgradeWriteToReadLockForbidden() {
+ try {
+ rwls().downgradeWriteToReadLock();
+ fail("downgradeWriteToReadLock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void upgradeReadToWriteLockForbidden() {
+ try {
+ rwls().tryUpgradeReadToWriteLock();
+ fail("tryUpgradeReadToWriteLock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void writeUnlockForbidden() {
+ try {
+ rwls().writeUnlock();
+ fail("writeUnlock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void readUnlockForbidden() {
+ try {
+ rwls().readUnlock();
+ fail("readUnlock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testReadWriteUpgradeLockTransitions() {
+ assumeReadWriteUpdateLock();
+
+ // forbid upgrades/downgrades/unlocks when lock is not held
+ updateUnlockForbidden();
+ upgradeReadToUpdateLockForbidden();
+ upgradeUpdateToWriteLockForbidden();
+ downgradeUpdateToReadLockForbidden();
+ downgradeWriteToUpdateLockForbidden();
+
+ // Read lock is held
+ assertTrue(rwuls().tryReadLock());
+ updateUnlockForbidden();
+ upgradeUpdateToWriteLockForbidden();
+ downgradeUpdateToReadLockForbidden();
+ downgradeWriteToUpdateLockForbidden();
+
+ // allow upgrade to update lock
+ assertTrue(rwuls().tryUpgradeReadToUpdateLock());
+
+ // update lock is held
+ readUnlockForbidden();
+ writeUnlockForbidden();
+ upgradeReadToUpdateLockForbidden();
+ upgradeReadToWriteLockForbidden();
+ downgradeWriteToUpdateLockForbidden();
+ downgradeWriteToReadLockForbidden();
+
+ // allow unlock
+ rwuls().updateUnlock();
+ assertTrue(rwuls().tryUpdateLock());
+
+ // allow upgrade to write lock
+ assertTrue(rwuls().tryUpgradeUpdateToWriteLock());
+
+ // write lock is held
+ updateUnlockForbidden();
+ upgradeReadToUpdateLockForbidden();
+ upgradeUpdateToWriteLockForbidden();
+ downgradeUpdateToReadLockForbidden();
+
+ // allow downgrade to update lock
+ rwuls().downgradeWriteToUpdateLock();
+
+ rwuls().updateUnlock();
+ }
+
+ void downgradeWriteToUpdateLockForbidden() {
+ try {
+ rwuls().downgradeWriteToUpdateLock();
+ fail("downgradeWriteToUpdateLock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void downgradeUpdateToReadLockForbidden() {
+ try {
+ rwuls().downgradeUpdateToReadLock();
+ fail("downgradeUpdateToReadLock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void upgradeUpdateToWriteLockForbidden() {
+ try {
+ rwuls().tryUpgradeUpdateToWriteLock();
+ fail("tryUpgradeUpdateToWriteLock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void upgradeReadToUpdateLockForbidden() {
+ try {
+ rwuls().tryUpgradeReadToUpdateLock();
+ fail("tryUpgradeReadToUpdateLock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void updateUnlockForbidden() {
+ try {
+ rwuls().updateUnlock();
+ fail("updateUnlock() should fail");
+ } catch (IllegalMonitorStateException e) {
+ // expected
+ } catch (UnsupportedOperationException e2) {
+ // expected
+ }
+ }
+
+ void assumeReadWriteUpdateLock() {
+ assumeTrue(lockingStrategy instanceof ReadWriteUpdateLockingStrategy);
+ }
+
+ void assumeReadWriteLock() {
+ assumeTrue(lockingStrategy instanceof ReadWriteLockingStrategy);
+ }
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/model/DataValueGeneratorTest.java b/lang/src/test/java/net/openhft/lang/model/DataValueGeneratorTest.java
index 1310fde..111df21 100644..100755
--- a/lang/src/test/java/net/openhft/lang/model/DataValueGeneratorTest.java
+++ b/lang/src/test/java/net/openhft/lang/model/DataValueGeneratorTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
@@ -22,6 +22,7 @@ import net.openhft.lang.io.Bytes;
import org.junit.Test;
import java.nio.ByteBuffer;
+import java.util.Date;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -31,9 +32,9 @@ import static org.junit.Assert.assertTrue;
*/
public class DataValueGeneratorTest {
@Test
- public void testGenerateJavaCode() throws Exception {
+ public void testGenerateJavaCode() {
DataValueGenerator dvg = new DataValueGenerator();
-// dvg.setDumpCode(true);
+ //dvg.setDumpCode(true);
JavaBeanInterface jbi = dvg.heapInstance(JavaBeanInterface.class);
jbi.setByte((byte) 1);
jbi.setChar('2');
@@ -43,6 +44,7 @@ public class DataValueGeneratorTest {
jbi.setLong(6);
jbi.setDouble(7);
jbi.setFlag(true);
+
assertEquals(1, jbi.getByte());
assertEquals('2', jbi.getChar());
assertEquals(3, jbi.getShort());
@@ -54,7 +56,7 @@ public class DataValueGeneratorTest {
}
@Test
- public void testGenerateJavaCode2() throws Exception {
+ public void testGenerateJavaCode2() {
DataValueGenerator dvg = new DataValueGenerator();
MinimalInterface mi = dvg.heapInstance(MinimalInterface.class);
@@ -76,7 +78,7 @@ public class DataValueGeneratorTest {
assertEquals(7.0, mi.double$(), 0.0);
assertTrue(mi.flag());
- ByteBufferBytes bbb = new ByteBufferBytes(ByteBuffer.allocate(64));
+ Bytes bbb = ByteBufferBytes.wrap(ByteBuffer.allocate(64));
mi.writeMarshallable(bbb);
System.out.println("size: " + bbb.position());
@@ -84,7 +86,6 @@ public class DataValueGeneratorTest {
bbb.position(0);
mi2.readMarshallable(bbb);
-
assertEquals(1, mi2.byte$());
assertEquals('2', mi2.char$());
assertEquals(3, mi2.short$());
@@ -96,36 +97,44 @@ public class DataValueGeneratorTest {
}
@Test
- public void testGenerateNative() throws Exception {
- String actual = new DataValueGenerator().generateNativeObject(JavaBeanInterface.class);
-// System.out.println(actual);
+ public void testGenerateNativeWithGetUsing() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+ String actual = new DataValueGenerator().generateNativeObject(JavaBeanInterfaceGetUsing.class);
+ System.out.println(actual);
CachedCompiler cc = new CachedCompiler(null, null);
- Class aClass = cc.loadFromJava(JavaBeanInterface.class.getName() + "£native", actual);
- JavaBeanInterface jbi = (JavaBeanInterface) aClass.asSubclass(JavaBeanInterface.class).newInstance();
- Bytes bytes = new ByteBufferBytes(ByteBuffer.allocate(64));
- ((Byteable) jbi).bytes(bytes);
- jbi.setByte((byte) 1);
- jbi.setChar('2');
- jbi.setShort((short) 3);
- jbi.setInt(4);
- jbi.setFloat(5);
- jbi.setLong(6);
- jbi.setDouble(7);
- jbi.setFlag(true);
- assertEquals("", jbi.getString());
+ Class aClass = cc.loadFromJava(JavaBeanInterfaceGetUsing.class.getName() + "$$Native", actual);
+ JavaBeanInterfaceGetUsing jbi = (JavaBeanInterfaceGetUsing) aClass.asSubclass(JavaBeanInterfaceGetUsing.class).newInstance();
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(64));
+ ((Byteable) jbi).bytes(bytes, 0L);
+
jbi.setString("G'day");
- assertEquals(1, jbi.getByte());
- assertEquals('2', jbi.getChar());
- assertEquals(3, jbi.getShort());
- assertEquals(4, jbi.getInt());
- assertEquals(5.0, jbi.getFloat(), 0);
- assertEquals(6, jbi.getLong());
- assertEquals(7.0, jbi.getDouble(), 0.0);
- assertTrue(jbi.getFlag());
- assertEquals("G'day", jbi.getString());
- assertEquals(42, ((Byteable) jbi).maxSize());
+
+ assertEquals("G'day", jbi.getUsingString(new StringBuilder()).toString());
+ }
+
+ @Test
+ public void testGenerateNativeWithHasArrays() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+ String actual = new DataValueGenerator().generateNativeObject(HasArraysInterface.class);
+ System.out.println(actual);
+ CachedCompiler cc = new CachedCompiler(null, null);
+ Class aClass = cc.loadFromJava(HasArraysInterface.class.getName() + "$$Native", actual);
+ HasArraysInterface hai = (HasArraysInterface) aClass.asSubclass(HasArraysInterface.class).newInstance();
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(152));
+ ((Byteable) hai).bytes(bytes, 0L);
+
+ hai.setStringAt(0, "G'day");
+
+ assertEquals("G'day", hai.getStringAt(0));
}
+ @Test
+ public void testGenerateNativeWithGetUsingHeapInstance() {
+ DataValueGenerator dvg = new DataValueGenerator();
+ JavaBeanInterfaceGetUsingHeap si = dvg.heapInstance(JavaBeanInterfaceGetUsingHeap.class);
+
+ si.setString("G'day");
+
+ assertEquals("G'day", si.getUsingString(new StringBuilder()).toString());
+ }
@Test
public void testStringFields() {
@@ -135,8 +144,8 @@ public class DataValueGeneratorTest {
assertEquals("Hello world", si.getString());
StringInterface si2 = dvg.nativeInstance(StringInterface.class);
- Bytes bytes = new ByteBufferBytes(ByteBuffer.allocate(192));
- ((Byteable) si2).bytes(bytes);
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(192));
+ ((Byteable) si2).bytes(bytes, 0L);
si2.setString("Hello world £€");
si2.setText("Hello world £€");
assertEquals("Hello world £€", si2.getString());
@@ -144,6 +153,25 @@ public class DataValueGeneratorTest {
}
@Test
+ public void testGetUsingStringFieldsWithStringBuilderHeapInstance() {
+ DataValueGenerator dvg = new DataValueGenerator();
+ GetUsingStringInterface si = dvg.heapInstance(GetUsingStringInterface.class);
+ si.setSomeStringField("Hello world");
+ si.setAnotherStringField("Hello world 2");
+ assertEquals("Hello world", si.getSomeStringField());
+ {
+ StringBuilder builder = new StringBuilder();
+ si.getUsingSomeStringField(builder);
+ assertEquals("Hello world", builder.toString());
+ }
+ {
+ StringBuilder builder = new StringBuilder();
+ si.getUsingAnotherStringField(builder);
+ assertEquals("Hello world 2", builder.toString());
+ }
+ }
+
+ @Test
public void testNested() {
DataValueGenerator dvg = new DataValueGenerator();
// dvg.setDumpCode(true);
@@ -156,8 +184,8 @@ public class DataValueGeneratorTest {
// dvg.setDumpCode(true);
NestedA nestedA = dvg.nativeInstance(NestedA.class);
- Bytes bytes = new ByteBufferBytes(ByteBuffer.allocate(192));
- ((Byteable) nestedA).bytes(bytes);
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(192));
+ ((Byteable) nestedA).bytes(bytes, 0L);
nestedA.key("key");
nestedA.one(nestedB1);
nestedA.two(nestedB2);
@@ -171,4 +199,41 @@ public class DataValueGeneratorTest {
assertEquals(nestedB1.hashCode(), nestedA.one().hashCode());
assertEquals(nestedB2.hashCode(), nestedA.two().hashCode());
}
+
+ @Test
+ public void testGenerateInterfaceWithEnumOnHeap() {
+ DataValueGenerator dvg = new DataValueGenerator();
+ //dvg.setDumpCode(true);
+ JavaBeanInterfaceGetMyEnum jbie = dvg.heapInstance(JavaBeanInterfaceGetMyEnum.class);
+ jbie.setMyEnum(MyEnum.B);
+ }
+
+ @Test
+ public void testGenerateInterfaceWithEnumNativeInstance() {
+ DataValueGenerator dvg = new DataValueGenerator();
+ //dvg.setDumpCode(true);
+ JavaBeanInterfaceGetMyEnum jbie = dvg.nativeInstance(JavaBeanInterfaceGetMyEnum.class);
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(64));
+ ((Byteable) jbie).bytes(bytes, 0L);
+ jbie.setMyEnum(MyEnum.C);
+ }
+
+ @Test
+ public void testGenerateInterfaceWithDateOnHeap() {
+ DataValueGenerator dvg = new DataValueGenerator();
+ //dvg.setDumpCode(true);
+ JavaBeanInterfaceGetDate jbid = dvg.heapInstance(JavaBeanInterfaceGetDate.class);
+ jbid.setDate(new Date());
+ }
+
+ @Test
+ public void testGenerateInterfaceWithDateNativeInstace() {
+ DataValueGenerator dvg = new DataValueGenerator();
+ //dvg.setDumpCode(true);
+ JavaBeanInterfaceGetDate jbid = dvg.nativeInstance(JavaBeanInterfaceGetDate.class);
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(64));
+ ((Byteable) jbid).bytes(bytes, 0L);
+ jbid.setDate(new Date());
+ assertEquals(new Date(), jbid.getDate());
+ }
}
diff --git a/lang/src/test/java/net/openhft/lang/model/DataValueModelTest.java b/lang/src/test/java/net/openhft/lang/model/DataValueModelTest.java
index 0f7a8f0..14e1352 100644
--- a/lang/src/test/java/net/openhft/lang/model/DataValueModelTest.java
+++ b/lang/src/test/java/net/openhft/lang/model/DataValueModelTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
@@ -37,23 +37,35 @@ public class DataValueModelTest {
" short$=FieldModel{name='short$', getter=public abstract short net.openhft.lang.model.MinimalInterface.short$(), setter=public abstract void net.openhft.lang.model.MinimalInterface.short$(short)}}"
, midvm.fieldMap().toString().replaceAll("},", "}\n"));
DataValueModel<JavaBeanInterface> jbdvm = DataValueModels.acquireModel(JavaBeanInterface.class);
- assertEquals("{byte=FieldModel{name='byte', getter=public abstract byte net.openhft.lang.model.JavaBeanInterface.getByte(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setByte(byte)}\n" +
+
+ assertEquals("{byte=FieldModel{name='byte', getter=public abstract byte net.openhft.lang.model.JavaBeanInterface.getByte(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setByte(byte)}\n" +
" char=FieldModel{name='char', getter=public abstract char net.openhft.lang.model.JavaBeanInterface.getChar(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setChar(char)}\n" +
" double=FieldModel{name='double', getter=public abstract double net.openhft.lang.model.JavaBeanInterface.getDouble(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setDouble(double)}\n" +
" flag=FieldModel{name='flag', getter=public abstract boolean net.openhft.lang.model.JavaBeanInterface.getFlag(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setFlag(boolean)}\n" +
" float=FieldModel{name='float', getter=public abstract float net.openhft.lang.model.JavaBeanInterface.getFloat(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setFloat(float)}\n" +
" int=FieldModel{name='int', getter=public abstract int net.openhft.lang.model.JavaBeanInterface.getInt(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setInt(int)}\n" +
" long=FieldModel{name='long', getter=public abstract long net.openhft.lang.model.JavaBeanInterface.getLong(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setLong(long)}\n" +
- " record=FieldModel{name='record', getter=public abstract int net.openhft.lang.model.JavaBeanInterface.getRecord(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setRecord(int)}\n" +
+ " record=FieldModel{name='record', getter=null, setter=null, busyLock=public abstract void net.openhft.lang.model.JavaBeanInterface.busyLockRecord() throws java.lang.InterruptedException, tryLock=public abstract boolean net.openhft.lang.model.JavaBeanInterface.tryLockRecord(), unlock=public abstract void net.openhft.lang.model.JavaBeanInterface.unlockRecord()}\n" +
" short=FieldModel{name='short', getter=public abstract short net.openhft.lang.model.JavaBeanInterface.getShort(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setShort(short)}\n" +
" string=FieldModel{name='string', getter=public abstract java.lang.String net.openhft.lang.model.JavaBeanInterface.getString(), setter=public abstract void net.openhft.lang.model.JavaBeanInterface.setString(java.lang.String), size= @net.openhft.lang.model.constraints.MaxSize(value=8)}}"
, jbdvm.fieldMap().toString().replaceAll("},", "}\n"));
DataValueModel<NestedArrayInterface> nais = DataValueModels.acquireModel(NestedArrayInterface.class);
- assertEquals("{int=FieldModel{name='int', getter=public abstract int net.openhft.lang.model.NestedArrayInterface.getInt(int), setter=public abstract void net.openhft.lang.model.NestedArrayInterface.setInt(int,int), indexSize= @net.openhft.lang.model.constraints.MaxSize(value=16)}\n" +
- " jBI=FieldModel{name='jBI', getter=public abstract net.openhft.lang.model.JavaBeanInterface net.openhft.lang.model.NestedArrayInterface.getJBI(int), setter=public abstract void net.openhft.lang.model.NestedArrayInterface.setJBI(int,net.openhft.lang.model.JavaBeanInterface), indexSize= @net.openhft.lang.model.constraints.MaxSize(value=32)}\n" +
+ assertEquals("{int=FieldModel{name='int', getter=public abstract int net.openhft.lang.model.NestedArrayInterface.getIntAt(int), setter=public abstract void net.openhft.lang.model.NestedArrayInterface.setIntAt(int,int), indexSize= MaxSize(value=16)}\n" +
+ " jBI=FieldModel{name='jBI', getter=public abstract net.openhft.lang.model.JavaBeanInterface net.openhft.lang.model.NestedArrayInterface.getJBIAt(int), setter=public abstract void net.openhft.lang.model.NestedArrayInterface.setJBIAt(int,net.openhft.lang.model.JavaBeanInterface), indexSize= MaxSize(value=32)}\n" +
" text=FieldModel{name='text', getter=public abstract java.lang.String net.openhft.lang.model.NestedArrayInterface.getText(), setter=public abstract void net.openhft.lang.model.NestedArrayInterface.setText(java.lang.String)}}"
, nais.fieldMap().toString().replaceAll("},", "}\n"));
+ DataValueModel<HasArraysInterface> haim = DataValueModels.acquireModel(HasArraysInterface.class);
+ assertEquals("{byte=FieldModel{name='byte', getter=public abstract byte net.openhft.lang.model.HasArraysInterface.getByteAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setByteAt(int,byte), indexSize= MaxSize(value=4)}\n" +
+ " char=FieldModel{name='char', getter=public abstract char net.openhft.lang.model.HasArraysInterface.getCharAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setCharAt(int,char), indexSize= MaxSize(value=4)}\n" +
+ " double=FieldModel{name='double', getter=public abstract double net.openhft.lang.model.HasArraysInterface.getDoubleAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setDoubleAt(int,double), indexSize= MaxSize(value=4)}\n" +
+ " flag=FieldModel{name='flag', getter=public abstract boolean net.openhft.lang.model.HasArraysInterface.getFlagAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setFlagAt(int,boolean), indexSize= MaxSize(value=4)}\n" +
+ " float=FieldModel{name='float', getter=public abstract float net.openhft.lang.model.HasArraysInterface.getFloatAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setFloatAt(int,float), indexSize= MaxSize(value=4)}\n" +
+ " int=FieldModel{name='int', getter=public abstract int net.openhft.lang.model.HasArraysInterface.getIntAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setIntAt(int,int), indexSize= MaxSize(value=4)}\n" +
+ " long=FieldModel{name='long', getter=public abstract long net.openhft.lang.model.HasArraysInterface.getLongAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setLongAt(int,long), indexSize= MaxSize(value=4)}\n" +
+ " short=FieldModel{name='short', getter=public abstract short net.openhft.lang.model.HasArraysInterface.getShortAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setShortAt(int,short), indexSize= MaxSize(value=4)}\n" +
+ " string=FieldModel{name='string', getter=public abstract java.lang.String net.openhft.lang.model.HasArraysInterface.getStringAt(int), setter=public abstract void net.openhft.lang.model.HasArraysInterface.setStringAt(int,java.lang.String), size= @net.openhft.lang.model.constraints.MaxSize(value=8), indexSize= MaxSize(value=4)}}"
+ , haim.fieldMap().toString().replaceAll("},", "}\n"));
}
}
diff --git a/lang/src/test/java/net/openhft/lang/model/FirstPrimitiveFieldTest.java b/lang/src/test/java/net/openhft/lang/model/FirstPrimitiveFieldTest.java
new file mode 100644
index 0000000..12c98c7
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/FirstPrimitiveFieldTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.lang.model.constraints.MaxSize;
+import net.openhft.lang.values.IntValue;
+import net.openhft.lang.values.LongValue;
+import org.junit.Test;
+
+import static net.openhft.lang.model.DataValueGenerator.firstPrimitiveFieldType;
+import static org.junit.Assert.assertEquals;
+
+public class FirstPrimitiveFieldTest {
+
+ @Test
+ public void firstPrimitiveFieldTest() {
+ assertEquals(int.class, firstPrimitiveFieldType(IntValue.class));
+ assertEquals(long.class, firstPrimitiveFieldType(LongValue.class));
+ assertEquals(long.class,
+ firstPrimitiveFieldType(DataValueClasses.directClassFor(LongValue.class)));
+ assertEquals(long.class, firstPrimitiveFieldType(FiveLongValues.class));
+ assertEquals(boolean.class, firstPrimitiveFieldType(FiveBooleanValues.class));
+ assertEquals(long.class, firstPrimitiveFieldType(FiveLongAndBooleanValues.class));
+ }
+}
+
+interface FiveLongValues {
+ void setValueAt(@MaxSize(5) int i, long v);
+ long getValueAt(int i);
+}
+
+interface FiveBooleanValues {
+ void setValueAt(@MaxSize(5) int i, boolean v);
+ boolean getValueAt(int i);
+}
+
+interface FiveLongAndBooleanValues {
+ void setLongValues(FiveLongValues values);
+ FiveLongValues getLongValues();
+ void setBooleanValues(FiveBooleanValues values);
+ FiveBooleanValues getBooleanValues();
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/GetUsingStringInterface.java b/lang/src/test/java/net/openhft/lang/model/GetUsingStringInterface.java
new file mode 100644
index 0000000..b5fc1c4
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/GetUsingStringInterface.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.lang.model.constraints.MaxSize;
+
+/**
+ * User: peter.lawrey Date: 08/10/13 Time: 09:09
+ */
+public interface GetUsingStringInterface {
+
+ void setSomeStringField(@MaxSize(64) String s);
+
+ void setAnotherStringField(@MaxSize(64) String s);
+
+ String getSomeStringField();
+
+ void getUsingSomeStringField(StringBuilder builder);
+
+ StringBuilder getUsingAnotherStringField(StringBuilder builder);
+}
+
diff --git a/lang/src/test/java/net/openhft/lang/model/HasArraysInterface.java b/lang/src/test/java/net/openhft/lang/model/HasArraysInterface.java
new file mode 100644
index 0000000..422e90c
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/HasArraysInterface.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.lang.model.constraints.MaxSize;
+
+public interface HasArraysInterface {
+ void setFlagAt(@MaxSize(4) int idx, boolean flag);
+
+ boolean getFlagAt(int idx);
+
+ void setByteAt(@MaxSize(4) int idx, byte b);
+
+ byte getByteAt(int idx);
+
+ void setShortAt(@MaxSize(4) int idx, short s);
+
+ short getShortAt(int idx);
+
+ void setCharAt(@MaxSize(4) int idx, char ch);
+
+ char getCharAt(int idx);
+
+ void setIntAt(@MaxSize(4) int idx, int i);
+
+ int getIntAt(int idx);
+
+ void setFloatAt(@MaxSize(4) int idx, float f);
+
+ float getFloatAt(int idx);
+
+ void setLongAt(@MaxSize(4) int idx, long l);
+
+ long getLongAt(int idx);
+
+ void setDoubleAt(@MaxSize(4) int idx, double d);
+
+ double getDoubleAt(int idx);
+
+ void setStringAt(@MaxSize(4) int idx, @MaxSize(8) String s);
+
+ String getStringAt(int idx);
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/JavaBeanInterface.java b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterface.java
index 0cf0675..ee6fe80 100644
--- a/lang/src/test/java/net/openhft/lang/model/JavaBeanInterface.java
+++ b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterface.java
@@ -1,35 +1,28 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
import net.openhft.lang.model.constraints.MaxSize;
-/**
- * User: peter.lawrey
- * Date: 06/10/13
- * Time: 16:59
- */
public interface JavaBeanInterface {
- int getRecord();
-
- void setRecord(int record);
-
void busyLockRecord() throws InterruptedException;
+ boolean tryLockRecord();
+
void unlockRecord();
void setFlag(boolean flag);
@@ -50,6 +43,10 @@ public interface JavaBeanInterface {
void setInt(int i);
+ int getVolatileInt();
+
+ void setOrderedInt(int i);
+
int getInt();
void setFloat(float f);
@@ -60,11 +57,17 @@ public interface JavaBeanInterface {
long getLong();
+ long addAtomicLong(long toAdd);
+
void setDouble(double d);
double getDouble();
+ double addAtomicDouble(double toAdd);
+
void setString(@MaxSize(8) String s);
String getString();
+
+ StringBuilder getUsingString(StringBuilder b);
}
diff --git a/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetDate.java b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetDate.java
new file mode 100644
index 0000000..f35f979
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetDate.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import java.util.Date;
+
+/**
+ * Created by pct25 on 6/4/2015.
+ */
+public interface JavaBeanInterfaceGetDate {
+
+ void setDate(Date date);
+
+ Date getDate();
+
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetMyEnum.java b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetMyEnum.java
new file mode 100644
index 0000000..ca96a34
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetMyEnum.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+/**
+ * Created by pct25 on 6/4/2015.
+ */
+public interface JavaBeanInterfaceGetMyEnum {
+
+ void setMyEnum( MyEnum myEnum);
+
+ MyEnum getMyEnum();
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsing.java b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsing.java
new file mode 100644
index 0000000..05ce14e
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsing.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.lang.model.constraints.MaxSize;
+
+/**
+ * User: peter.lawrey Date: 06/10/13 Time: 16:59
+ */
+public interface JavaBeanInterfaceGetUsing {
+
+ void setString(@MaxSize(8) String s);
+
+ StringBuilder getUsingString(StringBuilder b);
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsingHeap.java b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsingHeap.java
new file mode 100644
index 0000000..c90743f
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/JavaBeanInterfaceGetUsingHeap.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.lang.model.constraints.MaxSize;
+
+/**
+ * User: peter.lawrey Date: 06/10/13 Time: 16:59
+ */
+public interface JavaBeanInterfaceGetUsingHeap {
+
+ void setString(@MaxSize(8) String s);
+
+ StringBuilder getUsingString(StringBuilder b);
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/MinimalInterface.java b/lang/src/test/java/net/openhft/lang/model/MinimalInterface.java
index 2379b2e..d1362cc 100644
--- a/lang/src/test/java/net/openhft/lang/model/MinimalInterface.java
+++ b/lang/src/test/java/net/openhft/lang/model/MinimalInterface.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
diff --git a/lang/src/test/java/net/openhft/lang/model/MyEnum.java b/lang/src/test/java/net/openhft/lang/model/MyEnum.java
new file mode 100644
index 0000000..a9b0e7a
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/MyEnum.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+/**
+ * Created by pct25 on 6/4/2015.
+ */
+public enum MyEnum {
+ A(1), B(2), C(3);
+
+ private final int var;
+
+ MyEnum(int var) {
+ this.var = var;
+ }
+
+ public int getVar() {
+ return this.var;
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/model/NestedA.java b/lang/src/test/java/net/openhft/lang/model/NestedA.java
index 70d5f8a..e440615 100644
--- a/lang/src/test/java/net/openhft/lang/model/NestedA.java
+++ b/lang/src/test/java/net/openhft/lang/model/NestedA.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
@@ -35,5 +35,4 @@ public interface NestedA {
void two(NestedB one);
NestedB two();
-
}
diff --git a/lang/src/test/java/net/openhft/lang/model/NestedArrayInterface.java b/lang/src/test/java/net/openhft/lang/model/NestedArrayInterface.java
index 22caef0..81d7dcc 100644
--- a/lang/src/test/java/net/openhft/lang/model/NestedArrayInterface.java
+++ b/lang/src/test/java/net/openhft/lang/model/NestedArrayInterface.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
@@ -25,11 +25,11 @@ public interface NestedArrayInterface {
void setText(String text);
- int getInt(int index);
+ int getIntAt(int index);
- void setInt(@MaxSize(16) int index, int value);
+ void setIntAt(@MaxSize(16) int index, int value);
- JavaBeanInterface getJBI(@MaxSize(32) int index);
+ JavaBeanInterface getJBIAt(@MaxSize(32) int index);
- void setJBI(int index, JavaBeanInterface jbi);
+ void setJBIAt(int index, JavaBeanInterface jbi);
}
diff --git a/lang/src/test/java/net/openhft/lang/model/NestedB.java b/lang/src/test/java/net/openhft/lang/model/NestedB.java
index 5b4807b..1465853 100644
--- a/lang/src/test/java/net/openhft/lang/model/NestedB.java
+++ b/lang/src/test/java/net/openhft/lang/model/NestedB.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
diff --git a/lang/src/test/java/net/openhft/lang/model/StringInterface.java b/lang/src/test/java/net/openhft/lang/model/StringInterface.java
index 14d5d19..57a4526 100644
--- a/lang/src/test/java/net/openhft/lang/model/StringInterface.java
+++ b/lang/src/test/java/net/openhft/lang/model/StringInterface.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.model;
diff --git a/lang/src/test/java/net/openhft/lang/model/VolatileTest.java b/lang/src/test/java/net/openhft/lang/model/VolatileTest.java
new file mode 100644
index 0000000..9191549
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/model/VolatileTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.model;
+
+import net.openhft.compiler.CachedCompiler;
+import net.openhft.lang.io.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
+import net.openhft.lang.model.constraints.MaxSize;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Created by daniel on 11/06/2014.
+ */
+public class VolatileTest {
+ @Test
+ public void testGenerateJavaCode() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+ DataValueGenerator dvg = new DataValueGenerator();
+ // dvg.setDumpCode(true);
+
+ /* try{
+ BadInterface1 jbi = dvg.heapInstance(BadInterface1.class);
+ assertFalse("Should have thrown an IllegalArgumentException", true);
+ }catch(AssertionError e){
+ assertTrue("Throws an IllegalArgumentException", true);
+ }
+
+ try{
+ BadInterface2 jbi = dvg.heapInstance(BadInterface2.class);
+ assertFalse("Should have thrown an IllegalArgumentException", true);
+ }catch(AssertionError e){
+ assertTrue("Throws an IllegalArgumentException", true);
+ }
+*/
+ //Test the heap interface
+ try{
+ GoodInterface jbi = dvg.heapInstance(GoodInterface.class);
+
+ jbi.setOrderedY(5);
+ assertEquals(5, jbi.getVolatileY());
+ jbi.setOrderedIntAt(0,0);
+ jbi.setOrderedIntAt(1,1);
+ jbi.setOrderedIntAt(2,2);
+ jbi.setOrderedIntAt(3,3);
+
+ assertEquals(0, jbi.getVolatileIntAt(0));
+ assertEquals(1, jbi.getVolatileIntAt(1));
+ assertEquals(2, jbi.getVolatileIntAt(2));
+ assertEquals(3, jbi.getVolatileIntAt(3));
+ }catch(AssertionError e){
+ e.printStackTrace();
+ assertFalse("Throws an IllegalArgumentException", true);
+ }
+
+ //Test the native interface
+ try{
+ String actual = new DataValueGenerator().generateNativeObject(GoodInterface.class);
+ System.out.println(actual);
+ CachedCompiler cc = new CachedCompiler(null, null);
+ Class aClass = cc.loadFromJava(GoodInterface.class.getName() + "$$Native", actual);
+ GoodInterface jbi = (GoodInterface) aClass.asSubclass(GoodInterface.class).newInstance();
+ Bytes bytes = ByteBufferBytes.wrap(ByteBuffer.allocate(64));
+ ((Byteable) jbi).bytes(bytes, 0L);
+
+ jbi.setOrderedY(5);
+ assertEquals(5, jbi.getVolatileY());
+ jbi.setOrderedIntAt(0,0);
+ jbi.setOrderedIntAt(1,1);
+ jbi.setOrderedIntAt(2,2);
+ jbi.setOrderedIntAt(3,3);
+
+ assertEquals(0, jbi.getVolatileIntAt(0));
+ assertEquals(1, jbi.getVolatileIntAt(1));
+ assertEquals(2, jbi.getVolatileIntAt(2));
+ assertEquals(3, jbi.getVolatileIntAt(3));
+ }catch(AssertionError e){
+ e.printStackTrace();
+ assertFalse("Throws an IllegalArgumentException", true);
+ }
+ }
+
+ public interface BadInterface1{
+ int getX();
+
+ void setOrderedX(int x);
+ }
+
+ public interface BadInterface2{
+ int getVolatileX();
+
+ void setX(int x);
+ }
+
+ public interface GoodInterface{
+ int getX();
+
+ void setX(int x);
+
+ int getVolatileY();
+
+ void setOrderedY(int y);
+
+ int getY();
+
+ void setY(int y);
+
+ void setOrderedIntAt(@MaxSize(4) int idx, int i);
+ int getVolatileIntAt(int idx);
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/testing/RunningMinimumTest.java b/lang/src/test/java/net/openhft/lang/testing/RunningMinimumTest.java
index a6c0ddb..916ccdc 100644
--- a/lang/src/test/java/net/openhft/lang/testing/RunningMinimumTest.java
+++ b/lang/src/test/java/net/openhft/lang/testing/RunningMinimumTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.testing;
@@ -27,7 +27,7 @@ import static org.junit.Assert.assertEquals;
*/
public class RunningMinimumTest {
@Test
- public void testSample() throws Exception {
+ public void testSample() {
for (int k = 0; k < 1000; k++) {
for (long delta : new long[]{0, Integer.MIN_VALUE, Integer.MAX_VALUE}) {
RunningMinimum rm = new RunningMinimum(50 * 1000);
diff --git a/lang/src/test/java/net/openhft/lang/thread/LightPauserTest.java b/lang/src/test/java/net/openhft/lang/thread/LightPauserTest.java
new file mode 100755
index 0000000..f37cfcb
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/thread/LightPauserTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 higherfrequencytrading.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.openhft.lang.thread;
+
+import org.junit.Test;
+
+/**
+ * Created by peter.lawrey on 11/12/14.
+ */
+public class LightPauserTest {
+ @Test
+ public void testLightPauser() throws InterruptedException {
+ final LightPauser pauser = new LightPauser(100 * 1000, 100 * 1000);
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ while (!Thread.interrupted())
+ pauser.pause();
+ }
+ };
+ thread.start();
+
+ for (int t = 0; t < 3; t++) {
+ long start = System.nanoTime();
+ int runs = 10000000;
+ for (int i = 0; i < runs; i++)
+ pauser.unpause();
+ long time = System.nanoTime() - start;
+ System.out.printf("Average time to unpark was %,d ns%n", time / runs);
+ Thread.sleep(20);
+ }
+ thread.interrupt();
+ }
+}
diff --git a/lang/src/test/java/net/openhft/lang/values/BuySell.java b/lang/src/test/java/net/openhft/lang/values/BuySell.java
new file mode 100755
index 0000000..2a7b860
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/values/BuySell.java
@@ -0,0 +1,5 @@
+package net.openhft.lang.values;
+
+enum BuySell {
+ Buy, Sell
+} \ No newline at end of file
diff --git a/lang/src/test/java/net/openhft/lang/values/BuySellValues.java b/lang/src/test/java/net/openhft/lang/values/BuySellValues.java
new file mode 100755
index 0000000..e85c9d6
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/values/BuySellValues.java
@@ -0,0 +1,12 @@
+package net.openhft.lang.values;
+
+import net.openhft.lang.model.constraints.MaxSize;
+
+/**
+ * Created by peter.lawrey on 06/08/2015.
+ */
+public interface BuySellValues {
+ BuySell getValue();
+
+ void setValue(@MaxSize(5) BuySell buySell);
+}
diff --git a/lang/src/test/java/net/openhft/lang/values/CheckValuesBuildTest.java b/lang/src/test/java/net/openhft/lang/values/CheckValuesBuildTest.java
index f10ae6e..52301fa 100644
--- a/lang/src/test/java/net/openhft/lang/values/CheckValuesBuildTest.java
+++ b/lang/src/test/java/net/openhft/lang/values/CheckValuesBuildTest.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
diff --git a/lang/src/test/java/net/openhft/lang/values/EnumValuesTest.java b/lang/src/test/java/net/openhft/lang/values/EnumValuesTest.java
new file mode 100755
index 0000000..72d4471
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/values/EnumValuesTest.java
@@ -0,0 +1,53 @@
+package net.openhft.lang.values;
+
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.DirectStore;
+import net.openhft.lang.io.serialization.BytesMarshallable;
+import net.openhft.lang.model.DataValueClasses;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNull;
+
+/**
+ * Created by peter.lawrey on 06/08/2015.
+ */
+public class EnumValuesTest {
+ @Test
+ public void testSetNull() {
+ BuySellValues value = DataValueClasses.newInstance(BuySellValues.class);
+ value.setValue(null);
+ assertNull(value.getValue());
+ }
+
+ @Test
+ public void testBytesMarshallable() {
+ BuySellValues value = DataValueClasses.newInstance(BuySellValues.class);
+ DirectBytes bytes = DirectStore.allocate(8).bytes();
+ ((BytesMarshallable) value).writeMarshallable(bytes);
+
+ bytes.clear();
+
+ BuySellValues value2 = DataValueClasses.newInstance(BuySellValues.class);
+ // to ensure, in assert below, that readMarshallable indeed reads and sets null
+ value2.setValue(BuySell.Sell);
+ ((BytesMarshallable) value2).readMarshallable(bytes);
+ assertNull(value2.getValue());
+ }
+
+ @Test
+ public void testBytesMarshallable2() {
+ BuySellValues value = DataValueClasses.newInstance(BuySellValues.class);
+ DirectBytes bytes = DirectStore.allocate(8).bytes();
+ value.setValue(BuySell.Buy);
+ ((BytesMarshallable) value).writeMarshallable(bytes);
+
+ bytes.clear();
+
+ BuySellValues value2 = DataValueClasses.newInstance(BuySellValues.class);
+ ((BytesMarshallable) value2).readMarshallable(bytes);
+ Assert.assertEquals(BuySell.Buy, value2.getValue());
+ }
+}
+
diff --git a/lang/src/test/java/net/openhft/lang/values/NestAll.java b/lang/src/test/java/net/openhft/lang/values/NestAll.java
index cb629b6..10b2b6c 100644
--- a/lang/src/test/java/net/openhft/lang/values/NestAll.java
+++ b/lang/src/test/java/net/openhft/lang/values/NestAll.java
@@ -1,17 +1,17 @@
/*
- * Copyright 2013 Peter Lawrey
+ * Copyright (C) 2015 higherfrequencytrading.com
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.openhft.lang.values;
@@ -49,5 +49,4 @@ public interface NestAll {
UnsignedIntValue getUI();
UnsignedShortValue getUS();
-
}
diff --git a/lang/src/test/java/net/openhft/lang/values/StringValueTest.java b/lang/src/test/java/net/openhft/lang/values/StringValueTest.java
new file mode 100755
index 0000000..4ca867b
--- /dev/null
+++ b/lang/src/test/java/net/openhft/lang/values/StringValueTest.java
@@ -0,0 +1,37 @@
+package net.openhft.lang.values;
+
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.DirectStore;
+import net.openhft.lang.io.serialization.BytesMarshallable;
+import net.openhft.lang.model.DataValueClasses;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNull;
+
+/**
+ * Created by peter.lawrey on 06/08/2015.
+ */
+public class StringValueTest {
+ @Test
+ public void testSetNull() {
+ StringValue value = DataValueClasses.newInstance(StringValue.class);
+ value.setValue(null);
+ assertNull(value.getValue());
+ }
+
+ @Test
+ public void testBytesMarshallable() {
+ StringValue value = DataValueClasses.newInstance(StringValue.class);
+ DirectBytes bytes = DirectStore.allocate(8).bytes();
+ ((BytesMarshallable) value).writeMarshallable(bytes);
+
+ bytes.clear();
+
+ StringValue value2 = DataValueClasses.newInstance(StringValue.class);
+ // to ensure, in assert below, that readMarshallable indeed reads and sets null
+ value2.setValue("foo");
+ ((BytesMarshallable) value2).readMarshallable(bytes);
+ assertNull(value2.getValue());
+ }
+} \ No newline at end of file
diff --git a/lang8/pom.xml b/lang8/pom.xml
new file mode 100755
index 0000000..d2a2963
--- /dev/null
+++ b/lang8/pom.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2015 higherfrequencytrading.com
+ ~
+ ~ This program is free software: you can redistribute it and/or modify
+ ~ it under the terms of the GNU Lesser General Public License as published by
+ ~ the Free Software Foundation, either version 3 of the License.
+ ~
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>net.openhft</groupId>
+ <artifactId>java-parent-pom</artifactId>
+ <version>1.1.2</version>
+ <relativePath/>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>lang</artifactId>
+ <version>8.0.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>OpenHFT/Java-Lang/lang v8</name>
+ <description>Java Lang library for High Frequency Trading (Java 8+)</description>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>third-party-bom</artifactId>
+ <type>pom</type>
+ <version>3.4.20</version>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>compiler</artifactId>
+ <version>2.2.0</version>
+ </dependency>
+
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.java</groupId>
+ <artifactId>tools</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>net.openhft</groupId>
+ <artifactId>compiler</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.xerial.snappy</groupId>
+ <artifactId>snappy-java</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+
+ <plugins>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-publish-plugin</artifactId>
+ <configuration>
+ <checkoutDirectory>${project.build.directory}/scmpublish/javadoc</checkoutDirectory>
+ <checkinComment>Publishing javadoc for ${project.artifactId}:${project.version}
+ </checkinComment>
+ <content>${project.reporting.outputDirectory}</content>
+ <skipDeletedFiles>true</skipDeletedFiles>
+ <pubScmUrl>scm:git:git@github.com:OpenHFT/Java-Lang</pubScmUrl>
+ <scmBranch>gh-pages</scmBranch>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Bundle-Name>OpenHFT :: ${project.artifactId}</Bundle-Name>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ <Export-Package>
+ net.openhft.lang.*
+ </Export-Package>
+ </instructions>
+ </configuration>
+ <executions>
+ <!--
+ This execution makes sure that the manifest is available
+ when the tests are executed
+ -->
+ <execution>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <!-- to use this run with the profile -->
+ <id>pitest</id>
+ <build>
+ <plugins>
+ <plugin>
+ <!-- For debugging in IntelliJ IDEA -->
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <systemPropertyVariables>
+ <project.build.directory>${project.build.directory}</project.build.directory>
+ </systemPropertyVariables>
+
+ <forkMode>never</forkMode>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.pitest</groupId>
+ <artifactId>pitest-maven</artifactId>
+ <version>0.33</version>
+ <configuration>
+ <targetClasses>
+ <param>net.openhft.lang.collection.*</param>
+ </targetClasses>
+ <targetTests>
+ <param>net.openhft.lang.collection.*</param>
+ </targetTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <scm>
+ <url>scm:git:git@github.com:OpenHFT/Java-Lang.git</url>
+ <connection>scm:git:git@github.com:OpenHFT/Java-Lang.git</connection>
+ <developerConnection>scm:git:git@github.com:OpenHFT/Java-Lang.git</developerConnection>
+ <tag>master</tag>
+ </scm>
+
+</project>
diff --git a/pom.xml b/pom.xml
index d6cd748..555634a 100644..100755
--- a/pom.xml
+++ b/pom.xml
@@ -1,28 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- ~ Copyright 2013 Peter Lawrey
+ ~ Copyright (C) 2015 higherfrequencytrading.com
~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
+ ~ This program is free software: you can redistribute it and/or modify
+ ~ it under the terms of the GNU Lesser General Public License as published by
+ ~ the Free Software Foundation, either version 3 of the License.
~
- ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~ This program is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU Lesser General Public License for more details.
~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
+ ~ You should have received a copy of the GNU Lesser General Public License
+ ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>net.openhft</groupId>
+ <parent>
+ <groupId>net.openhft</groupId>
+ <artifactId>root-parent-pom</artifactId>
+ <version>1.1.1</version>
+ <relativePath/>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
<artifactId>Java-Lang</artifactId>
- <version>6.1.3</version>
+ <version>6.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Java Lang Parent</name>
@@ -30,7 +36,17 @@
<modules>
<module>lang</module>
- <module>lang-osgi</module>
- <module>lang-integration</module>
+ <!-- <module>lang-test</module> -->
+ <!--<module>lang-sandbox</module>-->
</modules>
-</project> \ No newline at end of file
+
+
+ <scm>
+ <url>scm:git:git@github.com:OpenHFT/Java-Lang.git</url>
+ <connection>scm:git:git@github.com:OpenHFT/Java-Lang.git</connection>
+ <developerConnection>scm:git:git@github.com:OpenHFT/Java-Lang.git</developerConnection>
+ <tag>master</tag>
+ </scm>
+
+</project>
+