completed PrimitiveList implementation

This commit is contained in:
00asdf 2023-04-18 23:03:05 +02:00
parent 6c5b1b899e
commit 2a7da78acb
17 changed files with 1622 additions and 1465 deletions

View File

@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="GeneralUtils:jar">
<output-path>$PROJECT_DIR$/out/artifacts/GeneralUtils_jar</output-path>
<root id="archive" name="GeneralUtils.jar">
<element id="module-output" name="GeneralUtils" />
</root>
</artifact>
</component>

View File

@ -4,8 +4,19 @@
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library" scope="TEST">
<library name="JUnit4">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/4.13.1/junit-4.13.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component> </component>
</module> </module>

View File

@ -1,27 +1,26 @@
package dev.asdf00.general.utils.list; package dev.asdf00.general.utils.list;
import dev.asdf00.general.utils.list.internal.AbstractBaseList; import dev.asdf00.general.utils.list.internal.*;
import dev.asdf00.general.utils.list.internal.ByteList;
public abstract class PrimitiveList<T> extends AbstractBaseList<T> { public abstract class PrimitiveList<T> extends AbstractBaseList<T> {
public static <T> PrimitiveList<T> create(Class<T> boxedType) { public static <T> PrimitiveList<T> create(Class<T> boxedType) {
if (Byte.class == boxedType) { if (Byte.class == boxedType) {
return (PrimitiveList<T>) new ByteList(); return (PrimitiveList<T>) new ByteList();
} else if (Short.class.equals(boxedType)) { } else if (Short.class == boxedType) {
return null; return (PrimitiveList<T>) new ShortList();
} else if (Integer.class.equals(boxedType)) { } else if (Integer.class == boxedType) {
return null; return (PrimitiveList<T>) new IntegerList();
} else if (Long.class.equals(boxedType)) { } else if (Long.class == boxedType) {
return null; return (PrimitiveList<T>) new LongList();
} else if (Float.class.equals(boxedType)) { } else if (Float.class == boxedType) {
return null; return (PrimitiveList<T>) new FloatList();
} else if (Double.class.equals(boxedType)) { } else if (Double.class == boxedType) {
return null; return (PrimitiveList<T>) new DoubleList();
} else if (Character.class.equals(boxedType)) { } else if (Character.class == boxedType) {
return null; return (PrimitiveList<T>) new CharacterList();
} else if (Boolean.class.equals(boxedType)) { } else if (Boolean.class == boxedType) {
return null; return (PrimitiveList<T>) new BooleanList();
} else { } else {
throw new IllegalArgumentException("%s is not a boxed type!".formatted(boxedType)); throw new IllegalArgumentException("%s is not a boxed type!".formatted(boxedType));
} }

View File

@ -37,12 +37,12 @@ public abstract class AbstractBaseList<T> implements List<T> {
@Override @Override
public int size() { public int size() {
return size(); return size;
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return size() < 1; return size < 1;
} }
@Override @Override
@ -78,8 +78,12 @@ public abstract class AbstractBaseList<T> implements List<T> {
@Override @Override
public boolean removeAll(Collection<?> c) { public boolean removeAll(Collection<?> c) {
boolean changed = false; boolean changed = false;
for (Object o : c) { ListIterator<T> itr = listIterator();
changed = remove(o) || changed; while (itr.hasNext()) {
if (c.contains(itr.next())) {
itr.remove();
changed = true;
}
} }
return changed; return changed;
} }
@ -89,7 +93,7 @@ public abstract class AbstractBaseList<T> implements List<T> {
boolean changed = false; boolean changed = false;
ListIterator<T> itr = listIterator(); ListIterator<T> itr = listIterator();
while (itr.hasNext()) { while (itr.hasNext()) {
if (c.contains(itr.next())) { if (!c.contains(itr.next())) {
itr.remove(); itr.remove();
changed = true; changed = true;
} }
@ -113,12 +117,6 @@ public abstract class AbstractBaseList<T> implements List<T> {
return directSet(index, element); return directSet(index, element);
} }
@Override
public boolean add(T t) {
directSet(size++, t);
return true;
}
@Override @Override
public ListIterator<T> listIterator() { public ListIterator<T> listIterator() {
return new ListItr<>(this, 0); return new ListItr<>(this, 0);
@ -133,8 +131,10 @@ public abstract class AbstractBaseList<T> implements List<T> {
@Override @Override
public List<T> subList(int fromIndex, int toIndex) { public List<T> subList(int fromIndex, int toIndex) {
Objects.checkIndex(fromIndex, size); Objects.checkIndex(fromIndex, size);
Objects.checkIndex(fromIndex, toIndex); if (toIndex < 0 || toIndex > size) {
int len = (toIndex - fromIndex) + 1; throw new IndexOutOfBoundsException();
}
int len = toIndex - fromIndex;
if (len < 0) { if (len < 0) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@ -211,13 +211,12 @@ public abstract class AbstractBaseList<T> implements List<T> {
@Override @Override
public void remove() { public void remove() {
checkConcurrentModification(); checkConcurrentModification();
Objects.checkIndex(cur, base.size);
if (last == -1) { if (last == -1) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
modCnt++; modCnt++;
base.remove(--cur); base.remove(last);
last = -1; cur--;
} }
@Override @Override
@ -235,12 +234,16 @@ public abstract class AbstractBaseList<T> implements List<T> {
@Override @Override
public void add(E e) { public void add(E e) {
checkConcurrentModification(); checkConcurrentModification();
Objects.checkIndex(cur, base.size);
if (last == -1) { if (last == -1) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
modCnt++; modCnt++;
base.add(cur, e); last++;
if (last == base.size) {
base.add(e);
} else {
base.add(last, e);
}
last = -1; last = -1;
} }
@ -263,11 +266,25 @@ public abstract class AbstractBaseList<T> implements List<T> {
modCnt = base.modCnt; modCnt = base.modCnt;
} }
@Override
public boolean add(E e) {
checkConcurrentModification();
modCnt++;
if (start + size == base.size) {
base.add(e);
} else {
base.add(start + size, e);
}
size++;
return true;
}
@Override @Override
public boolean addAll(Collection<? extends E> c) { public boolean addAll(Collection<? extends E> c) {
for (E e : c) { for (E e : c) {
add(e); add(e);
} }
size += c.size();
return c.size() > 0; return c.size() > 0;
} }
@ -278,13 +295,15 @@ public abstract class AbstractBaseList<T> implements List<T> {
for (E e : c) { for (E e : c) {
add(i, e); add(i, e);
} }
return false; size += c.size();
return c.size() > 0;
} }
@Override @Override
public void clear() { public void clear() {
checkConcurrentModification(); checkConcurrentModification();
modCnt++; modCnt++;
base.modCnt++;
base.closeGap(start, size); base.closeGap(start, size);
size = 0; size = 0;
} }
@ -306,25 +325,20 @@ public abstract class AbstractBaseList<T> implements List<T> {
@Override @Override
public E remove(int index) { public E remove(int index) {
return null; checkConcurrentModification();
}
@Override
public ListIterator<E> listIterator() {
return new SubListItr<>(base, start, start, start + (size - 1));
}
@Override
public ListIterator<E> listIterator(int index) {
Objects.checkIndex(index, size); Objects.checkIndex(index, size);
return new SubListItr<>(base, start + index, start, start + (size - 1)); modCnt++;
size--;
return base.remove(start + index);
} }
@Override @Override
public List<E> subList(int fromIndex, int toIndex) { public List<E> subList(int fromIndex, int toIndex) {
checkConcurrentModification(); checkConcurrentModification();
Objects.checkIndex(fromIndex, size); Objects.checkIndex(fromIndex, size);
Objects.checkIndex(toIndex, size); if (toIndex < 0 || toIndex > size) {
throw new IndexOutOfBoundsException();
}
int len = (toIndex - fromIndex) + 1; int len = (toIndex - fromIndex) + 1;
if (len < 0) { if (len < 0) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@ -373,114 +387,5 @@ public abstract class AbstractBaseList<T> implements List<T> {
throw new ConcurrentModificationException(); throw new ConcurrentModificationException();
} }
} }
private static class SubListItr<TYPE> implements ListIterator<TYPE> {
private final AbstractBaseList<TYPE> base;
private int modCnt;
private int cur;
private int lower;
private int higher;
private int last;
public SubListItr(AbstractBaseList<TYPE> base, int start, int lower, int higher) {
this.base = base;
modCnt = base.modCnt;
cur = start;
this.lower = lower;
this.higher = higher;
last = -1;
} }
@Override
public boolean hasNext() {
return cur <= higher;
}
@Override
public TYPE next() {
checkConcurrentModification();
if (!hasNext()) {
throw new IndexOutOfBoundsException();
}
last = cur;
return base.get(cur++);
}
@Override
public boolean hasPrevious() {
return cur > lower;
}
@Override
public TYPE previous() {
checkConcurrentModification();
if (!hasPrevious()) {
throw new IndexOutOfBoundsException();
}
last = --cur;
return base.get(cur);
}
@Override
public int nextIndex() {
return cur - lower;
}
@Override
public int previousIndex() {
return cur - lower - 1;
}
@Override
public void remove() {
checkConcurrentModification();
rangeCheck();
if (last == -1) {
throw new IllegalStateException();
}
modCnt++;
base.remove(last);
last = -1;
}
@Override
public void set(TYPE element) {
checkConcurrentModification();
rangeCheck();
if (last == -1) {
throw new IllegalStateException();
}
modCnt++;
base.set(last, element);
last = -1;
}
@Override
public void add(TYPE element) {
checkConcurrentModification();
rangeCheck();
if (last == -1) {
throw new IllegalStateException();
}
modCnt++;
base.add(last, element);
last = -1;
}
private void checkConcurrentModification() {
if (base.modCnt != modCnt) {
throw new ConcurrentModificationException();
}
}
private void rangeCheck() {
if (cur < lower || cur > higher) {
throw new IndexOutOfBoundsException();
}
}
}
}
} }

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class BooleanList extends PrimitiveList<Boolean> {
private boolean[] data;
public BooleanList() {
data = new boolean[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Boolean.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Boolean)) {
return -1;
}
boolean target = ((Boolean) o).booleanValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Boolean)) {
return -1;
}
boolean target = ((Boolean) o).booleanValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Boolean directSet(int index, Boolean element) {
boolean result = data[index];
data[index] = element.booleanValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Boolean element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Boolean> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Boolean b : c) {
data[i] = b.booleanValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Boolean> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Boolean b : c) {
data[i] = b.booleanValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new boolean[8];
size = 0;
}
@Override
public Boolean get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Boolean element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Boolean remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
boolean result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addBoolean(boolean value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public boolean getBoolean(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public boolean[] toBooleanArray() {
return Arrays.copyOf(data, size);
}
@Override
public boolean[] finalizeAsBooleanArray() {
if (data == null) {
throw new NullPointerException();
}
boolean[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -32,6 +32,9 @@ public class ByteList extends PrimitiveList<Byte> {
@Override @Override
protected int indexOf(Object o, int start, int len) { protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Byte)) { if (!(o instanceof Byte)) {
return -1; return -1;
} }
@ -46,6 +49,9 @@ public class ByteList extends PrimitiveList<Byte> {
@Override @Override
protected int lastIndexOf(Object o, int start, int len) { protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Byte)) { if (!(o instanceof Byte)) {
return -1; return -1;
} }
@ -72,7 +78,7 @@ public class ByteList extends PrimitiveList<Byte> {
if (Integer.bitCount(size) == 1) { if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size); data = Arrays.copyOf(data, size);
} else { } else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) + 1); data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
} }
} }
System.arraycopy(data, start, data, start + len, (size - len) - start); System.arraycopy(data, start, data, start + len, (size - len) - start);
@ -84,6 +90,16 @@ public class ByteList extends PrimitiveList<Byte> {
size -= len; size -= len;
} }
@Override
public boolean add(Byte element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override @Override
public boolean addAll(Collection<? extends Byte> c) { public boolean addAll(Collection<? extends Byte> c) {
modCnt++; modCnt++;
@ -127,38 +143,49 @@ public class ByteList extends PrimitiveList<Byte> {
@Override @Override
public void add(int index, Byte element) { public void add(int index, Byte element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
} }
@Override @Override
public Byte remove(int index) { public Byte remove(int index) {
return null; Objects.checkIndex(index, size);
modCnt++;
byte result = data[index];
closeGap(index, 1);
return result;
} }
@Override @Override
public void addByte(byte value) { public void addByte(byte value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
} }
@Override @Override
public byte getByte(int index) { public byte getByte(int index) {
return 0; Objects.checkIndex(index, size);
return data[index];
} }
@Override @Override
public byte[] toByteArray() { public byte[] toByteArray() {
return new byte[0]; return Arrays.copyOf(data, size);
} }
@Override @Override
public byte[] finalizeAsByteArray() { public byte[] finalizeAsByteArray() {
if (data == null) {
throw new NullPointerException();
}
byte[] res = data; byte[] res = data;
data = null; data = null;
AbstractBaseList.UNSAFE.putInt(data, AbstractBaseList.OFFSET_LEN, size); AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res; return res;
} }
private void reallocateWithLen(int newLen) {
data = Arrays.copyOf(data, newLen);
}
} }

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class CharacterList extends PrimitiveList<Character> {
private char[] data;
public CharacterList() {
data = new char[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Character.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Character)) {
return -1;
}
char target = ((Character) o).charValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Character)) {
return -1;
}
char target = ((Character) o).charValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Character directSet(int index, Character element) {
char result = data[index];
data[index] = element.charValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Character element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Character> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Character b : c) {
data[i] = b.charValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Character> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Character b : c) {
data[i] = b.charValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new char[8];
size = 0;
}
@Override
public Character get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Character element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Character remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
char result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addChar(char value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public char getChar(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public char[] toCharArray() {
return Arrays.copyOf(data, size);
}
@Override
public char[] finalizeAsCharArray() {
if (data == null) {
throw new NullPointerException();
}
char[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class DoubleList extends PrimitiveList<Double> {
private double[] data;
public DoubleList() {
data = new double[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Double.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Double)) {
return -1;
}
double target = ((Double) o).doubleValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Double)) {
return -1;
}
double target = ((Double) o).doubleValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Double directSet(int index, Double element) {
double result = data[index];
data[index] = element.doubleValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Double element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Double> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Double b : c) {
data[i] = b.doubleValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Double> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Double b : c) {
data[i] = b.doubleValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new double[8];
size = 0;
}
@Override
public Double get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Double element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Double remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
double result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addDouble(double value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public double getDouble(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public double[] toDoubleArray() {
return Arrays.copyOf(data, size);
}
@Override
public double[] finalizeAsDoubleArray() {
if (data == null) {
throw new NullPointerException();
}
double[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class FloatList extends PrimitiveList<Float> {
private float[] data;
public FloatList() {
data = new float[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Float.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Float)) {
return -1;
}
float target = ((Float) o).floatValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Float)) {
return -1;
}
float target = ((Float) o).floatValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Float directSet(int index, Float element) {
float result = data[index];
data[index] = element.floatValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Float element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Float> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Float b : c) {
data[i] = b.floatValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Float> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Float b : c) {
data[i] = b.floatValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new float[8];
size = 0;
}
@Override
public Float get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Float element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Float remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
float result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addFloat(float value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public float getFloat(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public float[] toFloatArray() {
return Arrays.copyOf(data, size);
}
@Override
public float[] finalizeAsFloatArray() {
if (data == null) {
throw new NullPointerException();
}
float[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class IntegerList extends PrimitiveList<Integer> {
private int[] data;
public IntegerList() {
data = new int[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Integer.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Integer)) {
return -1;
}
int target = ((Integer) o).intValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Integer)) {
return -1;
}
int target = ((Integer) o).intValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Integer directSet(int index, Integer element) {
int result = data[index];
data[index] = element.intValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Integer element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Integer> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Integer b : c) {
data[i] = b.intValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Integer> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Integer b : c) {
data[i] = b.intValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new int[8];
size = 0;
}
@Override
public Integer get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Integer element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Integer remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
int result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addInt(int value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public int getInt(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public int[] toIntArray() {
return Arrays.copyOf(data, size);
}
@Override
public int[] finalizeAsIntArray() {
if (data == null) {
throw new NullPointerException();
}
int[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class LongList extends PrimitiveList<Long> {
private long[] data;
public LongList() {
data = new long[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Long.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Long)) {
return -1;
}
long target = ((Long) o).longValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Long)) {
return -1;
}
long target = ((Long) o).longValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Long directSet(int index, Long element) {
long result = data[index];
data[index] = element.longValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Long element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Long> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Long b : c) {
data[i] = b.longValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Long> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Long b : c) {
data[i] = b.longValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new long[8];
size = 0;
}
@Override
public Long get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Long element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Long remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
long result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addLong(long value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public long getLong(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public long[] toLongArray() {
return Arrays.copyOf(data, size);
}
@Override
public long[] finalizeAsLongArray() {
if (data == null) {
throw new NullPointerException();
}
long[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -0,0 +1,191 @@
package dev.asdf00.general.utils.list.internal;
import dev.asdf00.general.utils.list.PrimitiveList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
public class ShortList extends PrimitiveList<Short> {
private short[] data;
public ShortList() {
data = new short[8];
size = 0;
modCnt = 0;
}
@Override
public boolean isFinalized() {
return data == null;
}
@Override
protected <T1> T1[] toArray(T1[] a, int start, int len) {
Object[] result = Arrays.copyOf(a, len, a.getClass());
for (int i = 0, j = start; i < len; i++, j++) {
result[i] = Short.valueOf(data[j]);
}
return (T1[]) result;
}
@Override
protected int indexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Short)) {
return -1;
}
short target = ((Short) o).shortValue();
for (int i = start; i < start + len; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected int lastIndexOf(Object o, int start, int len) {
if (data == null) {
throw new NullPointerException();
}
if (!(o instanceof Short)) {
return -1;
}
short target = ((Short) o).shortValue();
for (int i = (start + len) - 1; i >= start; i++) {
if (data[i] == target) {
return i;
}
}
return -1;
}
@Override
protected Short directSet(int index, Short element) {
short result = data[index];
data[index] = element.shortValue();
return result;
}
@Override
protected void createGap(int start, int len) {
size += len;
if (size > data.length) {
if (Integer.bitCount(size) == 1) {
data = Arrays.copyOf(data, size);
} else {
data = Arrays.copyOf(data, Integer.highestOneBit(size) << 1);
}
}
System.arraycopy(data, start, data, start + len, (size - len) - start);
}
@Override
protected void closeGap(int start, int len) {
System.arraycopy(data, start + len, data, start, size - (start + len));
size -= len;
}
@Override
public boolean add(Short element) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, element);
return true;
}
@Override
public boolean addAll(Collection<? extends Short> c) {
modCnt++;
int i = size;
createGap(size, c.size());
for (Short b : c) {
data[i] = b.shortValue();
i++;
}
return true;
}
@Override
public boolean addAll(int index, Collection<? extends Short> c) {
Objects.checkIndex(index, size);
modCnt++;
int i = index;
createGap(index, c.size());
for (Short b : c) {
data[i] = b.shortValue();
i++;
}
return true;
}
@Override
public void clear() {
if (data == null) {
throw new NullPointerException();
}
modCnt++;
data = new short[8];
size = 0;
}
@Override
public Short get(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public void add(int index, Short element) {
Objects.checkIndex(index, size);
modCnt++;
createGap(index, 1);
directSet(index, element);
}
@Override
public Short remove(int index) {
Objects.checkIndex(index, size);
modCnt++;
short result = data[index];
closeGap(index, 1);
return result;
}
@Override
public void addShort(short value) {
modCnt++;
if (size == data.length) {
data = Arrays.copyOf(data, data.length << 1);
}
directSet(size++, value);
}
@Override
public short getShort(int index) {
Objects.checkIndex(index, size);
return data[index];
}
@Override
public short[] toShortArray() {
return Arrays.copyOf(data, size);
}
@Override
public short[] finalizeAsShortArray() {
if (data == null) {
throw new NullPointerException();
}
short[] res = data;
data = null;
AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size);
return res;
}
}

View File

@ -1,79 +0,0 @@
package dev.asdf00.general.utils.listOld;
import dev.asdf00.general.utils.listOld.internal.PrimitiveListImpl;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.List;
import java.util.RandomAccess;
public abstract class PrimitiveList<T> implements List<T>, RandomAccess {
private static final Unsafe UNSAFE;
static {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
UNSAFE = (Unsafe) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static boolean isSupportedOnCurrentJVMConfiguration() {
return UNSAFE.arrayIndexScale(byte[].class) == 1 && UNSAFE.arrayIndexScale(short[].class) == 2 &&
UNSAFE.arrayIndexScale(int[].class) == 4 && UNSAFE.arrayIndexScale(long[].class) == 8 &&
UNSAFE.arrayIndexScale(float[].class) == 4 && UNSAFE.arrayIndexScale(double[].class) == 8;
}
public static <T> PrimitiveList<T> create(Class<T> boxedType) throws IllegalArgumentException, UnsupportedOperationException {
return PrimitiveListImpl.create(boxedType);
}
public abstract byte[] toByteArray();
public abstract short[] toShortArray();
public abstract int[] toIntArray();
public abstract long[] toLongArray();
public abstract float[] toFloatArray();
public abstract double[] toDoubleArray();
public abstract char[] toCharArray();
public abstract boolean[] toBooleanArray();
public abstract byte getByte(int index);
public abstract short getShort(int index);
public abstract int getInt(int index);
public abstract long getLong(int index);
public abstract float getFloat(int index);
public abstract double getDouble(int index);
public abstract char getChar(int index);
public abstract boolean getBoolean(int index);
public abstract byte[] finalizeAsByteArray();
public abstract short[] finalizeAsShortArray();
public abstract int[] finalizeAsIntArray();
public abstract long[] finalizeAsLongArray();
public abstract float[] finalizeAsFloatArray();
public abstract double[] finalizeAsDoubleArray();
public abstract boolean isFinalized();
}

View File

@ -1,5 +1,4 @@
module GeneralUtils { module GeneralUtils {
requires jdk.unsupported; requires jdk.unsupported;
exports dev.asdf00.general.utils.listOld;
exports dev.asdf00.general.utils.list; exports dev.asdf00.general.utils.list;
} }

View File

@ -0,0 +1,138 @@
package dev.asdf00.general.utils.list;
import dev.asdf00.general.utils.list.internal.ByteList;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
import static dev.asdf00.general.utils.list.internal.ListReader.*;
import static org.junit.Assert.*;
public class TestList {
@Test
public void basicByteTest() {
var list = PrimitiveList.create(Byte.class);
list.add((byte) 3);
list.addByte((byte) 4);
assertListStats(list, 2, 2, 8);
var array = createByteArray(14);
list.addAll(1, toBoxedBytes(array));
assertListStats(list, 16, 3, 16);
assertEquals("last element", 4, list.getByte(15));
assertEquals("first element", Byte.valueOf((byte) 3), list.get(0));
list.add(1, (byte) 11);
assertListStats(list, 17, 4, 32);
list.remove(Byte.valueOf((byte) 3));
assertListStats(list, 16, 5, 32);
assertEquals("first element", 11, list.getByte(0));
assertThrows(ConcurrentModificationException.class, () -> {
for (Byte b : list) {
list.remove(b);
}
});
list.remove(14);
assertListStats(list, 14, 7, 32);
assertArrayEquals("toArray", toBoxedBytes(array).toArray(Byte[]::new), list.toArray(Byte[]::new));
assertArrayEquals("finalizeAsArray", array, list.finalizeAsByteArray());
assertTrue("isFinalized", list.isFinalized());
assertThrows(NullPointerException.class, () -> list.lastIndexOf(12));
assertThrows(NullPointerException.class, () -> list.get(0));
assertThrows(NullPointerException.class, () -> list.finalizeAsByteArray());
assertThrows(UnsupportedOperationException.class, () -> list.toBooleanArray());
}
@Test
public void indexOutOfBoundsByte() {
assertThrows(IllegalArgumentException.class, () -> PrimitiveList.create(Object.class));
var list = PrimitiveList.create(Byte.class);
assertTrue("empty", list.isEmpty());
assertEquals("size", 0, list.size());
assertThrows(IndexOutOfBoundsException.class, () -> list.getByte(-1));
assertThrows(IndexOutOfBoundsException.class, () -> list.getByte(0));
assertThrows(IndexOutOfBoundsException.class, () -> list.get(0));
assertThrows(IndexOutOfBoundsException.class, () -> list.add(-1, Byte.valueOf((byte) 1)));
list.add((byte) 2);
list.add((byte) 2);
assertThrows(IllegalArgumentException.class, () -> list.subList(1, 0));
}
@Test
public void subListTestByte() {
var a0 = new byte[]{0, 1, 1, 1, 0, 0};
var list = PrimitiveList.create(Byte.class);
list.addAll(toBoxedBytes(a0));
List<Byte> subList = list.subList(3, 6);
subList.remove(0);
assertListStats(list, 5, 2, 8);
assertArrayEquals("data", new byte[]{0, 1, 1, 0, 0}, list.toByteArray());
subList.add((byte) 1);
assertListStats(list, 6, 3, 8);
assertArrayEquals("data", new byte[]{0, 1, 1, 0, 0, 1}, list.toByteArray());
subList = list.subList(2, 2);
assertTrue("subList empty", subList.isEmpty());
subList.add((byte) 2);
assertListStats(list, 7, 4, 8);
assertArrayEquals("data", new byte[]{0, 1, 2, 1, 0, 0, 1}, list.toByteArray());
subList.clear();
assertListStats(list, 6, 5, 8);
assertArrayEquals("data", new byte[]{0, 1, 1, 0, 0, 1}, list.toByteArray());
list.add(3, (byte) 2);
subList = list.subList(1, 5);
subList.removeAll(List.of((byte) 1, (byte) 2));
assertListStats(list, 4, 9, 8);
assertArrayEquals("data", new byte[]{0, 0, 0, 1}, list.toByteArray());
list.addAll(List.of((byte) 0, (byte) 1, (byte) 0, (byte) 2, (byte) 3));
final List<Byte> finalSubList = subList;
assertThrows(ConcurrentModificationException.class, () -> finalSubList.get(0));
assertListStats(list, 9, 10, 16);
assertArrayEquals("data", new byte[]{0, 0, 0, 1, 0, 1, 0, 2, 3}, list.toByteArray());
list.retainAll(List.of((byte) 1, (byte) 2));
assertListStats(list, 3, 16, 16);
assertArrayEquals("data", new byte[]{1, 1, 2}, list.toByteArray());
list.clear();
assertListStats(list, 0, 17, 8);
}
public static void assertListStats(PrimitiveList<?> list, int size, int modCnt, int length) {
assertEquals("size", size, getSize(list));
assertEquals("modCnt", modCnt, getModCnt(list));
assertEquals("length", length, getLength(list));
}
public static final Random seedRng = new Random(42);
public static byte[] createByteArray(int len) {
return createByteArray(len, seedRng.nextInt());
}
public static byte[] createByteArray(int len, int seed) {
Random rng = new Random(seed);
var array = new byte[len];
for (int i = 0; i < len; array[i++] = (byte) rng.nextInt());
return array;
}
public static Collection<Byte> toBoxedBytes(byte[] array) {
var result = new ArrayList<Byte>(array.length);
for (byte b : array) {
result.add(b);
}
return result;
}
}

View File

@ -0,0 +1,30 @@
package dev.asdf00.general.utils.list.internal;
import java.lang.reflect.Field;
public class ListReader {
public static int getSize(AbstractBaseList list) {
return list.size;
}
public static int getModCnt(AbstractBaseList list) {
return list.modCnt;
}
public static int getLength(AbstractBaseList list) {
try {
Class<?> cls = list.getClass();
Field data = cls.getDeclaredField("data");
if (!data.canAccess(list)) {
data.setAccessible(true);
}
Object array = data.get(list);
if (array == null) {
throw new NullPointerException();
}
return AbstractBaseList.UNSAFE.getInt(array, AbstractBaseList.OFFSET_LEN);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}