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 67eb12f..1077637 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 @@ -1,5 +1,6 @@ package it.cavallium.buffer; +import it.cavallium.data.generator.nativedata.Int52; import it.cavallium.stream.SafeByteArrayInputStream; import it.cavallium.stream.SafeByteArrayOutputStream; import it.cavallium.stream.SafeDataOutput; @@ -99,6 +100,49 @@ public interface Buf extends ByteList, RandomAccess { void writeTo(SafeDataOutput dataOutput); + /** + * @param i byte offset + */ + default float getFloat(int i) { + return Float.intBitsToFloat(getInt(i)); + } + + /** + * @param i byte offset + */ + default double getDouble(int i) { + return Double.longBitsToDouble(getLong(i)); + } + + /** + * @param i byte offset + */ + default char getChar(int i) { + byte b1 = getByte(i); + byte b2 = getByte(i + 1); + return (char) ((b1 & 0xFF) << 8 | (b2 & 0xFF)); + } + + /** + * @param i byte offset + */ + default short getShort(int i) { + byte b1 = getByte(i); + byte b2 = getByte(i + 1); + return (short) ((b1 & 0xFF) << 8 | (b2 & 0xFF)); + } + + /** + * @param i byte offset + */ + default int getInt(int i) { + byte b1 = getByte(i); + byte b2 = getByte(i + 1); + byte b3 = getByte(i + 2); + byte b4 = getByte(i + 3); + return b1 << 24 | (b2 & 0xFF) << 16 | (b3 & 0xFF) << 8 | (b4 & 0xFF); + } + /** * @param i byte offset */ @@ -124,26 +168,21 @@ public interface Buf extends ByteList, RandomAccess { /** * @param i byte offset */ - default int getInt(int i) { + default long getInt52(int i) { byte b1 = getByte(i); byte b2 = getByte(i + 1); byte b3 = getByte(i + 2); byte b4 = getByte(i + 3); - return b1 << 24 | (b2 & 0xFF) << 16 | (b3 & 0xFF) << 8 | (b4 & 0xFF); - } - - /** - * @param i byte offset - */ - default float getFloat(int i) { - return Float.intBitsToFloat(getInt(i)); - } - - /** - * @param i byte offset - */ - default double getDouble(int i) { - return Double.longBitsToDouble(getLong(i)); + byte b5 = getByte(i + 4); + byte b6 = getByte(i + 5); + byte b7 = getByte(i + 6); + return (b1 & 0xFFL) << 48 + | (b2 & 0xFFL) << 40 + | (b3 & 0xFFL) << 32 + | (b4 & 0xFFL) << 24 + | (b5 & 0xFFL) << 16 + | (b6 & 0xFFL) << 8 + | (b7 & 0xFFL); } /** @@ -153,6 +192,27 @@ public interface Buf extends ByteList, RandomAccess { return getByte(i) != 0; } + /** + * @param i byte offset + */ + default String getShortText(int i, Charset charset) { + var len = getShort(i); + return getString(i + Short.BYTES, len, charset); + } + + /** + * @param i byte offset + */ + default String getMediumText(int i, Charset charset) { + var len = getInt(i); + return getString(i + Integer.BYTES, len, charset); + } + + /** + * @param i byte offset + */ + String getString(int i, int length, Charset charset); + /** * @param i byte offset */ @@ -167,6 +227,22 @@ public interface Buf extends ByteList, RandomAccess { set(i, val); } + /** + * @param i byte offset + */ + default void setChar(int i, char val) { + set(i, (byte) (val >> 8)); + set(i + 1, (byte) val); + } + + /** + * @param i byte offset + */ + default void setShort(int i, short val) { + set(i, (byte) (val >> 8)); + set(i + 1, (byte) val); + } + /** * @param i byte offset */ @@ -191,6 +267,20 @@ public interface Buf extends ByteList, RandomAccess { set(i + 7, (byte) val); } + /** + * @param i byte offset + */ + default void setInt52(int i, long val) { + Int52.checkValidity(val); + set(i, (byte) (val >> 48)); + set(i + 1, (byte) (val >> 40)); + set(i + 2, (byte) (val >> 32)); + set(i + 3, (byte) (val >> 24)); + set(i + 4, (byte) (val >> 16)); + set(i + 5, (byte) (val >> 8)); + set(i + 6, (byte) val); + } + /** * @param i byte offset */ diff --git a/data-generator-runtime/src/main/java/it/cavallium/buffer/BufDataOutput.java b/data-generator-runtime/src/main/java/it/cavallium/buffer/BufDataOutput.java index f01e108..0bd62eb 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/buffer/BufDataOutput.java +++ b/data-generator-runtime/src/main/java/it/cavallium/buffer/BufDataOutput.java @@ -1,17 +1,17 @@ package it.cavallium.buffer; +import static java.util.Objects.checkFromToIndex; + import it.cavallium.stream.SafeByteArrayOutputStream; import it.cavallium.stream.SafeDataOutput; import it.cavallium.stream.SafeDataOutputStream; -import it.unimi.dsi.fastutil.Arrays; import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Objects; import org.jetbrains.annotations.NotNull; -import static java.util.Objects.checkFromToIndex; - public class BufDataOutput implements SafeDataOutput { private final SafeByteArrayOutputStream buf; @@ -62,6 +62,8 @@ public class BufDataOutput implements SafeDataOutput { } } + @IgnoreCoverage + @Deprecated(forRemoval = true) public static BufDataOutput wrap(Buf buf, int from, int to) { checkFromToIndex(from, to, buf.size()); if (buf.isEmpty()) { @@ -71,6 +73,8 @@ public class BufDataOutput implements SafeDataOutput { } } + @IgnoreCoverage + @Deprecated(forRemoval = true) public static BufDataOutput wrap(Buf buf) { if (buf.isEmpty()) { return createLimited(0); @@ -234,6 +238,11 @@ public class BufDataOutput implements SafeDataOutput { return Buf.wrap(this.buf.array, this.buf.length); } + public Buf toList() { + dOut.flush(); + return Buf.wrap(Arrays.copyOf(this.buf.array, this.buf.length)); + } + @Override public String toString() { return dOut.toString(); 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 07ff663..df949b8 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 @@ -1,21 +1,35 @@ package it.cavallium.buffer; -import static it.unimi.dsi.fastutil.Arrays.ensureFromTo; +import static java.util.Objects.checkFromIndexSize; import static java.util.Objects.checkFromToIndex; import it.cavallium.stream.SafeByteArrayInputStream; import it.cavallium.stream.SafeByteArrayOutputStream; import it.cavallium.stream.SafeDataOutput; -import it.unimi.dsi.fastutil.bytes.*; - +import it.unimi.dsi.fastutil.bytes.AbstractByteList; +import it.unimi.dsi.fastutil.bytes.ByteArrayList; +import it.unimi.dsi.fastutil.bytes.ByteArrays; +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.BytePredicate; +import it.unimi.dsi.fastutil.bytes.ByteSpliterator; +import it.unimi.dsi.fastutil.bytes.ByteSpliterators; +import it.unimi.dsi.fastutil.bytes.ByteUnaryOperator; import java.io.Serial; import java.nio.charset.Charset; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NoSuchElementException; import java.util.function.IntPredicate; import java.util.function.IntUnaryOperator; import java.util.function.Predicate; import java.util.function.UnaryOperator; - import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.VisibleForTesting; @@ -220,7 +234,12 @@ class ByteListBuf extends ByteArrayList implements Buf { @Override public String toString(Charset charset) { - return new String(a, 0, size, charset); + return getString(0, size, charset); + } + + @Override + public String getString(int i, int length, Charset charset) { + return new String(a, i, length, charset); } class SubList extends AbstractByteList.ByteRandomAccessSubList implements Buf { @@ -509,6 +528,12 @@ class ByteListBuf extends ByteArrayList implements Buf { public String toString(Charset charset) { return new String(a, from, size(), charset); } + + @Override + public String getString(int i, int length, Charset charset) { + checkFromIndexSize(i, length, to - from); + return new String(a, from + i, length, charset); + } } @IgnoreCoverage diff --git a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/ArrayStringSerializer.java b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/ArrayStringSerializer.java index 5b9dce1..7841f30 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/ArrayStringSerializer.java +++ b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/ArrayStringSerializer.java @@ -14,7 +14,7 @@ public class ArrayStringSerializer implements DataSerializer> { public void serialize(SafeDataOutput dataOutput, @NotNull List data) { dataOutput.writeInt(data.size()); for (String item : data) { - dataOutput.writeUTF(item); + dataOutput.writeShortText(item, StandardCharsets.UTF_8); } } diff --git a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/Int52.java b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/Int52.java index 2af94c1..4951e0f 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/Int52.java +++ b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/Int52.java @@ -1,7 +1,6 @@ package it.cavallium.data.generator.nativedata; import java.lang.annotation.Native; -import java.util.Objects; import org.jetbrains.annotations.NotNull; public class Int52 extends Number implements Comparable { @@ -23,6 +22,10 @@ public class Int52 extends Number implements Comparable { public static final Int52 ONE = new Int52(1L); public static final Int52 TWO = new Int52(2L); public static final Int52 TEN = new Int52(10L); + public static final long MAX_VALUE_L = 0x0F_FF_FF_FF_FF_FF_FFL; + public static final long MIN_VALUE_L = 0; + public static final Int52 MAX_VALUE = fromLongSafe(MAX_VALUE_L); + public static final Int52 MIN_VALUE = ZERO; private final long value; @@ -30,7 +33,18 @@ public class Int52 extends Number implements Comparable { this.value = value; } + public static void checkValidity(long value) { + if (value < 0 || value > MAX_VALUE_L) { + throw new IllegalArgumentException("Only positive values below or equal to " + MAX_VALUE_L + " are supported: " + value); + } + } + public static Int52 fromLong(long value) { + checkValidity(value); + return fromLongSafe(value); + } + + private static Int52 fromLongSafe(long value) { if (value == 0) { return ZERO; } else if (value == 1) { @@ -39,15 +53,33 @@ public class Int52 extends Number implements Comparable { return TWO; } else if (value == 10) { return TEN; - } else if (value <= 0) { - throw new IllegalArgumentException("Only positive values are supported"); - } else if (value > 0x0F_FF_FF_FF_FF_FF_FFL) { - throw new IllegalArgumentException("Only values below or equal to " + 0xFFFFFFFFFFFFFL + " are supported"); } else { return new Int52(value); } } + public static Int52 fromByteArray(byte[] bytes) { + return fromLongSafe(fromByteArrayL(bytes)); + } + + public static Int52 fromBytes(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7) { + return fromLongSafe(fromBytesL(b1, b2, b3, b4, b5, b6, b7)); + } + + public static long fromByteArrayL(byte[] bytes) { + return fromBytesL(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6]); + } + + public static long fromBytesL(byte b1, byte b2, byte b3, byte b4, byte b5, byte b6, byte b7) { + return (b1 & 0xFFL) << 48 + | (b2 & 0xFFL) << 40 + | (b3 & 0xFFL) << 32 + | (b4 & 0xFFL) << 24 + | (b5 & 0xFFL) << 16 + | (b6 & 0xFFL) << 8 + | (b7 & 0xFFL); + } + long getValue() { return value; } diff --git a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableStringSerializer.java b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableStringSerializer.java index e6cf45c..f690152 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableStringSerializer.java +++ b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableStringSerializer.java @@ -18,7 +18,7 @@ public class NullableStringSerializer implements DataSerializer } else { dataOutput.writeBoolean(true); String dataContent = data.get(); - dataOutput.writeUTF(dataContent); + dataOutput.writeShortText(dataContent, StandardCharsets.UTF_8); } } diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/NullOutputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/NullOutputStream.java new file mode 100644 index 0000000..7c6b6a5 --- /dev/null +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/NullOutputStream.java @@ -0,0 +1,36 @@ +package it.cavallium.stream; + +import it.cavallium.buffer.IgnoreCoverage; +import java.util.Objects; +import org.jetbrains.annotations.NotNull; + +class NullOutputStream extends SafeOutputStream { + + private volatile boolean closed; + + @IgnoreCoverage + private void ensureOpen() { + if (closed) { + throw new IllegalStateException("Stream closed"); + } + } + + @IgnoreCoverage + @Override + public void write(int b) { + ensureOpen(); + } + + @IgnoreCoverage + @Override + public void write(byte @NotNull [] b, int off, int len) { + Objects.checkFromIndexSize(off, len, b.length); + ensureOpen(); + } + + @IgnoreCoverage + @Override + public void close() { + closed = true; + } +} diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeByteArrayOutputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeByteArrayOutputStream.java index 803c4b3..2a87419 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeByteArrayOutputStream.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeByteArrayOutputStream.java @@ -16,15 +16,14 @@ package it.cavallium.stream; +import static java.util.Objects.checkFromToIndex; + import it.cavallium.buffer.IgnoreCoverage; import it.unimi.dsi.fastutil.bytes.ByteArrays; - import java.util.Arrays; import java.util.HexFormat; import java.util.Objects; -import static java.util.Objects.checkFromToIndex; - /** Simple, fast byte-array output stream that exposes the backing array. * *

{@link java.io.ByteArrayOutputStream} is nice, but to get its content you @@ -143,32 +142,19 @@ public class SafeByteArrayOutputStream extends SafeMeasurableOutputStream implem private void growBy(int len) { if (wrapped) { ensureWrappedBounds(arrayPosition, arrayPosition + len); - } - if (arrayPosition + len > array.length) { - if (wrapped) { - throw new ArrayIndexOutOfBoundsException(arrayPosition + len - 1); - } else { - array = ByteArrays.grow(array, arrayPosition + len, arrayPosition); - } + } else if (arrayPosition + len > array.length) { + array = ByteArrays.grow(array, arrayPosition + len, arrayPosition); } } @Override public void position(final long newPosition) { - if (wrapped) { - arrayPosition = (int) (newPosition + wrappedFrom); - } else { - arrayPosition = (int)newPosition; - } + arrayPosition = (int) (newPosition + wrappedFrom); } @Override public long position() { - if (wrapped) { - return arrayPosition - wrappedFrom; - } else { - return arrayPosition; - } + return arrayPosition - wrappedFrom; } @Override diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutput.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutput.java index d92dddb..2b648ac 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutput.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutput.java @@ -25,8 +25,6 @@ package it.cavallium.stream; -import org.jetbrains.annotations.NotNull; - import java.nio.charset.Charset; /** @@ -291,6 +289,7 @@ public interface SafeDataOutput { * * @param s the string of bytes to be written. */ + @Deprecated void writeBytes(String s); /** @@ -310,6 +309,7 @@ public interface SafeDataOutput { * * @param s the string value to be written. */ + @Deprecated void writeChars(String s); /** diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutputStream.java index b351b82..44952b8 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutputStream.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeDataOutputStream.java @@ -25,7 +25,7 @@ package it.cavallium.stream; -import java.io.DataOutputStream; +import it.cavallium.buffer.IgnoreCoverage; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -63,11 +63,7 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe * until it reaches Integer.MAX_VALUE. */ private void incCount(int value) { - int temp = written + value; - if (temp < 0) { - temp = Integer.MAX_VALUE; - } - written = temp; + written = Math.addExact(written, value); } /** @@ -113,6 +109,7 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe * @see SafeFilterOutputStream#out * @see java.io.OutputStream#flush() */ + @IgnoreCoverage public void flush() { out.flush(); } @@ -274,6 +271,8 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe * @param s a string of bytes to be written. * @see SafeFilterOutputStream#out */ + @Deprecated + @IgnoreCoverage public final void writeBytes(String s) { int len = s.length(); for (int i = 0 ; i < len ; i++) { @@ -293,6 +292,8 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe * @see SafeDataOutputStream#writeChar(int) * @see SafeFilterOutputStream#out */ + @Deprecated + @IgnoreCoverage public final void writeChars(String s) { int len = s.length(); for (int i = 0 ; i < len ; i++) { @@ -322,6 +323,7 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe * @param str a string to be written. * @see #writeChars(String) */ + @IgnoreCoverage @Deprecated public final void writeUTF(String str) { writeShortText(str, StandardCharsets.UTF_8); @@ -363,8 +365,4 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe public final int size() { return written; } - - public DataOutputStream asDataOutputStream() { - return new DataOutputStream(this.out); - } } diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeFilterOutputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeFilterOutputStream.java index 737cb75..593d658 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeFilterOutputStream.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeFilterOutputStream.java @@ -1,6 +1,9 @@ package it.cavallium.stream; +import it.cavallium.buffer.IgnoreCoverage; +import org.jetbrains.annotations.NotNull; + /** * This class is the superclass of all classes that filter output * streams. These streams sit on top of an already existing output @@ -21,17 +24,7 @@ public class SafeFilterOutputStream extends SafeOutputStream { /** * The underlying output stream to be filtered. */ - protected SafeOutputStream out; - - /** - * Whether the stream is closed; implicitly initialized to false. - */ - private volatile boolean closed; - - /** - * Object used to prevent a race on the 'closed' instance variable. - */ - private final Object closeLock = new Object(); + protected final SafeOutputStream out; /** * Creates an output stream filter built on top of the specified @@ -58,6 +51,7 @@ public class SafeFilterOutputStream extends SafeOutputStream { * @param b the {@code byte}. */ @Override + @IgnoreCoverage public void write(int b) { out.write(b); } @@ -77,9 +71,10 @@ public class SafeFilterOutputStream extends SafeOutputStream { * @param b the data to be written. * @see SafeFilterOutputStream#write(byte[], int, int) */ + @IgnoreCoverage @Override - public void write(byte b[]) { - write(b, 0, b.length); + public void write(byte @NotNull [] b) { + out.write(b); } /** @@ -101,14 +96,10 @@ public class SafeFilterOutputStream extends SafeOutputStream { * @param len the number of bytes to write. * @see SafeFilterOutputStream#write(int) */ + @IgnoreCoverage @Override - public void write(byte b[], int off, int len) { - if ((off | len | (b.length - (len + off)) | (off + len)) < 0) - throw new IndexOutOfBoundsException(); - - for (int i = 0 ; i < len ; i++) { - write(b[off + i]); - } + public void write(byte[] b, int off, int len) { + out.write(b, off, len); } /** @@ -120,6 +111,7 @@ public class SafeFilterOutputStream extends SafeOutputStream { * * @see SafeFilterOutputStream#out */ + @IgnoreCoverage @Override public void flush() { out.flush(); @@ -136,45 +128,9 @@ public class SafeFilterOutputStream extends SafeOutputStream { * @see SafeFilterOutputStream#flush() * @see SafeFilterOutputStream#out */ + @IgnoreCoverage @Override public void close() { - if (closed) { - return; - } - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - - Throwable flushException = null; - try { - flush(); - } catch (Throwable e) { - flushException = e; - throw e; - } finally { - if (flushException == null) { - out.close(); - } else { - try { - out.close(); - } catch (Throwable closeException) { - // evaluate possible precedence of flushException over closeException - if ((flushException instanceof ThreadDeath) && - !(closeException instanceof ThreadDeath)) { - flushException.addSuppressed(closeException); - throw (ThreadDeath) flushException; - } - - if (flushException != closeException) { - closeException.addSuppressed(flushException); - } - - throw closeException; - } - } - } + out.close(); } } diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeInputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeInputStream.java index e802d97..26245c1 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeInputStream.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeInputStream.java @@ -52,6 +52,7 @@ public abstract class SafeInputStream extends InputStream { return i; } + @IgnoreCoverage public byte[] readAllBytes() { return readNBytes(Integer.MAX_VALUE); } @@ -121,6 +122,7 @@ public abstract class SafeInputStream extends InputStream { return result; } + @IgnoreCoverage public int readNBytes(byte[] b, int off, int len) { Objects.checkFromIndexSize(off, len, b.length); @@ -134,10 +136,12 @@ public abstract class SafeInputStream extends InputStream { return n; } + @IgnoreCoverage public String readString(int length, Charset charset) { return new String(readNBytes(length), charset); } + @IgnoreCoverage public long skip(long n) { long remaining = n; int nr; @@ -159,6 +163,7 @@ public abstract class SafeInputStream extends InputStream { return n - remaining; } + @IgnoreCoverage public void skipNBytes(long n) { if (n > 0) { long ns = skip(n); @@ -193,6 +198,7 @@ public abstract class SafeInputStream extends InputStream { throw new UnsupportedOperationException("mark/reset not supported"); } + @IgnoreCoverage public long transferTo(OutputStream out) { Objects.requireNonNull(out, "out"); long transferred = 0; diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeMeasurableInputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeMeasurableInputStream.java index a64d3c4..c0acaa2 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeMeasurableInputStream.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeMeasurableInputStream.java @@ -17,12 +17,13 @@ package it.cavallium.stream; */ +import it.cavallium.buffer.IgnoreCoverage; import java.io.InputStream; /** An {@link InputStream} that implements also the {@link SafeMeasurableStream} interface. * * @since 5.0.4 */ - +@IgnoreCoverage public abstract class SafeMeasurableInputStream extends SafeInputStream implements SafeMeasurableStream { } diff --git a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeOutputStream.java b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeOutputStream.java index b03fd6b..8243673 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/stream/SafeOutputStream.java +++ b/data-generator-runtime/src/main/java/it/cavallium/stream/SafeOutputStream.java @@ -1,5 +1,6 @@ package it.cavallium.stream; +import it.cavallium.buffer.IgnoreCoverage; import java.io.Closeable; import java.io.Flushable; import java.io.OutputStream; @@ -47,32 +48,8 @@ public abstract class SafeOutputStream extends OutputStream implements Closeable * * @since 11 */ - public static OutputStream nullOutputStream() { - return new OutputStream() { - private volatile boolean closed; - - private void ensureOpen() { - if (closed) { - throw new IllegalStateException("Stream closed"); - } - } - - @Override - public void write(int b) { - ensureOpen(); - } - - @Override - public void write(byte @NotNull [] b, int off, int len) { - Objects.checkFromIndexSize(off, len, b.length); - ensureOpen(); - } - - @Override - public void close() { - closed = true; - } - }; + public static SafeOutputStream nullOutputStream() { + return new NullOutputStream(); } /** @@ -127,6 +104,7 @@ public abstract class SafeOutputStream extends OutputStream implements Closeable * @param off the start offset in the data. * @param len the number of bytes to write. */ + @IgnoreCoverage public void write(byte[] b, int off, int len) { Objects.checkFromIndexSize(off, len, b.length); // len == 0 condition implicitly handled by loop bounds @@ -152,6 +130,7 @@ public abstract class SafeOutputStream extends OutputStream implements Closeable * The {@code flush} method of {@code OutputStream} does nothing. * */ + @IgnoreCoverage public void flush() { } @@ -166,4 +145,5 @@ public abstract class SafeOutputStream extends OutputStream implements Closeable */ public void close() { } + } 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 index dabf0dd..bbc4867 100644 --- a/data-generator-runtime/src/test/java/it/cavallium/buffer/TestBuffer.java +++ b/data-generator-runtime/src/test/java/it/cavallium/buffer/TestBuffer.java @@ -1,20 +1,31 @@ package it.cavallium.buffer; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import com.google.common.primitives.Chars; import com.google.common.primitives.Longs; +import com.google.common.primitives.Shorts; +import it.cavallium.data.generator.nativedata.Int52; import it.cavallium.stream.SafeByteArrayInputStream; import it.cavallium.stream.SafeByteArrayOutputStream; import it.cavallium.stream.SafeDataOutputStream; -import it.unimi.dsi.fastutil.bytes.*; - +import it.unimi.dsi.fastutil.bytes.ByteArrayList; +import it.unimi.dsi.fastutil.bytes.ByteCollections; +import it.unimi.dsi.fastutil.bytes.ByteList; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.List; +import java.util.Spliterators; import java.util.concurrent.atomic.LongAdder; import java.util.stream.Stream; import java.util.stream.StreamSupport; - import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -109,12 +120,14 @@ public class TestBuffer { var wrapSmallByteArrayListCappedRangeOffsetAndLen = new BufArg("wrap(small byte array list, 5, same-3)", Buf.wrap(ByteArrayList.of(small.clone()), 5, small.length - 3), small.length - 5 - 3, Arrays.copyOfRange(small, 5, small.length - 3)); var wrapSmallByteListCappedRangeOffsetAndLen = new BufArg("wrap(small byte list, 5, same-3)", Buf.wrap(ByteList.of(small.clone()), 5, small.length - 3), small.length - 5 - 3, Arrays.copyOfRange(small, 5, small.length - 3)); - return List.of(emptyBuf, byteListBuf, byteListBufOf, def0Buf, def10Buf, def10000Buf, zeroedBuf, zeroed10Buf, zeroed10000Buf, copyOfEmpty, - copyOfSmall, copyOfBig, wrapByteArrayList, wrapBufSmall, wrapSmallArray, wrapBigArray, wrapSmallByteList, wrapBigByteList, - wrapSmallCapped, wrapBigCapped, wrapSmallCappedSame, wrapBigCappedSame, wrapSmallCappedMinusOne, - wrapBigCappedMinusOne, wrapSmallCappedRangeSame, wrapBigCappedRangeSame, wrapSmallCappedRangeOffset, - wrapBigCappedRangeOffset, wrapSmallCappedRangeOffsetAndLen, wrapBigCappedRangeOffsetAndLen, - wrapSmallCappedRangeLen, wrapBigCappedRangeLen, wrapSmallByteArrayListCappedRangeOffsetAndLen, wrapSmallByteListCappedRangeOffsetAndLen); + return List.of(emptyBuf, byteListBuf, byteListBufOf, def0Buf, def10Buf, def10000Buf, zeroedBuf, zeroed10Buf, + zeroed10000Buf, copyOfEmpty, copyOfSmall, copyOfBig, wrapByteArrayList, wrapBufSmall, wrapSmallArray, + wrapBigArray, wrapSmallByteList, wrapBigByteList, wrapSmallCapped, wrapBigCapped, wrapSmallCappedSame, + wrapBigCappedSame, wrapSmallCappedMinusOne, wrapBigCappedMinusOne, wrapSmallCappedRangeSame, + wrapBigCappedRangeSame, wrapSmallCappedRangeOffset, wrapBigCappedRangeOffset, + wrapSmallCappedRangeOffsetAndLen, wrapBigCappedRangeOffsetAndLen, wrapSmallCappedRangeLen, + wrapBigCappedRangeLen, wrapSmallBufCappedRangeOffsetAndLen, wrapSmallByteArrayListCappedRangeOffsetAndLen, + wrapSmallByteListCappedRangeOffsetAndLen); } public static List createSubListBufs() { @@ -275,6 +288,46 @@ public class TestBuffer { return provideBufs().filter(ba -> ba.initialSize >= Long.BYTES * 2); } + @ParameterizedTest + @MethodSource + public void testShorts(BufArg bufArg) { + var short1 = bufArg.b.getShort(0); + assertEquals(Shorts.fromByteArray(bufArg.initialContent), short1); + var short2 = bufArg.b.getShort(Short.BYTES); + assertEquals(Shorts.fromByteArray(Arrays.copyOfRange(bufArg.initialContent, Short.BYTES, Short.BYTES * 2)), short2); + + var expected1 = (short) (short1 + 1); + bufArg.b.setShort(0, expected1); + var expected2 = (short) (short2 + 1); + bufArg.b.setShort(Short.BYTES, expected2); + assertEquals(expected1, bufArg.b.getShort(0)); + assertEquals(expected2, bufArg.b.getShort(Short.BYTES)); + } + + public static Stream testShorts() { + return provideBufs().filter(ba -> ba.initialSize >= Short.BYTES * 2); + } + + @ParameterizedTest + @MethodSource + public void testChars(BufArg bufArg) { + var char1 = bufArg.b.getChar(0); + assertEquals(Chars.fromByteArray(bufArg.initialContent), char1); + var char2 = bufArg.b.getChar(Character.BYTES); + assertEquals(Chars.fromByteArray(Arrays.copyOfRange(bufArg.initialContent, Character.BYTES, Character.BYTES * 2)), char2); + + var expected1 = (char) (char1 + 1); + bufArg.b.setChar(0, expected1); + var expected2 = (char) (char2 + 1); + bufArg.b.setChar(Character.BYTES, expected2); + assertEquals(expected1, bufArg.b.getChar(0)); + assertEquals(expected2, bufArg.b.getChar(Character.BYTES)); + } + + public static Stream testChars() { + return provideBufs().filter(ba -> ba.initialSize >= Character.BYTES * 2); + } + @ParameterizedTest @MethodSource public void testInts(BufArg bufArg) { @@ -383,6 +436,26 @@ public class TestBuffer { return provideBufs().filter(ba -> ba.initialSize >= 2); } + @ParameterizedTest + @MethodSource + public void testInt52s(BufArg bufArg) { + var int521 = bufArg.b.getInt52(0); + assertEquals(Int52.fromByteArrayL(bufArg.initialContent), int521); + var int522 = bufArg.b.getInt52(Int52.BYTES); + assertEquals(Int52.fromByteArrayL(Arrays.copyOf(Arrays.copyOfRange(bufArg.initialContent, Int52.BYTES, Int52.BYTES * 2), Long.BYTES)), int522); + + var expected1 = (int521 * 3) % Int52.MAX_VALUE_L; + bufArg.b.setInt52(0, expected1); + var expected2 = (int522 * 3) % Int52.MAX_VALUE_L; + bufArg.b.setInt52(Int52.BYTES, expected2); + assertEquals(expected1, bufArg.b.getInt52(0)); + assertEquals(expected2, bufArg.b.getInt52(Int52.BYTES)); + } + + public static Stream testInt52s() { + return provideBufs().filter(ba -> ba.initialSize >= Int52.BYTES * 2); + } + @ParameterizedTest @MethodSource("provideBufs") public void testString(BufArg bufArg) { diff --git a/data-generator-runtime/src/test/java/it/cavallium/stream/TestOutput.java b/data-generator-runtime/src/test/java/it/cavallium/stream/TestOutput.java index 40fe281..6676cd2 100644 --- a/data-generator-runtime/src/test/java/it/cavallium/stream/TestOutput.java +++ b/data-generator-runtime/src/test/java/it/cavallium/stream/TestOutput.java @@ -1,44 +1,74 @@ package it.cavallium.stream; -import it.cavallium.buffer.Buf; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import it.cavallium.buffer.Buf; +import it.cavallium.buffer.BufDataOutput; +import it.cavallium.data.generator.nativedata.Int52; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; public class TestOutput { @Test public void testBufOutputStream() throws IOException { - var buf = Buf.createZeroes(Integer.BYTES * 3); + var buf = Buf.createZeroes(Integer.BYTES * 3 + Short.BYTES + Character.BYTES + 4); var subMiddleBuf = buf.subList(Integer.BYTES, Integer.BYTES * 2); buf.setInt(0, 0); buf.setInt(Integer.BYTES, 5); buf.setInt(Integer.BYTES * 2, 4); - var subBuf = buf.subList(Integer.BYTES, Integer.BYTES * 3); + var subBuf = buf.subList(Integer.BYTES, Integer.BYTES * 3 + Short.BYTES + Character.BYTES + 4); var subBufOut = subBuf.binaryOutputStream(); var subBufOutData = new SafeDataOutputStream(subBufOut); + assertEquals(0, subBufOutData.size()); subBufOutData.writeInt(9); subBufOut.position(0); subBufOutData.writeInt(1); subBufOutData.writeInt(2); + subBufOutData.writeShort(1); + subBufOutData.writeChar(1); + subBufOutData.write(new byte[] {1, 2}); + subBufOutData.write(new byte[] {0, 0, 3, 4, 0, 0}, 2, 2); + assertEquals(Integer.BYTES, Integer.BYTES * 3 + Short.BYTES + Character.BYTES + 4, subBufOutData.size()); + assertDoesNotThrow(subBufOutData::toString); + assertDoesNotThrow(subBufOut::toString); + assertThrows(Exception.class, () -> subBufOutData.writeByte(1)); + assertThrows(Exception.class, () -> subBufOut.ensureWritable(1)); var i0 = buf.getInt(0); var i1 = buf.getInt(Integer.BYTES); var i2 = buf.getInt(Integer.BYTES * 2); + var s1 = (buf.getByte(Integer.BYTES * 3) << 8) | buf.getByte(Integer.BYTES * 3 + 1); + var c1 = (buf.getByte(Integer.BYTES * 3 + Short.BYTES) << 8) | buf.getByte(Integer.BYTES * 3 + Short.BYTES + 1); + var b1 = buf.getByte(Integer.BYTES * 3 + Short.BYTES + Character.BYTES); + var b2 = buf.getByte(Integer.BYTES * 3 + Short.BYTES + Character.BYTES + 1); + var b3 = buf.getByte(Integer.BYTES * 3 + Short.BYTES + Character.BYTES + 2); + var b4 = buf.getByte(Integer.BYTES * 3 + Short.BYTES + Character.BYTES + 3); assertEquals(List.of(0, 1, 2), List.of(i0, i1, i2)); + assertEquals(1, s1); + assertEquals(1, c1); + assertEquals(List.of(1, 2, 3, 4), List.of((int) b1, (int) b2, (int) b3, (int) b4)); { var baos = new ByteArrayOutputStream(); var dos = new DataOutputStream(baos); dos.writeInt(1); dos.writeInt(2); + dos.writeShort(1); + dos.writeChar(1); + dos.writeByte(1); + dos.writeByte(2); + dos.writeByte(3); + dos.writeByte(4); assertArrayEquals(baos.toByteArray(), subBufOut.toByteArray()); } { @@ -47,6 +77,12 @@ public class TestOutput { dos.writeInt(0); dos.writeInt(1); dos.writeInt(2); + dos.writeShort(1); + dos.writeChar(1); + dos.writeByte(1); + dos.writeByte(2); + dos.writeByte(3); + dos.writeByte(4); assertArrayEquals(baos.toByteArray(), buf.toByteArray()); } { @@ -55,6 +91,104 @@ public class TestOutput { dos.writeInt(1); assertArrayEquals(baos.toByteArray(), subMiddleBuf.toByteArray()); } + { + var b = Buf.createZeroes(Long.BYTES * 4); + var os = b.binaryOutputStream(); + var ds = new SafeDataOutputStream(os); + ds.writeBoolean(true); + assertTrue(b.getBoolean(0)); + os.reset(); + + ds.writeByte(Byte.MAX_VALUE - 1); + assertEquals(Byte.MAX_VALUE - 1, b.getByte(0)); + os.reset(); + + ds.writeShort(Short.MAX_VALUE - 1); + assertEquals(Short.MAX_VALUE - 1, b.getShort(0)); + os.reset(); + + ds.writeChar(Character.MAX_VALUE - 1); + assertEquals(Character.MAX_VALUE - 1, b.getChar(0)); + os.reset(); + + ds.writeInt(Integer.MAX_VALUE - 1); + assertEquals(Integer.MAX_VALUE - 1, b.getInt(0)); + os.reset(); + + ds.writeLong(Long.MAX_VALUE - 1); + assertEquals(Long.MAX_VALUE - 1, b.getLong(0)); + os.reset(); + + ds.writeInt52(Int52.MAX_VALUE_L - 1); + assertEquals(Int52.MAX_VALUE_L - 1, b.getInt52(0)); + os.reset(); + + ds.writeFloat(Float.MAX_VALUE - 1); + assertEquals(Float.MAX_VALUE - 1, b.getFloat(0)); + os.reset(); + + ds.writeDouble(Double.MAX_VALUE - 1); + assertEquals(Double.MAX_VALUE - 1, b.getDouble(0)); + os.reset(); + + ds.write(10); + ds.write(10); + ds.writeShortText("Ciao", StandardCharsets.UTF_8); + assertEquals("Ciao", b.getShortText(2, StandardCharsets.UTF_8)); + assertEquals("Ciao", b.subList(1, b.size()).getShortText(1, StandardCharsets.UTF_8)); + assertThrows(Exception.class, () -> ds.writeShortText("1".repeat(Short.MAX_VALUE + 1), StandardCharsets.UTF_8)); + os.reset(); + + ds.write(10); + ds.write(10); + ds.writeMediumText("Ciao", StandardCharsets.UTF_8); + assertEquals("Ciao", b.getMediumText(2, StandardCharsets.UTF_8)); + assertEquals("Ciao", b.subList(1, b.size()).getMediumText(1, StandardCharsets.UTF_8)); + os.reset(); + } + } + + @Test + public void testWrappedBufDataOutput() throws IOException { + var sz = Long.BYTES * 4; + BufDataOutput bdo; + Buf buf; + { + bdo = BufDataOutput.createLimited(sz); + bdo.writeBoolean(true); + buf = bdo.asList(); + assertTrue(buf.getBoolean(0)); + } + { + bdo = BufDataOutput.createLimited(sz); + bdo.writeByte(Byte.MAX_VALUE - 1); + buf = bdo.asList(); + assertEquals(Byte.MAX_VALUE - 1, buf.getByte(0)); + } + { + bdo = BufDataOutput.createLimited(sz); + bdo.writeShort(Short.MAX_VALUE - 1); + buf = bdo.asList(); + assertEquals(Short.MAX_VALUE - 1, buf.getShort(0)); + } + { + bdo = BufDataOutput.createLimited(sz); + bdo.writeChar(Character.MAX_VALUE - 1); + buf = bdo.asList(); + assertEquals(Character.MAX_VALUE - 1, buf.getChar(0)); + } + { + bdo = BufDataOutput.createLimited(sz); + bdo.writeInt(Integer.MAX_VALUE - 1); + buf = bdo.asList(); + assertEquals(Integer.MAX_VALUE - 1, buf.getInt(0)); + } + { + bdo = BufDataOutput.createLimited(sz); + bdo.writeLong(Long.MAX_VALUE - 1); + buf = bdo.asList(); + assertEquals(Long.MAX_VALUE - 1, buf.getLong(0)); + } } @ParameterizedTest @@ -64,12 +198,15 @@ public class TestOutput { baos.write(0); baos.write(0); baos.write(0); - assertArrayEquals(new byte[3], baos.toByteArray()); + var x = new byte[] {1, 2, 3, 4}; + baos.write(x); + baos.write(x, 1, 2); + assertArrayEquals(new byte[] {0, 0, 0, 1, 2, 3, 4, 2, 3}, baos.toByteArray()); } @ParameterizedTest @MethodSource("provideByteArrayOutputStreams") - public void testTrim(SafeByteArrayOutputStream baos) { + public void testTrimAndGrow(SafeByteArrayOutputStream baos) { baos.trim(); assertEquals(0, baos.array.length); baos.write(10); @@ -81,6 +218,21 @@ public class TestOutput { assertArrayEquals(new byte[] {10, 0, 0}, baos.array); } + @ParameterizedTest + @MethodSource("provideByteArrayOutputStreams") + public void testReset(SafeByteArrayOutputStream baos) { + baos.trim(); + baos.write(10); + baos.write(10); + assertEquals(2, baos.position()); + assertEquals(2, baos.length()); + assertEquals(2, baos.array.length); + baos.reset(); + assertEquals(0, baos.position()); + assertEquals(0, baos.length()); + assertEquals(2, baos.array.length); + } + public static Stream provideByteArrayOutputStreams() { return Stream.of(new SafeByteArrayOutputStream(), new SafeByteArrayOutputStream(10), @@ -89,4 +241,12 @@ public class TestOutput { new SafeByteArrayOutputStream() ); } + + @Test + public void testNOS() { + try (var nos = SafeDataOutputStream.nullOutputStream()) { + nos.write(0); + nos.flush(); + } + } }