org.magicwerk.brownies.collections.IList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of brownies-collections Show documentation
Show all versions of brownies-collections Show documentation
Brownies Collections complements the Java Collections Framework.
GapList combines the strengths of both ArrayList and LinkedList.
BigList is a list optimized for storing large number of elements.
There are specialized List implementations for all primitive data types (IntGapList, IntBigList, IntObjGapList, IntObjBigList).
The key collection classes offer support for keys and constraints for lists and collections
(KeyList, KeyCollection, KeySet, Key1List, Key1Collection, Key1Set, Key2List, Key2Collection, Key2Set).
/*
* Copyright 2012 by Thomas Mauch
*
* 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.
*
* $Id: IList.java 3150 2016-04-13 14:29:16Z origo $
*/
package org.magicwerk.brownies.collections;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.RandomAccess;
import java.util.Set;
import org.magicwerk.brownies.collections.function.IFunction;
import org.magicwerk.brownies.collections.function.IPredicate;
/**
* IList is an abstract class which offers all interfaces offered by both ArrayList and LinkedList.
* It also offers additional methods which are then available in all implementations of GapList and BigList.
*
* @author Thomas Mauch
* @version $Id: IList.java 3150 2016-04-13 14:29:16Z origo $
*
* @param type of elements stored in the list
* @see java.util.List
* @see java.util.Deque
* @see java.util.ArrayList
* @see java.util.LinkedList
*/
@SuppressWarnings("serial")
public abstract class IList
// AbstractList provides method subList()
extends AbstractList
implements
// All interfaces of ArrayList
List, RandomAccess, Cloneable, Serializable,
// Additional interfaces of LinkedList and ArrayDeque
Deque {
/**
* Copies the collection values into an array.
*
* @param coll collection of values
* @return array containing the collection values
*/
static Object[] toArray(Collection> coll) {
Object[] values = coll.toArray();
// as in ArrayList: toArray() might (incorrectly) not return Object[] (see bug 6260652)
if (values.getClass() != Object[].class) {
values = Arrays.copyOf(values, values.length, Object[].class);
}
return values;
}
/**
* Returns a shallow copy of this list instance.
* (the new list will contain the same elements as the source list, i.e. the elements themselves are not copied).
* This method is identical to clone() except that the result is casted to an IList.
*
* @return a clone of this instance
* @see #clone
*/
@SuppressWarnings("unchecked")
public IList copy() {
return (IList) clone();
}
/**
* Returns an unmodifiable view of this list. This method allows
* modules to provide users with "read-only" access to internal lists.
* Query operations on the returned list "read through" to the specified
* list, and attempts to modify the returned list, whether direct or
* via its iterator, result in an UnsupportedOperationException.
*
* @return an unmodifiable view of the specified list
*/
abstract public IList unmodifiableList();
/**
* Returns a shallow copy of this list instance.
* (The elements themselves are not copied).
*
* @return a clone of this list instance
*/
@SuppressWarnings("unchecked")
@Override
public Object clone() {
try {
IList list = (IList) super.clone();
list.doClone(this);
return list;
}
catch (CloneNotSupportedException e) {
// This shouldn't happen, since we are Cloneable
throw new AssertionError(e);
}
}
/**
* Initialize this object after the bitwise copy has been made
* by Object.clone().
*
* @param that source object
*/
abstract protected void doClone(IList that);
@Override
public void clear() {
doClear();
}
protected void doClear() {
doRemoveAll(0, size());
}
/**
* Resizes the list so it will afterwards have a size of
* len
. If the list must grow, the specified
* element elem
will be used for filling.
*
* @param len length of list
* @param elem element which will be used for extending the list
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void resize(int len, E elem) {
checkLength(len);
int size = size();
if (len < size) {
remove(len, size-len);
} else {
for (int i=size; iGapList instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
// Note: Provide this method to make transition from ArrayList as
// smooth as possible
public void ensureCapacity(int minCapacity) {
doModify();
doEnsureCapacity(minCapacity);
}
/**
* Increases the capacity of this list instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
abstract protected void doEnsureCapacity(int minCapacity);
/**
* An application can use this operation to minimize the storage of an instance.
*/
// Note: Provide this method to make transition from ArrayList as
// smooth as possible
abstract public void trimToSize();
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof List>)) {
return false;
}
@SuppressWarnings("unchecked")
List list = (List) obj;
int size = size();
if (size != list.size()) {
return false;
}
for (int i=0; i 0) {
buf.append(", ");
}
buf.append(doGet(i));
}
buf.append("]");
return buf.toString();
}
@Override
public boolean isEmpty() {
return size() == 0;
}
/**
* Helper function to check two elements stored in the list for equality.
*
* @param elem1 first element
* @param elem2 second element
* @return true if the elements are equal, otherwise false
*/
static boolean equalsElem(Object elem1, Object elem2) {
if (elem1 == null) {
if (elem2 == null) {
return true;
}
} else {
if (elem1.equals(elem2)) {
return true;
}
}
return false;
}
/**
* Helper method to calculate hash code of a element stored in the list.
*
* @param elem element
* @return hash code for element
*/
static int hashCodeElem(Object elem) {
if (elem == null) {
return 0;
} else {
return elem.hashCode();
}
}
/**
* Counts how many times the specified element is contained in the list.
*
* @param elem element to count
* @return count how many times the specified element is contained in the list
*/
public int getCount(E elem) {
int count = 0;
int size = size();
for (int i=0; i getAll(E elem) {
IList list = doCreate(-1);
int size = size();
for (int i=0; i getWhere(IPredicate predicate) {
IList list = doCreate(-1);
int size = size();
for (int i=0; i predicate) {
int size = size();
for (int i=0; i predicate) {
int size = size();
for (int i=0; i extractWhere(IPredicate predicate) {
IList list = doCreate(-1);
int size = size();
for (int i=0; i getDistinct() {
Set set = new HashSet();
int size = size();
for (int i=0; i IList mappedList(IFunction mapper) {
int size = size();
@SuppressWarnings("unchecked")
IList mappedList = (IList) doCreate(size);
for (int i=0; i predicate) {
// It is typically faster to copy the allowed elements in a new list
// than to remove the not allowed from the existing one
IList list = doCreate(-1);
int size = size();
for (int i=0; i=0; i--) {
if (equalsElem(doGet(i), elem)) {
return i;
}
}
return -1;
}
/**
* Returns the index of the first occurrence of the specified element in this list, starting the search at the specified position.
* If the element is not found, -1 is returned.
*
* @param elem element to search for
* @param fromIndex start index for search
* @return the index of the first occurrence of the specified element in this list that is greater than or equal to fromIndex,
* or -1 if this list does not contain the element
* @see #indexOf(Object)
*/
public int indexOf(Object elem, int fromIndex) {
if (fromIndex < 0) {
fromIndex = 0;
}
int size = size();
for (int i=fromIndex; i= size) {
fromIndex = size-1;
}
for (int i=fromIndex; i>=0; i--) {
if (equalsElem(doGet(i), elem)) {
return i;
}
}
return -1;
}
@Override
public boolean remove(Object elem) {
int index = indexOf(elem);
if (index == -1) {
return false;
}
doRemove(index);
return true;
}
@Override
public boolean contains(Object elem) {
return indexOf(elem) != -1;
}
/**
* Add elements if it is not already contained in the list.
*
* @param elem element to add
* @return true if element has been added, false if not
*/
// CopyOnWriteArrayList contains methods addIfAbsent() and addAllAbsent()
public boolean addIfAbsent(E elem) {
if (contains(elem)) {
return false;
}
return add(elem);
}
/**
* Returns true if any of the elements of the specified collection is contained in the list.
*
* @param coll collection with elements to be contained
* @return true if any element is contained, false otherwise
*/
public boolean containsAny(Collection> coll) {
// Note that the signature has been chosen as in List:
// - boolean addAll(Collection extends E> c);
// - boolean containsAll(Collection> c);
for (Object elem: coll) {
if (contains(elem)) {
return true;
}
}
return false;
}
@Override
public boolean containsAll(Collection> coll) {
// Note that this method is already implemented in AbstractCollection.
// It has been duplicated so the method is also available in the primitive classes.
for (Object elem: coll) {
if (!contains(elem)) {
return false;
}
}
return true;
}
/**
* Removes all equal elements.
*
* @param elem element
* @return removed equal elements (never null)
*/
public IList removeAll(E elem) {
IList list = doCreate(-1);
int size = size();
for (int i=0; i coll) {
// Note that this method is already implemented in AbstractCollection.
// It has been duplicated so the method is also available in the primitive classes.
checkNonNull(coll);
boolean modified = false;
int size = size();
for (int i=0; i coll) {
// There is a special implementation accepting an IList
// so the method is also available in the primitive classes.
checkNonNull(coll);
boolean modified = false;
int size = size();
for (int i=0; i coll) {
// Note that this method is already implemented in AbstractCollection.
// It has been duplicated so the method is also available in the primitive classes.
checkNonNull(coll);
boolean modified = false;
int size = size();
for (int i=0; i coll) {
// There is a special implementation accepting an IList
// so the method is also available in the primitive classes.
checkNonNull(coll);
boolean modified = false;
int size = size();
for (int i=0; i T[] toArray(T[] array) {
int size = size();
if (array.length < size) {
array = (T[]) java.lang.reflect.Array.newInstance(array.getClass().getComponentType(), size);
}
doGetAll(array, 0, size);
if (array.length > size) {
array[size] = null;
}
return array;
}
/**
* Helper method to fill the specified elements in an array.
*
* @param array array to store the list elements
* @param index index of first element to copy
* @param len number of elements to copy
* @param type of elements stored in the list
*/
@SuppressWarnings("unchecked")
protected void doGetAll(T[] array, int index, int len) {
for (int i=0; i list) {
int listSize = list.size();
doEnsureCapacity(size() + listSize);
if (listSize == 0) {
return false;
}
boolean changed = false;
int prevSize = size();
for (int i=0; i iterator() {
return new Iter(true);
}
@Override
public ListIterator listIterator() {
return new ListIter(0);
}
@Override
public ListIterator listIterator(int index) {
return new ListIter(index);
}
@Override
public Iterator descendingIterator() {
return new Iter(false);
}
// Queue operations
@Override
public E peek() {
if (size() == 0) {
return null;
}
return getFirst();
}
@Override
public E element() {
// inline version of getFirst():
if (size() == 0) {
throw new NoSuchElementException();
}
return doGet(0);
}
@Override
public E poll() {
if (size() == 0) {
return null;
}
return doRemove(0);
}
@Override
public E remove() {
// inline version of removeFirst():
if (size() == 0) {
throw new NoSuchElementException();
}
return doRemove(0);
}
@Override
public boolean offer(E elem) {
// inline version of add(elem):
return doAdd(-1, elem);
}
// Deque operations
@Override
public E getFirst() {
if (size() == 0) {
throw new NoSuchElementException();
}
return doGet(0);
}
@Override
public E getLast() {
int size = size();
if (size == 0) {
throw new NoSuchElementException();
}
return doGet(size-1);
}
@Override
public void addFirst(E elem) {
doAdd(0, elem);
}
@Override
public void addLast(E elem) {
// inline version of add(elem):
doAdd(-1, elem);
}
@Override
public E removeFirst() {
if (size() == 0) {
throw new NoSuchElementException();
}
return doRemove(0);
}
@Override
public E removeLast() {
int size = size();
if (size == 0) {
throw new NoSuchElementException();
}
return doRemove(size-1);
}
@Override
public boolean offerFirst(E elem) {
// inline version of addFirst(elem):
doAdd(0, elem);
return true;
}
@Override
public boolean offerLast(E elem) {
// inline version of addLast(elem):
doAdd(-1, elem);
return true;
}
@Override
public E peekFirst() {
if (size() == 0) {
return null;
}
return doGet(0);
}
@Override
public E peekLast() {
int size = size();
if (size == 0) {
return null;
}
return doGet(size-1);
}
@Override
public E pollFirst() {
if (size() == 0) {
return null;
}
return doRemove(0);
}
@Override
public E pollLast() {
int size = size();
if (size == 0) {
return null;
}
return doRemove(size-1);
}
@Override
public E pop() {
// inline version of removeFirst():
if (size() == 0) {
throw new NoSuchElementException();
}
return doRemove(0);
}
@Override
public void push(E elem) {
// inline version of addFirst();
doAdd(0, elem);
}
@Override
public boolean removeFirstOccurrence(Object elem) {
int index = indexOf(elem);
if (index == -1) {
return false;
}
doRemove(index);
return true;
}
@Override
public boolean removeLastOccurrence(Object elem) {
int index = lastIndexOf(elem);
if (index == -1) {
return false;
}
doRemove(index);
return true;
}
// --- Static bulk transfer methods working with two ILists ---
/**
* Copies elements from one list to another.
* Elements and size of source list do not change.
* The elements in the specified range in the destination list are removed and
* the elements specified to be copied are inserted.
*
* If source and destination list are identical, the method behaves like {@link #copy(int, int, int)}.
*
* @param src source list
* @param srcIndex index of first element in source list
* @param srcLen number of elements to copy
* @param dst destination list
* @param dstIndex index of first element in destination list
* @param dstLen number of elements to replace in destination list
* @param type of elements stored in the list
* @throws IndexOutOfBoundsException if the ranges are invalid
*/
public static void transferCopy(IList src, int srcIndex, int srcLen, IList super E> dst, int dstIndex, int dstLen) {
if (src == dst) {
src.checkLengths(srcLen, dstLen);
src.copy(srcIndex, dstIndex, srcLen);
} else {
src.doTransfer(TRANSFER_COPY, srcIndex, srcLen, dst, dstIndex, dstLen);
}
}
/**
* Moves elements from one list to another by setting it to null in the source list.
* Elements in the source range are set to null, but size of source list does not change.
* The elements in the specified range in the destination list are removed and
* the elements specified to be moved are inserted.
*
* If source and destination list are identical, the method behaves like {@link #move(int, int, int)}.
*
* @param src source list
* @param srcIndex index of first element in source list
* @param srcLen number of elements to copy
* @param dst destination list
* @param dstIndex index of first element in destination list
* @param dstLen number of elements to replace in destination list
* @param type of elements stored in the list
* @throws IndexOutOfBoundsException if the ranges are invalid
*/
public static void transferMove(IList src, int srcIndex, int srcLen, IList super E> dst, int dstIndex, int dstLen) {
if (src == dst) {
src.checkLengths(srcLen, dstLen);
src.move(srcIndex, dstIndex, srcLen);
} else {
src.doTransfer(TRANSFER_MOVE, srcIndex, srcLen, dst, dstIndex, dstLen);
}
}
/**
* Moves elements from one list to another by removing it from the source list.
* So the size of source list will change.
* The elements in the specified range in the destination list are removed and
* the elements specified to be moved are inserted.
*
* If source and destination list are identical, the method behaves like {@link #drag(int, int, int)}.
*
* @param src source list
* @param srcIndex index of first element in source list
* @param srcLen number of elements to copy
* @param dst destination list
* @param dstIndex index of first element in destination list
* @param dstLen number of elements to replace in destination list
* @param type of elements stored in the list
* @throws IndexOutOfBoundsException if the ranges are invalid
*/
public static void transferRemove(IList src, int srcIndex, int srcLen, IList super E> dst, int dstIndex, int dstLen) {
if (src == dst) {
src.checkLengths(srcLen, dstLen);
src.drag(srcIndex, dstIndex, srcLen);
} else {
src.doTransfer(TRANSFER_REMOVE, srcIndex, srcLen, dst, dstIndex, dstLen);
}
}
private static final int TRANSFER_COPY = 0;
private static final int TRANSFER_MOVE = 1;
private static final int TRANSFER_REMOVE = 2;
void doTransfer(int transferMode, int srcIndex, int srcLen, IList super E> dst, int dstIndex, int dstLen) {
// Prepare arguments
if (srcLen == -1) {
srcLen = size()-srcIndex;
}
checkRange(srcIndex, srcLen);
if (dstIndex == -1) {
dstIndex = dst.size();
} else {
dst.checkIndexAdd(dstIndex);
}
if (dstLen == -1) {
dstLen = dst.size() - dstIndex;
} else {
dst.checkLength(dstLen);
}
E defaultElem = getDefaultElem();
if (dstLen > srcLen) {
// Remove elements from destination because the source range is smaller than the destination range
dst.remove(dstIndex, dstLen-srcLen);
} else if (srcLen > dstLen) {
// Add elements to destination because the source range is larger than the destination range
dst.addMult(dstIndex, srcLen-dstLen, defaultElem);
}
// Overwrite the range starting at dstIndex with length srcIndex in dst
if (transferMode == TRANSFER_MOVE) {
// Move
for (int i=0; i type of elements stored in the list
* @throws IndexOutOfBoundsException if the ranges are invalid
*/
public static void transferSwap(IList src, int srcIndex, IList dst, int dstIndex, int len) {
if (src == dst) {
src.swap(srcIndex, dstIndex, len);
} else {
src.doTransferSwap(srcIndex, dst, dstIndex, len);
}
}
void doTransferSwap(int srcIndex, IList dst, int dstIndex, int len) {
checkRange(srcIndex, len);
dst.checkRange(dstIndex, len);
for (int i=0; i doCreate(int capacity);
/**
* Assign this list the content of the that list.
* This is done by bitwise copying so the that list should not be used afterwards.
*
* @param that list to copy content from
*/
abstract protected void doAssign(IList that);
/**
* Returns specified range of elements from list.
*
* @param index index of first element to retrieve
* @param len number of elements to retrieve
* @return list containing the specified range of elements
*/
public IList getAll(int index, int len) {
checkRange(index, len);
IList list = doCreate(len);
for (int i=0; i extract(int index, int len) {
checkRange(index, len);
IList list = doCreate(len);
for (int i=0; i=index; i--) {
doRemove(i);
}
}
// -- addAll()
/**
* Adds all of the elements in the specified list into this list.
*
* @param list collection containing elements to be added to this list
* @return true if this list changed as a result of the call
* @throws NullPointerException if the specified list is null
*/
public boolean addAll(IList extends E> list) {
return doAddAll(-1, list);
}
/**
* Inserts all of the elements in the specified list into this
* list, starting at the specified position.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (increases their indices).
*
* @param index index at which to insert the first element from the
* specified collection
* @param list list containing elements to be inserted into this list
* @return true if this list changed as a result of the call
* @throws IndexOutOfBoundsException if the index is invalid
* @throws NullPointerException if the specified collection is null
*/
public boolean addAll(int index, IList extends E> list) {
checkIndexAdd(index);
return doAddAll(index, list);
}
/**
* Adds all of the elements in the specified collection into this list.
* The new elements will appear in the list in the order that they
* are returned by the specified collection's iterator.
*
* @param coll collection containing elements to be added to this list
* @return true if this list changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
@Override
public boolean addAll(Collection extends E> coll) {
if (coll instanceof List) {
return doAddAll(-1, new IReadOnlyListFromList((List extends E>) coll));
} else {
return doAddAll(-1, new IReadOnlyListFromCollection(coll));
}
}
/**
* Inserts all of the elements in the specified collection into this
* list, starting at the specified position.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (increases their indices).
* The new elements will appear in the list in the order that they
* are returned by the specified collection's iterator.
*
* @param index index at which to insert the first element from the
* specified collection
* @param coll collection containing elements to be inserted into this list
* @return true if this list changed as a result of the call
* @throws IndexOutOfBoundsException if the index is invalid
* @throws NullPointerException if the specified collection is null
*/
@Override
public boolean addAll(int index, Collection extends E> coll) {
checkIndexAdd(index);
if (coll instanceof List) {
return doAddAll(index, new IReadOnlyListFromList((List extends E>) coll));
} else {
return doAddAll(index, new IReadOnlyListFromCollection(coll));
}
}
/**
* Adds all specified elements into this list.
*
* @param elems elements to be added to this list
* @return true if this list changed as a result of the call
*/
public boolean addArray(E... elems) {
return doAddAll(-1, new IReadOnlyListFromArray(elems));
}
/**
* Inserts the specified elements into this list,
* starting at the specified position.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (increases their indices).
*
* @param index index at which to insert the first element from the
* specified collection
* @param elems elements to be inserted into this list
* @return true if this list changed as a result of the call
* @throws IndexOutOfBoundsException if the index is invalid
*/
public boolean addArray(int index, E... elems) {
checkIndexAdd(index);
return doAddAll(index, new IReadOnlyListFromArray(elems));
}
/**
* Adds element multiple time to list.
*
* @param elem element to be added to this list
* @return true if this list changed as a result of the call
*/
public boolean addMult(int len, E elem) {
return doAddAll(-1, new IReadOnlyListFromMult(len, elem));
}
/**
* Inserts element multiple time to list, starting at the specified position.
* Shifts the element currently at that position (if any) and any
* subsequent elements to the right (increases their indices).
*
* @param index index at which to insert the first element from the
* specified collection
* @param elem element to be inserted into this list
* @return true if this list changed as a result of the call
* @throws IndexOutOfBoundsException if the index is invalid
*/
public boolean addMult(int index, int len, E elem) {
checkIndexAdd(index);
return doAddAll(index, new IReadOnlyListFromMult(len, elem));
}
// -- setAll()
/**
* Sets the specified elements.
*
* @param index index of first element to set
* @param list list with elements to set
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void setAll(int index, IList extends E> list) {
int listSize = list.size();
checkRange(index, listSize);
doReplaceAll(index, listSize, list);
}
/**
* Sets the specified elements.
*
* @param index index of first element to set
* @param coll collection with elements to set
*/
public void setAll(int index, Collection extends E> coll) {
int collSize = coll.size();
checkRange(index, collSize);
if (coll instanceof List) {
doReplaceAll(index, collSize, new IReadOnlyListFromList((List extends E>) coll));
} else {
doReplaceAll(index, collSize, new IReadOnlyListFromCollection(coll));
}
}
/**
* Sets the specified elements.
*
* @param index index of first element to set
* @param elemes array with elements to set
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void setArray(int index, E... elems) {
int arrayLen = elems.length;
checkRange(index, arrayLen);
doReplaceAll(index, arrayLen, new IReadOnlyListFromArray(elems));
}
/**
* Sets the element multiple times.
*
* @param index index of first element to set
* @param elem element to set
*/
public void setMult(int index, int len, E elem) {
checkRange(index, len);
doReplaceAll(index, len, new IReadOnlyListFromMult(len, elem));
}
// -- putAll()
/**
* Set or add the specified elements.
*
* @param index index of first element to set or add
* @param list list with elements to set or add
*/
public void putAll(int index, IList extends E> list) {
checkIndexAdd(index);
checkNonNull(list);
int len = size()-index;
if (list != null) {
if (list.size() < len) {
len = list.size();
}
}
// Call worker method
doReplaceAll(index, len, list);
}
/**
* Set or add the specified elements.
* If the index is smaller than the size of the list, the existing element is replaced.
* If the index equals the size of the list, the element is added.
*
* @param index index of first element to set or add
* @param coll collection with elements to set or add
*/
public void putAll(int index, Collection extends E> coll) {
if (coll instanceof IList) {
putAll(index, (IList extends E>) coll);
} else if (coll instanceof List) {
putAll(index, new IReadOnlyListFromList((List extends E>) coll));
} else {
putAll(index, new IReadOnlyListFromCollection(coll));
}
}
/**
* Set or add the specified elements.
* If the index is smaller than the size of the list, the existing element is replaced.
* If the index equals the size of the list, the element is added.
*
* @param index index of first element to set or add
* @param elems array with elements to set or add
*/
public void putArray(int index, E... elems) {
putAll(index, new IReadOnlyListFromArray(elems));
}
/**
* Set or add the specified element multiple times.
* If the index is smaller than the size of the list, the existing element is replaced.
* If the index equals the size of the list, the element is added.
*
* @param index index of first element to set or add
* @param len element to set or add
*/
public void putMult(int index, int len, E elem) {
putAll(index, new IReadOnlyListFromMult(len, elem));
}
// -- initAll()
/**
* Initializes the list so it will afterwards only contain the elements of the collection.
* The list will grow or shrink as needed.
*
* @param list list with elements
* @throws IndexOutOfBoundsException if the length is invalid
*/
public void initAll(IList extends E> list) {
checkNonNull(list);
doReplaceAll(0, size(), list);
}
/**
* Initializes the list so it will afterwards only contain the elements of the collection.
* The list will grow or shrink as needed.
*
* @param coll collection with elements
* @throws IndexOutOfBoundsException if the length is invalid
*/
public void initAll(Collection extends E> coll) {
if (coll instanceof IList) {
initAll((IList extends E>) coll);
} else if (coll instanceof List) {
initAll(new IReadOnlyListFromList((List extends E>) coll));
} else {
initAll(new IReadOnlyListFromCollection(coll));
}
}
/**
* Initializes the list so it will afterwards only contain the elements of the array.
* The list will grow or shrink as needed.
*
* @param elems array with elements
* @throws IndexOutOfBoundsException if the length is invalid
*/
public void initArray(E... elems) {
initAll(new IReadOnlyListFromArray(elems));
}
/**
* Initializes the list so it will afterwards have a size of
* len
and contain only the element elem
.
* The list will grow or shrink as needed.
*
* @param len length of list
* @param elem element which the list will contain
* @throws IndexOutOfBoundsException if the length is invalid
*/
public void initMult(int len, E elem) {
checkLength(len);
initAll(new IReadOnlyListFromMult(len, elem));
}
// -- replaceAll()
/**
* Replaces the specified range with new elements.
* This method is very powerful as it offers the functionality of many other methods
* which are therefore only offered for convenience:
* - addAll(index, list) -> replaceAll(index, 0, list)
* - setAll(index, list) -> replaceAll(index, list.size(), list)
* - putAll(index, list) -> replaceAll(index, -1, list)
* - initAll(list) -> replaceAll(0, this.size(), list)
* - remove(index, list) -> replaceAll(index, list.size(), null)
*
* @param index index of first element to replace, use -1 for the position after the last element (this.size())
* @param len number of elements to replace, use -1 for getting behavior of putAll()
* @param coll collection with elements which replace the old elements, use null if elements should only be removed
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void replaceAll(int index, int len, Collection extends E> coll) {
if (coll instanceof IList) {
replaceAll(index, len, (IList extends E>) coll);
} else if (coll instanceof List) {
replaceAll(index, len, new IReadOnlyListFromList((List extends E>) coll));
} else {
replaceAll(index, len, new IReadOnlyListFromCollection(coll));
}
}
/**
* Replaces the specified range with new elements.
* This method is very powerful as it offers the functionality of many other methods
* which are therefore only offered for convenience:
* - addAll(index, list) -> replaceAll(index, 0, list)
* - setAll(index, list) -> replaceAll(index, list.size(), list)
* - putAll(index, list) -> replaceAll(index, -1, list)
* - initAll(list) -> replaceAll(0, this.size(), list)
* - remove(index, list) -> replaceAll(index, list.size(), null)
*
* @param index index of first element to replace, use -1 for the position after the last element (this.size())
* @param len number of elements to replace, use -1 for getting behavior of putAll()
* @param elems array with elements which replace the old elements, use null if elements should only be removed
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void replaceArray(int index, int len, E... elems) {
replaceAll(index, len, new IReadOnlyListFromArray(elems));
}
/**
* Replaces the specified range with new elements.
* This method is very powerful as it offers the functionality of many other methods
* which are therefore only offered for convenience:
* - addAll(index, list) -> replaceAll(index, 0, list)
* - setAll(index, list) -> replaceAll(index, list.size(), list)
* - putAll(index, list) -> replaceAll(index, -1, list)
* - initAll(list) -> replaceAll(0, this.size(), list)
* - remove(index, list) -> replaceAll(index, list.size(), null)
*
* @param index index of first element to replace, use -1 for the position after the last element (this.size())
* @param len number of elements to replace, use -1 for getting behavior of putAll()
* @param numElems number of time element has to be added
* @param elem element to add
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void replaceMult(int index, int len, int numElems, E elem) {
replaceAll(index, len, new IReadOnlyListFromMult(numElems, elem));
}
/**
* Replaces the specified range with new elements.
* This method is very powerful as it offers the functionality of many other methods
* which are therefore only offered for convenience:
* - addAll(index, list) -> replaceAll(index, 0, list)
* - setAll(index, list) -> replaceAll(index, list.size(), list)
* - putAll(index, list) -> replaceAll(index, -1, list)
* - initAll(list) -> replaceAll(0, this.size(), list)
* - remove(index, list) -> replaceAll(index, list.size(), null)
*
* @param index index of first element to replace, use -1 for the position after the last element (this.size())
* @param len number of elements to replace, use -1 for getting behavior of putAll()
* @param list list with elements which replace the old elements, use null if elements should only be removed
* @throws IndexOutOfBoundsException if the range is invalid
*/
public void replaceAll(int index, int len, IList extends E> list) {
// Check arguments
if (index == -1) {
index = size();
} else {
checkIndexAdd(index);
}
if (len == -1) {
len = size()-index;
if (list != null) {
if (list.size() < len) {
len = list.size();
}
}
} else {
checkRange(index, len);
}
// Call worker method
doReplaceAll(index, len, list);
}
// -- doReplaceAll()
protected boolean doReplaceAll(int index, int len, IList extends E> list) {
// There is a special implementation accepting an IList
// so the method is also available in the primitive classes.
assert(index >= 0 && index <= size());
assert(len >= 0 && index+len <= size());
int srcLen = 0;
if (list != null) {
srcLen = list.size();
}
doEnsureCapacity(size()-len+srcLen);
// Remove elements
doRemoveAll(index, len);
// Add elements
for (int i=0; i 0 || srcLen > 0;
}
//
/**
* Fill list.
*
* @param elem element used for filling
*/
// see java.util.Arrays#fill
public void fill(E elem) {
int size = size();
for (int i=0; i=0; i--) {
doReSet(dstIndex+i, doGet(srcIndex+i));
}
} else if (srcIndex > dstIndex) {
for (int i=0; i=0; i--) {
doReSet(dstIndex+i, doGet(srcIndex+i));
}
} else if (srcIndex > dstIndex) {
for (int i=0; i dstIndex) {
int fill = Math.min(len, srcIndex-dstIndex);
setMult(srcIndex+len-fill, fill, null);
}
}
/**
* Drag specified elements.
* Source and destination ranges may overlap.
* The size of the list does not change and it contains the same elements as before, but in changed order.
*
* @param srcIndex index of first source element to move
* @param dstIndex index of first destination element to move
* @param len number of elements to move
* @throws IndexOutOfBoundsException if the ranges are invalid
*/
public void drag(int srcIndex, int dstIndex, int len) {
checkRange(srcIndex, len);
checkRange(dstIndex, len);
if (srcIndex < dstIndex) {
doRotate(srcIndex, len+(dstIndex-srcIndex), dstIndex-srcIndex);
} else if (srcIndex > dstIndex) {
doRotate(dstIndex, len+(srcIndex-dstIndex), dstIndex-srcIndex);
}
}
/**
* Swap the specified elements in the list.
*
* @param index1 index of first element in first range to swap
* @param index2 index of first element in second range to swap
* @param len number of elements to swap
* @throws IndexOutOfBoundsException if the ranges are invalid
*/
public void swap(int index1, int index2, int len) {
checkRange(index1, len);
checkRange(index2, len);
if ((index1 < index2 && index1+len > index2) ||
index1 > index2 && index2+len > index1) {
throw new IndexOutOfBoundsException("Swap ranges overlap");
}
for (int i=0; i= 0 && distance < len);
int num = 0;
for (int start=0; num != len; start++) {
E elem = doGet(index+start);
int i = start;
do {
i += distance;
if (i >= len) {
i -= len;
}
elem = doReSet(index+i, elem);
num++;
} while (i != start);
}
}
/**
* Sort elements in the list using the specified comparator.
*
* @param comparator comparator to use for sorting
* (null means the elements natural ordering should be used)
*
* @see Arrays#sort
*/
public void sort(Comparator super E> comparator) {
sort(0, size(), comparator);
}
/**
* Sort specified elements in the list using the specified comparator.
*
* @param index index of first element to sort
* @param len number of elements to sort
* @param comparator comparator to use for sorting
* (null means the elements natural ordering should be used)
* @throws IndexOutOfBoundsException if the range is invalid
*
* @see Arrays#sort
*/
abstract public void sort(int index, int len, Comparator super E> comparator);
/*
Question:
Why is the signature of method binarySearch
public int binarySearch(K key, Comparator super K> comparator)
and not
public int binarySearch(E key, Comparator super E> comparator)
as you could expect?
Answer:
This allows to use the binarySearch method not only with keys of
the type stored in the GapList, but also with any other type you
are prepared to handle in you Comparator.
So if we have a class Name and its comparator as defined in the
following code snippets, both method calls are possible:
new GapList().binarySearch(new Name("a"), new NameComparator());
new GapList().binarySearch("a", new NameComparator());
class Name {
String name;
public Name(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String toString() {
return name;
}
}
static class NameComparator implements Comparator