From e49993f88a26b2475e527299aa7c35e375778de5 Mon Sep 17 00:00:00 2001 From: 00asdf Date: Tue, 18 Apr 2023 04:36:04 +0200 Subject: [PATCH] initial commit --- .gitignore | 31 + GeneralUtils.iml | 11 + .../general/utils/list/PrimitiveList.java | 162 +++ .../utils/list/internal/AbstractBaseList.java | 489 +++++++ .../general/utils/list/internal/ByteList.java | 97 ++ .../general/utils/listOld/PrimitiveList.java | 79 ++ .../listOld/internal/PrimitiveListImpl.java | 1218 +++++++++++++++++ src/module-info.java | 5 + 8 files changed, 2092 insertions(+) create mode 100644 .gitignore create mode 100644 GeneralUtils.iml create mode 100644 src/dev/asdf00/general/utils/list/PrimitiveList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java create mode 100644 src/dev/asdf00/general/utils/list/internal/ByteList.java create mode 100644 src/dev/asdf00/general/utils/listOld/PrimitiveList.java create mode 100644 src/dev/asdf00/general/utils/listOld/internal/PrimitiveListImpl.java create mode 100644 src/module-info.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0683b2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store + +.idea \ No newline at end of file diff --git a/GeneralUtils.iml b/GeneralUtils.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/GeneralUtils.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ 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 new file mode 100644 index 0000000..9be2b45 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/PrimitiveList.java @@ -0,0 +1,162 @@ +package dev.asdf00.general.utils.list; + +import dev.asdf00.general.utils.list.internal.AbstractBaseList; +import dev.asdf00.general.utils.list.internal.ByteList; + +public abstract class PrimitiveList extends AbstractBaseList { + + public static PrimitiveList create(Class type) { + return create(type, 8); + } + + public static PrimitiveList create(Class boxedType, int initial) { + if (Byte.class == boxedType) { + return (PrimitiveList) new ByteList(initial); + } 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 { + throw new IllegalArgumentException("%s is not a boxed type!".formatted(boxedType)); + } + } + + public void addByte(byte value) { + throw new UnsupportedOperationException("this list is not of type Byte!"); + } + + public void addShort(short value) { + throw new UnsupportedOperationException("this list is not of type Short!"); + } + + public void addInt(int value) { + throw new UnsupportedOperationException("this list is not of type Integer!"); + } + + public void addLong(long value) { + throw new UnsupportedOperationException("this list is not of type Long!"); + } + + public void addFloat(float value) { + throw new UnsupportedOperationException("this list is not of type Float!"); + } + + public void addDouble(double value) { + throw new UnsupportedOperationException("this list is not of type Double!"); + } + + public void addChar(char value) { + throw new UnsupportedOperationException("this list is not of type Character!"); + } + + public void addBoolean(boolean value) { + throw new UnsupportedOperationException("this list is not of type Boolean!"); + } + + public byte getByte(int index) { + throw new UnsupportedOperationException("this list is not of type Byte!"); + } + + public short getShort(int index) { + throw new UnsupportedOperationException("this list is not of type Short!"); + } + + public int getInt(int index) { + throw new UnsupportedOperationException("this list is not of type Integer!"); + } + + public long getLong(int index) { + throw new UnsupportedOperationException("this list is not of type Long!"); + } + + public float getFloat(int index) { + throw new UnsupportedOperationException("this list is not of type Float!"); + } + + public double getDouble(int index) { + throw new UnsupportedOperationException("this list is not of type Double!"); + } + + public char getChar(int index) { + throw new UnsupportedOperationException("this list is not of type Character!"); + } + + public boolean getBoolean(int index) { + throw new UnsupportedOperationException("this list is not of type Boolean!"); + } + public byte[] toByteArray() { + throw new UnsupportedOperationException("this list is not of type Byte!"); + } + + public short[] toShortArray() { + throw new UnsupportedOperationException("this list is not of type Short!"); + } + + public int[] toIntArray() { + throw new UnsupportedOperationException("this list is not of type Integer!"); + } + + public long[] toLongArray() { + throw new UnsupportedOperationException("this list is not of type Long!"); + } + + public float[] toFloatArray() { + throw new UnsupportedOperationException("this list is not of type Float!"); + } + + public double[] toDoubleArray() { + throw new UnsupportedOperationException("this list is not of type Double!"); + } + + public char[] toCharArray() { + throw new UnsupportedOperationException("this list is not of type Character!"); + } + + public boolean[] toBooleanArray() { + throw new UnsupportedOperationException("this list is not of type Boolean!"); + } + + public byte[] finalizeAsByteArray() { + throw new UnsupportedOperationException("this list is not of type Byte!"); + } + + public short[] finalizeAsShortArray() { + throw new UnsupportedOperationException("this list is not of type Short!"); + } + + public int[] finalizeAsIntArray() { + throw new UnsupportedOperationException("this list is not of type Integer!"); + } + + public long[] finalizeAsLongArray() { + throw new UnsupportedOperationException("this list is not of type Long!"); + } + + public float[] finalizeAsFloatArray() { + throw new UnsupportedOperationException("this list is not of type Float!"); + } + + public double[] finalizeAsDoubleArray() { + throw new UnsupportedOperationException("this list is not of type Double!"); + } + + public char[] finalizeAsCharArray() { + throw new UnsupportedOperationException("this list is not of type Character!"); + } + + public boolean[] finalizeAsBooleanArray() { + throw new UnsupportedOperationException("this list is not of type Boolean!"); + } + + public abstract boolean isFinalized(); +} diff --git a/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java b/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java new file mode 100644 index 0000000..2205115 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/AbstractBaseList.java @@ -0,0 +1,489 @@ +package dev.asdf00.general.utils.list.internal; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; +import java.util.*; + +public abstract class AbstractBaseList implements List { + + static final Unsafe UNSAFE; + static final long OFFSET_LEN; + + static { + try { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (Unsafe) f.get(null); + // OFFSET_LEN = sizeof(mark-word) + sizeof(klass-ptr) + OFFSET_LEN = UNSAFE.addressSize() + (UNSAFE.addressSize() == 8 && System.getProperty("java.vm.compressedOopsMode") == null ? 8 : 4); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + protected int size; + protected int modCnt; + + @Override + public Object[] toArray() { + return toArray(Object[]::new); + } + + @Override + public T1[] toArray(T1[] a) { + return toArray(a, 0, size); + } + + @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 boolean containsAll(Collection c) { + for (Object o : c) { + if (!contains(o)) { + return false; + } + } + return true; + } + + @Override + public T remove(int index) { + Objects.checkIndex(index, size); + return remove(index, 0, size); + } + + @Override + public boolean remove(Object o) { + int index = indexOf(o); + if (index >= 0) { + remove(index); + return true; + } + return false; + } + + @Override + public boolean removeAll(Collection c) { + boolean changed = false; + for (Object o : c) { + changed = remove(o) || changed; + } + return changed; + } + + @Override + public boolean retainAll(Collection c) { + boolean changed = false; + ListIterator itr = listIterator(); + while (itr.hasNext()) { + if (c.contains(itr.next())) { + itr.remove(); + changed = true; + } + } + return changed; + } + + @Override + public int indexOf(Object o) { + return indexOf(o, 0, size); + } + + @Override + public int lastIndexOf(Object o) { + return lastIndexOf(o, 0, size); + } + + @Override + public T set(int index, T element) { + Objects.checkIndex(index, size); + return directSet(index, element); + } + + @Override + public boolean add(T t) { + directSet(size++, t); + return true; + } + + @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(fromIndex, toIndex); + int len = (toIndex - fromIndex) + 1; + if (len < 0) { + throw new IllegalArgumentException(); + } + return new SubList<>(this, fromIndex, len); + } + + protected abstract T1[] toArray(T1[] a, int start, int len); + + protected abstract T remove(Object o, int start, int len); + + protected abstract int indexOf(Object o, int start, int len); + + protected abstract int lastIndexOf(Object o, int start, int len); + + protected abstract T directSet(int index, T element); + + protected abstract void removeRange(int start, int len); + + + private static class ListItr implements ListIterator { + + private final AbstractBaseList base; + private int modCnt; + private int cur; + private int last; + + public ListItr(AbstractBaseList base, int start) { + this.base = base; + modCnt = base.modCnt; + cur = start; + last = -1; + } + + @Override + public boolean hasNext() { + return cur < base.size; + } + + @Override + public E next() { + checkConcurrentModification(); + if (!hasNext()) { + throw new IndexOutOfBoundsException(); + } + last = cur; + return base.get(cur++); + } + + @Override + public boolean hasPrevious() { + return cur > 1; + } + + @Override + public E previous() { + checkConcurrentModification(); + if (!hasPrevious()) { + throw new IndexOutOfBoundsException(); + } + last = --cur; + return base.get(cur); + } + + @Override + public int nextIndex() { + return cur; + } + + @Override + public int previousIndex() { + return cur - 1; + } + + @Override + public void remove() { + checkConcurrentModification(); + Objects.checkIndex(cur, base.size); + if (last == -1) { + throw new IllegalStateException(); + } + modCnt++; + base.remove(--cur); + last = -1; + } + + @Override + public void set(E e) { + checkConcurrentModification(); + Objects.checkIndex(cur, base.size); + if (last == -1) { + throw new IllegalStateException(); + } + modCnt++; + base.set(cur, e); + last = -1; + } + + @Override + public void add(E e) { + checkConcurrentModification(); + Objects.checkIndex(cur, base.size); + if (last == -1) { + throw new IllegalStateException(); + } + modCnt++; + base.add(cur, e); + last = -1; + } + + private void checkConcurrentModification() { + if (base.modCnt != modCnt) { + throw new ConcurrentModificationException(); + } + } + } + + private static class SubList extends AbstractBaseList { + + private final AbstractBaseList base; + private final int start; + + public SubList(AbstractBaseList base, int start, int size) { + this.base = base; + this.start = start; + this.size = size; + modCnt = base.modCnt; + } + + @Override + public boolean addAll(Collection c) { + for (E e : c) { + add(e); + } + return c.size() > 0; + } + + @Override + public boolean addAll(int index, Collection c) { + Objects.checkIndex(index, size); + int i = 0; + for (E e : c) { + add(i, e); + } + return false; + } + + @Override + public void clear() { + checkConcurrentModification(); + modCnt++; + base.removeRange(start, size); + size = 0; + } + + @Override + public E get(int index) { + checkConcurrentModification(); + Objects.checkIndex(index, size); + return base.get(start + index); + } + + @Override + public void add(int index, E element) { + checkConcurrentModification(); + Objects.checkIndex(index, size); + modCnt++; + base.add(start + index, element); + } + + @Override + public ListIterator listIterator() { + return new SubListItr<>(base, start, start, start + (size - 1)); + } + + @Override + public ListIterator listIterator(int index) { + Objects.checkIndex(index, size); + return new SubListItr<>(base, start + index, start, start + (size - 1)); + } + + @Override + public List subList(int fromIndex, int toIndex) { + checkConcurrentModification(); + Objects.checkIndex(fromIndex, size); + Objects.checkIndex(toIndex, size); + int len = (toIndex - fromIndex) + 1; + if (len < 0) { + throw new IllegalArgumentException(); + } + return new SubList<>(base, start + fromIndex, len); + } + + @Override + protected T1[] toArray(T1[] a, int start, int len) { + checkConcurrentModification(); + modCnt++; + return base.toArray(a, this.start + start, len); + } + + @Override + protected E remove(Object o, int start, int len) { + checkConcurrentModification(); + modCnt++; + return base.remove(o, this.start + start, len); + } + + @Override + protected int indexOf(Object o, int start, int len) { + checkConcurrentModification(); + return base.indexOf(o, this.start + start, len); + } + + @Override + protected int lastIndexOf(Object o, int start, int len) { + checkConcurrentModification(); + return base.lastIndexOf(o, this.start + start, len); + } + + @Override + protected E directSet(int index, E element) { + checkConcurrentModification(); + modCnt++; + return base.directSet(index, element); + } + + @Override + protected void removeRange(int start, int len) { + throw new UnsupportedOperationException(); + } + + private void checkConcurrentModification() { + if (base.modCnt != modCnt) { + 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/ByteList.java b/src/dev/asdf00/general/utils/list/internal/ByteList.java new file mode 100644 index 0000000..2567f85 --- /dev/null +++ b/src/dev/asdf00/general/utils/list/internal/ByteList.java @@ -0,0 +1,97 @@ +package dev.asdf00.general.utils.list.internal; + +import dev.asdf00.general.utils.list.PrimitiveList; + +import java.util.Collection; + +public class ByteList extends PrimitiveList { + + private byte[] data; + + public ByteList(int initial) { + + } + + @Override + public boolean isFinalized() { + return data == null; + } + + @Override + protected T1[] toArray(T1[] a, int start, int len) { + return null; + } + + @Override + protected Boolean remove(Object o, int start, int len) { + return null; + } + + @Override + protected int indexOf(Object o, int start, int len) { + return 0; + } + + @Override + protected int lastIndexOf(Object o, int start, int len) { + return 0; + } + + @Override + protected Boolean directSet(int index, Boolean element) { + return null; + } + + @Override + protected void removeRange(int start, int len) { + + } + + @Override + public boolean addAll(Collection c) { + return false; + } + + @Override + public boolean addAll(int index, Collection c) { + return false; + } + + @Override + public void clear() { + + } + + @Override + public Boolean get(int index) { + return null; + } + + @Override + public void add(int index, Boolean element) { + + } + + @Override + public void addByte(byte value) { + + } + + @Override + public byte getByte(int index) { + return 0; + } + + @Override + public byte[] toByteArray() { + return new byte[0]; + } + + @Override + public byte[] finalizeAsByteArray() { + byte[] res = data; + data = null; + AbstractBaseList.UNSAFE.putInt(data, 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 new file mode 100644 index 0000000..53b7549 --- /dev/null +++ b/src/dev/asdf00/general/utils/listOld/PrimitiveList.java @@ -0,0 +1,79 @@ +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 new file mode 100644 index 0000000..cd0044e --- /dev/null +++ b/src/dev/asdf00/general/utils/listOld/internal/PrimitiveListImpl.java @@ -0,0 +1,1218 @@ +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 new file mode 100644 index 0000000..f003344 --- /dev/null +++ b/src/module-info.java @@ -0,0 +1,5 @@ +module GeneralUtils { + requires jdk.unsupported; + exports dev.asdf00.general.utils.listOld; + exports dev.asdf00.general.utils.list; +} \ No newline at end of file