package speiger.src.collections.PACKAGE.queues; #if TYPE_OBJECT import java.util.Arrays; import java.util.Comparator; import java.util.function.Consumer; #endif import java.util.Objects; import java.util.NoSuchElementException; import speiger.src.collections.PACKAGE.collections.ITERATOR; #if !TYPE_OBJECT import speiger.src.collections.PACKAGE.functions.COMPARATOR; import speiger.src.collections.PACKAGE.functions.CONSUMER; #endif import speiger.src.collections.PACKAGE.functions.consumer.BI_OBJECT_CONSUMER; import speiger.src.collections.PACKAGE.functions.function.PREDICATE; import speiger.src.collections.utils.ITrimmable; /** * A Simple First In First Out Priority Queue that is a Good Replacement for a linked list (or ArrayDequeue) * Its specific implementation uses a backing array that grows and shrinks as it is needed. * @Type(T) */ public class ARRAY_FIFO_QUEUE KEY_GENERIC_TYPE implements PRIORITY_DEQUEUE KEY_GENERIC_TYPE, ITrimmable { /** Max Possible ArraySize without the JVM Crashing */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** The Minimum Capacity that is allowed */ public static final int MIN_CAPACITY = 4; /** The Backing array */ protected transient KEY_TYPE[] array; /** The First Index pointer */ protected int first; /** The Last Index pointer */ protected int last; /** * Constructor using a initial array * @param values the Array that should be used */ public ARRAY_FIFO_QUEUE(KEY_TYPE[] values) { this(values, 0, values.length); } /** * Constructor using a initial array * @param values the Array that should be used * @param size the amount of elements that are in the initial array * @throws IllegalStateException if values is smaller then size */ public ARRAY_FIFO_QUEUE(KEY_TYPE[] values, int size) { this(values, 0, size); } /** * Constructor using a initial array * @param values the Array that should be used * @param offset where to begin in the initial array * @param size the amount of elements that are in the initial array * @throws IllegalStateException if values is smaller then size */ public ARRAY_FIFO_QUEUE(KEY_TYPE[] values, int offset, int size) { if (values.length < size) throw new IllegalArgumentException("Initial array (" + values.length + ") is smaller then the expected size (" + size + ")"); if(values.length <= 0) values = NEW_KEY_ARRAY(1); array = values; first = offset; last = (offset + size) % array.length; if(array.length == size) expand(); } /** * Constructor with a Min Capacity * @param capacity the initial capacity of the backing array * @throws IllegalStateException if the initial size is smaller 0 */ public ARRAY_FIFO_QUEUE(int capacity) { if (capacity < 0) throw new IllegalArgumentException("Initial capacity (" + capacity + ") is negative"); array = NEW_KEY_ARRAY(Math.max(1, capacity)); } /** * Default Construtor */ public ARRAY_FIFO_QUEUE() { this(MIN_CAPACITY); } @Override public ITERATOR KEY_GENERIC_TYPE iterator() { return new Iter(); } @Override public int size() { final int apparentLength = last - first; return apparentLength >= 0 ? apparentLength : array.length + apparentLength; } @Override public void clear() { #if TYPE_OBJECT Arrays.fill(array, null); #endif first = last = 0; } @Override public void enqueue(KEY_TYPE e) { array[last] = e; last = ++last % array.length; if(last == first) expand(); } @Override public void enqueueFirst(KEY_TYPE e) { if(first == 0) first = array.length; array[--first] = e; if(first == last) expand(); } @Override public KEY_TYPE dequeue() { if(first == last) throw new NoSuchElementException(); KEY_TYPE data = array[first]; #if TYPE_OBJECT array[first] = null; #endif first = ++first % array.length; reduce(); return data; } @Override public KEY_TYPE dequeueLast() { if(first == last) throw new NoSuchElementException(); if(last == 0) last = array.length; KEY_TYPE data = array[--last]; #if TYPE_OBJECT array[last] = null; #endif reduce(); return data; } @Override public KEY_TYPE peek(int index) { if(first == last || index < 0 || index > size()) throw new NoSuchElementException(); return array[(first + index) % array.length]; } @Override public boolean removeFirst(KEY_TYPE e) { if(first == last) return false; for(int i = 0,m=size();i=0;i--) { int index = (first + i) % array.length; if(e == array[index]) return removeIndex(index); } return false; } protected boolean removeIndex(int index) { if(first >= last ? index < first && index > last : index < first || index > last) return false; if(index == first) { #if TYPE_OBJECT array[first] = null; #endif first++; } else if(index == last) { last--; #if TYPE_OBJECT array[last] = null; #endif } else if(index > last) { System.arraycopy(array, first, array, first+1, (index - first)); #if TYPE_OBJECT array[first] = null; #endif first = ++first % array.length; } else if(index < first) { System.arraycopy(array, index+1, array, index, (last - index) - 1); #if TYPE_OBJECT array[last] = null; #endif if(--last < 0) last += array.length; } else { if(index - first < last - index) { System.arraycopy(array, first, array, first+1, (index - first)); #if TYPE_OBJECT array[first] = null; #endif first = ++first % array.length; } else { System.arraycopy(array, index+1, array, index, (last - index) - 1); #if TYPE_OBJECT array[last] = null; #endif if(--last < 0) last += array.length; } } reduce(); return true; } @Override public void onChanged() {} @Override public COMPARATOR KEY_SUPER_GENERIC_TYPE comparator() { return null; } @Override public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) { Objects.requireNonNull(action); if(first == last) return; for(int i = 0,m=size();i void forEach(E input, BI_OBJECT_CONSUMER KEY_VALUE_SPECIAL_GENERIC_TYPE action) { Objects.requireNonNull(action); if(first == last) return; for(int i = 0,m=size();i= array.length) return false; KEY_TYPE[] newArray = NEW_KEY_ARRAY(newSize); if(first <= last) System.arraycopy(array, first, newArray, 0, last - first); else { System.arraycopy(array, first, newArray, 0, array.length - first); System.arraycopy(array, 0, newArray, array.length - first, last); } first = 0; last = size(); array = newArray; return true; } /** * Trims the collection down to the requested size and clears all elements while doing so * @param size the amount of elements that should be allowed * @note this will enforce minimum size of the collection itself */ @Override public void clearAndTrim(int size) { int newSize = Math.max(MIN_CAPACITY, size); if(array.length <= newSize) { clear(); return; } first = last = 0; array = NEW_KEY_ARRAY(newSize); } @Override public KEY_GENERIC_SPECIAL_TYPE KEY_SPECIAL_TYPE[] TO_ARRAY(KEY_SPECIAL_TYPE[] input) { if(input == null || input.length < size()) input = NEW_SPECIAL_KEY_ARRAY(size()); if (first <= last) System.arraycopy(array, first, input, 0, last - first); else { System.arraycopy(array, first, input, 0, array.length - first); System.arraycopy(array, 0, input, array.length - first, last); } return input; } protected void reduce() { final int size = size(); if (array.length > MIN_CAPACITY && size <= array.length / 4) resize(size, array.length / 2); } protected void expand() { resize(array.length, (int)Math.min(MAX_ARRAY_SIZE, 2L * array.length)); } protected final void resize(int oldSize, int newSize) { KEY_TYPE[] newArray = NEW_KEY_ARRAY(newSize); if(first >= last) { if(oldSize != 0) { System.arraycopy(array, first, newArray, 0, array.length - first); System.arraycopy(array, 0, newArray, array.length - first, last); } } else System.arraycopy(array, first, newArray, 0, last-first); first = 0; last = oldSize; array = newArray; } private class Iter implements ITERATOR KEY_GENERIC_TYPE { int index = first; @Override public boolean hasNext() { return index != last; } @Override public KEY_TYPE NEXT() { KEY_TYPE value = array[index]; removeIndex(index); index = ++index % array.length; return value; } } }