data-generator/data-generator-runtime/src/main/java/it/cavallium/buffer/ByteListBuf.java

477 lines
11 KiB
Java

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.*;
import java.io.Serial;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
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;
protected ByteListBuf(byte[] a, boolean wrapped) {
super(a, wrapped);
}
public ByteListBuf(int capacity) {
super(capacity);
}
public ByteListBuf() {
}
public ByteListBuf(Collection<? extends Byte> c) {
super(c);
}
public ByteListBuf(ByteCollection c) {
super(c);
}
public ByteListBuf(ByteList l) {
super(l);
}
public ByteListBuf(byte[] a) {
super(a);
}
public ByteListBuf(byte[] a, int offset, int length) {
super(a, offset, length);
}
public ByteListBuf(Iterator<? extends Byte> i) {
super(i);
}
public ByteListBuf(ByteIterator i) {
super(i);
}
/**
* Wraps a given array into an array list of given size.
*
* <p>
* Note it is guaranteed that the type of the array returned by {@link #elements()} will be the same
* (see the comments in the class documentation).
*
* @param a an array to wrap.
* @param length the length of the resulting array list.
* @return a new array list of the given size, wrapping the given array.
*/
public static ByteListBuf wrap(final byte[] a, final int length) {
ByteArrays.ensureFromTo(a, 0, length);
final ByteListBuf l = new ByteListBuf(a, true);
l.size = length;
return l;
}
/**
* Wraps a given array into an array list.
*
* <p>
* Note it is guaranteed that the type of the array returned by {@link #elements()} will be the same
* (see the comments in the class documentation).
*
* @param a an array to wrap.
* @return a new array list wrapping the given array.
*/
public static ByteListBuf wrap(final byte[] a) {
return wrap(a, a.length);
}
/**
* Creates a new empty array list.
*
* @return a new empty array list.
*/
public static ByteListBuf of() {
return new ByteListBuf();
}
/**
* Creates an array list using an array of elements.
*
* @param init a the array the will become the new backing array of the array list.
* @return a new array list backed by the given array.
* @see #wrap
*/
public static ByteListBuf of(final byte... init) {
return wrap(init);
}
@Override
public byte @NotNull [] asArray() {
if (this.size() == a.length) {
return this.a;
} else {
return this.toByteArray();
}
}
@Override
public byte @Nullable [] asArrayStrict() {
if (this.size() == a.length) {
return a;
} else {
return null;
}
}
@Override
public byte[] asUnboundedArray() {
return a;
}
@Override
public byte @Nullable [] asUnboundedArrayStrict() {
return a;
}
@Override
public boolean isMutable() {
return mutable;
}
@Override
public ByteListBuf freeze() {
mutable = false;
return this;
}
@Override
public Buf subList(int from, int to) {
if (from == 0 && to == size()) return this;
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() {
return ByteListBuf.wrap(this.a.clone(), this.size);
}
@Override
public SafeByteArrayInputStream binaryInputStream() {
return new SafeByteArrayInputStream(this.a, 0, this.size);
}
@Override
public void writeTo(SafeDataOutput dataOutput) {
dataOutput.write(this.a, 0, this.size);
}
@Override
public SafeByteArrayOutputStream binaryOutputStream(int from, int to) {
ensureFromTo(size, from, to);
return new SafeByteArrayOutputStream(a, from, to);
}
@Override
public boolean equals(int aStartIndex, Buf b, int bStartIndex, int length) {
return b.equals(bStartIndex, this.a, aStartIndex, length);
}
@Override
public boolean equals(int aStartIndex, byte[] b, int bStartIndex, int length) {
if (aStartIndex < 0) return false;
if (aStartIndex + length > this.size) {
return false;
}
return Arrays.equals(a, aStartIndex, aStartIndex + length, b, bStartIndex, bStartIndex + length);
}
@Override
public String toString(Charset charset) {
return new String(a, 0, size, charset);
}
class SubList extends AbstractByteList.ByteRandomAccessSubList implements Buf {
@Serial
private static final long serialVersionUID = -3185226345314976296L;
protected SubList(int from, int to) {
super(ByteListBuf.this, from, to);
}
// Most of the inherited methods should be fine, but we can override a few of them for performance.
// Needed because we can't access the parent class' instance variables directly in a different
// instance of SubList.
private byte[] getParentArray() {
return a;
}
@Override
public @NotNull Buf subList(int from, int 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(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
public Buf copy() {
return Buf.wrap(Arrays.copyOfRange(a, from, to));
}
@Override
public SafeByteArrayInputStream binaryInputStream() {
return new SafeByteArrayInputStream(a, from, size());
}
@Override
public void writeTo(SafeDataOutput dataOutput) {
dataOutput.write(a, from, size());
}
@Override
public SafeByteArrayOutputStream binaryOutputStream(int from, int to) {
ensureFromTo(size(), from, to);
return new SafeByteArrayOutputStream(a, from + this.from, to + this.from);
}
@Override
public boolean equals(int aStartIndex, Buf b, int bStartIndex, int length) {
return b.equals(bStartIndex, a, aStartIndex + from, length);
}
@Override
public boolean equals(int aStartIndex, byte[] b, int bStartIndex, int length) {
var aFrom = from + aStartIndex;
var aTo = from + aStartIndex + length;
if (aFrom < from) return false;
if (aTo > to) return false;
return Arrays.equals(a, aFrom, aTo, b, bStartIndex, bStartIndex + length);
}
@Override
public byte getByte(int i) {
ensureRestrictedIndex(i);
return a[i + from];
}
@Override
public byte @NotNull [] asArray() {
if (this.from == 0 && this.to == a.length) {
return a;
} else {
return SubList.this.toByteArray();
}
}
@Override
public byte @Nullable [] asArrayStrict() {
if (this.from == 0 && this.to == a.length) {
return a;
} else {
return null;
}
}
@Override
public byte[] asUnboundedArray() {
if (from == 0) {
return a;
} else {
return toByteArray();
}
}
@Override
public byte @Nullable [] asUnboundedArrayStrict() {
if (from == 0) {
return a;
} else {
return null;
}
}
@Override
public boolean isMutable() {
return mutable;
}
@Override
public SubList freeze() {
mutable = false;
return this;
}
private final class SubListIterator extends ByteIterators.AbstractIndexBasedListIterator {
// We are using pos == 0 to be 0 relative to SubList.from (meaning you need to do a[from + i] when
// accessing array).
SubListIterator(int index) {
super(0, index);
}
@Override
protected byte get(int i) {
return a[from + i];
}
@Override
protected void add(int i, byte k) {
ByteListBuf.SubList.this.add(i, k);
}
@Override
protected void set(int i, byte k) {
ByteListBuf.SubList.this.set(i, k);
}
@Override
protected void remove(int i) {
ByteListBuf.SubList.this.removeByte(i);
}
@Override
protected int getMaxPos() {
return to - from;
}
@Override
public byte nextByte() {
if (!hasNext()) throw new NoSuchElementException();
return a[from + (lastReturned = pos++)];
}
@Override
public byte previousByte() {
if (!hasPrevious()) throw new NoSuchElementException();
return a[from + (lastReturned = --pos)];
}
@Override
public void forEachRemaining(final ByteConsumer action) {
final int max = to - from;
while (pos < max) {
action.accept(a[from + (lastReturned = pos++)]);
}
}
}
@Override
public @NotNull ByteListIterator listIterator(int index) {
return new ByteListBuf.SubList.SubListIterator(index);
}
private final class SubListSpliterator extends ByteSpliterators.LateBindingSizeIndexBasedSpliterator {
// We are using pos == 0 to be 0 relative to real array 0
SubListSpliterator() {
super(from);
}
private SubListSpliterator(int pos, int maxPos) {
super(pos, maxPos);
}
@Override
protected int getMaxPosFromBackingStore() {
return to;
}
@Override
protected byte get(int i) {
return a[i];
}
@Override
protected ByteListBuf.SubList.SubListSpliterator makeForSplit(int pos, int maxPos) {
return new ByteListBuf.SubList.SubListSpliterator(pos, maxPos);
}
@Override
public boolean tryAdvance(final ByteConsumer action) {
if (pos >= getMaxPos()) return false;
action.accept(a[pos++]);
return true;
}
@Override
public void forEachRemaining(final ByteConsumer action) {
final int max = getMaxPos();
while (pos < max) {
action.accept(a[pos++]);
}
}
}
@Override
public ByteSpliterator spliterator() {
return new ByteListBuf.SubList.SubListSpliterator();
}
boolean contentsEquals(byte[] otherA, int otherAFrom, int otherATo) {
if (a == otherA && from == otherAFrom && to == otherATo) return true;
return Arrays.equals(a, from, to, otherA, otherAFrom, otherATo);
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == null) return false;
if (!(o instanceof java.util.List)) return false;
if (o instanceof ByteListBuf other) {
return contentsEquals(other.a, 0, other.size());
}
if (o instanceof SubList other) {
return contentsEquals(other.getParentArray(), other.from, other.to);
}
return super.equals(o);
}
int contentsCompareTo(byte[] otherA, int otherAFrom, int otherATo) {
if (a == otherA && from == otherAFrom && to == otherATo) return 0;
return Arrays.compareUnsigned(a, from, to, otherA, otherAFrom, otherATo);
}
@Override
public int compareTo(final java.util.@NotNull List<? extends Byte> l) {
if (l instanceof ByteListBuf other) {
return contentsCompareTo(other.a, 0, other.size());
}
if (l instanceof ByteListBuf.SubList other) {
return contentsCompareTo(other.getParentArray(), other.from, other.to);
}
return super.compareTo(l);
}
@Override
public String toString(Charset charset) {
return new String(a, from, to, charset);
}
}
}