/************************************************************************** * Copyright (c) 2001 by Punch Telematix. All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix nor the names of * * other contributors may be used to endorse or promote products * * derived from this software without specific prior written permission.* * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX OR OTHER CONTRIBUTORS BE LIABLE * * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ /* ** $Id: LinkedList.java,v 1.3 2006/10/04 14:24:15 cvsroot Exp $ */ package java.util; import java.io.Serializable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Array; public class LinkedList extends AbstractSequentialList implements List, Cloneable, Serializable { // All iterators of this class are fail-fast --> if you override a method of this class private static final long serialVersionUID = 876323262645176354L; transient int size; private transient Link first; private transient Link stop; public LinkedList() { setup(); } public LinkedList(Collection c) { setup(); addAll(c); } public boolean add(Object e) { modCount++; Link l = new Link(stop.before, stop, e); l.before.after = l; stop.before = l; size++; return true; } public void addLast(Object e){ add(e); } public void addFirst(Object e) { modCount++; Link l = new Link(first, first.after, e); l.after.before = l; first.after = l; size++; } public void clear () { modCount++; size = 0; first.after=stop; stop.before=first; } public Object getFirst() { if (size==0) { throw new NoSuchElementException(); } return first.after.data; } public Object getLast() { if (size==0) { throw new NoSuchElementException(); } return stop.before.data; } public Object removeFirst() { if (size==0) { throw new NoSuchElementException(); } Link l = first.after; Object o = l.data; modCount++; first.after = l.after; l.after.before=first; size--; return o; } public Object removeLast() { if (size==0) { throw new NoSuchElementException(); } Link last = stop.before; Object o = last.data; modCount++; last.before.after = stop; stop.before = last.before; size--; return o; } public boolean addAll(Collection c){ int sz = c.size(); if (sz == 0 ) { return false; } Iterator it = c.iterator(); modCount++; size += sz; Link l = stop.before; while (it.hasNext()) { l.after = new Link(l , stop, it.next()); l = l.after; } stop.before = l; return true; } /** ** we have this method so we can optimize the search procedures ... ** if position < size() / 2 then we start browsing with first else we use last ** to start with ... */ Link findLink(int position) { Link l=null; //System.out.println("calling findLink() -->"+position+", size is "+size+" last ="+last); if (position < size/2+1) { // lookup using first Link as start ... l = first.after; while (position-- > 0) { l = l.after; } } else { // lookup using last Link as start ... l = stop; while (position++ < size) { //System.out.println("calling findLink() -->"+position+", size is "+size+", l ="+l+" -->"+l.before); l = l.before; } } //if (l != null) System.out.println("returning findLink() -->"+l+", before "+l.before+", after "+l.after+", data "+l.data+", pos "+position); return l; } public boolean addAll(int idx, Collection c){ // it is possible this method is called on an empty LinkedList // we don't do checks to prevent accessing first and last (which // are null at that point) since that case is delegated to addAll(Collection c) if (idx < 0 || idx > size) { throw new IndexOutOfBoundsException(); } int sz = c.size(); //this will trigger the NullPointerException ! if (sz == 0 ) { return false; } Iterator it = c.iterator(); modCount++; Link next=stop; if (idx != size) { next = findLink(idx); } Link l = next.before; size += sz; while (it.hasNext()) { l.after = new Link(l , next, it.next()); l = l.after; } next.before = l; return true; } public void add(int idx, Object e){ if (idx < 0 || idx > size) { throw new IndexOutOfBoundsException(); } Link l = stop; if (idx < size) { l = findLink(idx); } modCount++; size++; l = new Link (l.before, l, e); l.before.after = l; l.after.before = l; } public Object remove(int idx){ if (idx < 0 || idx >= size) { throw new IndexOutOfBoundsException(); } Link l = findLink(idx); modCount++; size--; l.before.after = l.after; l.after.before = l.before; return l.data; } public Object set(int idx, Object e){ if (idx < 0 || idx >= size) { throw new IndexOutOfBoundsException(); } Link l = findLink(idx); Object d = l.data; l.data = e; return d; } public boolean contains(Object o) { Link l = first.after; if (o==null) { for (int i=0; i < size; i++){ if (l.data == null) { return true; } l = l.after; } } else { for (int i=0; i < size; i++){ if (o.equals(l.data)) { return true; } l = l.after; } } return false; } public int indexOf(Object o) { Link l = first.after; if (o==null) { for (int i=0; i < size; i++){ if (l.data == null) { return i; } l = l.after; } } else { for (int i=0; i < size; i++){ if (o.equals(l.data)) { return i; } l = l.after; } } return -1; } public int lastIndexOf(Object o){ Link l = stop.before; if (o==null) { for (int i=size-1; i >= 0; i--){ if (l.data == null) { return i; } l = l.before; } } else { for (int i=size-1; i >= 0; i--){ if (o.equals(l.data)) { return i; } l = l.before; } } return -1; } public boolean remove(Object e) { Link l = first.after; if (e==null) { for (int i=0; i < size; i++){ if (l.data == null) { l.before.after = l.after; l.after.before = l.before; size--; return true; } l = l.after; } } else { for (int i=0; i < size; i++){ if (e.equals(l.data)) { l.before.after = l.after; l.after.before = l.before; size--; return true; } l = l.after; } } return false; } public Object[] toArray(){ Object [] array = new Object[size]; Link l = first.after; for (int i=0 ; i < size; i++) { array[i] = l.data; l = l.after; } return array; } public Object[] toArray(Object[] arr){ Object [] array = arr; if ( array.length < size ) array = (Object[])Array.newInstance(arr.getClass().getComponentType(),size); if ( array.length > size ) array[size] = null ; Link l = first.after; for (int i=0; i < size ; i++) { array[i] = l.data; l = l.after; } return array; } public Object clone() { LinkedList ll = null; try { ll = (LinkedList) super.clone(); } catch(CloneNotSupportedException cnse) {} ll.size = 0; ll.setup(); ll.addAll(this); return ll; } public int size() { return size; } public ListIterator listIterator(int i) { //System.out.println("calling ListIterator in LinkedList"); if ( i < 0 || i >size ) { throw new IndexOutOfBoundsException(); } return new LListIterator(i); } private class LListIterator implements ListIterator { private int index; private int status = 0; private int m = modCount; private Link link; public LListIterator(int idx) { index = idx; link = findLink(idx); } public Object next() { if (modCount!=m) throw new ConcurrentModificationException(); if (size <= index) { throw new NoSuchElementException("No next element"); } Object answer = link.data; index++; link = link.after; status = -1; return answer; } public Object previous() { if (modCount!=m) throw new ConcurrentModificationException(); if (index <= 0) { throw new NoSuchElementException("No previous element"); } //System.out.println("calling previous() -->"+link.data); index--; status = +1; link = link.before; Object answer = link.data; //System.out.println("calling previous() "+answer+"--> at "+(index+1)+" and size "+size); return answer; } public boolean hasNext() { return index < size; } public boolean hasPrevious() { return index > 0; } public int nextIndex() { return index; } public int previousIndex() { return index-1; } public void add(Object e) { if (modCount!=m) { throw new ConcurrentModificationException(); } status = 0; m++; Link l = new Link (link.before, link, e); link.before = l; l.before.after = l; modCount++; size++; index++; if (modCount!=m) { throw new ConcurrentModificationException("warning: the original LinkedList might be corrupted"); } } public void remove(){ if (modCount!=m) { throw new ConcurrentModificationException(); } if ( status == 0 ) throw new IllegalStateException("remove must be called after next or previous"); if ( status == -1 ) {//remove after a next: shift cursor one back index--; link = link.before; } status = 0; m++; modCount++; size--; Link l = link.after; l.before = link.before; link.before.after = l; link = l; if (modCount!=m) { throw new ConcurrentModificationException("warning: the original LinkedList might be corrupted"); } } public void set(Object e) { if (modCount!=m) { throw new ConcurrentModificationException(); } if ( status == 0 ) throw new IllegalStateException("set must be called after next or previous"); m++; modCount++; if (status == -1) { link.before.data = e; } else { link.data = e; } if (modCount!=m) { throw new ConcurrentModificationException(); } } } private class Link { public Link before; public Link after; public Object data; public Link (Link f, Link a , Object d) { before = f; after = a; data = d; } public Link(Object d) { before = null; after = null; data = d; } } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { setup(); int s = in.readInt(); for(int i = 0 ; i < s ; i++){ add(in.readObject()); } } private void setup() { stop = new Link( null, null, "BUG: the LinkedList got screwed up! --> last element is bad"); first = new Link(null, stop, "BUG: the LinkedList got screwed up! --> first element is bad"); stop.after=stop; stop.before=first; first.before=first; first.after=stop; } private void writeObject(ObjectOutputStream out) throws IOException { int s = size; out.writeInt(s); Link l = first.after; for(int i = 0 ; i < s ; i++){ out.writeObject(l.data); l = l.after; } } }