powerconverters/src/main/java/covers1624/repack/cofh/lib/util/LinkedHashList.java
2023-06-16 22:17:05 +02:00

472 lines
13 KiB
Java

package covers1624.repack.cofh.lib.util;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import com.google.common.base.Objects;
public class LinkedHashList extends AbstractCollection implements Cloneable {
protected transient Entry head;
protected transient Entry tail;
protected transient int size;
protected transient int mask;
protected transient Entry[] hashTable;
protected transient int modCount;
protected static int roundUpToPowerOf2(int number) {
return number >= 1073741824
? 1073741824
: (number > 2 ? Integer.highestOneBit(number - 1 << 1) : 2);
}
public LinkedHashList() {
this.hashTable = new Entry[8];
this.mask = 7;
}
public LinkedHashList(int size) {
size = roundUpToPowerOf2(size);
this.hashTable = new Entry[size];
this.mask = size - 1;
}
public LinkedHashList(Collection col) {
int size = roundUpToPowerOf2(col.size());
this.hashTable = new Entry[size];
this.mask = size - 1;
this.addAll(col);
}
protected int hash(Object n) {
int h = n == null ? 0 : n.hashCode();
h ^= h >>> 20 ^ h >>> 12;
return h ^ h >>> 7 ^ h >>> 4;
}
public int size() {
return this.size;
}
public boolean add(Object e) {
return this.push(e);
}
public Object get(int index) {
this.checkElementIndex(index);
return this.index(index).key;
}
public boolean push(Object obj) {
int hash = this.hash(obj);
if (this.seek(obj, hash) != null) {
return false;
} else {
++this.modCount;
Entry e;
this.insert(e = new Entry(obj, hash));
this.rehashIfNecessary();
e.prev = this.tail;
e.next = null;
if (this.tail != null) {
this.tail.next = e;
} else {
this.head = e;
}
this.tail = e;
return true;
}
}
public Object pop() {
Entry e = this.tail;
if (e != null) {
++this.modCount;
this.delete(e);
this.tail = e.prev;
e.prev = null;
if (this.tail != null) {
this.tail.next = null;
} else {
this.head = null;
}
return e.key;
} else {
return null;
}
}
public Object peek() {
return this.tail != null ? this.tail.key : null;
}
public Object poke() {
return this.head != null ? this.head.key : null;
}
public boolean unshift(Object obj) {
int hash = this.hash(obj);
if (this.seek(obj, hash) != null) {
return false;
} else {
++this.modCount;
Entry e;
this.insert(e = new Entry(obj, hash));
this.rehashIfNecessary();
e.next = this.head;
e.prev = null;
if (this.head != null) {
this.head.prev = e;
} else {
this.tail = e;
}
this.head = e;
return true;
}
}
public Object shift() {
Entry e = this.head;
if (e != null) {
++this.modCount;
this.delete(e);
this.head = e.next;
e.next = null;
if (this.head != null) {
this.head.prev = null;
} else {
this.tail = null;
}
return e.key;
} else {
return null;
}
}
public boolean contains(Object obj) {
return this.seek(obj, this.hash(obj)) != null;
}
public boolean remove(Object obj) {
Entry e = this.seek(obj, this.hash(obj));
if (e == null) {
return false;
} else {
this.unlink(e);
return true;
}
}
protected Entry index(int index) {
Entry x;
int i;
if (index < this.size >> 1) {
x = this.head;
for (i = index; i-- > 0; x = x.next) {}
} else {
x = this.tail;
for (i = this.size - 1; i-- > index; x = x.prev) {}
}
return x;
}
protected Entry seek(Object obj, int hash) {
for (Entry entry = this.hashTable[hash & this.mask]; entry != null;
entry = entry.nextInBucket) {
if (hash == entry.hash && Objects.equal(obj, entry.key)) {
return entry;
}
}
return null;
}
protected void insert(Entry entry) {
int bucket = entry.hash & this.mask;
entry.nextInBucket = this.hashTable[bucket];
this.hashTable[bucket] = entry;
++this.size;
}
protected boolean linkBefore(Object obj, Entry succ) {
int hash = this.hash(obj);
if (this.seek(obj, hash) != null) {
return false;
} else {
Entry pred = succ.prev;
Entry newNode = new Entry(obj, hash);
++this.modCount;
this.insert(newNode);
this.rehashIfNecessary();
newNode.next = succ;
newNode.prev = pred;
succ.prev = newNode;
if (pred == null) {
this.head = newNode;
} else {
pred.next = newNode;
}
return true;
}
}
protected void delete(Entry entry) {
synchronized (this.hashTable) {
int bucket = entry.hash & this.mask;
Entry prev = null;
Entry cur = this.hashTable[bucket];
if (cur == entry) {
this.hashTable[bucket] = cur.nextInBucket;
} else {
while (cur != entry) {
prev = cur;
cur = cur.nextInBucket;
}
prev.nextInBucket = entry.nextInBucket;
}
}
--this.size;
}
protected Object unlink(Entry x) {
Object element = x.key;
Entry next = x.next;
Entry prev = x.prev;
if (prev == null) {
this.head = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
this.tail = prev;
} else {
next.prev = prev;
x.next = null;
}
this.delete(x);
++this.modCount;
return element;
}
protected void rehashIfNecessary() {
Entry[] old = this.hashTable;
if (this.size > old.length * 2 && old.length < 1073741824) {
synchronized (this.hashTable) {
int newTableSize = old.length * 2;
int newMask = newTableSize - 1;
Entry[] newTable = new Entry[newTableSize];
this.mask = newMask;
int bucket = old.length;
Entry nextEntry;
while (bucket-- > 0) {
for (Entry entry = old[bucket]; entry != null; entry = nextEntry) {
nextEntry = entry.nextInBucket;
int keyBucket = entry.hash & newMask;
entry.nextInBucket = newTable[keyBucket];
newTable[keyBucket] = entry;
}
}
this.hashTable = newTable;
}
}
}
public LinkedHashList clone() {
return new LinkedHashList(this);
}
public Iterator iterator() {
return this.listIterator();
}
public ListIterator listIterator() {
return this.listIterator(0);
}
public ListIterator listIterator(int index) {
this.checkPositionIndex(index);
return new ListItr(index);
}
public Iterator descendingIterator() {
return new DescendingIterator();
}
protected boolean isElementIndex(int index) {
return index >= 0 && index < this.size;
}
protected boolean isPositionIndex(int index) {
return index >= 0 && index <= this.size;
}
protected String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + this.size;
}
protected void checkElementIndex(int index) {
if (!this.isElementIndex(index)) {
throw new IndexOutOfBoundsException(this.outOfBoundsMsg(index));
}
}
protected void checkPositionIndex(int index) {
if (!this.isPositionIndex(index)) {
throw new IndexOutOfBoundsException(this.outOfBoundsMsg(index));
}
}
protected class DescendingIterator implements Iterator {
protected final ListItr itr
= LinkedHashList.this.new ListItr(LinkedHashList.this.size());
public boolean hasNext() {
return this.itr.hasPrevious();
}
public Object next() {
return this.itr.previous();
}
public void remove() {
this.itr.remove();
}
}
protected class ListItr implements ListIterator {
protected Entry lastReturned = null;
protected Entry next;
protected int nextIndex;
protected int expectedModCount;
protected ListItr(int index) {
this.expectedModCount = LinkedHashList.this.modCount;
this.next = index == LinkedHashList.this.size
? null
: LinkedHashList.this.index(index);
this.nextIndex = index;
}
public boolean hasNext() {
return this.nextIndex < LinkedHashList.this.size;
}
public Object next() {
this.checkForComodification();
if (!this.hasNext()) {
throw new NoSuchElementException();
} else {
this.lastReturned = this.next;
this.next = this.next.next;
++this.nextIndex;
return this.lastReturned.key;
}
}
public boolean hasPrevious() {
return this.nextIndex > 0;
}
public Object previous() {
this.checkForComodification();
if (!this.hasPrevious()) {
throw new NoSuchElementException();
} else {
this.lastReturned = this.next
= this.next == null ? LinkedHashList.this.tail : this.next.prev;
--this.nextIndex;
return this.lastReturned.key;
}
}
public int nextIndex() {
return this.nextIndex;
}
public int previousIndex() {
return this.nextIndex - 1;
}
public void remove() {
this.checkForComodification();
if (this.lastReturned == null) {
throw new IllegalStateException();
} else {
Entry lastNext = this.lastReturned.next;
LinkedHashList.this.unlink(this.lastReturned);
if (this.next == this.lastReturned) {
this.next = lastNext;
} else {
--this.nextIndex;
}
this.lastReturned = null;
++this.expectedModCount;
}
}
public void set(Object e) {
this.checkForComodification();
if (this.lastReturned == null) {
throw new IllegalStateException();
} else {
LinkedHashList.this.linkBefore(e, this.lastReturned);
LinkedHashList.this.unlink(this.lastReturned);
this.lastReturned
= this.next == null ? LinkedHashList.this.tail : this.next.prev;
this.expectedModCount += 2;
}
}
public void add(Object e) {
this.checkForComodification();
this.lastReturned = null;
if (this.next == null) {
LinkedHashList.this.push(e);
} else {
LinkedHashList.this.linkBefore(e, this.next);
}
++this.nextIndex;
++this.expectedModCount;
}
protected final void checkForComodification() {
if (LinkedHashList.this.modCount != this.expectedModCount) {
throw new ConcurrentModificationException();
}
}
}
protected static final class Entry {
protected Entry next;
protected Entry prev;
protected final Object key;
protected final int hash;
protected Entry nextInBucket;
protected Entry(Object key, int keyHash) {
this.key = key;
this.hash = keyHash;
}
}
}