/******************************************************************************* * Copyright (c) 2015 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.common.utils.collections.list; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Iterator; /** * This class implements a double linked list of {@link DoubleLinkedListItem}s. * * @author Andreas Eberle * */ public final class DoubleLinkedList<T extends DoubleLinkedListItem<T>> implements Serializable, Iterable<T> { private static final long serialVersionUID = -8229566677756169997L; transient T head; private transient int size = 0; public DoubleLinkedList() { initHead(); } @SuppressWarnings("unchecked") private void initHead() { head = (T) new DoubleLinkedListItem<T>(); head.next = head; head.prev = head; } public void pushFront(T newItem) { newItem.next = head.next; newItem.prev = head; newItem.next.prev = newItem; head.next = newItem; size++; } public void pushEnd(T newItem) { newItem.next = head; newItem.prev = head.prev; newItem.prev.next = newItem; head.prev = newItem; size++; } /** * Pops the first element from this list. * <p /> * NOTE: NEVER EVER call popFront on an empty queue! There will be no internal checks! * * @return */ public T popFront() { final T item = head.next; item.next.prev = head; head.next = item.next; item.next = null; item.prev = null; size--; return item; } public T getFront() { return head.next; } public void remove(DoubleLinkedListItem<T> item) { item.prev.next = item.next; item.next.prev = item.prev; size--; } public int size() { return size; } public void clear() { head.next = head; head.prev = head; size = 0; } public boolean isEmpty() { return size == 0; } /** * Generates a new array of {@link DoubleLinkedList}s of the given length. The array will be filled with new {@link DoubleLinkedList} objects. * * @param length * Length of the resulting array. * @return */ public static <T extends DoubleLinkedListItem<T>> DoubleLinkedList<T>[] getArray(final int length) { @SuppressWarnings("unchecked") DoubleLinkedList<T>[] array = new DoubleLinkedList[length]; for (int i = 0; i < length; i++) { array[i] = new DoubleLinkedList<T>(); } return array; } private void writeObject(ObjectOutputStream oos) throws IOException { oos.writeInt(size); T curr = head.next; for (int i = 0; i < size; i++) { oos.writeObject(curr); curr = curr.next; } } @SuppressWarnings("unchecked") private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { initHead(); int size = ois.readInt(); for (int i = 0; i < size; i++) { pushEnd((T) ois.readObject()); } } @Override public Iterator<T> iterator() { return new DoubleLinkedListIterator<T>(this); } /** * Adds all elements of this list to the given {@link DoubleLinkedList}. After this operation this list will not contain any elements. * * @param newList * The list to append all the elements of this list. */ public void mergeInto(DoubleLinkedList<T> newList) { newList.head.prev.next = this.head.next; this.head.next.prev = newList.head.prev; this.head.prev.next = newList.head; newList.head.prev = this.head.prev; newList.size += size; clear(); } @Override public int hashCode() { final int prime = 31; int result = 1; T curr = head.next; while (curr != head) { result = prime * result + curr.hashCode(); curr = curr.next; } result = prime * result + size; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DoubleLinkedList<?> other = (DoubleLinkedList<?>) obj; if (head == null) { if (other.head != null) return false; } else { DoubleLinkedListItem<?> currThis = head.next; DoubleLinkedListItem<?> currOther = other.head.next; while (currThis != head && currOther != other.head) { if (!currThis.equals(currOther)) { return false; } currThis = currThis.next; currOther = currOther.next; } if (currThis != this.head || currOther != other.head) { return false; } } if (size != other.size) return false; return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("DoubleLinkedList [size="); builder.append(size); for (T e : this) { builder.append(", "); builder.append(e.toString()); } builder.append("]"); return builder.toString(); } }