package net.minecraft.util; import com.google.common.annotations.VisibleForTesting; import java.util.AbstractList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.UnaryOperator; import org.jetbrains.annotations.Nullable; public class ArrayListDeque extends AbstractList implements ListAndDeque { private static final int MIN_GROWTH = 1; private Object[] contents; private int head; private int size; public ArrayListDeque() { this(1); } public ArrayListDeque(int size) { this.contents = new Object[size]; this.head = 0; this.size = 0; } public int size() { return this.size; } @VisibleForTesting public int capacity() { return this.contents.length; } private int getIndex(int index) { return (index + this.head) % this.contents.length; } public T get(int i) { this.verifyIndexInRange(i); return this.getInner(this.getIndex(i)); } private static void verifyIndexInRange(int index, int size) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(index); } } private void verifyIndexInRange(int index) { verifyIndexInRange(index, this.size); } private T getInner(int index) { return (T)this.contents[index]; } public T set(int i, T object) { this.verifyIndexInRange(i); Objects.requireNonNull(object); int j = this.getIndex(i); T object2 = this.getInner(j); this.contents[j] = object; return object2; } public void add(int i, T object) { verifyIndexInRange(i, this.size + 1); Objects.requireNonNull(object); if (this.size == this.contents.length) { this.grow(); } int j = this.getIndex(i); if (i == this.size) { this.contents[j] = object; } else if (i == 0) { this.head--; if (this.head < 0) { this.head = this.head + this.contents.length; } this.contents[this.getIndex(0)] = object; } else { for (int k = this.size - 1; k >= i; k--) { this.contents[this.getIndex(k + 1)] = this.contents[this.getIndex(k)]; } this.contents[j] = object; } this.modCount++; this.size++; } private void grow() { int i = this.contents.length + Math.max(this.contents.length >> 1, 1); Object[] objects = new Object[i]; this.copyCount(objects, this.size); this.head = 0; this.contents = objects; } public T remove(int i) { this.verifyIndexInRange(i); int j = this.getIndex(i); T object = this.getInner(j); if (i == 0) { this.contents[j] = null; this.head++; } else if (i == this.size - 1) { this.contents[j] = null; } else { for (int k = i + 1; k < this.size; k++) { this.contents[this.getIndex(k - 1)] = this.get(k); } this.contents[this.getIndex(this.size - 1)] = null; } this.modCount++; this.size--; return object; } public boolean removeIf(Predicate predicate) { int i = 0; for (int j = 0; j < this.size; j++) { T object = this.get(j); if (predicate.test(object)) { i++; } else if (i != 0) { this.contents[this.getIndex(j - i)] = object; this.contents[this.getIndex(j)] = null; } } this.modCount += i; this.size -= i; return i != 0; } private void copyCount(Object[] output, int count) { for (int i = 0; i < count; i++) { output[i] = this.get(i); } } public void replaceAll(UnaryOperator unaryOperator) { for (int i = 0; i < this.size; i++) { int j = this.getIndex(i); this.contents[j] = Objects.requireNonNull(unaryOperator.apply(this.getInner(i))); } } public void forEach(Consumer consumer) { for (int i = 0; i < this.size; i++) { consumer.accept(this.get(i)); } } @Override public void addFirst(T object) { this.add(0, object); } @Override public void addLast(T object) { this.add(this.size, object); } public boolean offerFirst(T object) { this.addFirst(object); return true; } public boolean offerLast(T object) { this.addLast(object); return true; } @Override public T removeFirst() { if (this.size == 0) { throw new NoSuchElementException(); } else { return this.remove(0); } } @Override public T removeLast() { if (this.size == 0) { throw new NoSuchElementException(); } else { return this.remove(this.size - 1); } } @Override public ListAndDeque reversed() { return new ArrayListDeque.ReversedView(this); } @Nullable public T pollFirst() { return this.size == 0 ? null : this.removeFirst(); } @Nullable public T pollLast() { return this.size == 0 ? null : this.removeLast(); } @Override public T getFirst() { if (this.size == 0) { throw new NoSuchElementException(); } else { return this.get(0); } } @Override public T getLast() { if (this.size == 0) { throw new NoSuchElementException(); } else { return this.get(this.size - 1); } } @Nullable public T peekFirst() { return this.size == 0 ? null : this.getFirst(); } @Nullable public T peekLast() { return this.size == 0 ? null : this.getLast(); } public boolean removeFirstOccurrence(Object object) { for (int i = 0; i < this.size; i++) { T object2 = this.get(i); if (Objects.equals(object, object2)) { this.remove(i); return true; } } return false; } public boolean removeLastOccurrence(Object object) { for (int i = this.size - 1; i >= 0; i--) { T object2 = this.get(i); if (Objects.equals(object, object2)) { this.remove(i); return true; } } return false; } public Iterator descendingIterator() { return new ArrayListDeque.DescendingIterator(); } class DescendingIterator implements Iterator { private int index = ArrayListDeque.this.size() - 1; public DescendingIterator() { } public boolean hasNext() { return this.index >= 0; } public T next() { return ArrayListDeque.this.get(this.index--); } public void remove() { ArrayListDeque.this.remove(this.index + 1); } } class ReversedView extends AbstractList implements ListAndDeque { private final ArrayListDeque source; public ReversedView(final ArrayListDeque source) { this.source = source; } @Override public ListAndDeque reversed() { return this.source; } @Override public T getFirst() { return this.source.getLast(); } @Override public T getLast() { return this.source.getFirst(); } @Override public void addFirst(T object) { this.source.addLast(object); } @Override public void addLast(T object) { this.source.addFirst(object); } public boolean offerFirst(T object) { return this.source.offerLast(object); } public boolean offerLast(T object) { return this.source.offerFirst(object); } public T pollFirst() { return this.source.pollLast(); } public T pollLast() { return this.source.pollFirst(); } public T peekFirst() { return this.source.peekLast(); } public T peekLast() { return this.source.peekFirst(); } @Override public T removeFirst() { return this.source.removeLast(); } @Override public T removeLast() { return this.source.removeFirst(); } public boolean removeFirstOccurrence(Object object) { return this.source.removeLastOccurrence(object); } public boolean removeLastOccurrence(Object object) { return this.source.removeFirstOccurrence(object); } public Iterator descendingIterator() { return this.source.iterator(); } public int size() { return this.source.size(); } public boolean isEmpty() { return this.source.isEmpty(); } public boolean contains(Object object) { return this.source.contains(object); } public T get(int i) { return this.source.get(this.reverseIndex(i)); } public T set(int i, T object) { return this.source.set(this.reverseIndex(i), object); } public void add(int i, T object) { this.source.add(this.reverseIndex(i) + 1, object); } public T remove(int i) { return this.source.remove(this.reverseIndex(i)); } public int indexOf(Object object) { return this.reverseIndex(this.source.lastIndexOf(object)); } public int lastIndexOf(Object object) { return this.reverseIndex(this.source.indexOf(object)); } public List subList(int i, int j) { return this.source.subList(this.reverseIndex(j) + 1, this.reverseIndex(i) + 1).reversed(); } public Iterator iterator() { return this.source.descendingIterator(); } public void clear() { this.source.clear(); } private int reverseIndex(int index) { return index == -1 ? -1 : this.source.size() - 1 - index; } } }