All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tommyettinger.ds.ObjectDeque Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022-2025 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.tommyettinger.ds;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Random;

/**
 * A resizable, insertion-ordered double-ended queue of objects with efficient add and remove at the beginning and end. Values in the
 * backing array may wrap back to the beginning, making add and remove at the beginning and end O(1) (unless the backing array needs to
 * resize when adding). Deque functionality is provided via {@link #removeLast()} and {@link #addFirst(Object)}.
 * 
* Unlike most Deque implementations in the JDK, you can get and set items anywhere in the deque in constant time with {@link #get(int)} * and {@link #set(int, Object)}. Unlike ArrayDeque in the JDK, this implements {@link #equals(Object)} and {@link #hashCode()}, as well * as {@link #equalsIdentity(Object)}. */ public class ObjectDeque implements Deque, Arrangeable, EnhancedCollection { /** * The value returned when nothing can be obtained from this deque and an exception is not meant to be thrown, * such as when calling {@link #peek()} on an empty deque. */ @Nullable protected T defaultValue = null; /** * Contains the values in the queue. Head and tail indices go in a circle around this array, wrapping at the end. */ protected T[] values; /** * Index of first element. Logically smaller than tail. Unless empty, it points to a valid element inside queue. */ protected int head = 0; /** * Index of last element. Logically bigger than head. Usually points to an empty position, but points to the head when full * {@code (size == values.length)}. */ protected int tail = 0; /** * Number of elements in the queue. */ public int size = 0; protected transient @Nullable ObjectDequeIterator iterator1; protected transient @Nullable ObjectDequeIterator iterator2; protected transient @Nullable ObjectDequeIterator descendingIterator1; protected transient @Nullable ObjectDequeIterator descendingIterator2; /** * Creates a new ObjectDeque which can hold 16 values without needing to resize backing array. */ public ObjectDeque () { this(16); } /** * Creates a new ObjectDeque which can hold the specified number of values without needing to resize backing array. */ public ObjectDeque (int initialSize) { // noinspection unchecked this.values = (T[])new Object[initialSize]; } /** * Creates a new ObjectDeque using all the contents of the given Collection. * * @param coll a Collection of T that will be copied into this and used in full */ public ObjectDeque (Collection coll) { this(coll.size()); addAll(coll); } /** * Creates a new instance containing the items in the specified iterator. * * @param coll an iterator that will have its remaining contents added to this */ public ObjectDeque (Iterator coll) { this(); addAll(coll); } /** * Copies the given ObjectDeque exactly into this one. Individual values will be shallow-copied. * * @param deque another ObjectDeque to copy */ public ObjectDeque (ObjectDeque deque) { this.values = Arrays.copyOf(deque.values, deque.values.length); this.size = deque.size; this.head = deque.head; this.tail = deque.tail; this.defaultValue = deque.defaultValue; } /** * Creates a new ObjectDeque using all of the contents of the given array. * * @param a an array of T that will be copied into this and used in full */ public ObjectDeque (T[] a) { tail = a.length; this.values = Arrays.copyOf(a, tail); size = tail; } /** * Creates a new ObjectDeque using {@code count} items from {@code a}, starting at {@code offset}. * * @param a an array of T * @param offset where in {@code a} to start using items * @param count how many items to use from {@code a} */ public ObjectDeque (T[] a, int offset, int count) { this.values = Arrays.copyOfRange(a, offset, offset + count); tail = count; size = count; } @Nullable public T getDefaultValue () { return defaultValue; } public void setDefaultValue (@Nullable T defaultValue) { this.defaultValue = defaultValue; } /** * Append given object to the tail (enqueue to tail). Unless backing array needs resizing, operates in O(1) time. * * @param object can be null */ public void addLast (@Nullable T object) { T[] values = this.values; if (size == values.length) { resize(values.length << 1); values = this.values; } if (tail == values.length) { tail = 0; } values[tail++] = object; size++; } /** * Prepend given object to the head (enqueue to head). Unless backing array needs resizing, operates in O(1) time. * * @param object can be null * @see #addLast(Object) */ public void addFirst (@Nullable T object) { T[] values = this.values; if (size == values.length) { resize(values.length << 1); values = this.values; } int head = this.head; head--; if (head == -1) { head = values.length - 1; } values[head] = object; this.head = head; size++; } /** * Increases the size of the backing array to accommodate the specified number of additional items. Useful before adding many * items to avoid multiple backing array resizes. */ public void ensureCapacity (int additional) { final int needed = size + additional; if (values.length < needed) { resize(needed); } } /** * Resize backing array. newSize must be bigger than current size. */ protected void resize (int newSize) { final T[] values = this.values; final int head = this.head; final int tail = this.tail; final T[] newArray = (T[])new Object[Math.max(1, newSize)]; if (head < tail) { // Continuous System.arraycopy(values, head, newArray, 0, tail - head); } else if (size > 0) { // Wrapped final int rest = values.length - head; System.arraycopy(values, head, newArray, 0, rest); System.arraycopy(values, 0, newArray, rest, tail); } this.values = newArray; this.head = 0; this.tail = size; } /** * Remove the first item from the queue. (dequeue from head) Always O(1). * * @return removed object * @throws NoSuchElementException when queue is empty */ @Nullable public T removeFirst () { if (size == 0) { // Underflow throw new NoSuchElementException("ObjectDeque is empty."); } final T[] values = this.values; final T result = values[head]; values[head] = null; head++; if (head == values.length) { head = 0; } size--; return result; } /** * Remove the last item from the queue. (dequeue from tail) Always O(1). * * @return removed object * @throws NoSuchElementException when queue is empty * @see #removeFirst() */ @Nullable public T removeLast () { if (size == 0) { throw new NoSuchElementException("ObjectDeque is empty."); } final T[] values = this.values; int tail = this.tail; tail--; if (tail == -1) { tail = values.length - 1; } final T result = values[tail]; values[tail] = null; this.tail = tail; size--; return result; } /** * Inserts the specified element at the front of this deque unless it would * violate capacity restrictions. When using a capacity-restricted deque, * this method is generally preferable to the {@link #addFirst} method, * which can fail to insert an element only by throwing an exception. * * @param t the element to add * @return {@code true} if the element was added to this deque, else * {@code false} * @throws ClassCastException if the class of the specified element * prevents it from being added to this deque * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this deque */ @Override public boolean offerFirst (@Nullable T t) { int oldSize = size; addFirst(t); return oldSize != size; } /** * Inserts the specified element at the end of this deque unless it would * violate capacity restrictions. When using a capacity-restricted deque, * this method is generally preferable to the {@link #addLast} method, * which can fail to insert an element only by throwing an exception. * * @param t the element to add * @return {@code true} if the element was added to this deque, else * {@code false} * @throws ClassCastException if the class of the specified element * prevents it from being added to this deque * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this deque */ @Override public boolean offerLast (@Nullable T t) { int oldSize = size; addLast(t); return oldSize != size; } /** * Retrieves and removes the first element of this deque, * or returns {@link #getDefaultValue() defaultValue} if this deque is empty. * * @return the head of this deque, or {@link #getDefaultValue() defaultValue} if this deque is empty */ @Override @Nullable public T pollFirst () { if (size == 0) { // Underflow return defaultValue; } final T[] values = this.values; final T result = values[head]; values[head] = null; head++; if (head == values.length) { head = 0; } size--; return result; } /** * Retrieves and removes the last element of this deque, * or returns {@link #getDefaultValue() defaultValue} if this deque is empty. * * @return the tail of this deque, or {@link #getDefaultValue() defaultValue} if this deque is empty */ @Override @Nullable public T pollLast () { if (size == 0) { return defaultValue; } final T[] values = this.values; int tail = this.tail; tail--; if (tail == -1) { tail = values.length - 1; } final T result = values[tail]; values[tail] = null; this.tail = tail; size--; return result; } /** * Retrieves, but does not remove, the first element of this deque. *

* This method differs from {@link #peekFirst peekFirst} only in that it * throws an exception if this deque is empty. * * @return the head of this deque * @throws NoSuchElementException if this deque is empty */ @Override @Nullable public T getFirst () { return first(); } /** * Retrieves, but does not remove, the last element of this deque. * This method differs from {@link #peekLast peekLast} only in that it * throws an exception if this deque is empty. * * @return the tail of this deque * @throws NoSuchElementException if this deque is empty */ @Override @Nullable public T getLast () { return last(); } /** * Retrieves, but does not remove, the first element of this deque, * or returns {@link #getDefaultValue() defaultValue} if this deque is empty. * * @return the head of this deque, or {@link #getDefaultValue() defaultValue} if this deque is empty */ @Override @Nullable public T peekFirst () { if (size == 0) { // Underflow return defaultValue; } return values[head]; } /** * Retrieves, but does not remove, the last element of this deque, * or returns {@link #getDefaultValue() defaultValue} if this deque is empty. * * @return the tail of this deque, or {@link #getDefaultValue() defaultValue} if this deque is empty */ @Override @Nullable public T peekLast () { if (size == 0) { // Underflow return defaultValue; } final T[] values = this.values; int tail = this.tail; tail--; if (tail == -1) { tail = values.length - 1; } return values[tail]; } /** * Removes the first occurrence of the specified element from this deque. * If the deque does not contain the element, it is unchanged. * More formally, removes the first element {@code e} such that * {@code Objects.equals(o, e)} (if such an element exists). * Returns {@code true} if this deque contained the specified element * (or equivalently, if this deque changed as a result of the call). * * @param o element to be removed from this deque, if present * @return {@code true} if an element was removed as a result of this call * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * (optional) */ @Override public boolean removeFirstOccurrence (@Nullable Object o) { return removeValue(o, false); } /** * Removes the last occurrence of the specified element from this deque. * If the deque does not contain the element, it is unchanged. * More formally, removes the last element {@code e} such that * {@code Objects.equals(o, e)} (if such an element exists). * Returns {@code true} if this deque contained the specified element * (or equivalently, if this deque changed as a result of the call). * * @param o element to be removed from this deque, if present * @return {@code true} if an element was removed as a result of this call * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * (optional) */ @Override public boolean removeLastOccurrence (@Nullable Object o) { return removeLastValue(o, false); } /** * Inserts the specified element into the queue represented by this deque * (in other words, at the tail of this deque) if it is possible to do so * immediately without violating capacity restrictions, returning * {@code true} upon success and throwing an * {@code IllegalStateException} if no space is currently available. * When using a capacity-restricted deque, it is generally preferable to * use {@link #offer(Object) offer}. * *

This method is equivalent to {@link #addLast}. * * @param t the element to add * @return {@code true} (as specified by {@link Collection#add}) * @throws IllegalStateException if the element cannot be added at this * time due to capacity restrictions * @throws ClassCastException if the class of the specified element * prevents it from being added to this deque * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this deque */ @Override public boolean add (@Nullable T t) { int oldSize = size; addLast(t); return oldSize != size; } /** * Inserts the specified element into this deque at the specified index. * Unlike {@link #offerFirst(Object)} and {@link #offerLast(Object)}, this does not run in expected constant time unless * the index is less than or equal to 0 (where it acts like offerFirst()) or greater than or equal to {@link #size()} * (where it acts like offerLast()). * @param index the index in the deque's insertion order to insert the item * @param item a T item to insert; may be null * @return true if this deque was modified */ public boolean add (int index, @Nullable T item) { int oldSize = size; if(index <= 0) addFirst(item); else if(index >= oldSize) addLast(item); else { T[] values = this.values; if (size == values.length) { resize(values.length << 1); values = this.values; } if(head < tail) { index += head; if(index >= values.length) index -= values.length; System.arraycopy(values, index, values, (index + 1) % values.length, tail - index); values[index] = item; tail++; if (tail > values.length) { tail = 1; } } else { if (head + index < values.length) { // backward shift System.arraycopy(values, head, values, head - 1, index); values[head - 1 + index] = item; head--; // don't need to check for head being negative, because head is always > tail } else { // forward shift index -= values.length - 1; System.arraycopy(values, head + index, values, head + index + 1, tail - head - index); values[head + index] = item; tail++; // again, don't need to check for tail going around, because the head is in the way and doesn't need to move } } size++; } return oldSize != size; } /** * This is an alias for {@link #add(int, Object)} to improve compatibility with primitive lists. * * @param index index at which the specified element is to be inserted * @param element element to be inserted */ public boolean insert (int index, @Nullable T element) { return add(index, element); } /** * Inserts the specified element into the queue represented by this deque * (in other words, at the tail of this deque) if it is possible to do so * immediately without violating capacity restrictions, returning * {@code true} upon success and {@code false} if no space is currently * available. When using a capacity-restricted deque, this method is * generally preferable to the {@link #add} method, which can fail to * insert an element only by throwing an exception. * *

This method is equivalent to {@link #offerLast}. * * @param t the element to add * @return {@code true} if the element was added to this deque, else * {@code false} * @throws ClassCastException if the class of the specified element * prevents it from being added to this deque * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this deque */ @Override public boolean offer (@Nullable T t) { int oldSize = size; addLast(t); return oldSize != size; } /** * Retrieves and removes the head of the queue represented by this deque * (in other words, the first element of this deque). * This method differs from {@link #poll() poll()} only in that it * throws an exception if this deque is empty. * *

This method is equivalent to {@link #removeFirst()}. * * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ @Override @Nullable public T remove () { return removeFirst(); } /** * Retrieves and removes the head of the queue represented by this deque * (in other words, the first element of this deque), or returns * {@link #getDefaultValue() defaultValue} if this deque is empty. * *

This method is equivalent to {@link #pollFirst()}. * * @return the first element of this deque, or {@link #getDefaultValue() defaultValue} if * this deque is empty */ @Override @Nullable public T poll () { return pollFirst(); } /** * Retrieves, but does not remove, the head of the queue represented by * this deque (in other words, the first element of this deque). * This method differs from {@link #peek peek} only in that it throws an * exception if this deque is empty. * *

This method is equivalent to {@link #getFirst()}. * * @return the head of the queue represented by this deque * @throws NoSuchElementException if this deque is empty */ @Override @Nullable public T element () { return first(); } /** * Retrieves, but does not remove, the head of the queue represented by * this deque (in other words, the first element of this deque), or * returns {@link #getDefaultValue() defaultValue} if this deque is empty. * *

This method is equivalent to {@link #peekFirst()}. * * @return the head of the queue represented by this deque, or * {@link #getDefaultValue() defaultValue} if this deque is empty */ @Override @Nullable public T peek () { return peekFirst(); } /** * Adds all of the elements in the specified collection at the end * of this deque, as if by calling {@link #addLast} on each one, * in the order that they are returned by the collection's iterator. * *

When using a capacity-restricted deque, it is generally preferable * to call {@link #offer(Object) offer} separately on each element. * *

An exception encountered while trying to add an element may result * in only some of the elements having been successfully added when * the associated exception is thrown. * * @param c the elements to be inserted into this deque * @return {@code true} if this deque changed as a result of the call * @throws IllegalStateException if not all the elements can be added at * this time due to insertion restrictions * @throws ClassCastException if the class of an element of the specified * collection prevents it from being added to this deque * @throws NullPointerException if the specified collection contains a * null element and this deque does not permit null elements, * or if the specified collection is null * @throws IllegalArgumentException if some property of an element of the * specified collection prevents it from being added to this deque */ @Override public boolean addAll (Collection c) { int oldSize = size; for (T t : c) { addLast(t); } return oldSize != size; } /** * Exactly like {@link #addAll(Collection)}, but takes an array instead of a Collection. * @see #addAll(Collection) * @param array the elements to be inserted into this deque * @return {@code true} if this deque changed as a result of the call */ public boolean addAll (T[] array) { return addAll(array, 0, array.length); } /** * Like {@link #addAll(Object[])}, but only uses at most {@code length} items from {@code array}, starting at {@code offset}. * @see #addAll(Object[]) * @param array the elements to be inserted into this deque * @param offset the index of the first item in array to add * @param length how many items, at most, to add from array into this * @return {@code true} if this deque changed as a result of the call */ public boolean addAll (T[] array, int offset, int length) { int oldSize = size; for (int i = offset, n = 0; n < length && i < array.length; i++, n++) { addLast(array[i]); } return oldSize != size; } /** * Pushes an element onto the stack represented by this deque (in other * words, at the head of this deque) if it is possible to do so * immediately without violating capacity restrictions, throwing an * {@code IllegalStateException} if no space is currently available. * *

This method is equivalent to {@link #addFirst}. * * @param t the element to push * @throws IllegalStateException if the element cannot be added at this * time due to capacity restrictions * @throws ClassCastException if the class of the specified element * prevents it from being added to this deque * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * @throws IllegalArgumentException if some property of the specified * element prevents it from being added to this deque */ @Override public void push (@Nullable T t) { addFirst(t); } /** * Pops an element from the stack represented by this deque. In other * words, removes and returns the first element of this deque. * *

This method is equivalent to {@link #removeFirst()}. * * @return the element at the front of this deque (which is the top * of the stack represented by this deque) * @throws NoSuchElementException if this deque is empty */ @Override @Nullable public T pop () { return removeFirst(); } /** * Removes the first occurrence of the specified element from this deque. * If the deque does not contain the element, it is unchanged. * More formally, removes the first element {@code e} such that * {@code Objects.equals(o, e)} (if such an element exists). * Returns {@code true} if this deque contained the specified element * (or equivalently, if this deque changed as a result of the call). * *

This method is equivalent to {@link #removeFirstOccurrence(Object)}. * * @param o element to be removed from this deque, if present * @return {@code true} if an element was removed as a result of this call * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * (optional) */ @Override public boolean remove (@Nullable Object o) { return removeFirstOccurrence(o); } /** * Returns {@code true} if this deque contains the specified element. * More formally, returns {@code true} if and only if this deque contains * at least one element {@code e} such that {@code Objects.equals(o, e)}. * * @param o element whose presence in this deque is to be tested * @return {@code true} if this deque contains the specified element * @throws ClassCastException if the class of the specified element * is incompatible with this deque * (optional) * @throws NullPointerException if the specified element is null and this * deque does not permit null elements * (optional) */ @Override public boolean contains (@Nullable Object o) { return indexOf(o, false) != -1; } /** * Returns the number of elements in this deque. * * @return the number of elements in this deque */ @Override public int size () { return size; } /** * Returns an array containing all of the elements in this collection. * If this collection makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements in * the same order. The returned array's {@linkplain Class#getComponentType * runtime component type} is {@code Object}. * *

The returned array will be "safe" in that no references to it are * maintained by this collection. (In other words, this method must * allocate a new array even if this collection is backed by an array). * The caller is thus free to modify the returned array. * * @return an array, whose {@linkplain Class#getComponentType runtime component * type} is {@code Object}, containing all of the elements in this collection */ @Override public Object @NonNull [] toArray () { Object[] next = new Object[size]; if (head < tail) { System.arraycopy(values, head, next, 0, tail - head); } else { System.arraycopy(values, head, next, 0, size - head); System.arraycopy(values, 0, next, size - head, tail); } return next; } /** * Returns an array containing all of the elements in this collection; * the runtime type of the returned array is that of the specified array. * If the collection fits in the specified array, it is returned therein. * Otherwise, a new array is allocated with the runtime type of the * specified array and the size of this collection. * *

If this collection fits in the specified array with room to spare * (i.e., the array has more elements than this collection), the element * in the array immediately following the end of the collection is set to * {@code null}. (This is useful in determining the length of this * collection only if the caller knows that this collection does * not contain any {@code null} elements.) * *

If this collection makes any guarantees as to what order its elements * are returned by its iterator, this method must return the elements in * the same order. * * @param a the array into which the elements of this collection are to be * stored, if it is big enough; otherwise, a new array of the same * runtime type is allocated for this purpose. * @return an array containing all of the elements in this collection * @throws ArrayStoreException if the runtime type of any element in this * collection is not assignable to the {@linkplain Class#getComponentType * runtime component type} of the specified array * @throws NullPointerException if the specified array is null */ @Override public E @NonNull [] toArray (E[] a) { int oldSize = size; if (a.length < oldSize) { a = Arrays.copyOf(a, oldSize); } Object[] result = a; Iterator it = iterator(); for (int i = 0; i < oldSize; ++i) { result[i] = it.next(); } if (a.length > oldSize) { a[oldSize] = null; } return a; } /** * Returns {@code true} if this collection contains all of the elements * in the specified collection. * * @param c collection to be checked for containment in this collection * @return {@code true} if this collection contains all of the elements * in the specified collection * @throws ClassCastException if the types of one or more elements * in the specified collection are incompatible with this * collection * (optional) * @throws NullPointerException if the specified collection contains one * or more null elements and this collection does not permit null * elements * (optional), * or if the specified collection is null. * @see #contains(Object) */ @Override public boolean containsAll (Collection c) { for (Object o : c) { if (!contains(o)) return false; } return true; } /** * Exactly like {@link #containsAll(Collection)}, but takes an array instead of a Collection. * @see #containsAll(Collection) * @param array array to be checked for containment in this deque * @return {@code true} if this deque contains all the elements * in the specified array */ public boolean containsAll (Object[] array) { for (Object o : array) { if (!contains(o)) return false; } return true; } /** * Like {@link #containsAll(Object[])}, but only uses at most {@code length} items from {@code array}, starting at {@code offset}. * @see #containsAll(Object[]) * @param array array to be checked for containment in this deque * @param offset the index of the first item in array to check * @param length how many items, at most, to check from array * @return {@code true} if this deque contains all the elements * in the specified range of array */ public boolean containsAll (Object[] array, int offset, int length) { for (int i = offset, n = 0; n < length && i < array.length; i++, n++) { if(!contains(array[i])) return false; } return true; } /** * Returns true if this ObjectDeque contains any of the specified values. * * @param values may contain nulls, but must not be null itself * @return true if this ObjectDeque contains any of the items in {@code values}, false otherwise */ public boolean containsAny (Iterable values) { for (Object v : values) { if (contains(v)) {return true;} } return false; } /** * Returns true if this ObjectDeque contains any of the specified values. * * @param values may contain nulls, but must not be null itself * @return true if this ObjectDeque contains any of the items in {@code values}, false otherwise */ public boolean containsAny (Object[] values) { for (Object v : values) { if (contains(v)) {return true;} } return false; } /** * Returns true if this ObjectDeque contains any items from the specified range of values. * * @param values may contain nulls, but must not be null itself * @param offset the index to start checking in values * @param length how many items to check from values * @return true if this ObjectDeque contains any of the items in the given range of {@code values}, false otherwise */ public boolean containsAny (Object[] values, int offset, int length) { for (int i = offset, n = 0; n < length && i < values.length; i++, n++) { if (contains(values[i])) {return true;} } return false; } /** * Removes all of this collection's elements that are also contained in the * specified collection (optional operation). After this call returns, * this collection will contain no elements in common with the specified * collection. * * @param other collection containing elements to be removed from this collection * @return {@code true} if this deque changed as a result of the call * @throws UnsupportedOperationException if the {@code removeAll} method * is not supported by this collection * @throws ClassCastException if the types of one or more elements * in this collection are incompatible with the specified * collection * (optional) * @throws NullPointerException if this collection contains one or more * null elements and the specified collection does not support * null elements * (optional), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) */ @Override public boolean removeAll (Collection other) { ObjectDequeIterator me = iterator(); int originalSize = size(); for (Object item : other) { me.reset(); while (me.hasNext()) { if (Objects.equals(me.next(), item)) { me.remove(); } } } return originalSize != size(); } /** * Exactly like {@link #removeAll(Collection)}, but takes an array instead of a Collection. * @see #removeAll(Collection) * @param other array containing elements to be removed from this collection * @return {@code true} if this deque changed as a result of the call */ public boolean removeAll (Object[] other) { return removeAll(other, 0, other.length); } /** * Like {@link #removeAll(Object[])}, but only uses at most {@code length} items from {@code array}, starting at {@code offset}. * @see #removeAll(Object[]) * @param array the elements to be removed from this deque * @param offset the index of the first item in array to remove * @param length how many items, at most, to get from array and remove from this * @return {@code true} if this deque changed as a result of the call */ public boolean removeAll (Object[] array, int offset, int length) { ObjectDequeIterator me = iterator(); int originalSize = size(); for (int i = offset, n = 0; n < length && i < array.length; i++, n++) { Object item = array[i]; me.reset(); while (me.hasNext()) { if (Objects.equals(me.next(), item)) { me.remove(); } } } return originalSize != size(); } /** * Removes from this collection element-wise occurrences of elements contained in the specified other collection. * Note that if a value is present more than once in this collection, only one of those occurrences * will be removed for each occurrence of that value in {@code other}. If {@code other} has the same * contents as this collection or has additional items, then removing each of {@code other} will clear this. * * @param other a Collection of items to remove one-by-one, such as an ObjectList or an ObjectSet * @return true if this deque was modified. */ public boolean removeEach (Iterable other) { boolean changed = false; for(Object item : other) { changed |= remove(item); } return changed; } /** * Exactly like {@link #removeEach(Iterable)}, but takes an array instead of a Collection. * @see #removeEach(Iterable) * @param array array containing elements to be removed from this collection * @return {@code true} if this deque changed as a result of the call */ public boolean removeEach (Object[] array) { return removeEach(array, 0, array.length); } /** * Like {@link #removeEach(Object[])}, but only uses at most {@code length} items from {@code array}, starting at {@code offset}. * @see #removeEach(Object[]) * @param array the elements to be removed from this deque * @param offset the index of the first item in array to remove * @param length how many items, at most, to get from array and remove from this * @return {@code true} if this deque changed as a result of the call */ public boolean removeEach (Object[] array, int offset, int length) { boolean changed = false; for (int i = offset, n = 0; n < length && i < array.length; i++, n++) { changed |= remove(array[i]); } return changed; } /** * Retains only the elements in this collection that are contained in the * specified collection (optional operation). In other words, removes from * this collection all of its elements that are not contained in the * specified collection. * * @param c collection containing elements to be retained in this collection * @return {@code true} if this collection changed as a result of the call * @throws UnsupportedOperationException if the {@code retainAll} operation * is not supported by this collection * @throws ClassCastException if the types of one or more elements * in this collection are incompatible with the specified * collection * (optional) * @throws NullPointerException if this collection contains one or more * null elements and the specified collection does not permit null * elements * (optional), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) */ @Override public boolean retainAll (Collection c) { int oldSize = size; for (Object o : c) { int idx; do { if ((idx = indexOf(o, false)) != -1) removeAt(idx); } while (idx == -1); } return oldSize != size; } /** * Exactly like {@link #retainAll(Collection)}, but takes an array instead of a Collection. * @see #retainAll(Collection) * @param array array containing elements to be retained in this collection * @return {@code true} if this deque changed as a result of the call */ public boolean retainAll (Object[] array) { int oldSize = size; for (Object o : array) { int idx; do { if ((idx = indexOf(o, false)) != -1) removeAt(idx); } while (idx == -1); } return oldSize != size; } /** * Like {@link #retainAll(Object[])}, but only uses at most {@code length} items from {@code array}, starting at {@code offset}. * @see #retainAll(Object[]) * @param array the elements to be retained in this deque * @param offset the index of the first item in array to retain * @param length how many items, at most, to retain from array in this * @return {@code true} if this deque changed as a result of the call */ public boolean retainAll (Object[] array, int offset, int length) { int oldSize = size; for (int i = offset, n = 0; n < length && i < array.length; i++, n++) { Object o = array[i]; int idx; do { if ((idx = indexOf(o, false)) != -1) removeAt(idx); } while (idx == -1); } return oldSize != size; } /** * Reduces the size of the deque to the specified size. If the deque is already smaller than the specified * size, no action is taken. */ public void truncate (int newSize) { newSize = Math.max(0, newSize); if (size() > newSize) { if(head < tail) { // only removing from tail, near the end, toward head, near the start Arrays.fill(values, head + newSize, tail, null); tail -= size() - newSize; size = newSize; } else if(head + newSize < values.length) { // tail is near the start, but we have to remove elements through the start and into the back Arrays.fill(values, 0, tail, null); tail = head + newSize; Arrays.fill(values, tail, values.length, null); size = newSize; } else { // tail is near the start, but we only have to remove some elements between tail and the start final int newTail = tail - (size() - newSize); Arrays.fill(values, newTail, tail, null); tail = newTail; size = newSize; } } } /** * Returns the index of the first occurrence of value in the queue, or -1 if no such value exists. * Uses .equals() to compare items. * * @return An index of the first occurrence of value in queue or -1 if no such value exists */ public int indexOf (@Nullable Object value) { return indexOf(value, false); } /** * Returns the index of first occurrence of value in the queue, or -1 if no such value exists. * * @param identity If true, == comparison will be used. If false, .equals() comparison will be used. * @return An index of first occurrence of value in queue or -1 if no such value exists */ public int indexOf (@Nullable Object value, boolean identity) { if (size == 0) return -1; T[] values = this.values; final int head = this.head, tail = this.tail; if (identity || value == null) { if (head < tail) { for (int i = head; i < tail; i++) if (values[i] == value) return i - head; } else { for (int i = head, n = values.length; i < n; i++) if (values[i] == value) return i - head; for (int i = 0; i < tail; i++) if (values[i] == value) return i + values.length - head; } } else { if (head < tail) { for (int i = head; i < tail; i++) if (value.equals(values[i])) return i - head; } else { for (int i = head, n = values.length; i < n; i++) if (value.equals(values[i])) return i - head; for (int i = 0; i < tail; i++) if (value.equals(values[i])) return i + values.length - head; } } return -1; } /** * Returns the index of the last occurrence of value in the queue, or -1 if no such value exists. * Uses .equals() to compare items. * * @return An index of the last occurrence of value in queue or -1 if no such value exists */ public int lastIndexOf (@Nullable Object value) { return lastIndexOf(value, false); } /** * Returns the index of last occurrence of value in the queue, or -1 if no such value exists. * * @param identity If true, == comparison will be used. If false, .equals() comparison will be used. * @return An index of last occurrence of value in queue or -1 if no such value exists */ public int lastIndexOf (@Nullable Object value, boolean identity) { if (size == 0) return -1; T[] values = this.values; final int head = this.head, tail = this.tail; if (identity || value == null) { if (head < tail) { for (int i = tail - 1; i >= head; i--) if (values[i] == value) return i - head; } else { for (int i = tail - 1; i >= 0; i--) if (values[i] == value) return i + values.length - head; for (int i = values.length - 1; i >= head; i--) if (values[i] == value) return i - head; } } else { if (head < tail) { for (int i = tail - 1; i >= head; i--) if (value.equals(values[i])) return i - head; } else { for (int i = tail - 1; i >= 0; i--) if (value.equals(values[i])) return i + values.length - head; for (int i = values.length - 1; i >= head; i--) if (value.equals(values[i])) return i - head; } } return -1; } /** * Removes the first instance of the specified value in the queue. * * @param identity If true, == comparison will be used. If false, .equals() comparison will be used. * @return true if value was found and removed, false otherwise */ public boolean removeValue (@Nullable Object value, boolean identity) { int index = indexOf(value, identity); if (index == -1) return false; removeAt(index); return true; } /** * Removes the last instance of the specified value in the queue. * * @param identity If true, == comparison will be used. If false, .equals() comparison will be used. * @return true if value was found and removed, false otherwise */ public boolean removeLastValue (@Nullable Object value, boolean identity) { int index = lastIndexOf(value, identity); if (index == -1) return false; removeAt(index); return true; } /** * Removes and returns the item at the specified index. */ @Nullable public T removeAt (int index) { if (index < 0) throw new IndexOutOfBoundsException("index can't be < 0: " + index); if (index >= size) throw new IndexOutOfBoundsException("index can't be >= size: " + index + " >= " + size); T[] values = this.values; int head = this.head, tail = this.tail; index += head; T value; if (head < tail) { // index is between head and tail. value = values[index]; System.arraycopy(values, index + 1, values, index, tail - index - 1); this.tail--; values[this.tail] = null; } else if (index >= values.length) { // index is between 0 and tail. index -= values.length; value = values[index]; System.arraycopy(values, index + 1, values, index, tail - index - 1); this.tail--; values[this.tail] = null; } else { // index is between head and values.length. value = values[index]; System.arraycopy(values, head, values, head + 1, index - head); values[this.head] = null; this.head++; if (this.head == values.length) { this.head = 0; } } size--; return value; } /** * Returns true if the queue has one or more items. */ public boolean notEmpty () { return size != 0; } /** * Returns true if the queue is empty. */ public boolean isEmpty () { return size == 0; } /** * Returns the first (head) item in the queue (without removing it). * * @throws NoSuchElementException when queue is empty * @see #addFirst(Object) * @see #removeFirst() */ public @Nullable T first () { if (size == 0) { // Underflow throw new NoSuchElementException("ObjectDeque is empty."); } return values[head]; } /** * Returns the last (tail) item in the queue (without removing it). * * @throws NoSuchElementException when queue is empty * @see #addLast(Object) * @see #removeLast() */ public @Nullable T last () { if (size == 0) { // Underflow throw new NoSuchElementException("ObjectDeque is empty."); } final T[] values = this.values; int tail = this.tail; tail--; if (tail == -1) tail = values.length - 1; return values[tail]; } /** * Retrieves the value in queue without removing it. Indexing is from the front to back, zero based. Therefore get(0) is the * same as {@link #first()}. * * @throws IndexOutOfBoundsException when the index is negative or >= size */ public @Nullable T get (int index) { if (index < 0) throw new IndexOutOfBoundsException("index can't be < 0: " + index); if (index >= size) throw new IndexOutOfBoundsException("index can't be >= size: " + index + " >= " + size); final T[] values = this.values; int i = head + index; if (i >= values.length) i -= values.length; return values[i]; } /** * Sets an existing position in this deque to the given item. Indexing is from the front to back, zero based. * * @param index the index to set * @param item what value should replace the contents of the specified index * @return the previous contents of the specified index * @throws IndexOutOfBoundsException when the index is negative or >= size */ public @Nullable T set (int index, @Nullable T item) { if (index < 0) throw new IndexOutOfBoundsException("index can't be < 0: " + index); if (index >= size) throw new IndexOutOfBoundsException("index can't be >= size: " + index + " >= " + size); final T[] values = this.values; int i = head + index; if (i >= values.length) i -= values.length; T old = values[i]; values[i] = item; return old; } /** * Removes all values from this queue. Values in backing array are set to null to prevent memory leak, so this operates in * O(n). */ public void clear () { if (size == 0) return; final T[] values = this.values; final int head = this.head; final int tail = this.tail; if (head < tail) { // Continuous Utilities.clear(values, head, tail - head); } else { // Wrapped Utilities.clear(values, head, values.length - head); Utilities.clear(values, 0, tail); } this.head = 0; this.tail = 0; this.size = 0; } /** * Returns an iterator for the items in the deque. Remove is supported. *
* Reuses one of two iterators for this deque. For nested or multithreaded * iteration, use {@link ObjectDequeIterator#ObjectDequeIterator(ObjectDeque)}. */ @Override public @NonNull ObjectDequeIterator iterator () { if (iterator1 == null || iterator2 == null) { iterator1 = new ObjectDequeIterator<>(this); iterator2 = new ObjectDequeIterator<>(this); } if (!iterator1.valid) { iterator1.reset(); iterator1.valid = true; iterator2.valid = false; return iterator1; } iterator2.reset(); iterator2.valid = true; iterator1.valid = false; return iterator2; } /** * Returns an iterator over the elements in this deque in reverse * sequential order. The elements will be returned in order from * last (tail) to first (head). *
* Reuses one of two descending iterators for this deque. For nested or multithreaded * iteration, use {@link ObjectDequeIterator#ObjectDequeIterator(ObjectDeque, boolean)}. * * @return an iterator over the elements in this deque in reverse sequence */ @Override public @NonNull ObjectDequeIterator descendingIterator () { if (descendingIterator1 == null || descendingIterator2 == null) { descendingIterator1 = new ObjectDequeIterator<>(this, true); descendingIterator2 = new ObjectDequeIterator<>(this, true); } if (!descendingIterator1.valid) { descendingIterator1.reset(); descendingIterator1.valid = true; descendingIterator2.valid = false; return descendingIterator1; } descendingIterator2.reset(); descendingIterator2.valid = true; descendingIterator1.valid = false; return descendingIterator2; } @Override public String toString () { return toString(", ", true); } public int hashCode () { final int size = this.size; final T[] values = this.values; final int backingLength = values.length; int index = this.head; int hash = size + 1; for (int s = 0; s < size; s++) { final T value = values[index]; hash *= 31; if (value != null) hash += value.hashCode(); index++; if (index == backingLength) index = 0; } return hash; } /** * Using {@link Object#equals(Object)} between each item in order, compares for equality specifically with * other ObjectDeque collections. If {@code o} is not an ObjectDeque * (and is also not somehow reference-equivalent to this collection), this returns false. * @param o object to be compared for equality with this collection * @return true if this is equal to o, or false otherwise */ public boolean equals (Object o) { if (this == o) return true; if (!(o instanceof ObjectDeque)) return false; ObjectDeque q = (ObjectDeque)o; final int size = this.size; if (q.size != size) return false; final T[] myValues = this.values; final int myBackingLength = myValues.length; final Object[] itsValues = q.values; final int itsBackingLength = itsValues.length; int myIndex = head; int itsIndex = q.head; for (int s = 0; s < size; s++) { T myValue = myValues[myIndex]; Object itsValue = itsValues[itsIndex]; if (!(Objects.equals(myValue, itsValue))) return false; myIndex++; itsIndex++; if (myIndex == myBackingLength) myIndex = 0; if (itsIndex == itsBackingLength) itsIndex = 0; } return true; } /** * Using {@code ==} between each item in order, compares for equality specifically with * other ObjectDeque collections. If {@code o} is not an ObjectDeque * (and is also not somehow reference-equivalent to this collection), this returns false. * @param o object to be compared for equality with this collection * @return true if this is equal to o, or false otherwise */ public boolean equalsIdentity (Object o) { if (this == o) return true; if (!(o instanceof ObjectDeque)) return false; ObjectDeque q = (ObjectDeque)o; final int size = this.size; if (q.size != size) return false; final T[] myValues = this.values; final int myBackingLength = myValues.length; final Object[] itsValues = q.values; final int itsBackingLength = itsValues.length; int myIndex = head; int itsIndex = q.head; for (int s = 0; s < size; s++) { if (myValues[myIndex] != itsValues[itsIndex]) return false; myIndex++; itsIndex++; if (myIndex == myBackingLength) myIndex = 0; if (itsIndex == itsBackingLength) itsIndex = 0; } return true; } /** * Switches the ordering of positions {@code first} and {@code second}, without changing any items beyond that. * * @param first the first position, must not be negative and must be less than {@link #size()} * @param second the second position, must not be negative and must be less than {@link #size()} */ @Override public void swap (int first, int second) { if (first < 0) throw new IndexOutOfBoundsException("first index can't be < 0: " + first); if (first >= size) throw new IndexOutOfBoundsException("first index can't be >= size: " + first + " >= " + size); if (second < 0) throw new IndexOutOfBoundsException("second index can't be < 0: " + second); if (second >= size) throw new IndexOutOfBoundsException("second index can't be >= size: " + second + " >= " + size); final T[] values = this.values; int f = head + first; if (f >= values.length) f -= values.length; int s = head + second; if (s >= values.length) s -= values.length; T fv = values[f]; values[f] = values[s]; values[s] = fv; } /** * Reverses this ObjectDeque in-place. */ @Override public void reverse () { final T[] values = this.values; int f, s, len = values.length; T fv; for (int n = size >> 1, b = 0, t = size - 1; b <= n && b != t; b++, t--) { f = head + b; if (f >= len) f -= len; s = head + t; if (s >= len) s -= len; fv = values[f]; values[f] = values[s]; values[s] = fv; } } /** * Attempts to sort this deque in-place using its natural ordering, which requires T to * implement {@link Comparable} of T. */ public void sort () { sort(null); } /** * Sorts this deque in-place using {@link Arrays#sort(Object[], int, int, Comparator)}. * This should operate in O(n log(n)) time or less when the internals of the deque are * continuous (the head is before the tail in the array). If the internals are not * continuous, this takes an additional O(n) step (where n is less than the size of * the deque) to rearrange the internals before sorting. You can pass null as the value * for {@code comparator} if T implements {@link Comparable} of T, which will make this * use the natural ordering for T. * * @param comparator the Comparator to use for T items; may be null to use the natural * order of T items when T implements Comparable of T */ public void sort (@Nullable Comparator comparator) { if (head <= tail) { Arrays.sort(values, head, tail, comparator); } else { System.arraycopy(values, head, values, tail, values.length - head); Arrays.sort(values, 0, tail + values.length - head, comparator); tail = tail + values.length - head; head = 0; } } @Nullable public T random (Random random) { if (size <= 0) { throw new NoSuchElementException("ObjectDeque is empty."); } return get(random.nextInt(size)); } /** * An {@link Iterator} and {@link ListIterator} over the elements of an ObjectDeque, while also an {@link Iterable}. * @param the generic type for the ObjectDeque this iterates over */ public static class ObjectDequeIterator implements Iterable, ListIterator { protected int index, latest = -1; protected ObjectDeque deque; protected boolean valid = true; private final int direction; public ObjectDequeIterator (ObjectDeque deque) { this(deque, false); } public ObjectDequeIterator (ObjectDeque deque, boolean descendingOrder) { this.deque = deque; direction = descendingOrder ? -1 : 1; } public ObjectDequeIterator (ObjectDeque deque, int index, boolean descendingOrder) { if (index < 0 || index >= deque.size()) throw new IndexOutOfBoundsException("ObjectDequeIterator does not satisfy index >= 0 && index < deque.size()"); this.deque = deque; this.index = index; direction = descendingOrder ? -1 : 1; } /** * Returns the next {@code T} element in the iteration. * * @return the next {@code T} element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ @Override @Nullable public T next () { if (!hasNext()) {throw new NoSuchElementException();} latest = index; index += direction; return deque.get(latest); } /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@link #next} would * return an element rather than throwing an exception.) * * @return {@code true} if the iteration has more elements */ @Override public boolean hasNext () { if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} return direction == 1 ? index < deque.size() : index > 0 && deque.notEmpty(); } /** * Returns {@code true} if this list iterator has more elements when * traversing the list in the reverse direction. (In other words, * returns {@code true} if {@link #previous} would return an element * rather than throwing an exception.) * * @return {@code true} if the list iterator has more elements when * traversing the list in the reverse direction */ @Override public boolean hasPrevious () { if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} return direction == -1 ? index < deque.size() : index > 0 && deque.notEmpty(); } /** * Returns the previous element in the list and moves the cursor * position backwards. This method may be called repeatedly to * iterate through the list backwards, or intermixed with calls to * {@link #next} to go back and forth. (Note that alternating calls * to {@code next} and {@code previous} will return the same * element repeatedly.) * * @return the previous element in the list * @throws NoSuchElementException if the iteration has no previous * element */ @Override @Nullable public T previous () { if (!hasPrevious()) {throw new NoSuchElementException();} return deque.get(latest = (index -= direction)); } /** * Returns the index of the element that would be returned by a * subsequent call to {@link #next}. (Returns list size if the list * iterator is at the end of the list.) * * @return the index of the element that would be returned by a * subsequent call to {@code next}, or list size if the list * iterator is at the end of the list */ @Override public int nextIndex () { return index; } /** * Returns the index of the element that would be returned by a * subsequent call to {@link #previous}. (Returns -1 if the list * iterator is at the beginning of the list.) * * @return the index of the element that would be returned by a * subsequent call to {@code previous}, or -1 if the list * iterator is at the beginning of the list */ @Override public int previousIndex () { return index - 1; } /** * Removes from the list the last element that was returned by {@link * #next} or {@link #previous} (optional operation). This call can * only be made once per call to {@code next} or {@code previous}. * It can be made only if {@link #add} has not been * called after the last call to {@code next} or {@code previous}. * * @throws UnsupportedOperationException if the {@code remove} * operation is not supported by this list iterator * @throws IllegalStateException if neither {@code next} nor * {@code previous} have been called, or {@code remove} or * {@code add} have been called after the last call to * {@code next} or {@code previous} */ @Override public void remove () { if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} if (latest == -1 || latest >= deque.size()) {throw new NoSuchElementException();} deque.removeAt(latest); index = latest; latest = -1; } /** * Replaces the last element returned by {@link #next} or * {@link #previous} with the specified element (optional operation). * This call can be made only if neither {@link #remove} nor {@link * #add} have been called after the last call to {@code next} or * {@code previous}. * * @param t the element with which to replace the last element returned by * {@code next} or {@code previous} * @throws UnsupportedOperationException if the {@code set} operation * is not supported by this list iterator * @throws ClassCastException if the class of the specified element * prevents it from being added to this list * @throws IllegalArgumentException if some aspect of the specified * element prevents it from being added to this list * @throws IllegalStateException if neither {@code next} nor * {@code previous} have been called, or {@code remove} or * {@code add} have been called after the last call to * {@code next} or {@code previous} */ @Override public void set (@Nullable T t) { if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} if (latest == -1 || latest >= deque.size()) {throw new NoSuchElementException();} deque.set(latest, t); } /** * Inserts the specified element into the list (optional operation). * The element is inserted immediately before the element that * would be returned by {@link #next}, if any, and after the element * that would be returned by {@link #previous}, if any. (If the * list contains no elements, the new element becomes the sole element * on the list.) The new element is inserted before the implicit * cursor: a subsequent call to {@code next} would be unaffected, and a * subsequent call to {@code previous} would return the new element. * (This call increases by one the value that would be returned by a * call to {@code nextIndex} or {@code previousIndex}.) * * @param t the element to insert * @throws UnsupportedOperationException if the {@code add} method is * not supported by this list iterator * @throws ClassCastException if the class of the specified element * prevents it from being added to this list * @throws IllegalArgumentException if some aspect of this element * prevents it from being added to this list */ @Override public void add (@Nullable T t) { if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} if (index > deque.size()) {throw new NoSuchElementException();} deque.insert(index, t); index += direction; latest = -1; } public void reset () { index = deque.size - 1 & direction >> 31; latest = -1; } public void reset (int index) { if (index < 0 || index >= deque.size()) throw new IndexOutOfBoundsException("ObjectDequeIterator does not satisfy index >= 0 && index < deque.size()"); this.index = index; latest = -1; } /** * Returns an iterator over elements of type {@code T}. * * @return a ListIterator; really this same ObjectDequeIterator. */ @Override public @NonNull ObjectDequeIterator iterator () { return this; } } /** * Constructs an empty deque given the type as a generic type argument. * This is usually less useful than just using the constructor, but can be handy * in some code-generation scenarios when you don't know how many arguments you will have. * * @param the type of items; must be given explicitly * @return a new deque containing nothing */ public static ObjectDeque with () { return new ObjectDeque<>(0); } /** * Creates a new ObjectDeque that holds only the given item, but can be resized. * @param item one T item * @return a new ObjectDeque that holds the given item * @param the type of item, typically inferred */ public static ObjectDeque with (T item) { ObjectDeque deque = new ObjectDeque<>(1); deque.add(item); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1) { ObjectDeque deque = new ObjectDeque<>(2); deque.add(item0, item1); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @param item2 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1, T item2) { ObjectDeque deque = new ObjectDeque<>(3); deque.add(item0, item1, item2); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @param item2 a T item * @param item3 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1, T item2, T item3) { ObjectDeque deque = new ObjectDeque<>(4); deque.add(item0, item1, item2, item3); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @param item2 a T item * @param item3 a T item * @param item4 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1, T item2, T item3, T item4) { ObjectDeque deque = new ObjectDeque<>(5); deque.add(item0, item1, item2, item3); deque.add(item4); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @param item2 a T item * @param item3 a T item * @param item4 a T item * @param item5 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1, T item2, T item3, T item4, T item5) { ObjectDeque deque = new ObjectDeque<>(6); deque.add(item0, item1, item2, item3); deque.add(item4, item5); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @param item2 a T item * @param item3 a T item * @param item4 a T item * @param item5 a T item * @param item6 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1, T item2, T item3, T item4, T item5, T item6) { ObjectDeque deque = new ObjectDeque<>(7); deque.add(item0, item1, item2, item3); deque.add(item4, item5, item6); return deque; } /** * Creates a new ObjectDeque that holds only the given items, but can be resized. * @param item0 a T item * @param item1 a T item * @param item2 a T item * @param item3 a T item * @param item4 a T item * @param item5 a T item * @param item6 a T item * @return a new ObjectDeque that holds the given items * @param the type of item, typically inferred */ public static ObjectDeque with (T item0, T item1, T item2, T item3, T item4, T item5, T item6, T item7) { ObjectDeque deque = new ObjectDeque<>(8); deque.add(item0, item1, item2, item3); deque.add(item4, item5, item6, item7); return deque; } /** * Creates a new ObjectDeque that will hold the items in the given array or varargs. * This overload will only be used when an array is supplied and the type of the * items requested is the component type of the array, or if varargs are used and * there are 9 or more arguments. * @param varargs either 0 or more T items, or an array of T * @return a new ObjectDeque that holds the given T items * @param the type of items, typically inferred by all the items being the same type */ @SafeVarargs public static ObjectDeque with (T... varargs) { return new ObjectDeque<>(varargs); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy