diff --git a/data-generator-runtime/pom.xml b/data-generator-runtime/pom.xml
index e236e0d..2221bd8 100644
--- a/data-generator-runtime/pom.xml
+++ b/data-generator-runtime/pom.xml
@@ -143,7 +143,7 @@
org.jetbrains
annotations
-
+
it.unimi.dsi
fastutil
@@ -159,6 +159,11 @@
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
@@ -175,7 +180,7 @@
org.junit.jupiter
junit-jupiter-api
- 5.9.0
+ 5.9.2
org.hamcrest
@@ -183,6 +188,11 @@
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.9.2
+
\ No newline at end of file
diff --git a/data-generator-runtime/src/main/java/it/cavallium/buffer/Buf.java b/data-generator-runtime/src/main/java/it/cavallium/buffer/Buf.java
index dc56e3c..5403272 100644
--- a/data-generator-runtime/src/main/java/it/cavallium/buffer/Buf.java
+++ b/data-generator-runtime/src/main/java/it/cavallium/buffer/Buf.java
@@ -72,7 +72,7 @@ public interface Buf extends ByteList, RandomAccess {
* Get this element as an array with equal or bigger size, converting it if needed
* The returned array may be bigger than expected!
*/
- byte @Nullable[] asUnboundedArray();
+ byte[] asUnboundedArray();
/**
* Get this element as an array with equal or bigger size, only if it's already an array, otherwise return null
@@ -82,11 +82,13 @@ public interface Buf extends ByteList, RandomAccess {
boolean isMutable();
- void freeze();
+ Buf freeze();
@Override
Buf subList(int from, int to);
+ Buf copyOfRange(int from, int to);
+
Buf copy();
SafeByteArrayInputStream binaryInputStream();
diff --git a/data-generator-runtime/src/main/java/it/cavallium/buffer/ByteListBuf.java b/data-generator-runtime/src/main/java/it/cavallium/buffer/ByteListBuf.java
index 954b2bd..912cd93 100644
--- a/data-generator-runtime/src/main/java/it/cavallium/buffer/ByteListBuf.java
+++ b/data-generator-runtime/src/main/java/it/cavallium/buffer/ByteListBuf.java
@@ -3,16 +3,8 @@ package it.cavallium.buffer;
import it.cavallium.stream.SafeByteArrayInputStream;
import it.cavallium.stream.SafeByteArrayOutputStream;
import it.cavallium.stream.SafeDataOutput;
-import it.unimi.dsi.fastutil.bytes.AbstractByteList;
-import it.unimi.dsi.fastutil.bytes.ByteArrayList;
-import it.unimi.dsi.fastutil.bytes.ByteCollection;
-import it.unimi.dsi.fastutil.bytes.ByteConsumer;
-import it.unimi.dsi.fastutil.bytes.ByteIterator;
-import it.unimi.dsi.fastutil.bytes.ByteIterators;
-import it.unimi.dsi.fastutil.bytes.ByteList;
-import it.unimi.dsi.fastutil.bytes.ByteListIterator;
-import it.unimi.dsi.fastutil.bytes.ByteSpliterator;
-import it.unimi.dsi.fastutil.bytes.ByteSpliterators;
+import it.unimi.dsi.fastutil.bytes.*;
+
import java.io.Serial;
import java.nio.charset.Charset;
import java.util.Arrays;
@@ -22,6 +14,8 @@ import java.util.NoSuchElementException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static it.unimi.dsi.fastutil.Arrays.ensureFromTo;
+
class ByteListBuf extends ByteArrayList implements Buf {
private boolean mutable = true;
@@ -77,7 +71,7 @@ class ByteListBuf extends ByteArrayList implements Buf {
* @return a new array list of the given size, wrapping the given array.
*/
public static ByteListBuf wrap(final byte[] a, final int length) {
- if (length > a.length) throw new IllegalArgumentException("The specified length (" + length + ") is greater than the array size (" + a.length + ")");
+ ByteArrays.ensureFromTo(a, 0, length);
final ByteListBuf l = new ByteListBuf(a, true);
l.size = length;
return l;
@@ -137,7 +131,7 @@ class ByteListBuf extends ByteArrayList implements Buf {
}
@Override
- public byte @Nullable [] asUnboundedArray() {
+ public byte[] asUnboundedArray() {
return a;
}
@@ -152,24 +146,30 @@ class ByteListBuf extends ByteArrayList implements Buf {
}
@Override
- public void freeze() {
+ public ByteListBuf freeze() {
mutable = false;
+ return this;
}
@Override
public Buf subList(int from, int to) {
if (from == 0 && to == size()) return this;
- ensureIndex(from);
- ensureIndex(to);
- if (from > to) throw new IndexOutOfBoundsException("Start index (" + from + ") is greater than end index (" + to + ")");
+ ensureFromTo(this.size(), from, to);
return new SubList(from, to);
}
+ @Override
+ public Buf copyOfRange(int from, int to) {
+ if (from == 0 && to == size()) {
+ return copy();
+ } else {
+ return ByteListBuf.wrap(Arrays.copyOfRange(this.a, from, to), to - from);
+ }
+ }
+
@Override
public Buf copy() {
- var copied = ByteListBuf.wrap(this.a.clone());
- copied.size = this.size;
- return copied;
+ return ByteListBuf.wrap(this.a.clone(), this.size);
}
@Override
@@ -184,7 +184,7 @@ class ByteListBuf extends ByteArrayList implements Buf {
@Override
public SafeByteArrayOutputStream binaryOutputStream(int from, int to) {
- it.unimi.dsi.fastutil.Arrays.ensureFromTo(size, from, to);
+ ensureFromTo(size, from, to);
return new SafeByteArrayOutputStream(a, from, to);
}
@@ -207,12 +207,10 @@ class ByteListBuf extends ByteArrayList implements Buf {
return new String(a, 0, size, charset);
}
- private class SubList extends AbstractByteList.ByteRandomAccessSubList implements Buf {
+ class SubList extends AbstractByteList.ByteRandomAccessSubList implements Buf {
@Serial
private static final long serialVersionUID = -3185226345314976296L;
- private boolean subMutable = true;
-
protected SubList(int from, int to) {
super(ByteListBuf.this, from, to);
}
@@ -226,11 +224,21 @@ class ByteListBuf extends ByteArrayList implements Buf {
@Override
public @NotNull Buf subList(int from, int to) {
- it.unimi.dsi.fastutil.Arrays.ensureFromTo(a.length, from, to);
- if (from > to) throw new IllegalArgumentException("Start index (" + from + ") is greater than end index (" + to + ")");
+ ensureFromTo(this.to, from, to);
+ var fromAbs = this.from + from;
+ var toAbs = this.from + to;
// Sadly we have to rewrap this, because if there is a sublist of a sublist, and the
// subsublist adds, both sublists need to update their "to" value.
- return new SubList(from, to);
+ return new SubList(fromAbs, toAbs);
+ }
+
+ @Override
+ public Buf copyOfRange(int from, int to) {
+ if (from == 0 && to == size()) {
+ return copy();
+ } else {
+ return Buf.wrap(Arrays.copyOfRange(a, this.from + from, this.from + to));
+ }
}
@Override
@@ -250,7 +258,7 @@ class ByteListBuf extends ByteArrayList implements Buf {
@Override
public SafeByteArrayOutputStream binaryOutputStream(int from, int to) {
- it.unimi.dsi.fastutil.Arrays.ensureFromTo(size(), from, to);
+ ensureFromTo(size(), from, to);
return new SafeByteArrayOutputStream(a, from + this.from, to + this.from);
}
@@ -279,7 +287,7 @@ class ByteListBuf extends ByteArrayList implements Buf {
if (this.from == 0 && this.to == a.length) {
return a;
} else {
- return toByteArray();
+ return SubList.this.toByteArray();
}
}
@@ -293,7 +301,7 @@ class ByteListBuf extends ByteArrayList implements Buf {
}
@Override
- public byte @Nullable [] asUnboundedArray() {
+ public byte[] asUnboundedArray() {
if (from == 0) {
return a;
} else {
@@ -312,12 +320,13 @@ class ByteListBuf extends ByteArrayList implements Buf {
@Override
public boolean isMutable() {
- return mutable && subMutable;
+ return mutable;
}
@Override
- public void freeze() {
- subMutable = false;
+ public SubList freeze() {
+ mutable = false;
+ return this;
}
private final class SubListIterator extends ByteIterators.AbstractIndexBasedListIterator {
diff --git a/data-generator-runtime/src/test/java/it/cavallium/buffer/TestBuffer.java b/data-generator-runtime/src/test/java/it/cavallium/buffer/TestBuffer.java
new file mode 100644
index 0000000..6133781
--- /dev/null
+++ b/data-generator-runtime/src/test/java/it/cavallium/buffer/TestBuffer.java
@@ -0,0 +1,241 @@
+package it.cavallium.buffer;
+
+import it.unimi.dsi.fastutil.bytes.ByteList;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.HexFormat;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class TestBuffer {
+
+ private record BufArg(String name, Buf b, int initialSize, byte[] initialContent) {
+ private static final HexFormat HEX = HexFormat.of();
+
+ @Override
+ public String toString() {
+ var bs = toStringArrayb(b.toByteArray());
+ var ic = toStringArrayb(initialContent);
+ return "BufArg{" +
+ "name='" + name + '\'' +
+ ", b=" + bs +
+ ", initialSize=" + initialSize +
+ ", initialContent=" + ic +
+ '}';
+ }
+
+ private String toStringArraya(byte[] byteArray) {
+ var bs = Arrays.toString(Arrays.copyOf(byteArray, 24));
+ if (byteArray.length > 24) {
+ bs = bs.substring(0, bs.length() - 1) + ", ...]";
+ }
+ return bs;
+ }
+
+ private String toStringArrayb(byte[] byteArray) {
+ var out = HEX.formatHex(byteArray, 0, Math.min(byteArray.length, 24));
+ if (byteArray.length > 24) {
+ out += "...";
+ }
+ return out;
+ }
+
+ public BufArg subList(int from, int to) {
+ return new BufArg(name + ".subList(" + from + "," + to + ")", b.subList(from, to), to - from, Arrays.copyOfRange(initialContent, from, to));
+ }
+
+ public BufArg copyOfRange(int from, int to) {
+ return new BufArg(name + ".copyOfRange(" + from + "," + to + ")", b.copyOfRange(from, to), to - from, Arrays.copyOfRange(initialContent, from, to));
+ }
+ }
+
+ static Stream provideBufs() {
+ List primaryBufs = createPrimaryBufs();
+ List subListBufs = createSubListBufs();
+ return Stream.concat(primaryBufs.stream(), subListBufs.stream());
+ }
+
+ private static List createPrimaryBufs() {
+ var emptyBuf = new BufArg("create()", Buf.create(), 0, new byte[0]);
+ var def0Buf = new BufArg("create(0)", Buf.create(0), 0, new byte[0]);
+ var def10Buf = new BufArg("create(10)", Buf.create(10), 0, new byte[0]);
+ var def10000Buf = new BufArg("create(10000)", Buf.create(10000), 0, new byte[0]);
+ var zeroedBuf = new BufArg("createZeroes(0)", Buf.createZeroes(0), 0, new byte[0]);
+ var zeroed10Buf = new BufArg("createZeroes(10)", Buf.createZeroes(10), 10, new byte[10]);
+ var zeroed10000Buf = new BufArg("createZeroes(10000)", Buf.createZeroes(10000), 10000, new byte[10000]);
+ var copyOfEmpty = new BufArg("copyOf(empty)", Buf.copyOf(new byte[0]), 0, new byte[0]);
+ var small = new byte[] {126, 19, 118, 33, -24, -65, 56, 17, 0, 90};
+ var copyOfSmall = new BufArg("copyOfSmall(small)", Buf.copyOf(small), small.length, small);
+ var big = new byte[10000];
+ for (int i = 0; i < big.length; i++) {
+ big[i] = (byte) (i * i);
+ }
+ var copyOfBig = new BufArg("copyOfBig(big)", Buf.copyOf(big), big.length, big);
+ var wrapSmallArray = new BufArg("wrap(small array)", Buf.wrap(small.clone()), small.length, small);
+ var wrapBigArray = new BufArg("wrap(big array)", Buf.wrap(big.clone()), big.length, big);
+ var wrapSmallByteList = new BufArg("wrap(small byte list)", Buf.wrap(ByteList.of(small)), small.length, small);
+ var wrapBigByteList = new BufArg("wrap(big byte list)", Buf.wrap(ByteList.of(big)), big.length, big);
+ var wrapSmallCapped = new BufArg("wrap(small array, 10)", Buf.wrap(small.clone(), 10), 10, Arrays.copyOf(small, 10));
+ var wrapBigCapped = new BufArg("wrap(big array, 10)", Buf.wrap(big.clone(), 10), 10, Arrays.copyOf(big, 10));
+ var wrapSmallCappedSame = new BufArg("wrap(small array, same)", Buf.wrap(small.clone(), small.length), small.length, small);
+ var wrapBigCappedSame = new BufArg("wrap(big array, same)", Buf.wrap(big.clone(), big.length), big.length, big);
+ var wrapSmallCappedMinusOne = new BufArg("wrap(small array, same-1)", Buf.wrap(small.clone(), small.length - 1), small.length - 1, Arrays.copyOf(small, small.length - 1));
+ var wrapBigCappedMinusOne = new BufArg("wrap(big array, same-1)", Buf.wrap(big.clone(), big.length - 1), big.length - 1, Arrays.copyOf(big, big.length - 1));
+ var wrapSmallCappedRangeSame = new BufArg("wrap(small array, 0, same)", Buf.wrap(small.clone(), 0, small.length), small.length, small);
+ var wrapBigCappedRangeSame = new BufArg("wrap(big array, 0, same)", Buf.wrap(big.clone(), 0, big.length), big.length, big);
+ var wrapSmallCappedRangeOffset = new BufArg("wrap(small array, 5, same)", Buf.wrap(small.clone(), 5, small.length), small.length - 5, Arrays.copyOfRange(small, 5, small.length));
+ var wrapBigCappedRangeOffset = new BufArg("wrap(big array, 500, same)", Buf.wrap(big.clone(), 500, big.length), big.length - 500, Arrays.copyOfRange(big, 500, big.length));
+ var wrapSmallCappedRangeOffsetAndLen = new BufArg("wrap(small array, 5, same-3)", Buf.wrap(small.clone(), 5, small.length - 3), small.length - 5 - 3, Arrays.copyOfRange(small, 5, small.length - 3));
+ var wrapBigCappedRangeOffsetAndLen = new BufArg("wrap(big array, 500, same-100)", Buf.wrap(big.clone(), 500, big.length - 100), big.length - 500 - 100, Arrays.copyOfRange(big, 500, big.length - 100));
+ var wrapSmallCappedRangeLen = new BufArg("wrap(small array, 0, same-5)", Buf.wrap(small.clone(), 0, small.length - 5), small.length - 5, Arrays.copyOf(small, small.length - 5));
+ var wrapBigCappedRangeLen = new BufArg("wrap(big array, 0, same-500)", Buf.wrap(big.clone(), 0, big.length - 500), big.length - 500, Arrays.copyOf(big, big.length - 500));
+
+ return List.of(emptyBuf, def0Buf, def10Buf, def10000Buf, zeroedBuf, zeroed10Buf, zeroed10000Buf, copyOfEmpty,
+ copyOfSmall, copyOfBig, wrapSmallArray, wrapBigArray, wrapSmallByteList, wrapBigByteList,
+ wrapSmallCapped, wrapBigCapped, wrapSmallCappedSame, wrapBigCappedSame, wrapSmallCappedMinusOne,
+ wrapBigCappedMinusOne, wrapSmallCappedRangeSame, wrapBigCappedRangeSame, wrapSmallCappedRangeOffset,
+ wrapBigCappedRangeOffset, wrapSmallCappedRangeOffsetAndLen, wrapBigCappedRangeOffsetAndLen,
+ wrapSmallCappedRangeLen, wrapBigCappedRangeLen);
+ }
+
+ private static List createSubListBufs() {
+ var sameSizeArgs = createPrimaryBufs().stream().filter(b -> b.initialSize > 0).map(bufArg -> new BufArg(bufArg.name + ".subList(0, same)", bufArg.b.subList(0, bufArg.initialSize), bufArg.initialSize, bufArg.initialContent)).toList();
+ var firstHalfArgs = createPrimaryBufs().stream().filter(b -> b.initialSize > 0).map(bufArg -> new BufArg(bufArg.name + ".subList(0, half)", bufArg.b.subList(0, bufArg.initialSize/2), bufArg.initialSize/2, Arrays.copyOfRange(bufArg.initialContent, 0, bufArg.initialSize/2))).toList();
+ var lastHalfArgs = createPrimaryBufs().stream().filter(b -> b.initialSize > 0).map(bufArg -> new BufArg(bufArg.name + ".subList(half, same)", bufArg.b.subList(bufArg.initialSize/2, bufArg.initialSize), bufArg.initialSize - bufArg.initialSize/2, Arrays.copyOfRange(bufArg.initialContent, bufArg.initialSize/2, bufArg.initialSize))).toList();
+ return Stream.concat(Stream.concat(sameSizeArgs.stream(), firstHalfArgs.stream()), lastHalfArgs.stream()).toList();
+ }
+
+ @Test
+ public void testCreate() {
+ var buf = Buf.create();
+ assertEquals(0, buf.size());
+ assertTrue(buf.isMutable());
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBufs")
+ public void testInitialValidity(BufArg bufArg) {
+ assertEquals(bufArg.initialSize, bufArg.b.size());
+ assertEquals(bufArg.initialSize, bufArg.initialContent.length);
+ assertEquals(bufArg.initialSize == 0, bufArg.b.isEmpty());
+ assertTrue(bufArg.b.isMutable());
+ if (bufArg.b instanceof ByteListBuf.SubList subList) {
+ assertArrayEquals(bufArg.initialContent, subList.toByteArray());
+ } else if (bufArg.b instanceof ByteListBuf bytes) {
+ assertArrayEquals(bufArg.initialContent, bytes.toByteArray());
+ } else {
+ assertArrayEquals(bufArg.initialContent, bufArg.b.toByteArray());
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBufs")
+ public void testGet(BufArg bufArg) {
+ assertThrows(Exception.class, () -> bufArg.b.getByte(-1));
+ assertThrows(Exception.class, () -> bufArg.b.getByte(bufArg.initialContent.length));
+ if (bufArg.initialSize > 0) {
+ // Test first
+ var expected = bufArg.initialContent[0];
+ var bi = bufArg.b.getByte(0);
+ assertEquals(expected, bi, "The first element does not match");
+
+ // Test last
+ var expectedLast = bufArg.initialContent[bufArg.initialSize - 1];
+ var biLast = bufArg.b.getByte(bufArg.initialSize - 1);
+ assertEquals(expectedLast, biLast, "The last element does not match");
+ }
+
+ // Test the other
+ for (int i = 1; i < bufArg.initialContent.length - 1; i++) {
+ var expected = bufArg.initialContent[i];
+ var bi = bufArg.b.getByte(i);
+ assertEquals(expected, bi, "The element index " + i + " does not match");
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBufs")
+ public void testPut(BufArg bufArg) {
+ bufArg.b.copy().isMutable();
+ bufArg.b.size(10);
+ bufArg.b.size();
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBufs")
+ public void testFreeze(BufArg bufArg) {
+ var buf = bufArg.b;
+ assertTrue(buf.isMutable());
+ Buf subList1 = null;
+ Buf subList2 = null;
+ if (bufArg.initialSize >= 3) {
+ subList1 = buf.subList(0, 2);
+ subList2 = subList1.subList(0, 1);
+ }
+ buf.freeze();
+ assertFalse(buf.isMutable());
+ if (subList1 != null) {
+ Buf subList3 = buf.subList(0, 2);
+ Buf subList4 = subList3.subList(0, 1);
+ assertFalse(subList1.isMutable());
+ assertFalse(subList2.isMutable());
+ assertFalse(subList3.isMutable());
+ assertFalse(subList4.isMutable());
+ }
+ buf.freeze();
+ assertFalse(buf.isMutable());
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideBufs")
+ public void testAsArray(BufArg bufArg) {
+ assertArrayEquals(bufArg.initialContent, bufArg.b.asArray());
+ assertArrayEquals(bufArg.initialContent, bufArg.b.toByteArray());
+ assertArrayEquals(bufArg.initialContent, Arrays.copyOf(bufArg.b.asUnboundedArray(), bufArg.initialSize));
+ var strictArray = bufArg.b.asArrayStrict();
+ if (strictArray != null) {
+ assertArrayEquals(bufArg.initialContent, strictArray);
+ }
+ var strictUnboundedArray = bufArg.b.asUnboundedArrayStrict();
+ if (strictUnboundedArray != null) {
+ assertArrayEquals(bufArg.initialContent, Arrays.copyOf(strictUnboundedArray, bufArg.initialSize));
+ }
+ }
+
+ @ParameterizedTest
+ @MethodSource("generateWrapped")
+ public void testWrapSubList(BufArg bufArg) {
+ testInitialValidity(bufArg);
+ testAsArray(bufArg.subList(0, 5));
+ testAsArray(bufArg.subList(0, 2));
+ testAsArray(bufArg.subList(3, 5));
+ testAsArray(bufArg.subList(3, 4));
+ testAsArray(bufArg.subList(3, 3));
+ }
+
+ @ParameterizedTest
+ @MethodSource("generateWrapped")
+ public void testWrapCopyOfRange(BufArg bufArg) {
+ testInitialValidity(bufArg);
+ testAsArray(bufArg.copyOfRange(0, 5));
+ testAsArray(bufArg.copyOfRange(0, 2));
+ testAsArray(bufArg.copyOfRange(3, 5));
+ testAsArray(bufArg.copyOfRange(3, 4));
+ testAsArray(bufArg.copyOfRange(3, 3));
+ }
+
+ public static Stream generateWrapped() {
+ byte[] source = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ return Stream.of(
+ new BufArg("0-len", Buf.wrap(source), source.length, source),
+ new BufArg("2-len", Buf.wrap(source, 2, source.length), source.length - 2, Arrays.copyOfRange(source, 2, source.length)),
+ new BufArg("2-9", Buf.wrap(source, 2, 9), 9 - 2, Arrays.copyOfRange(source, 2, 9)),
+ new BufArg("0-9", Buf.wrap(source, 0, 9), 9, Arrays.copyOfRange(source, 0, 9))
+ );
+ }
+}