summaryrefslogtreecommitdiff
path: root/lang-sandbox
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 /lang-sandbox
parentb2ec1a2d459cfef3ff13133c1f7f5972e3740258 (diff)
Imported Upstream version 6.7.6
Diffstat (limited to 'lang-sandbox')
-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.java109
-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.java107
-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.java65
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java68
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java94
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java31
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java60
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java27
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.java25
-rw-r--r--lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java177
-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.java95
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java114
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java96
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java57
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java263
-rw-r--r--lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java109
30 files changed, 2721 insertions, 0 deletions
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-sandbox/src/main/java/net/openhft/lang/io/serialization/RawCopier.java b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/RawCopier.java
new file mode 100644
index 0000000..b5e224e
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/RawCopier.java
@@ -0,0 +1,109 @@
+/*
+ * 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;
+
+import net.openhft.lang.io.Bytes;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+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;
+ final int end;
+ private final Class<T> tClass;
+
+ private RawCopier(Class<T> tClass) {
+ this.tClass = tClass;
+ List<Field> fields = new ArrayList<Field>();
+ addAllFields(fields, tClass);
+ Collections.sort(fields, new Comparator<Field>() {
+ @Override
+ public int compare(Field o1, Field o2) {
+ long off1 = UNSAFE.objectFieldOffset(o1);
+ long off2 = UNSAFE.objectFieldOffset(o2);
+ return Double.compare(off1, off2);
+ }
+ });
+ start = (int) UNSAFE.objectFieldOffset(fields.get(0));
+ Field lastField = null;
+ for (Field field : fields) {
+ if (Modifier.isTransient(field.getModifiers()) || !field.getType().isPrimitive())
+ break;
+ lastField = field;
+ }
+ end = (int) UNSAFE.objectFieldOffset(lastField) + sizeOf(lastField.getType());
+
+ assert end > start : "end <= start, start: " + start + ", end: " + end;
+ }
+
+ public static <T> RawCopier<T> copies(Class<T> tClass) {
+ return new RawCopier<T>(tClass);
+ }
+
+ private static int sizeOf(Class<?> type) {
+ return UNSAFE.arrayIndexScale(Array.newInstance(type, 0).getClass());
+ }
+
+ public int start() {
+ return start;
+ }
+
+ public int end() {
+ return end;
+ }
+
+ public void toBytes(Object obj, Bytes bytes) {
+ bytes.writeObject(obj, start, end);
+ }
+
+ public void fromBytes(Bytes bytes, Object obj) {
+ bytes.readObject(obj, start, end);
+ }
+
+ public void copy(T from, T to) {
+ long i;
+ for (i = start; i < end - 7; i += 8) {
+ UNSAFE.putLong(to, i, UNSAFE.getLong(from, i));
+ }
+ for (; i < end; i++) {
+ UNSAFE.putByte(to, i, UNSAFE.getByte(from, i));
+ }
+ }
+
+ private static void addAllFields(List<Field> fields, Class tClass) {
+ if (tClass != null && tClass != Object.class)
+ addAllFields(fields, tClass.getSuperclass());
+ 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-sandbox/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
new file mode 100644
index 0000000..b18e521
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadata.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import static net.openhft.lang.io.NativeBytes.UNSAFE;
+
+public class DirectSerializationMetadata {
+ private static final int OBJECT_ALIGNMENT = 8;
+ private static final int OBJECT_ALIGNMENT_MASK = OBJECT_ALIGNMENT - 1;
+
+ static final long NATIVE_WORD_SIZE = Jvm.is64Bit() ? 8 : 4;
+ 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
+
+ private static final SerializationMetadata EmptyObjectMetadata = new SerializationMetadata(0, 0);
+
+ public static final class SerializationMetadata {
+ final long start;
+ final long length;
+
+ SerializationMetadata(long start, long length) {
+ this.start = start;
+ this.length = length;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("SerializationMetadata: Start %s Length %s", start, length);
+ }
+ }
+
+ public static SerializationMetadata extractMetadata(List<Field> fields) {
+ if (fields.isEmpty()) return EmptyObjectMetadata;
+
+ Offsets offsets = minMaxOffsets(fields);
+
+ long totalSize = OBJECT_HEADER_SIZE + offsets.max - offsets.min + 1;
+ return new SerializationMetadata(offsets.min, padToObjectAlignment(totalSize) - OBJECT_HEADER_SIZE);
+ }
+
+ public static SerializationMetadata extractMetadataForPartialCopy(List<Field> fields) {
+ if (fields.isEmpty()) return EmptyObjectMetadata;
+
+ Offsets offsets = minMaxOffsets(fields);
+
+ Field lastField = fields.get(fields.size() - 1);
+
+ return new SerializationMetadata(offsets.min, offsets.max + sizeOf(lastField) - OBJECT_HEADER_SIZE);
+ }
+
+ private static Offsets minMaxOffsets(List<Field> fields) {
+ long minOffset = UNSAFE.objectFieldOffset(fields.get(0));
+ long maxOffset = UNSAFE.objectFieldOffset(fields.get(fields.size() - 1));
+
+ return new Offsets(minOffset, maxOffset);
+ }
+
+ private static long padToObjectAlignment(long length) {
+ if ((length & OBJECT_ALIGNMENT_MASK) != 0) {
+ long padding = OBJECT_ALIGNMENT - (length & OBJECT_ALIGNMENT_MASK);
+ length += padding;
+ }
+
+ return length;
+ }
+
+ private static long sizeOf(Field field) {
+ if (boolean.class.equals(field.getType())) return 1;
+ else if (byte.class.equals(field.getType())) return 1;
+ else if (short.class.equals(field.getType())) return 2;
+ else if (char.class.equals(field.getType())) return 2;
+ else if (int.class.equals(field.getType())) return 4;
+ else if (float.class.equals(field.getType())) return 4;
+ else return 8;
+ }
+
+ private static final class Offsets {
+ public final long min;
+ public final long max;
+
+ private Offsets(long min, long max) {
+ this.min = min;
+ this.max = max;
+ }
+ }
+} \ No newline at end of file
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-sandbox/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
new file mode 100644
index 0000000..5152571
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/Introspect.java
@@ -0,0 +1,65 @@
+/*
+ * 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.Maths;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import static net.openhft.lang.io.NativeBytes.UNSAFE;
+import static net.openhft.lang.io.serialization.direct.FieldMetadata.isStatic;
+
+public class Introspect {
+ public static List<Field> fields(Class<?> clazz) {
+ ArrayList<Field> fields = new ArrayList<Field>();
+
+ addToFields(clazz, fields);
+ Collections.sort(fields, FieldOffsetComparator.Instance);
+
+ return fields;
+ }
+
+ private static List<Field> addToFields(Class<?> clazz, ArrayList<Field> accumulator) {
+ Collections.addAll(accumulator, clazz.getDeclaredFields());
+ Class<?> maybeSuper = clazz.getSuperclass();
+
+ return maybeSuper != null ?
+ addToFields(maybeSuper, accumulator) :
+ accumulator;
+ }
+
+ private static final class FieldOffsetComparator implements Comparator<Field> {
+ public static final FieldOffsetComparator Instance = new FieldOffsetComparator();
+
+ @Override
+ public int compare(Field first, Field second) {
+ return Maths.compare(offset(first), offset(second));
+ }
+
+ private static long offset(Field field) {
+ return isStatic(field) ?
+ UNSAFE.staticFieldOffset(field) :
+ UNSAFE.objectFieldOffset(field);
+ }
+ }
+} \ No newline at end of file
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..2520634
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshaller.java
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+import static net.openhft.lang.io.NativeBytes.UNSAFE;
+import static net.openhft.lang.io.serialization.direct.DirectSerializationMetadata.SerializationMetadata;
+
+public final class ObjectMarshaller<T> {
+ private final SerializationMetadata metadata;
+
+ public ObjectMarshaller(SerializationMetadata metadata) {
+ this.metadata = metadata;
+ }
+
+ public void write(Bytes bytes, T tObject) {
+ long i = metadata.start;
+ long end = metadata.start + metadata.length;
+
+ while (i < end - 7) {
+ bytes.writeLong(UNSAFE.getLong(tObject, i));
+ i += 8;
+ }
+
+ while (i < end) {
+ bytes.writeByte(UNSAFE.getByte(tObject, i));
+ ++i;
+ }
+ }
+
+ public T read(Bytes bytes, T tObject) {
+ long i = metadata.start;
+ long end = metadata.start + metadata.length;
+
+ while (i < end - 7) {
+ UNSAFE.putLong(tObject, i, bytes.readLong());
+ i += 8;
+ }
+
+ while (i < end) {
+ UNSAFE.putByte(tObject, i, bytes.readByte());
+ ++i;
+ }
+
+ return tObject;
+ }
+
+ public long length() {
+ return metadata.length;
+ }
+} \ No newline at end of file
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..d0f0a03
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/io/serialization/direct/ObjectMarshallers.java
@@ -0,0 +1,94 @@
+/*
+ * 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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static net.openhft.lang.io.serialization.direct.DirectSerializationMetadata.SerializationMetadata;
+
+final class ObjectMarshallers {
+ private static final Logger Log = LoggerFactory.getLogger(ObjectMarshallers.class);
+
+ private static final Map<Class, ObjectMarshaller> metadata = new HashMap<Class, ObjectMarshaller>();
+
+ @SuppressWarnings("unchecked")
+ public static <T> ObjectMarshaller<T> forClass(Class<T> clazz) {
+ ObjectMarshaller om = metadata.get(clazz);
+ if (om == null) {
+ List<Field> fields = Introspect.fields(clazz);
+ List<Field> eligibleFields = DirectSerializationFilter.stopAtFirstIneligibleField(fields);
+
+ SerializationMetadata serializationMetadata;
+
+ if (hasIneligibleFields(fields, eligibleFields)) {
+ WarnAboutIneligibleFields.apply(clazz, fields, eligibleFields);
+ serializationMetadata = DirectSerializationMetadata.extractMetadataForPartialCopy(eligibleFields);
+
+ } else {
+ serializationMetadata = DirectSerializationMetadata.extractMetadata(eligibleFields);
+ }
+
+ om = new ObjectMarshaller<T>(serializationMetadata);
+ Log.warn("Class {} has metadata {}", clazz.getName(), serializationMetadata);
+ metadata.put(clazz, om);
+ }
+
+ return (ObjectMarshaller<T>) om;
+ }
+
+ private static boolean hasIneligibleFields(List<Field> allFields, List<Field> eligibleFields) {
+ return allFields.size() != eligibleFields.size();
+ }
+
+ 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.warn(
+ "The following fields in Class {} will not be copied by ObjectMarshaller:\n{}",
+ clazz.getName(),
+ commaSeparate(ineligibleFields)
+ );
+ }
+
+ private static String commaSeparate(Collection<Field> fields) {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for (Field field : fields) {
+ if (first) {
+ sb.append('\t');
+ sb.append(field.getName());
+ first = false;
+
+ } else {
+ sb.append("\n\t");
+ sb.append(field.getName());
+ }
+ }
+
+ return sb.toString();
+ }
+ }
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java b/lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java
new file mode 100644
index 0000000..2777560
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/ClassModel.java
@@ -0,0 +1,31 @@
+/*
+ * 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.model;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import java.util.Set;
+
+public interface ClassModel {
+ void setMethod(String name, MethodFilter filter, Method method);
+
+ Set<String> getNames();
+
+ Map<MethodFilter, Method> filterMapFor(String name);
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java b/lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java
new file mode 100644
index 0000000..a381ad0
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/DataValueMetaModel.java
@@ -0,0 +1,60 @@
+/*
+ * 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.model;
+
+import net.openhft.lang.io.serialization.BytesMarshallable;
+
+import java.io.Externalizable;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+class DataValueMetaModel {
+ private final Set<Class> ignoredClasses = new HashSet<Class>();
+ private final List<MethodFilter> filters = new ArrayList<MethodFilter>();
+
+ public DataValueMetaModel() {
+ addIgnoredClass(Object.class);
+ addIgnoredClass(Externalizable.class);
+ addIgnoredClass(Copyable.class);
+ addIgnoredClass(Byteable.class);
+ addIgnoredClass(BytesMarshallable.class);
+
+ for (VanillaFilter vanillaFilter : VanillaFilter.values()) {
+ addMethodFilter(vanillaFilter);
+ }
+ }
+
+ void addIgnoredClass(Class aClass) {
+ ignoredClasses.add(aClass);
+ }
+
+ void addMethodFilter(MethodFilter filter) {
+ int pos = insertionPoint(filter);
+ filters.add(pos, filter);
+ }
+
+ private int insertionPoint(MethodFilter filter) {
+ for (int i = 0; i < filters.size(); i++)
+ if (filters.get(i).matches() < filter.matches())
+ return i;
+ return filters.size();
+ }
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java
new file mode 100644
index 0000000..22283ba
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodFilter.java
@@ -0,0 +1,27 @@
+/*
+ * 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.model;
+
+import java.lang.reflect.Method;
+
+interface MethodFilter {
+ int matches();
+
+ String nameFor(Method method, Class<?>[] parameterTypes);
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.java b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.java
new file mode 100644
index 0000000..f41e502
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/MethodTemplate.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.model;
+
+import java.lang.reflect.Method;
+
+public interface MethodTemplate {
+ void generate(Method method, ClassModel classModel);
+}
diff --git a/lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java b/lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java
new file mode 100644
index 0000000..b825675
--- /dev/null
+++ b/lang-sandbox/src/main/java/net/openhft/lang/model/VanillaFilter.java
@@ -0,0 +1,177 @@
+/*
+ * 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.model;
+
+import java.lang.reflect.Method;
+
+public enum VanillaFilter implements MethodFilter {
+ GET_VALUE {
+ @Override
+ public int matches() {
+ return 3;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 0 || method.getReturnType() != void.class)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("get") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ SET_VALUE {
+ @Override
+ public int matches() {
+ return 3;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1 || method.getReturnType() == void.class)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("set") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ ADD_VALUE {
+ @Override
+ public int matches() {
+ return 3;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("add") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ ADD_ATOMIC_VALUE {
+ @Override
+ public int matches() {
+ return 8;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("addAtomic") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ COMPARE_AND_SWAP_VALUE {
+ @Override
+ public int matches() {
+ return 15;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("compareAndSwap") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ TRY_LOCK_VALUE {
+ @Override
+ public int matches() {
+ return 7;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("tryLock") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ TRY_LOCK_NANOS_VALUE {
+ @Override
+ public int matches() {
+ return 12;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("tryLockNanos") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ BUSY_LOCK_VALUE {
+ @Override
+ public int matches() {
+ return 8;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("busyLock") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+ UNLOCK_VALUE {
+ @Override
+ public int matches() {
+ return 6;
+ }
+
+ @Override
+ public String nameFor(Method method, Class<?>[] parameterTypes) {
+ if (parameterTypes.length != 1)
+ return null;
+ final String name = method.getName();
+ final int pos = matches();
+ if (name.startsWith("unlock") && Character.isUpperCase(name.charAt(pos)))
+ return Character.toLowerCase(name.charAt(pos)) + name.substring(pos + 1);
+ return null;
+ }
+ },
+}
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-sandbox/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java
new file mode 100644
index 0000000..53d7abf
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/RawCopierTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+import net.openhft.lang.io.DirectBytes;
+import net.openhft.lang.io.DirectStore;
+import net.openhft.lang.io.NativeBytes;
+import org.junit.Test;
+
+import java.awt.geom.Point2D;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * User: peter.lawrey Date: 22/09/13 Time: 17:06
+ */
+public class RawCopierTest {
+ static void printInts(Object o, int len) {
+ for (long i = 0; i < len; i += 4) {
+ System.out.print(NativeBytes.UNSAFE.getInt(o, i) + " ");
+ }
+ System.out.println();
+ }
+
+ @Test
+ public void testStartEnd() {
+ RawCopier<A> aRawCopier = RawCopier.copies(A.class);
+ if (aRawCopier.start != 8)
+ assertEquals(12, aRawCopier.start);
+ assertEquals(aRawCopier.start + 3 * 4, aRawCopier.end);
+
+ RawCopier<B> bRawCopier = RawCopier.copies(B.class);
+ if (aRawCopier.start != 8)
+ assertEquals(16, bRawCopier.start);
+ assertEquals(bRawCopier.start + 4 * 8, bRawCopier.end);
+ }
+
+ @Test
+ public void testReadWrite() {
+ DirectStore ds = DirectStore.allocate(1024);
+ DirectBytes db = ds.bytes();
+ RawCopier<A> aRawCopier = RawCopier.copies(A.class);
+ A a = new A();
+ a.i = 111;
+ a.j = -222;
+ a.k = 333;
+ a.s = "Hello";
+ aRawCopier.toBytes(a, db);
+ assertEquals(12, db.position());
+
+ assertEquals(111, db.readInt(0));
+ assertEquals(-222, db.readInt(4));
+ assertEquals(333, db.readInt(8));
+
+ A a2 = new A();
+ a2.i = 1;
+ a2.j = 2;
+ a2.k = 3;
+// printInts(a2, 28);
+ db.position(0);
+ aRawCopier.fromBytes(db, a2);
+// printInts(a2, 28);
+ assertEquals(111, a2.i);
+ assertEquals(-222, a2.j);
+ assertEquals(333, a2.k);
+ assertEquals(null, a2.s);
+ }
+
+ static class A {
+ int i, j, k;
+ String s;
+ transient Map map;
+ }
+
+ static class B extends Point2D.Double {
+ double z, w;
+ }
+}
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..16f6b8b
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationFilterTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+import static net.openhft.lang.io.serialization.direct.DirectSerializationFilter.stopAtFirstIneligibleField;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class DirectSerializationFilterTest {
+
+ @Test
+ public void instancePrimitivesAreEligible() {
+ List<Field> field = fieldsNamed("intField");
+ assertEquals(field, stopAtFirstIneligibleField(field));
+ }
+
+ @Test
+ public void instancePrimitiveArraysAreNotEligible() {
+ List<Field> field = fieldsNamed("doubleArray");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void instanceReferencesAreNotEligible() {
+ List<Field> field = fieldsNamed("stringList");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void instanceReferenceArraysAreNotEligible() {
+ List<Field> field = fieldsNamed("objectArray");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void staticPrimitivesAreNotEligible() {
+ List<Field> field = fieldsNamed("staticIntField");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void staticPrimitiveArraysAreNotEligible() {
+ List<Field> field = fieldsNamed("staticDoubleArray");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void staticReferencesAreNotEligible() {
+ List<Field> field = fieldsNamed("staticStringList");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void staticReferenceArraysAreNotEligible() {
+ List<Field> field = fieldsNamed("staticObjectArray");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void transientPrimitivesAreNotEligible() {
+ List<Field> field = fieldsNamed("transientShort");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void transientReferencsAreNotEligible() {
+ List<Field> field = fieldsNamed("transientObject");
+ assertTrue(stopAtFirstIneligibleField(field).isEmpty());
+ }
+
+ @Test
+ public void includesAllEligibleFields() {
+ List<Field> fields = fieldsNamed("intField", "shortField", "longField", "byteField", "stringList");
+ List<Field> expectedfields = fields.subList(0, 4);
+
+ assertEquals(expectedfields, stopAtFirstIneligibleField(fields));
+ }
+
+ private static List<Field> fieldsNamed(String... names) {
+ ArrayList<Field> fields = new ArrayList<Field>();
+
+ for (String name : names) {
+ try {
+ fields.add(TestClasses.MixedFields.class.getDeclaredField(name));
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException("Exception retrieving " + name, e);
+ }
+ }
+
+ return fields;
+ }
+}
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..4642107
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/DirectSerializationMetadataTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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 static net.openhft.lang.io.AbstractBytes.UNSIGNED_INT_MASK;
+import static net.openhft.lang.io.NativeBytes.UNSAFE;
+import static net.openhft.lang.io.serialization.direct.DirectSerializationMetadata.*;
+import static net.openhft.lang.io.serialization.direct.TestClasses.*;
+import static org.junit.Assert.assertEquals;
+
+public class DirectSerializationMetadataTest {
+
+ @Test
+ public void primitives1Metadata() {
+ unsafeClassHeaderSize64BitCompressedOops(new Primitives1());
+
+ SerializationMetadata serializationMetadata = extractMetadata(Introspect.fields(Primitives1.class));
+ assertEquals(OBJECT_HEADER_SIZE, serializationMetadata.start);
+ assertEquals(4, serializationMetadata.length);
+ }
+
+ @Test
+ public void primitives2Metadata() {
+ unsafeClassHeaderSize64BitCompressedOops(new Primitives2());
+
+ SerializationMetadata serializationMetadata = extractMetadata(Introspect.fields(Primitives2.class));
+ assertEquals(OBJECT_HEADER_SIZE, serializationMetadata.start);
+ assertEquals(12, serializationMetadata.length);
+ }
+
+ @Test
+ public void primitives3Metadata() {
+ unsafeClassHeaderSize64BitCompressedOops(new Primitives3());
+
+ SerializationMetadata serializationMetadata = extractMetadata(Introspect.fields(Primitives3.class));
+ assertEquals(OBJECT_HEADER_SIZE, serializationMetadata.start);
+ assertEquals(12, serializationMetadata.length);
+ }
+
+ @Test
+ public void primitives4Metadata() {
+ unsafeClassHeaderSize64BitCompressedOops(new Primitives4());
+
+ SerializationMetadata serializationMetadata = extractMetadata(Introspect.fields(Primitives4.class));
+ assertEquals(OBJECT_HEADER_SIZE, serializationMetadata.start);
+ assertEquals(4, serializationMetadata.length);
+ }
+
+ @Test
+ public void primitives5Metadata() {
+ unsafeClassHeaderSize64BitCompressedOops(new Primitives5());
+
+ SerializationMetadata serializationMetadata = extractMetadata(Introspect.fields(Primitives5.class));
+ assertEquals(OBJECT_HEADER_SIZE, serializationMetadata.start);
+ assertEquals(12, serializationMetadata.length);
+ }
+
+ @Test
+ public void primitives6Metadata() {
+ unsafeClassHeaderSize64BitCompressedOops(new Primitives6());
+
+ SerializationMetadata serializationMetadata = extractMetadata(Introspect.fields(Primitives6.class));
+ assertEquals(OBJECT_HEADER_SIZE, serializationMetadata.start);
+ assertEquals(28, serializationMetadata.length);
+ }
+
+ private void unsafeClassHeaderSize64BitCompressedOops(Object instance) {
+ if (System.getProperty("useUnsafeClassHeaders") != null) {
+ long narrowKlassPointer = UNSAFE.getInt(instance, NATIVE_WORD_SIZE) & UNSIGNED_INT_MASK;
+ long wideKlassPointer = narrowKlassPointer << 3;
+ long sizeField = wideKlassPointer + 3 * UNSAFE.addressSize();
+
+ System.out.println(String.format("Size of %s is %s",
+ instance.getClass().getName(),
+ UNSAFE.getAddress(sizeField) & UNSIGNED_INT_MASK));
+ }
+ }
+}
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..609d020
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/IntrospectTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+import static net.openhft.lang.io.serialization.direct.TestClasses.*;
+import static org.junit.Assert.assertEquals;
+
+public class IntrospectTest {
+
+ @Test
+ public void returnsFieldsRegardlessOfVisibility() {
+ List<Field> fields = asFieldList(InstanceOnlyNoStaticFields.class);
+
+ assertEquals(3, fields.size());
+ }
+
+ @Test
+ public void returnsStaticAsWellAsInstanceFields() {
+ List<Field> fields = asFieldList(HasInstanceAndStaticFields.class);
+
+ assertEquals(6, fields.size());
+ }
+
+ @Test
+ public void walksClassHierarchyForAllFields() {
+ List<Field> fields = asFieldList(LevelTwoDerivedClass.class);
+
+ assertEquals(6, fields.size());
+ }
+
+ private static List<Field> asFieldList(Class<?> clazz) {
+ return new ArrayList<Field>(Introspect.fields(clazz));
+ }
+}
+
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..7c7efc9
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/ObjectMarshallerTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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.ByteBufferBytes;
+import net.openhft.lang.io.Bytes;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+
+import static net.openhft.lang.io.serialization.direct.TestClasses.*;
+import static org.junit.Assert.*;
+
+public class ObjectMarshallerTest {
+
+ @Test
+ public void marshalAndUnmarshalPrimitives1() {
+ Primitives1 p = new Primitives1();
+ p.a = 55;
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<Primitives1> marshaller = ObjectMarshallers.forClass(Primitives1.class);
+ marshaller.write(b, p);
+
+ p.a = 0;
+ b.clear();
+ marshaller.read(b, p);
+
+ assertEquals(55, p.a);
+
+ b.clear();
+
+ Primitives1 newP = new Primitives1();
+ marshaller.read(b, newP);
+
+ assertEquals(55, newP.a);
+ }
+
+ @Test
+ public void marshalAndUnmarshalPrimitives2() {
+ Primitives2 p = new Primitives2();
+ p.a = 55;
+ p.b = -10;
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<Primitives2> marshaller = ObjectMarshallers.forClass(Primitives2.class);
+ marshaller.write(b, p);
+
+ p.a = 0;
+ p.b = 0;
+ b.clear();
+ marshaller.read(b, p);
+
+ assertEquals(55, p.a);
+ assertEquals(-10, p.b);
+
+ b.clear();
+
+ Primitives2 newP = new Primitives2();
+ marshaller.read(b, newP);
+
+ assertEquals(55, newP.a);
+ assertEquals(-10, newP.b);
+ }
+
+ @Test
+ public void marshalAndUnmarshalPrimitives3() {
+ Primitives3 p = new Primitives3();
+ p.a = 55;
+ p.b = -10;
+ p.c = 92;
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<Primitives3> marshaller = ObjectMarshallers.forClass(Primitives3.class);
+ marshaller.write(b, p);
+
+ p.a = 0;
+ p.b = 0;
+ p.c = 0;
+ b.clear();
+ marshaller.read(b, p);
+
+ assertEquals(55, p.a);
+ assertEquals(-10, p.b);
+ assertEquals(92, p.c);
+
+ b.clear();
+
+ Primitives3 newP = new Primitives3();
+ marshaller.read(b, newP);
+
+ assertEquals(55, newP.a);
+ assertEquals(-10, newP.b);
+ assertEquals(92, newP.c);
+ }
+
+ @Test
+ public void marshalAndUnmarshalPrimitives4() {
+ Primitives4 p = new Primitives4();
+ p.a = true;
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<Primitives4> marshaller = ObjectMarshallers.forClass(Primitives4.class);
+ marshaller.write(b, p);
+
+ p.a = false;
+ b.clear();
+ marshaller.read(b, p);
+
+ assertTrue(p.a);
+
+ b.clear();
+
+ Primitives4 newP = new Primitives4();
+ marshaller.read(b, newP);
+
+ assertTrue(newP.a);
+ }
+
+ @Test
+ public void marshalAndUnmarshalPrimitives5() {
+ Primitives5 p = new Primitives5();
+ p.a = true;
+ p.b = Long.MIN_VALUE;
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<Primitives5> marshaller = ObjectMarshallers.forClass(Primitives5.class);
+ marshaller.write(b, p);
+
+ p.a = false;
+ p.b = 0;
+ b.clear();
+ marshaller.read(b, p);
+
+ assertTrue(p.a);
+ assertEquals(Long.MIN_VALUE, p.b);
+
+ b.clear();
+
+ Primitives5 newP = new Primitives5();
+ marshaller.read(b, newP);
+
+ assertTrue(newP.a);
+ assertEquals(Long.MIN_VALUE, newP.b);
+ }
+
+ @Test
+ public void marshalAndUnmarshalPrimitives6() {
+ Primitives6 p = new Primitives6();
+ p.a = true;
+ p.b = Integer.MAX_VALUE;
+ p.c = Short.MAX_VALUE;
+ p.d = Long.MAX_VALUE;
+ p.e = Double.MAX_VALUE;
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<Primitives6> marshaller = ObjectMarshallers.forClass(Primitives6.class);
+ marshaller.write(b, p);
+
+ p.a = false;
+ p.b = 0;
+ p.c = 0;
+ p.d = 0;
+ p.e = 0;
+ b.clear();
+ marshaller.read(b, p);
+
+ assertTrue(p.a);
+ assertEquals(Integer.MAX_VALUE, p.b);
+ assertEquals(Short.MAX_VALUE, p.c);
+ assertEquals(Long.MAX_VALUE, p.d);
+ assertEquals(Double.MAX_VALUE, p.e, 0);
+
+ b.clear();
+
+ Primitives6 newP = new Primitives6();
+ marshaller.read(b, newP);
+
+ assertTrue(newP.a);
+ assertEquals(Integer.MAX_VALUE, p.b);
+ assertEquals(Short.MAX_VALUE, p.c);
+ assertEquals(Long.MAX_VALUE, p.d);
+ assertEquals(Double.MAX_VALUE, p.e, 0);
+ }
+
+ @Test
+ public void marshalAndUnmarshalMixedClass() {
+ MixedFields m = new MixedFields();
+ m.intField = Integer.MIN_VALUE + 1;
+ m.byteField = Byte.MAX_VALUE - 1;
+ m.shortField = Short.MIN_VALUE + 1;
+ m.longField = Long.MAX_VALUE - 1;
+
+ m.doubleArray = new double[]{-50.0, 50.0};
+ m.stringList = Collections.singletonList("Foo");
+ m.objectArray = new Object[]{new Primitives1()};
+ m.transientShort = 12;
+ m.transientObject = new Primitives2();
+
+ Bytes b = createByteStore();
+ ObjectMarshaller<MixedFields> marshaller = ObjectMarshallers.forClass(MixedFields.class);
+ marshaller.write(b, m);
+
+ m.intField = 0;
+ m.byteField = 0;
+ m.shortField = 0;
+ m.longField = 0;
+ m.doubleArray = null;
+ m.stringList = null;
+ m.objectArray = null;
+ m.transientShort = 0;
+ m.transientObject = null;
+
+ b.clear();
+ marshaller.read(b, m);
+
+ assertEquals(Integer.MIN_VALUE + 1, m.intField);
+ assertEquals(0, m.byteField); // because of jvm field rearrangement the two shorts are packed into 4 bytes and this eligible field is skipped
+ assertEquals(Short.MIN_VALUE + 1, m.shortField);
+ assertEquals(Long.MAX_VALUE - 1, m.longField);
+ assertNull(m.doubleArray);
+ assertNull(m.stringList);
+ assertNull(m.objectArray);
+ assertNull(m.transientObject);
+ assertEquals(0, m.transientShort);
+
+ b.clear();
+
+ MixedFields newM = new MixedFields();
+ marshaller.read(b, newM);
+
+ assertEquals(Integer.MIN_VALUE + 1, newM.intField);
+ assertEquals(0, newM.byteField);
+ assertEquals(Short.MIN_VALUE + 1, newM.shortField);
+ assertEquals(Long.MAX_VALUE - 1, newM.longField);
+ assertNull(newM.doubleArray);
+ assertNull(newM.stringList);
+ assertNull(newM.objectArray);
+ assertNull(newM.transientObject);
+ assertEquals(0, newM.transientShort);
+ }
+
+ private Bytes createByteStore() {
+ return ByteBufferBytes.wrap(ByteBuffer.allocate(64));
+ }
+} \ No newline at end of file
diff --git a/lang-sandbox/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
new file mode 100644
index 0000000..420c2f2
--- /dev/null
+++ b/lang-sandbox/src/test/java/net/openhft/lang/io/serialization/direct/TestClasses.java
@@ -0,0 +1,109 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+class TestClasses {
+
+ public static class InstanceOnlyNoStaticFields {
+ public int intField;
+ protected String stringField;
+ private Object objectField;
+ }
+
+ public static class HasInstanceAndStaticFields {
+ public static int staticIntField;
+ protected static String staticStringField;
+ private static Object staticObjectField;
+
+ public int intField;
+ protected String stringField;
+ private Object objectField;
+ }
+
+ public static class BaseClass {
+ private static double staticBaseDoubleField;
+
+ protected List<String> baseListField;
+ }
+
+ public static class LevelOneDerivedClass extends BaseClass {
+ protected static Object staticLevelOneObjectField;
+
+ public long levelOneLongField;
+ }
+
+ public static class LevelTwoDerivedClass extends LevelOneDerivedClass {
+ public static String staticLevelTwoStringField;
+
+ final int levelTwoDerivedIntField = 0;
+ }
+
+ public static class MixedFields {
+ public static int staticIntField;
+ public static double[] staticDoubleArray;
+
+ public static List<String> staticStringList = Collections.singletonList("S1");
+ public static Object[] staticObjectArray = {new Object()};
+
+ public int intField;
+ public byte byteField;
+ public short shortField;
+ public long longField;
+ public double[] doubleArray;
+
+ public List<String> stringList;
+ public Object[] objectArray;
+
+ transient short transientShort;
+ public transient Object transientObject;
+ }
+
+ public static class Primitives1 {
+ public int a;
+ }
+
+ public static class Primitives2 {
+ public int a, b;
+ }
+
+ public static class Primitives3 {
+ public int a, b;
+ public short c;
+ }
+
+ public static class Primitives4 {
+ public boolean a;
+ }
+
+ public static class Primitives5 {
+ public boolean a;
+ public long b;
+ }
+
+ public static class Primitives6 {
+ public boolean a;
+ public int b;
+ public short c;
+ public long d;
+ public double e;
+ }
+}