From 2a7da78acb51cfb8314fbc7fc14da7c9f79fa24c Mon Sep 17 00:00:00 2001 From: 00asdf Date: Tue, 18 Apr 2023 23:03:05 +0200 Subject: [PATCH] completed PrimitiveList implementation --- .idea/artifacts/GeneralUtils_jar.xml | 8 + GeneralUtils.iml | 11 + .../general/utils/list/PrimitiveList.java | 31 +- .../utils/list/internal/AbstractBaseList.java | 185 +-- .../utils/list/internal/BooleanList.java | 191 +++ .../general/utils/list/internal/ByteList.java | 49 +- .../utils/list/internal/CharacterList.java | 191 +++ .../utils/list/internal/DoubleList.java | 191 +++ .../utils/list/internal/FloatList.java | 191 +++ .../utils/list/internal/IntegerList.java | 191 +++ .../general/utils/list/internal/LongList.java | 191 +++ .../utils/list/internal/ShortList.java | 191 +++ .../general/utils/listOld/PrimitiveList.java | 79 -- .../listOld/internal/PrimitiveListImpl.java | 1218 ----------------- src/module-info.java | 1 - .../asdf00/general/utils/list/TestList.java | 138 ++ .../utils/list/internal/ListReader.java | 30 + 17 files changed, 1622 insertions(+), 1465 deletions(-) create mode 100644 .idea/artifacts/GeneralUtils_jar.xml create mode 100644 src/dev/asdf00/general/utils/list/internal/BooleanList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/CharacterList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/DoubleList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/FloatList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/IntegerList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/LongList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/ShortList.java delete mode 100644 src/dev/asdf00/general/utils/listOld/PrimitiveList.java delete mode 100644 src/dev/asdf00/general/utils/listOld/internal/PrimitiveListImpl.java create mode 100644 test/dev/asdf00/general/utils/list/TestList.java create mode 100644 test/dev/asdf00/general/utils/list/internal/ListReader.java diff --git a/.idea/artifacts/GeneralUtils_jar.xml b/.idea/artifacts/GeneralUtils_jar.xml new file mode 100644 index 0000000..2047b5c --- /dev/null +++ b/.idea/artifacts/GeneralUtils_jar.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/out/artifacts/GeneralUtils_jar + + + + + \ No newline at end of file diff --git a/GeneralUtils.iml b/GeneralUtils.iml index c90834f..03a7b64 100644 --- a/GeneralUtils.iml +++ b/GeneralUtils.iml @@ -4,8 +4,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/dev/asdf00/general/utils/list/PrimitiveList.java b/src/dev/asdf00/general/utils/list/PrimitiveList.java index a955b43..a8f88ba 100644 --- a/src/dev/asdf00/general/utils/list/PrimitiveList.java +++ b/src/dev/asdf00/general/utils/list/PrimitiveList.java @@ -1,27 +1,26 @@ package dev.asdf00.general.utils.list; -import dev.asdf00.general.utils.list.internal.AbstractBaseList; -import dev.asdf00.general.utils.list.internal.ByteList; +import dev.asdf00.general.utils.list.internal.*; public abstract class PrimitiveList extends AbstractBaseList { public static PrimitiveList create(Class boxedType) { if (Byte.class == boxedType) { return (PrimitiveList) new ByteList(); - } else if (Short.class.equals(boxedType)) { - return null; - } else if (Integer.class.equals(boxedType)) { - return null; - } else if (Long.class.equals(boxedType)) { - return null; - } else if (Float.class.equals(boxedType)) { - return null; - } else if (Double.class.equals(boxedType)) { - return null; - } else if (Character.class.equals(boxedType)) { - return null; - } else if (Boolean.class.equals(boxedType)) { - return null; + } else if (Short.class == boxedType) { + return (PrimitiveList) new ShortList(); + } else if (Integer.class == boxedType) { + return (PrimitiveList) new IntegerList(); + } else if (Long.class == boxedType) { + return (PrimitiveList) new LongList(); + } else if (Float.class == boxedType) { + return (PrimitiveList) new FloatList(); + } else if (Double.class == boxedType) { + return (PrimitiveList) new DoubleList(); + } else if (Character.class == boxedType) { + return (PrimitiveList) new CharacterList(); + } else if (Boolean.class == boxedType) { + return (PrimitiveList) new BooleanList(); } else { throw new IllegalArgumentException("%s is not a boxed type!".formatted(boxedType)); } diff --git a/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java b/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java index 087eba9..26a2ed1 100644 --- a/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java +++ b/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java @@ -37,12 +37,12 @@ public abstract class AbstractBaseList implements List { @Override public int size() { - return size(); + return size; } @Override public boolean isEmpty() { - return size() < 1; + return size < 1; } @Override @@ -78,8 +78,12 @@ public abstract class AbstractBaseList implements List { @Override public boolean removeAll(Collection c) { boolean changed = false; - for (Object o : c) { - changed = remove(o) || changed; + ListIterator itr = listIterator(); + while (itr.hasNext()) { + if (c.contains(itr.next())) { + itr.remove(); + changed = true; + } } return changed; } @@ -89,7 +93,7 @@ public abstract class AbstractBaseList implements List { boolean changed = false; ListIterator itr = listIterator(); while (itr.hasNext()) { - if (c.contains(itr.next())) { + if (!c.contains(itr.next())) { itr.remove(); changed = true; } @@ -113,12 +117,6 @@ public abstract class AbstractBaseList implements List { return directSet(index, element); } - @Override - public boolean add(T t) { - directSet(size++, t); - return true; - } - @Override public ListIterator listIterator() { return new ListItr<>(this, 0); @@ -133,8 +131,10 @@ public abstract class AbstractBaseList implements List { @Override public List subList(int fromIndex, int toIndex) { Objects.checkIndex(fromIndex, size); - Objects.checkIndex(fromIndex, toIndex); - int len = (toIndex - fromIndex) + 1; + if (toIndex < 0 || toIndex > size) { + throw new IndexOutOfBoundsException(); + } + int len = toIndex - fromIndex; if (len < 0) { throw new IllegalArgumentException(); } @@ -211,13 +211,12 @@ public abstract class AbstractBaseList implements List { @Override public void remove() { checkConcurrentModification(); - Objects.checkIndex(cur, base.size); if (last == -1) { throw new IllegalStateException(); } modCnt++; - base.remove(--cur); - last = -1; + base.remove(last); + cur--; } @Override @@ -235,12 +234,16 @@ public abstract class AbstractBaseList implements List { @Override public void add(E e) { checkConcurrentModification(); - Objects.checkIndex(cur, base.size); if (last == -1) { throw new IllegalStateException(); } modCnt++; - base.add(cur, e); + last++; + if (last == base.size) { + base.add(e); + } else { + base.add(last, e); + } last = -1; } @@ -263,11 +266,25 @@ public abstract class AbstractBaseList implements List { 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 public boolean addAll(Collection c) { for (E e : c) { add(e); } + size += c.size(); return c.size() > 0; } @@ -278,13 +295,15 @@ public abstract class AbstractBaseList implements List { for (E e : c) { add(i, e); } - return false; + size += c.size(); + return c.size() > 0; } @Override public void clear() { checkConcurrentModification(); modCnt++; + base.modCnt++; base.closeGap(start, size); size = 0; } @@ -306,25 +325,20 @@ public abstract class AbstractBaseList implements List { @Override public E remove(int index) { - return null; - } - - @Override - public ListIterator listIterator() { - return new SubListItr<>(base, start, start, start + (size - 1)); - } - - @Override - public ListIterator listIterator(int index) { + checkConcurrentModification(); Objects.checkIndex(index, size); - return new SubListItr<>(base, start + index, start, start + (size - 1)); + modCnt++; + size--; + return base.remove(start + index); } @Override public List subList(int fromIndex, int toIndex) { checkConcurrentModification(); Objects.checkIndex(fromIndex, size); - Objects.checkIndex(toIndex, size); + if (toIndex < 0 || toIndex > size) { + throw new IndexOutOfBoundsException(); + } int len = (toIndex - fromIndex) + 1; if (len < 0) { throw new IllegalArgumentException(); @@ -373,114 +387,5 @@ public abstract class AbstractBaseList implements List { throw new ConcurrentModificationException(); } } - - - private static class SubListItr implements ListIterator { - - private final AbstractBaseList base; - private int modCnt; - private int cur; - private int lower; - private int higher; - private int last; - - public SubListItr(AbstractBaseList 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(); - } - } - } } - } diff --git a/src/dev/asdf00/general/utils/list/internal/BooleanList.java b/src/dev/asdf00/general/utils/list/internal/BooleanList.java new file mode 100644 index 0000000..972780d --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/BooleanList.java @@ -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 { + + private boolean[] data; + + public BooleanList() { + data = new boolean[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/list/internal/ByteList.java b/src/dev/asdf00/general/utils/list/internal/ByteList.java index 70d905e..4b89ac2 100644 --- a/src/dev/asdf00/general/utils/list/internal/ByteList.java +++ b/src/dev/asdf00/general/utils/list/internal/ByteList.java @@ -32,6 +32,9 @@ public class ByteList extends PrimitiveList { @Override protected int indexOf(Object o, int start, int len) { + if (data == null) { + throw new NullPointerException(); + } if (!(o instanceof Byte)) { return -1; } @@ -46,6 +49,9 @@ public class ByteList extends PrimitiveList { @Override protected int lastIndexOf(Object o, int start, int len) { + if (data == null) { + throw new NullPointerException(); + } if (!(o instanceof Byte)) { return -1; } @@ -72,7 +78,7 @@ public class ByteList extends PrimitiveList { if (Integer.bitCount(size) == 1) { data = Arrays.copyOf(data, size); } 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); @@ -84,6 +90,16 @@ public class ByteList extends PrimitiveList { 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 public boolean addAll(Collection c) { modCnt++; @@ -127,38 +143,49 @@ public class ByteList extends PrimitiveList { @Override public void add(int index, Byte element) { - + Objects.checkIndex(index, size); + modCnt++; + createGap(index, 1); + directSet(index, element); } @Override public Byte remove(int index) { - return null; + Objects.checkIndex(index, size); + modCnt++; + byte result = data[index]; + closeGap(index, 1); + return result; } @Override public void addByte(byte value) { - + modCnt++; + if (size == data.length) { + data = Arrays.copyOf(data, data.length << 1); + } + directSet(size++, value); } @Override public byte getByte(int index) { - return 0; + Objects.checkIndex(index, size); + return data[index]; } @Override public byte[] toByteArray() { - return new byte[0]; + return Arrays.copyOf(data, size); } @Override public byte[] finalizeAsByteArray() { + if (data == null) { + throw new NullPointerException(); + } byte[] res = data; data = null; - AbstractBaseList.UNSAFE.putInt(data, AbstractBaseList.OFFSET_LEN, size); + AbstractBaseList.UNSAFE.putInt(res, AbstractBaseList.OFFSET_LEN, size); return res; } - - private void reallocateWithLen(int newLen) { - data = Arrays.copyOf(data, newLen); - } } diff --git a/src/dev/asdf00/general/utils/list/internal/CharacterList.java b/src/dev/asdf00/general/utils/list/internal/CharacterList.java new file mode 100644 index 0000000..3edbddb --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/CharacterList.java @@ -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 { + + private char[] data; + + public CharacterList() { + data = new char[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/list/internal/DoubleList.java b/src/dev/asdf00/general/utils/list/internal/DoubleList.java new file mode 100644 index 0000000..17a79e9 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/DoubleList.java @@ -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 { + + private double[] data; + + public DoubleList() { + data = new double[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/list/internal/FloatList.java b/src/dev/asdf00/general/utils/list/internal/FloatList.java new file mode 100644 index 0000000..481ec57 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/FloatList.java @@ -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 { + + private float[] data; + + public FloatList() { + data = new float[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/list/internal/IntegerList.java b/src/dev/asdf00/general/utils/list/internal/IntegerList.java new file mode 100644 index 0000000..1b7ac56 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/IntegerList.java @@ -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 { + + private int[] data; + + public IntegerList() { + data = new int[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/list/internal/LongList.java b/src/dev/asdf00/general/utils/list/internal/LongList.java new file mode 100644 index 0000000..6512624 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/LongList.java @@ -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 { + + private long[] data; + + public LongList() { + data = new long[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/list/internal/ShortList.java b/src/dev/asdf00/general/utils/list/internal/ShortList.java new file mode 100644 index 0000000..7c9ce02 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/ShortList.java @@ -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 { + + private short[] data; + + public ShortList() { + data = new short[8]; + size = 0; + modCnt = 0; + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected 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 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 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; + } +} diff --git a/src/dev/asdf00/general/utils/listOld/PrimitiveList.java b/src/dev/asdf00/general/utils/listOld/PrimitiveList.java deleted file mode 100644 index 53b7549..0000000 --- a/src/dev/asdf00/general/utils/listOld/PrimitiveList.java +++ /dev/null @@ -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 implements List, 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 PrimitiveList create(Class 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(); -} diff --git a/src/dev/asdf00/general/utils/listOld/internal/PrimitiveListImpl.java b/src/dev/asdf00/general/utils/listOld/internal/PrimitiveListImpl.java deleted file mode 100644 index cd0044e..0000000 --- a/src/dev/asdf00/general/utils/listOld/internal/PrimitiveListImpl.java +++ /dev/null @@ -1,1218 +0,0 @@ -package dev.asdf00.general.utils.listOld.internal; - -import dev.asdf00.general.utils.listOld.PrimitiveList; -import sun.misc.Unsafe; - -import java.lang.reflect.Field; -import java.util.*; - -public final class PrimitiveListImpl extends PrimitiveList { - - private static final Unsafe UNSAFE; - private static final long OFFSET; - private static final int KLASS_WORD_OFFSET; - private static final int KLASS_WORD_SIZE; - private static final int LENGTH_OFFSET; - - static { - try { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (Unsafe) f.get(null); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException(e); - } - OFFSET = UNSAFE.arrayBaseOffset(long[].class); - KLASS_WORD_OFFSET = UNSAFE.addressSize(); - KLASS_WORD_SIZE = UNSAFE.addressSize() == 4 || System.getProperty("java.vm.compressedOopsMode") != null ? 4 : 8; - LENGTH_OFFSET = KLASS_WORD_OFFSET + KLASS_WORD_SIZE; - } - - - private long[] rawData; - private int size; - private int modCount = 0; - private int type; - - private PrimitiveListImpl(int type) { - this.type = type; - rawData = new long[16 >> (0xFF & (type >> 16))]; - size = 0; - } - - public static PrimitiveListImpl create(Class boxedType) throws UnsupportedOperationException { - if (!isSupportedOnCurrentJVMConfiguration()) { - throw new UnsupportedOperationException("this list is not supported with your current JVM settings due to a mismatch in array index scales!"); - } - int type; - if (Byte.class.equals(boxedType)) { - type = 0x03_01_00; - } else if (Short.class.equals(boxedType)) { - type = 0x02_02_01; - } else if (Integer.class.equals(boxedType)) { - type = 0x01_04_02; - } else if (Long.class.equals(boxedType)) { - type = 0x00_08_03;; - } else if (Float.class.equals(boxedType)) { - type = 0x01_04_04; - } else if (Double.class.equals(boxedType)) { - type = 0x00_08_05; - } else if (Character.class.equals(boxedType)) { - type = 0x01_04_06; - } else if (Boolean.class.equals(boxedType)) { - type = 0x03_01_07; - } else { - throw new IllegalArgumentException("%s is not a boxed type!".formatted(boxedType)); - } - return new PrimitiveListImpl<>(type); - } - - - @Override - public boolean isFinalized() { - return type == -1; - } - - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return size < 1; - } - - @Override - public boolean contains(Object o) { - return indexOf(o) >= 0; - } - - @Override - public Iterator iterator() { - return listIterator(); - } - - @Override - public Object[] toArray() { - return toArray(Object[]::new); - } - - @Override - public T1[] toArray(T1[] a) { - return toArray(a, 0, size); - } - - @Override - public boolean add(T t) { - increaseSize(1); - directSet(size - 1, t); - return true; - } - - @Override - public boolean remove(Object o) { - int index = indexOf(o); - if (index >= 0) { - remove(index); - return true; - } - return false; - } - - @Override - public boolean containsAll(Collection c) { - BitSet checked = new BitSet(c.size()); - int i; - for (T element : this) { - i = 0; - for (Object inner : c) { - if (element.equals(inner)) { - checked.set(i); - } - } - } - for (i = 0; i < c.size(); i++) { - if (!checked.get(i)) { - return false; - } - } - return true; - } - - @Override - public boolean addAll(Collection c) { - int i = size; - increaseSize(c.size()); - for (T element : c) { - directSet(i++, element); - } - return true; - } - - @Override - public boolean addAll(int index, Collection c) { - Objects.checkIndex(index, size); - increaseSize(c.size()); - openGap(index, c.size()); - int i = index; - for (T element : c) { - directSet(i, element); - } - return true; - } - - @Override - public boolean removeAll(Collection c) { - for (int i = 0; i < size; i++) { - if (c.contains(get(i))) { - remove(i); - } - } - return true; - } - - @Override - public boolean retainAll(Collection c) { - for (int i = 0; i < size; i++) { - if (!c.contains(get(i))) { - remove(i); - } - } - return false; - } - - @Override - public void clear() { - checkFinalized(); - modCount++; - size = 0; - rawData = new long[16 >> (0xFF & (type >> 16))]; - } - - @Override - public T get(int index) { - Objects.checkIndex(index, size); - switch (0xFF & type) { - case 0: - return (T) Byte.valueOf(UNSAFE.getByte(rawData, OFFSET + index)); - case 1: - return (T) Short.valueOf(UNSAFE.getShort(rawData, OFFSET + (index << 1))); - case 2: - return (T) Integer.valueOf(UNSAFE.getInt(rawData, OFFSET + (index << 2))); - case 3: - return (T) Long.valueOf(UNSAFE.getLong(rawData, OFFSET + (index << 3))); - case 4: - return (T) Float.valueOf(UNSAFE.getFloat(rawData, OFFSET + (index << 2))); - case 5: - return (T) Double.valueOf(UNSAFE.getDouble(rawData, OFFSET + (index << 3))); - case 6: - return (T) Character.valueOf((char) UNSAFE.getInt(rawData, OFFSET + (index << 2))); - case 7: - return (T) Boolean.valueOf(UNSAFE.getByte(rawData, OFFSET + index) != 0); - default: - throw new IllegalStateException("this list has been finalized!"); - } - } - - @Override - public T set(int index, T element) { - Objects.checkIndex(index, size); - T prev = get(index); - directSet(index, element); - return prev; - } - - @Override - public void add(int index, T element) { - Objects.checkIndex(index, size); - increaseSize(1); - openGap(index, 1); - directSet(index, element); - } - - @Override - public T remove(int index) { - Objects.checkIndex(index, size); - T removed = get(index); - fillGap(index, 1); - size--; - return removed; - } - - @Override - public int indexOf(Object o) { - return indexOf(o, 0, size); - } - - @Override - public int lastIndexOf(Object o) { - return lastIndexOf(o, 0, size); - } - - @Override - public ListIterator listIterator() { - return new ListItr<>(this, 0); - } - - @Override - public ListIterator listIterator(int index) { - Objects.checkIndex(index, size); - return new ListItr<>(this, index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - Objects.checkIndex(fromIndex, size); - Objects.checkIndex(toIndex, size); - checkFinalized(); - if (fromIndex > toIndex) { - throw new IllegalArgumentException(); - } - return new SubList<>(this, fromIndex, toIndex); - } - - //====================================================== - // additional primitive access points - //====================================================== - @Override - public byte[] toByteArray() { - checkFinalized(); - int shift = 3 - (0xFF & (type >> 16)); - int targetSize = size << shift; - byte[] result = new byte[targetSize]; - UNSAFE.copyMemory(rawData, OFFSET, result, UNSAFE.arrayBaseOffset(byte[].class), targetSize); - return result; - } - - @Override - public short[] toShortArray() { - checkFinalized(); - int shift = 2 - (0xFF & (type >> 16)); - if (shift < 0) { - throw new UnsupportedOperationException("cannot transform this into short[]"); - } - int targetSize = size << shift; - short[] result = new short[targetSize]; - UNSAFE.copyMemory(rawData, OFFSET, result, UNSAFE.arrayBaseOffset(short[].class), targetSize << 1); - return result; - } - - @Override - public int[] toIntArray() { - checkFinalized(); - int shift = 1 - (0xFF & (type >> 16)); - if (shift < 0) { - throw new UnsupportedOperationException("cannot transform this into int[]"); - } - int targetSize = size << shift; - int[] result = new int[targetSize]; - UNSAFE.copyMemory(rawData, OFFSET, result, UNSAFE.arrayBaseOffset(int[].class), targetSize << 2); - return result; - } - - @Override - public long[] toLongArray() { - checkFinalized(); - if ((0xFF & (type >> 16)) != 0) { - throw new UnsupportedOperationException("cannot transform this into long[]"); - } - return Arrays.copyOf(rawData, size); - } - - @Override - public float[] toFloatArray() { - checkFinalized(); - int shift = 1 - (0xFF & (type >> 16)); - if (shift < 0) { - throw new UnsupportedOperationException("cannot this transform into float[]"); - } - int targetSize = size << shift; - float[] result = new float[targetSize]; - UNSAFE.copyMemory(rawData, OFFSET, result, UNSAFE.arrayBaseOffset(float[].class), size << 2); - return result; - } - - @Override - public double[] toDoubleArray() { - checkFinalized(); - if ((0xFF & (type >> 16)) != 0) { - throw new UnsupportedOperationException("cannot transform this into double[]"); - } - double[] result = new double[size]; - UNSAFE.copyMemory(rawData, OFFSET, result, UNSAFE.arrayBaseOffset(byte[].class), size << 3); - return result; - } - - @Override - public char[] toCharArray() { - checkFinalized(); - int shift = 1 - (0xFF & (type >> 16)); - if (shift < 0) { - throw new UnsupportedOperationException("cannot transform this into char[]"); - } - int targetSize = size << shift; - char[] result = new char[targetSize]; - for (int i = 0; i < targetSize; i++) { - result[i] = (char) UNSAFE.getInt(rawData, OFFSET + (i << 2)); - } - return result; - } - - @Override - public boolean[] toBooleanArray() { - checkFinalized(); - int shift = 3 - (0xFF & (type >> 16)); - int targetSize = size << shift; - boolean[] result = new boolean[targetSize]; - for (int i = 0; i < targetSize; i++) { - result[i] = UNSAFE.getByte(rawData, OFFSET + i) != 0; - } - return result; - } - - @Override - public byte getByte(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 0) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Byte!"); - } - return UNSAFE.getByte(rawData, OFFSET + index); - } - - @Override - public short getShort(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 1) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Short!"); - } - return UNSAFE.getShort(rawData, OFFSET + (index << 1)); - } - - @Override - public int getInt(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 2) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Integer!"); - } - return UNSAFE.getInt(rawData, OFFSET + (index << 2)); - } - - @Override - public long getLong(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 3) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Long!"); - } - return UNSAFE.getLong(rawData, OFFSET + (index << 3)); - } - - @Override - public float getFloat(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 4) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Float!"); - } - return UNSAFE.getFloat(rawData, OFFSET + (index << 2)); - } - - @Override - public double getDouble(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 5) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Double!"); - } - return UNSAFE.getDouble(rawData, OFFSET + (index << 3)); - } - - @Override - public char getChar(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 6) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Character!"); - } - return (char) UNSAFE.getInt(rawData, OFFSET + (index << 2)); - } - - @Override - public boolean getBoolean(int index) { - Objects.checkIndex(index, size); - if ((0xFF & type) != 7) { - checkFinalized(); - throw new UnsupportedOperationException("this list is not of type Boolean!"); - } - return UNSAFE.getByte(rawData, OFFSET + index) != 0; - } - - @Override - public byte[] finalizeAsByteArray() { - checkFinalized(); - if ((0xFF & type) != 0) { - throw new UnsupportedOperationException("this list is not of type Byte!"); - } - rewriteArrayHeader(new byte[0]); - return (byte[]) (Object) rawData; - } - - @Override - public short[] finalizeAsShortArray() { - checkFinalized(); - if ((0xFF & type) != 1) { - throw new UnsupportedOperationException("this list is not of type Short!"); - } - rewriteArrayHeader(new short[0]); - return (short[]) (Object) rawData; - } - - @Override - public int[] finalizeAsIntArray() { - checkFinalized(); - if ((0xFF & type) != 2) { - throw new UnsupportedOperationException("this list is not of type Integer!"); - } - rewriteArrayHeader(new int[0]); - return (int[]) (Object) rawData; - } - - @Override - public long[] finalizeAsLongArray() { - checkFinalized(); - if ((0xFF & type) != 3) { - throw new UnsupportedOperationException("this list is not of type Long!"); - } - rewriteArrayHeader(new long[0]); - return rawData; - } - - @Override - public float[] finalizeAsFloatArray() { - checkFinalized(); - if ((0xFF & type) != 4) { - throw new UnsupportedOperationException("this list is not of type Float!"); - } - rewriteArrayHeader(new float[0]); - return (float[]) (Object) rawData; - } - - @Override - public double[] finalizeAsDoubleArray() { - checkFinalized(); - if ((0xFF & type) != 5) { - throw new UnsupportedOperationException("this list is not of type Float!"); - } - rewriteArrayHeader(new double[0]); - return (double[]) (Object) rawData; - } - - //====================================================== - // private helper methods - //====================================================== - private void rewriteArrayHeader(Object emptyArrayInstance) { - type = -1; - if (KLASS_WORD_SIZE == 4) { - UNSAFE.putInt(rawData, KLASS_WORD_OFFSET, UNSAFE.getInt(emptyArrayInstance, KLASS_WORD_OFFSET)); - } else { - UNSAFE.putLong(rawData, KLASS_WORD_OFFSET, UNSAFE.getLong(emptyArrayInstance, KLASS_WORD_OFFSET)); - } - UNSAFE.putInt(rawData, LENGTH_OFFSET, size); - } - - private void checkFinalized() { - if (type == -1) { - throw new IllegalStateException("this list has been finalized!"); - } - } - - private void increaseSize(int by) { - checkFinalized(); - if (Integer.MAX_VALUE - by < size) { - throw new IllegalStateException("size reached integer overflow!"); - } - int shiftBy = type >> 16; - // shiftBy gets implicitly masked to 0x1F - int capacity = rawData.length << shiftBy; - size += by; - if (capacity < size) { - capacity = Integer.highestOneBit(size); - if (capacity != size) { - capacity <<= 1; - } - rawData = Arrays.copyOf(rawData, capacity >> shiftBy); - } - } - - private void directSet(int index, T element) { - modCount++; - switch (0xFF & type) { - case 0: - UNSAFE.putByte(rawData, OFFSET + index, ((Byte) element).byteValue()); - return; - case 1: - UNSAFE.putShort(rawData, OFFSET + (index << 1), ((Short) element).shortValue()); - return; - case 2: - UNSAFE.putInt(rawData, OFFSET + (index << 2), ((Integer) element).intValue()); - return; - case 3: - UNSAFE.putLong(rawData, OFFSET + (index << 3), ((Long) element).longValue()); - return; - case 4: - UNSAFE.putFloat(rawData, OFFSET + (index << 2), ((Float) element).floatValue()); - return; - case 5: - UNSAFE.putDouble(rawData, OFFSET + (index << 3), ((Double) element).doubleValue()); - return; - case 6: - UNSAFE.putInt(rawData, OFFSET + (index << 2), ((Character) element).charValue()); - return; - case 7: - UNSAFE.putByte(rawData, OFFSET + index, ((Boolean) element) ? (byte) 1 : (byte) 0); - return; - default: - throw new IllegalStateException("this list has been finalized!"); - } - } - - private void fillGap(int at, int gapSize) { - modCount++; - switch (0xFF & (type >> 16)) { - case 3: // byte sized elements - for (int i = at; i + gapSize < size; i++) { - UNSAFE.putByte(rawData, OFFSET + i, UNSAFE.getByte(rawData, OFFSET + i + gapSize)); - } - break; - case 2: // short sized elements - for (int i = at; i + gapSize < size; i++) { - UNSAFE.putShort(rawData, OFFSET + (i << 1), UNSAFE.getShort(rawData, OFFSET + ((i + gapSize) << 1))); - } - break; - case 1: // int sized elements - for (int i = at; i + gapSize < size; i++) { - UNSAFE.putInt(rawData, OFFSET + (i << 2), UNSAFE.getInt(rawData, OFFSET + ((i + gapSize) << 2))); - } - break; - case 0: // long sized elements - for (int i = at; i + gapSize < size; i++) { - UNSAFE.putLong(rawData, OFFSET + (i << 3), UNSAFE.getLong(rawData, OFFSET + ((i + gapSize) << 3))); - } - break; - default: - throw new IllegalStateException("this list has been finalized!"); - } - } - - private void openGap(int at, int gapSize) { - modCount++; - switch (0xFF & (type >> 16)) { - case 3: // byte sized elements - for (int i = size - 1; i - gapSize >= at; i--) { - UNSAFE.putByte(rawData, OFFSET + i, UNSAFE.getByte(rawData, OFFSET + i - gapSize)); - } - break; - case 2: // short sized elements - for (int i = size - 1; i - gapSize >= at; i--) { - UNSAFE.putShort(rawData, OFFSET + (i << 1), UNSAFE.getShort(rawData, OFFSET + ((i - gapSize) << 1))); - } - break; - case 1: // int sized elements - for (int i = size - 1; i - gapSize >= at; i--) { - UNSAFE.putInt(rawData, OFFSET + (i << 2), UNSAFE.getInt(rawData, OFFSET + ((i - gapSize) << 2))); - } - break; - case 0: // long sized elements - for (int i = size - 1; i - gapSize >= at; i--) { - UNSAFE.putLong(rawData, OFFSET + (i << 3), UNSAFE.getLong(rawData, OFFSET + ((i - gapSize) << 3))); - } - break; - default: - throw new IllegalStateException("this list has been finalized!"); - } - } - - private T1[] toArray(T1[] a, int from, int to) { - Object[] dest = Arrays.copyOf(a, to - from, a.getClass()); - switch (0xFF & type) { - case 0: - for (int i = from; i < to; i++) { - dest[i] = Byte.valueOf(UNSAFE.getByte(rawData, OFFSET + i)); - } - break; - case 1: - for (int i = from; i < to; i++) { - dest[i] = Short.valueOf(UNSAFE.getShort(rawData, OFFSET + i * 2)); - } - break; - case 2: - for (int i = from; i < to; i++) { - dest[i] = Integer.valueOf(UNSAFE.getInt(rawData, OFFSET + i * 4)); - } - break; - case 3: - for (int i = from; i < to; i++) { - dest[i] = Long.valueOf(UNSAFE.getLong(rawData, OFFSET + i * 8)); - } - break; - case 4: - for (int i = from; i < to; i++) { - dest[i] = Float.valueOf(UNSAFE.getFloat(rawData, OFFSET + i * 4)); - } - break; - case 5: - for (int i = from; i < to; i++) { - dest[i] = Double.valueOf(UNSAFE.getDouble(rawData, OFFSET + i * 8)); - } - break; - case 6: - for (int i = from; i < to; i++) { - dest[i] = Character.valueOf((char) UNSAFE.getInt(rawData, OFFSET + i * 4)); - } - break; - case 7: - for (int i = from; i < to; i++) { - dest[i] = Boolean.valueOf(UNSAFE.getByte(rawData, OFFSET + i) == 1); - } - break; - default: - throw new IllegalStateException("this list has been finalized!"); - } - return (T1[]) dest; - } - - private int indexOf(Object o, int from, int to) { - switch (0xFF & type) { - case 0: { - byte target = ((Byte) o).byteValue(); - for (int i = from; i < to; i++) { - if (target == UNSAFE.getByte(rawData, OFFSET + i)) { - return i; - } - } - break; - } - case 1: { - short target = ((Short) o).shortValue(); - for (int i = from; i < to; i++) { - if (target == UNSAFE.getShort(rawData, OFFSET + (i << 1))) { - return i; - } - } - break; - } - case 2: { - int target = ((Integer) o).intValue(); - for (int i = from; i < to; i++) { - if (target == UNSAFE.getInt(rawData, OFFSET + (i << 2))) { - return i; - } - } - break; - } - case 3: { - long target = ((Long) o).longValue(); - for (int i = from; i < to; i++) { - if (target == UNSAFE.getLong(rawData, OFFSET + (i << 3))) { - return i; - } - } - break; - } - case 4: { - float target = ((Float) o).floatValue(); - for (int i = from; i < to; i++) { - if (Float.compare(target, UNSAFE.getFloat(rawData, OFFSET + (i << 2))) == 0) { - return i; - } - } - break; - } - case 5: { - double target = ((Double) o).doubleValue(); - for (int i = from; i < to; i++) { - if (Double.compare(target, UNSAFE.getDouble(rawData, OFFSET + (i << 3))) == 0) { - return i; - } - } - break; - } - case 6: { - int target = ((Character) o).charValue(); - for (int i = from; i < to; i++) { - if (target == UNSAFE.getInt(rawData, OFFSET + (i << 2))) { - return i; - } - } - break; - } - case 7: { - byte target = ((Boolean) o) ? (byte) 1 : (byte) 0; - for (int i = from; i < to; i++) { - if (target == UNSAFE.getByte(rawData, OFFSET + i)) { - return i; - } - } - break; - } - default: - throw new IllegalStateException("this list has been finalized!"); - } - return -1; - } - - private int lastIndexOf(Object o, int from, int to) { - switch (0xFF & type) { - case 0: { - byte target = ((Byte) o).byteValue(); - for (int i = to - 1; i >= from; i--) { - if (target == UNSAFE.getByte(rawData, OFFSET + i)) { - return i; - } - } - break; - } - case 1: { - short target = ((Short) o).shortValue(); - for (int i = to - 1; i >= from; i--) { - if (target == UNSAFE.getShort(rawData, OFFSET + (i << 1))) { - return i; - } - } - break; - } - case 2: { - int target = ((Integer) o).intValue(); - for (int i = to - 1; i >= from; i--) { - if (target == UNSAFE.getInt(rawData, OFFSET + (i << 2))) { - return i; - } - } - break; - } - case 3: { - long target = ((Long) o).longValue(); - for (int i = to - 1; i >= from; i--) { - if (target == UNSAFE.getLong(rawData, OFFSET + (i << 3))) { - return i; - } - } - break; - } - case 4: { - float target = ((Float) o).floatValue(); - for (int i = to - 1; i >= from; i--) { - if (Float.compare(target, UNSAFE.getFloat(rawData, OFFSET + (i << 2))) == 0) { - return i; - } - } - break; - } - case 5: { - double target = ((Double) o).doubleValue(); - for (int i = to - 1; i >= from; i--) { - if (Double.compare(target, UNSAFE.getDouble(rawData, OFFSET + (i << 3))) == 0) { - return i; - } - } - break; - } - case 6: { - int target = ((Character) o).charValue(); - for (int i = to - 1; i >= from; i--) { - if (target == UNSAFE.getInt(rawData, OFFSET + (i << 2))) { - return i; - } - } - break; - } - case 7: { - byte target = ((Boolean) o) ? (byte) 1 : (byte) 0; - for (int i = to - 1; i >= from; i--) { - if (target == UNSAFE.getByte(rawData, OFFSET + i)) { - return i; - } - } - break; - } - default: - throw new IllegalStateException("this list has been finalized!"); - } - return -1; - } - - //====================================================== - // internal classes - //====================================================== - private static class ListItr implements ListIterator { - private final PrimitiveListImpl parent; - private int cur; - private int expectedModCount; - - public ListItr(PrimitiveListImpl parent, int startingAt) { - if (parent.type == -1) { - throw new IllegalStateException("this list has been finalized!"); - } - this.parent = parent; - cur = startingAt; - expectedModCount = parent.modCount; - } - - @Override - public boolean hasNext() { - return cur < parent.size; - } - - @Override - public E next() { - checkForConcurrentModification(); - return parent.get(cur++); - } - - @Override - public boolean hasPrevious() { - return cur > 0; - } - - @Override - public E previous() { - checkForConcurrentModification(); - return parent.get(--cur); - } - - @Override - public int nextIndex() { - return cur; - } - - @Override - public int previousIndex() { - return cur - 1; - } - - @Override - public void remove() { - checkForConcurrentModification(); - parent.remove(cur); - expectedModCount++; - } - - @Override - public void set(E e) { - checkForConcurrentModification(); - parent.set(cur, e); - expectedModCount++; - } - - @Override - public void add(E e) { - checkForConcurrentModification(); - parent.add(cur, e); - expectedModCount += 2; - } - - private void checkForConcurrentModification() { - if (parent.modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - } - - private static class SubList implements List { - private final PrimitiveListImpl baseList; - private final int start; - private int to; - private int expectedModCount; - - public SubList(PrimitiveListImpl baseList, int start, int to) { - this.baseList = baseList; - this.start = start; - this.to = to; - expectedModCount = baseList.modCount; - } - - @Override - public int size() { - return to - start; - } - - @Override - public boolean isEmpty() { - return size() < 1; - } - - @Override - public boolean contains(Object o) { - checkForConcurrentModification(); - return indexOf(o) >= 0; - } - - @Override - public Iterator iterator() { - return listIterator(); - } - - @Override - public Object[] toArray() { - return toArray(Object[]::new); - } - - @Override - public T[] toArray(T[] a) { - checkForConcurrentModification(); - return baseList.toArray(a, start, to); - } - - @Override - public boolean add(E e) { - checkForConcurrentModification(); - expectedModCount += 2; - baseList.add(to, e); - to++; - return true; - } - - @Override - public boolean remove(Object o) { - checkForConcurrentModification(); - int index = indexOf(o); - if (index >= 0) { - remove(index); - return true; - } - return false; - } - - @Override - public boolean containsAll(Collection c) { - checkForConcurrentModification(); - BitSet checked = new BitSet(c.size()); - int i; - for (E element : this) { - i = 0; - for (Object inner : c) { - if (element.equals(inner)) { - checked.set(i); - } - } - } - for (i = 0; i < c.size(); i++) { - if (!checked.get(i)) { - return false; - } - } - return true; - } - - @Override - public boolean addAll(Collection c) { - checkForConcurrentModification(); - expectedModCount += 1 + c.size(); - baseList.addAll(to, c); - to += c.size(); - return true; - } - - @Override - public boolean addAll(int index, Collection c) { - Objects.checkIndex(index, size()); - checkForConcurrentModification(); - expectedModCount += 1 + c.size(); - baseList.addAll(start + index, c); - to += c.size(); - return true; - } - - @Override - public boolean removeAll(Collection c) { - checkForConcurrentModification(); - for (int i = 0; i < size(); i++) { - if (c.contains(get(i))) { - remove(i); - } - } - return true; - } - - @Override - public boolean retainAll(Collection c) { - for (int i = 0; i < size(); i++) { - if (!c.contains(get(i))) { - remove(i); - } - } - return true; - } - - @Override - public void clear() { - checkForConcurrentModification(); - baseList.fillGap(start, size()); - baseList.size -= size(); - expectedModCount++; - to = start; - } - - @Override - public E get(int index) { - Objects.checkIndex(index, size()); - checkForConcurrentModification(); - return get(start + index); - } - - @Override - public E set(int index, E element) { - Objects.checkIndex(index, size()); - checkForConcurrentModification(); - expectedModCount++; - return baseList.set(start + index, element); - } - - @Override - public void add(int index, E element) { - Objects.checkIndex(index, size()); - checkForConcurrentModification(); - expectedModCount += 2; - baseList.add(start, element); - } - - @Override - public E remove(int index) { - Objects.checkIndex(index, size()); - checkForConcurrentModification(); - expectedModCount++; - E result = baseList.get(start + index); - baseList.remove(start + index); - return result; - } - - @Override - public int indexOf(Object o) { - checkForConcurrentModification(); - return baseList.indexOf(o, start, to); - } - - @Override - public int lastIndexOf(Object o) { - checkForConcurrentModification(); - return baseList.lastIndexOf(o, start, to); - } - - @Override - public ListIterator listIterator() { - checkForConcurrentModification(); - return new InnerIterator<>(this, start); - } - - @Override - public ListIterator listIterator(int index) { - Objects.checkIndex(index, size()); - checkForConcurrentModification(); - return new InnerIterator<>(this, start + index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - if (fromIndex > toIndex) { - throw new IllegalArgumentException(); - } - Objects.checkIndex(fromIndex, size()); - Objects.checkIndex(toIndex, size()); - checkForConcurrentModification(); - return new SubList<>(baseList, start + fromIndex, start + fromIndex + toIndex); - } - - private void checkForConcurrentModification() { - if (baseList.modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - private static class InnerIterator implements ListIterator { - private final SubList parent; - private int cur; - private int expectedModCount; - - public InnerIterator(SubList parent, int startingAtBase) { - this.parent = parent; - cur = startingAtBase; - expectedModCount = parent.expectedModCount; - } - - @Override - public boolean hasNext() { - return cur < parent.to; - } - - @Override - public E next() { - checkBounds(cur); - checkForConcurrentModification(); - return parent.baseList.get(cur++); - } - - @Override - public boolean hasPrevious() { - return cur > parent.start; - } - - @Override - public E previous() { - checkBounds(cur); - checkForConcurrentModification(); - return parent.baseList.get(--cur); - } - - @Override - public int nextIndex() { - return cur; - } - - @Override - public int previousIndex() { - return cur - 1; - } - - @Override - public void remove() { - checkBounds(cur); - checkForConcurrentModification(); - expectedModCount++; - parent.baseList.remove(cur); - } - - @Override - public void set(E e) { - checkBounds(cur); - checkForConcurrentModification(); - expectedModCount++; - parent.baseList.set(cur, e); - } - - @Override - public void add(E e) { - checkBounds(cur); - checkForConcurrentModification(); - expectedModCount += 2; - parent.baseList.add(cur, e); - } - - private void checkForConcurrentModification() { - if (parent.baseList.modCount != expectedModCount) { - throw new ConcurrentModificationException(); - } - } - - private void checkBounds(int index) { - if (index < parent.start || index >= parent.to) { - throw new IndexOutOfBoundsException(); - } - } - } - } - -} diff --git a/src/module-info.java b/src/module-info.java index f003344..e9f306d 100644 --- a/src/module-info.java +++ b/src/module-info.java @@ -1,5 +1,4 @@ module GeneralUtils { requires jdk.unsupported; - exports dev.asdf00.general.utils.listOld; exports dev.asdf00.general.utils.list; } \ No newline at end of file diff --git a/test/dev/asdf00/general/utils/list/TestList.java b/test/dev/asdf00/general/utils/list/TestList.java new file mode 100644 index 0000000..e673f5a --- /dev/null +++ b/test/dev/asdf00/general/utils/list/TestList.java @@ -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 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 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 toBoxedBytes(byte[] array) { + var result = new ArrayList(array.length); + for (byte b : array) { + result.add(b); + } + return result; + } +} diff --git a/test/dev/asdf00/general/utils/list/internal/ListReader.java b/test/dev/asdf00/general/utils/list/internal/ListReader.java new file mode 100644 index 0000000..e6d74cc --- /dev/null +++ b/test/dev/asdf00/general/utils/list/internal/ListReader.java @@ -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); + } + } +}