package org.ObjectLayout.examples;/*
* Written by Gil Tene, and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
*/
import org.ObjectLayout.*;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;
import static java.lang.Long.valueOf;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class PointArrayTest {
@Test
public void shouldConstructArrayOfGivenDirectLengths() throws NoSuchMethodException {
final long[] lengths = {7L, 8L, 9L};
@SuppressWarnings("unchecked")
final StructuredArray<StructuredArray<PointArray>> array =
new StructuredArrayBuilder(
StructuredArray.class,
new StructuredArrayBuilder(
StructuredArray.class,
new StructuredArrayBuilder<PointArray, Point>(
PointArray.class,
Point.class,
lengths[2]
),
lengths[1]
),
lengths[0]
).build();
Assert.assertThat(valueOf(array.getLength()), CoreMatchers.is(lengths[0]));
Assert.assertThat(valueOf(array.get(0).getLength()), CoreMatchers.is(lengths[1]));
Assert.assertThat(valueOf(array.get(0).get(0).getLength()), CoreMatchers.is(lengths[2]));
Assert.assertTrue(array.getElementClass().isAssignableFrom(StructuredArray.class));
Assert.assertTrue(array.get(0).getElementClass().isAssignableFrom(PointArray.class));
Assert.assertTrue(array.get(0).get(0).getElementClass() == Point.class);
}
@Test
public void shouldConstructArrayOfGivenLengthWithNewInstance() throws NoSuchMethodException {
long length = 9L;
PointArray array = PointArray.newInstance(length);
Assert.assertThat(valueOf(array.getLength()), CoreMatchers.is(valueOf(length)));
Assert.assertTrue(array.getElementClass() == Point.class);
}
@Test
public void shouldConstructArrayOfGivenLengthWithBuilder() throws NoSuchMethodException {
long length = 9L;
PointArray array =
new StructuredArrayBuilder<PointArray, Point>(
PointArray.class,
Point.class,
length
).build();
Assert.assertThat(valueOf(array.getLength()), CoreMatchers.is(valueOf(length)));
Assert.assertTrue(array.getElementClass() == Point.class);
}
@Test
public void shouldConstructArrayOfGivenLengthAndInitValues() throws NoSuchMethodException {
final long initialX = 4;
final long initialY = 777;
long length = 9L;
final PointArray array =
PointArray.newInstance(length, initialX, initialY);
assertCorrectFixedInitialisation(initialX, initialY, new long[] {length}, array);
}
@Test
public void shouldConstructArrayElementsViaConstantCtorAndArgsProvider() throws NoSuchMethodException {
final Class[] initArgTypes = {long.class, long.class};
final long initialX = 4;
final long initialY = 777;
long length = 9L;
final CtorAndArgs<Point> ctorAndArgs =
new CtorAndArgs<Point>(Point.class, initArgTypes, initialX, initialY);
final CtorAndArgsProvider<Point> ctorAndArgsProvider =
new CtorAndArgsProvider<Point>() {
@Override
public CtorAndArgs<Point> getForContext(
ConstructionContext<Point> context) throws NoSuchMethodException {
return ctorAndArgs;
}
};
final PointArray array =
PointArray.newInstance(
PointArray.class, Point.class, length, ctorAndArgsProvider);
assertCorrectFixedInitialisation(initialX, initialY, new long[] {length}, array);
}
@Test
public void shouldConstructArrayElementsViaCtorAndArgsProvider() throws NoSuchMethodException {
final long[] lengths = {9};
final PointCtorAndArgsProvider ctorAndArgsProvider = new PointCtorAndArgsProvider();
final PointArray array =
PointArray.newInstance(lengths[0], ctorAndArgsProvider);
assertCorrectVariableInitialisation(lengths, array);
}
@SuppressWarnings("unchecked")
@Test
public void shouldConstructArrayElementsViaCtorAndArgsProvider3D() throws NoSuchMethodException {
final long[] lengths = {7, 8, 9};
final PointCtorAndArgsProvider ctorAndArgsProvider = new PointCtorAndArgsProvider();
final StructuredArrayBuilder<StructuredArray<StructuredArray<PointArray>>,
StructuredArray<PointArray>> builder = get3dBuilder(lengths);
builder.getStructuredSubArrayBuilder().
getStructuredSubArrayBuilder().
elementCtorAndArgsProvider(ctorAndArgsProvider);
final StructuredArray<StructuredArray<PointArray>> array = builder.build();
assertCorrectVariableInitialisation(lengths, array);
}
@Test
public void shouldSetAndGetCorrectValueAtGivenIndex() throws NoSuchMethodException {
final long[] lengths = {11, 10, 3};
final StructuredArray<StructuredArray<PointArray>> array = get3dBuilder(lengths).build();
initValues(lengths, array);
assertCorrectVariableInitialisation(lengths, array);
}
@Test
public void shouldIterateOverArray() throws NoSuchMethodException {
final long[] lengths = {11};
final PointArray array =
PointArray.newInstance(lengths[0]);
initValues(lengths, array);
PointArray.ElementIterator iter = array.iterator();
long sum = 0;
long elementCount = 0;
while (iter.hasNext()) {
final long index = iter.getCursor();
final Point point = iter.next();
Assert.assertThat(valueOf(point.getX()), CoreMatchers.is(valueOf(index)));
Assert.assertThat(valueOf(point.getY()), CoreMatchers.is(valueOf(index * 2)));
sum += index;
elementCount++;
}
long sum2 = 0;
long elementCount2 = 0;
for (final Point point : array) {
sum2 += point.getX();
elementCount2++;
}
Assert.assertThat(valueOf(elementCount), CoreMatchers.is(valueOf(array.getLength())));
Assert.assertThat(valueOf(sum), CoreMatchers.is(valueOf(sum2)));
Assert.assertThat(valueOf(elementCount), CoreMatchers.is(valueOf(elementCount2)));
}
@Test
public void shouldIterateOverArrayAndResetAgain() throws NoSuchMethodException {
final long length = 11;
final PointArray array =
PointArray.newInstance(length);
initValues(new long[] {length}, array);
int i = 0;
final PointArray.ElementIterator iter = array.iterator();
while (iter.hasNext()) {
final long index = iter.getCursor();
final Point point = iter.next();
Assert.assertThat(valueOf(point.getX()), CoreMatchers.is(valueOf(index)));
Assert.assertThat(valueOf(point.getY()), CoreMatchers.is(valueOf(index * 2)));
i++;
}
iter.reset();
i = 0;
while (iter.hasNext()) {
final long index = iter.getCursor();
final Point point = iter.next();
Assert.assertThat(valueOf(point.getX()), CoreMatchers.is(valueOf(index)));
Assert.assertThat(valueOf(point.getY()), CoreMatchers.is(valueOf(index * 2)));
i++;
}
Assert.assertThat(valueOf(i), CoreMatchers.is(valueOf(length)));
}
@Test
public void shouldConstructCopyOfArray() throws NoSuchMethodException {
final long length = 15;
final PointCtorAndArgsProvider ctorAndArgsProvider = new PointCtorAndArgsProvider();
final PointArray sourceArray =
PointArray.newInstance(length, ctorAndArgsProvider);
Assert.assertThat(valueOf(sourceArray.getLength()), CoreMatchers.is(valueOf(length)));
Assert.assertTrue(sourceArray.getElementClass() == Point.class);
final PointArray newArray =
(PointArray) StructuredArray.copyInstance(sourceArray);
// We expect MockStructure elements to be initialized with index = index, and testValue = index * 2:
assertCorrectVariableInitialisation(new long[] {length}, newArray);
}
@SuppressWarnings("unchecked")
@Test
public void shouldConstructCopyOfArray3D() throws NoSuchMethodException {
final long[] lengths = {15, 7, 5};
final PointCtorAndArgsProvider ctorAndArgsProvider = new PointCtorAndArgsProvider();
final StructuredArrayBuilder<StructuredArray<StructuredArray<PointArray>>,
StructuredArray<PointArray>> builder = get3dBuilder(lengths);
builder.getStructuredSubArrayBuilder().
getStructuredSubArrayBuilder().
elementCtorAndArgsProvider(ctorAndArgsProvider);
final StructuredArray<StructuredArray<PointArray>> sourceArray = builder.build();
StructuredArray<PointArray> subArray1 = sourceArray.get(0);
PointArray subArray2 = subArray1.get(0);
Assert.assertThat(valueOf(sourceArray.getLength()), CoreMatchers.is(valueOf(lengths[0])));
Assert.assertThat(valueOf(subArray1.getLength()), CoreMatchers.is(valueOf(lengths[1])));
Assert.assertThat(valueOf(subArray2.getLength()), CoreMatchers.is(valueOf(lengths[2])));
Assert.assertTrue(subArray2.getElementClass() == Point.class);
final StructuredArray<StructuredArray<PointArray>> newArray =
StructuredArray.copyInstance(sourceArray);
// We expect MockStructure elements to be initialized with index = index, and testValue = index * 2:
assertCorrectVariableInitialisation(lengths, newArray);
}
@SuppressWarnings("unchecked")
@Test
public void shouldConstructCopyOfArrayRange() throws NoSuchMethodException {
final long[] lengths = {15, 7, 5};
final PointCtorAndArgsProvider ctorAndArgsProvider = new PointCtorAndArgsProvider();
final StructuredArrayBuilder<StructuredArray<StructuredArray<PointArray>>,
StructuredArray<PointArray>> builder = get3dBuilder(lengths);
builder.getStructuredSubArrayBuilder().
getStructuredSubArrayBuilder().
elementCtorAndArgsProvider(ctorAndArgsProvider);
final StructuredArray<StructuredArray<PointArray>> sourceArray = builder.build();
StructuredArray<PointArray> subArray1 = sourceArray.get(0);
PointArray subArray2 = subArray1.get(0);
Assert.assertThat(valueOf(sourceArray.getLength()), CoreMatchers.is(valueOf(lengths[0])));
Assert.assertThat(valueOf(subArray1.getLength()), CoreMatchers.is(valueOf(lengths[1])));
Assert.assertThat(valueOf(subArray2.getLength()), CoreMatchers.is(valueOf(lengths[2])));
Assert.assertTrue(subArray2.getElementClass() == Point.class);
long[] offsets = {2, 2, 2};
long[] counts = {13, 5, 3};
final StructuredArray<StructuredArray<PointArray>> newArray =
StructuredArray.copyInstance(sourceArray, offsets, counts);
assertCorrectVariableInitialisation(counts, newArray, 2);
}
@Test(expected = ArrayIndexOutOfBoundsException.class)
public void shouldThrowOutOfBoundExceptionForAccessesOutOfBounds() throws NoSuchMethodException {
final long length = 11;
final PointArray array =
PointArray.newInstance(length);
array.get(length);
}
@Test
public void shouldNotThrowIncompatibleTypeExceptionForGetsOfProperTypes() throws NoSuchMethodException {
final long[] lengths = {11, 7, 4};
final StructuredArray<StructuredArray<PointArray>> array = get3dBuilder(lengths).build();
// Step by step gets of the correct type (array vs. element) per dimension:
StructuredArray<PointArray> subArray1 = array.get(2);
PointArray subArray2 = subArray1.get(2);
subArray2.get(2);
}
@Test
public void shouldCopyRegionLeftInArray() throws NoSuchMethodException {
final long length = 11;
final PointArray array =
PointArray.newInstance(length);
initValues(new long[]{length}, array);
StructuredArray.shallowCopy(array, 4, array, 3, 2, false);
Assert.assertThat(valueOf(array.get(3).getX()), CoreMatchers.is(valueOf(4)));
Assert.assertThat(valueOf(array.get(4).getX()), CoreMatchers.is(valueOf(5)));
Assert.assertThat(valueOf(array.get(5).getX()), CoreMatchers.is(valueOf(5)));
}
@Test
public void shouldCopyRegionRightInArray() throws NoSuchMethodException {
final long length = 11;
final PointArray array =
PointArray.newInstance(length);
initValues(new long[]{length}, array);
StructuredArray.shallowCopy(array, 5, array, 6, 2, false);
Assert.assertThat(valueOf(array.get(5).getX()), CoreMatchers.is(valueOf(5)));
Assert.assertThat(valueOf(array.get(6).getX()), CoreMatchers.is(valueOf(5)));
Assert.assertThat(valueOf(array.get(7).getX()), CoreMatchers.is(valueOf(6)));
}
@Test(expected = IllegalArgumentException.class)
public void shouldFailToConstructDirectly() throws NoSuchMethodException {
final PointArray array = new PointArray();
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Test support below
///////////////////////////////////////////////////////////////////////////////////////////////
private void assertCorrectFixedInitialisation(final long expectedX, final long expectedY, final long[] lengths,
final StructuredArray array) {
StructuredArray a = array;
for (int i = 0; i < lengths.length - 1; i++) {
Assert.assertThat(valueOf(a.getLength()), CoreMatchers.is(valueOf(lengths[i])));
a = (StructuredArray) a.get(0);
}
PointArray ap = (PointArray) a;
Assert.assertThat(valueOf(ap.getLength()), CoreMatchers.is(valueOf(lengths[lengths.length - 1])));
Assert.assertTrue(ap.getElementClass() == Point.class);
long totalElementCount = 1;
for (long l : lengths) {
totalElementCount *= l;
}
final long[] cursors = new long[lengths.length];
long elementCountToCursor = 0;
while (elementCountToCursor < totalElementCount) {
// Check element at cursors:
a = array;
for (int i = 0; i < cursors.length - 1; i++) {
a = (StructuredArray) a.get(cursors[i]);
}
ap = (PointArray) a;
Point point = ap.get(cursors[cursors.length - 1]);
Assert.assertThat(valueOf(point.getX()), CoreMatchers.is(valueOf(expectedX)));
Assert.assertThat(valueOf(point.getY()), CoreMatchers.is(valueOf(expectedY)));
// Increment cursors from inner-most dimension out:
for (int cursorDimension = cursors.length - 1; cursorDimension >= 0; cursorDimension--) {
if ((++cursors[cursorDimension]) < lengths[cursorDimension]) {
break;
}
// This dimension wrapped. Reset to zero and continue to one dimension higher
cursors[cursorDimension] = 0;
}
elementCountToCursor++;
}
}
private void assertCorrectVariableInitialisation(final long[] lengths,
final StructuredArray array) {
assertCorrectVariableInitialisation(lengths, array, 0);
}
private void assertCorrectVariableInitialisation(final long[] lengths,
final StructuredArray array, long indexOffset) {
StructuredArray a = array;
for (int i = 0; i < lengths.length - 1; i++) {
Assert.assertThat(valueOf(a.getLength()), CoreMatchers.is(valueOf(lengths[i])));
a = (StructuredArray) a.get(0);
}
PointArray ap = (PointArray) a;
Assert.assertThat(valueOf(ap.getLength()), CoreMatchers.is(valueOf(lengths[lengths.length - 1])));
Assert.assertTrue(ap.getElementClass() == Point.class);
long totalElementCount = 1;
for (long l : lengths) {
totalElementCount *= l;
}
final long[] cursors = new long[lengths.length];
long elementCountToCursor = 0;
while (elementCountToCursor < totalElementCount) {
// Check element at cursors:
a = array;
for (int i = 0; i < cursors.length - 1; i++) {
a = (StructuredArray) a.get(cursors[i]);
}
ap = (PointArray) a;
Point point = ap.get(cursors[cursors.length - 1]);
long indexSum = 0;
String cursorsString = "";
for (long index : cursors) {
indexSum += index + indexOffset;
cursorsString += index + ",";
}
Assert.assertThat("elementCountToCursor: " + elementCountToCursor + " cursors: " + cursorsString,
valueOf(point.getX()), CoreMatchers.is(valueOf(indexSum)));
Assert.assertThat("elementCountToCursor: " + elementCountToCursor + " cursors: " + cursorsString,
valueOf(point.getY()), CoreMatchers.is(valueOf(indexSum * 2)));
// Increment cursors from inner-most dimension out:
for (int cursorDimension = cursors.length - 1; cursorDimension >= 0; cursorDimension--) {
if ((++cursors[cursorDimension]) < lengths[cursorDimension]) {
break;
}
// This dimension wrapped. Reset to zero and continue to one dimension higher
cursors[cursorDimension] = 0;
}
elementCountToCursor++;
}
}
private void initValues(final long[] lengths, final StructuredArray array) {
final long[] cursors = new long[lengths.length];
long totalElementCount = 1;
for (long l : lengths) {
totalElementCount *= l;
}
long elementCountToCursor = 0;
while (elementCountToCursor < totalElementCount) {
// Check element at cursors:
StructuredArray a = array;
for (int i = 0; i < cursors.length - 1; i++) {
a = (StructuredArray) a.get(cursors[i]);
}
PointArray ap = (PointArray) a;
Point point = ap.get(cursors[cursors.length - 1]);
long indexSum = 0;
for (long index : cursors) {
indexSum += index;
}
point.set(indexSum, indexSum * 2);
// Increment cursors from inner-most dimension out:
for (int cursorDimension = cursors.length - 1; cursorDimension >= 0; cursorDimension--) {
if ((++cursors[cursorDimension]) < lengths[cursorDimension]) {
break;
}
// This dimension wrapped. Reset to zero and continue to one dimension higher
cursors[cursorDimension] = 0;
}
elementCountToCursor++;
}
}
private static class PointCtorAndArgsProvider implements CtorAndArgsProvider<Point> {
private final Class[] argsTypes = {long.class, long.class};
@Override
public CtorAndArgs<Point> getForContext(ConstructionContext<Point> context) throws NoSuchMethodException {
long indexSum = 0;
for (ConstructionContext c = context; c != null; c = c.getContainingContext()) {
indexSum += c.getIndex();
}
Object[] args = {(int)indexSum, (int)(indexSum * 2)};
// We could do this much more efficiently with atomic caching of a single allocated CtorAndArgs,
// as CopyCtorAndArgsProvider does, but no need to put in the effort in a test...
return new CtorAndArgs<Point>(Point.class.getConstructor(argsTypes), args); }
}
StructuredArrayBuilder<StructuredArray<StructuredArray<PointArray>>,
StructuredArray<PointArray>> get3dBuilder(long... lengths) {
@SuppressWarnings("unchecked")
StructuredArrayBuilder<StructuredArray<StructuredArray<PointArray>>,
StructuredArray<PointArray>> builder =
new StructuredArrayBuilder(
StructuredArray.class,
new StructuredArrayBuilder(
StructuredArray.class,
new StructuredArrayBuilder<PointArray, Point>(
PointArray.class,
Point.class,
lengths[2]
),
lengths[1]
),
lengths[0]
);
return builder;
}
}