/***
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Linking this library statically or dynamically with other modules
* is making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* As a special exception, the copyright holders of this library give
* you permission to link this library with independent modules to
* produce an executable, regardless of the license terms of these
* independent modules, and to copy and distribute the resulting
* executable under terms of your choice, provided that you also meet,
* for each linked independent module, the terms and conditions of the
* license of that module. An independent module is a module which
* is not derived from or based on this library. If you modify this
* library, you may extend this exception to your version of the
* library, but you are not obligated to do so. If you do not wish
* to do so, delete this exception statement from your version.
*
* Project: www.simpledbm.org
* Author : Dibyendu Majumdar
* Email : d dot majumdar at gmail dot com ignore
*/
//package org.simpledbm.common.util;
import java.util.Iterator;
/**
* This implementation of LinkedList that is optimized for element removal. The
* standard Java linked list implementation is non-intrusive and inefficient for
* element removals. This implementation requires elements to extend the
* {@link Linkable} abstract class.
*
* The implementation is not thread-safe. Caller must ensure thread safety.
*
* @author Dibyendu Majumdar
*/
public class SimpleLinkedList implements Iterable {
Linkable head;
Linkable tail;
/**
* Tracks the number of members in the list.
*/
int count;
private void setOwner(E link) {
assert !link.isMemberOf(this);
link.setOwner(this);
}
private void removeOwner(Linkable link) {
assert link.isMemberOf(this);
link.setOwner(null);
}
public final void addLast(E link) {
setOwner(link);
if (head == null)
head = link;
link.setPrev(tail);
if (tail != null)
tail.setNext(link);
tail = link;
link.setNext(null);
count++;
}
public final void addFirst(E link) {
setOwner(link);
if (tail == null)
tail = link;
link.setNext(head);
if (head != null)
head.setPrev(link);
head = link;
link.setPrev(null);
count++;
}
public final void insertBefore(E anchor, E link) {
setOwner(link);
if (anchor == null) {
addFirst(link);
} else {
Linkable prev = anchor.getPrev();
link.setNext(anchor);
link.setPrev(prev);
anchor.setPrev(link);
if (prev == null) {
head = link;
} else {
prev.setNext(link);
}
count++;
}
}
public final void insertAfter(E anchor, E link) {
setOwner(link);
if (anchor == null) {
addLast(link);
} else {
Linkable next = anchor.getNext();
link.setPrev(anchor);
link.setNext(next);
anchor.setNext(link);
if (next == null) {
tail = link;
} else {
next.setPrev(link);
}
count++;
}
}
private void removeInternal(Linkable link) {
removeOwner(link);
Linkable next = link.getNext();
Linkable prev = link.getPrev();
if (next != null) {
next.setPrev(prev);
} else {
tail = prev;
}
if (prev != null) {
prev.setNext(next);
} else {
head = next;
}
link.setNext(null);
link.setPrev(null);
count--;
}
public final void remove(E e) {
removeInternal(e);
}
public final boolean contains(E link) {
Linkable cursor = head;
while (cursor != null) {
if (cursor == link || cursor.equals(link)) {
return true;
} else {
cursor = cursor.getNext();
}
}
return false;
}
public final void clear() {
count = 0;
head = null;
tail = null;
}
@SuppressWarnings("unchecked")
public final E getFirst() {
return (E) head;
}
@SuppressWarnings("unchecked")
public final E getLast() {
return (E) tail;
}
@SuppressWarnings("unchecked")
public final E getNext(E cursor) {
return (E) cursor.getNext();
}
public final int size() {
return count;
}
public final boolean isEmpty() {
return count == 0;
}
public final void push(E link) {
addLast(link);
}
@SuppressWarnings("unchecked")
public final E pop() {
Linkable popped = tail;
if (popped != null) {
removeInternal(popped);
}
return (E) popped;
}
public Iterator iterator() {
return new Iter(this);
}
static final class Iter implements Iterator {
final SimpleLinkedList ll;
E nextE;
E currentE;
Iter(SimpleLinkedList ll) {
this.ll = ll;
nextE = ll.getFirst();
}
public boolean hasNext() {
return nextE != null;
}
@SuppressWarnings("unchecked")
public E next() {
currentE = nextE;
if (nextE != null) {
nextE = (E) nextE.getNext();
}
return currentE;
}
public void remove() {
if (currentE != null) {
ll.remove(currentE);
currentE = null;
}
}
}
}
/**
* Objects that need to be managed through the SimpleLinkedList must extend this
* class.
*
* @author Dibyendu Majumdar
* @since 06 Jan 2007
*/
abstract class Linkable {
Linkable next;
Linkable prev;
/**
* Notes that the element is a member of a list.
*/
Object owner;
Linkable getNext() {
return next;
}
void setNext(Linkable link) {
next = link;
}
Linkable getPrev() {
return prev;
}
void setPrev(Linkable link) {
prev = link;
}
public final boolean isMemberOf(SimpleLinkedList extends Linkable> list) {
return this.owner == list;
}
final void setOwner(SimpleLinkedList extends Linkable> list) {
this.owner = list;
}
}