package org.hypergraphdb.transaction;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* <p>
* Transactional linked list - random access is O(n)
* </p>
*
* @author Borislav Iordanov
*
* @param <E>
*/
public class TxList<E> implements List<E>
{
private static class Node<E>
{
E value;
VBox<Node<E>> next = null;
public Node(E value, VBox<Node<E>> next)
{
this.value = value;
this.next = next;
}
}
HGTransactionManager txManager = null;
private VBox<Integer> sizebox = null;
private VBox<Node<E>> head = null;
private VBox<Node<E>> tail = null;
Node<E> findNode(int index)
{
if (index < 0 || index >= sizebox.get())
throw new IndexOutOfBoundsException("In TxList: " + index);
VBox<Node<E>> result = head;
while (index-- > 0)
result = result.get().next;
return result.get();
}
public TxList(HGTransactionManager txManager)
{
this.txManager = txManager;
sizebox = new VBox<Integer>(txManager);
sizebox.put(0);
head = new VBox<Node<E>>(txManager, null);
tail = new VBox<Node<E>>(txManager, null);
}
public boolean add(E e)
{
Node<E> node = new Node<E>(e, new VBox<Node<E>>(txManager, null));
if (isEmpty())
head.put(node);
else
tail.get().next.put(node);
tail.put(node);
sizebox.put(sizebox.get() + 1);
return true;
}
public void add(int index, E e)
{
Node<E> node = new Node<E>(e, new VBox<Node<E>>(txManager, null));
if (index == 0) // this should become the first element
{
if (isEmpty()) // if the list is currently empty
tail.put(node);
node.next.put(head.get());
head.put(node);
}
else
{
// find the node after which we need to insert
Node<E> prev = findNode(index - 1);
node.next.put(prev.next.get());
prev.next.put(node);
}
sizebox.put(sizebox.get() + 1);
}
public boolean addAll(Collection<? extends E> c)
{
for (E x : c)
add(x);
return true;
}
public boolean addAll(int index, Collection<? extends E> c)
{
Node<E> prev = null;
if (index > 0)
prev = findNode(index - 1);
for (E e : c)
{
Node<E> node = new Node<E>(e, new VBox<Node<E>>(txManager, null));
if (prev == null)
{
node.next.put(head.get());
head.put(node);
}
else
{
node.next.put(prev.next.get());
prev.next.put(node);
}
if (tail.get() == prev) // if we're inserting at the end of the list, move the tail
tail.put(node);
prev = node;
}
sizebox.put(sizebox.get() + c.size());
return true;
}
public void clear()
{
head.put(null);
tail.put(null);
sizebox.put(0);
}
public boolean contains(Object o)
{
return indexOf(o) >= 0;
}
public boolean containsAll(Collection<?> c)
{
for (Object x : c)
if (!contains(x))
return false;
return true;
}
public E get(int index)
{
Node<E> x = findNode(index);
return x.value;
}
public int indexOf(Object o)
{
int i = 0;
for (Node<E> current = head.get(); current != null; current = current.next.get())
{
if (current.value == o || o != null && o.equals(current.value))
return i;
i++;
}
return -1;
}
public boolean isEmpty()
{
return sizebox.get() == 0;
}
public Iterator<E> iterator()
{
return new Iterator<E>()
{
private Node<E> next = head.get();
public boolean hasNext()
{
return next != null;
}
public E next()
{
E x = next.value;
next = next.next.get();
return x;
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public int lastIndexOf(Object o)
{
int last = -1;
int curr = 0;
for (Node<E> current = head.get(); current != null; current = current.next.get())
{
if (current.value == o || o != null && o.equals(current.value))
last = curr;
curr++;
}
return last;
}
public ListIterator<E> listIterator()
{
throw new UnsupportedOperationException();
}
public ListIterator<E> listIterator(int index)
{
throw new UnsupportedOperationException();
}
public E remove(int index)
{
E old;
if (index < 0 || index >= size())
throw new IndexOutOfBoundsException("In TxList: " + index);
if (index == 0)
{
old = head.get().value;
head.put(head.get().next.get());
if (sizebox.get() == 1)
tail.put(null);
}
else
{
Node<E> prev = findNode(index - 1);
if (tail.get() == prev.next.get())
tail.put(prev);
old = prev.next.get().value;
// prev.next = prev.next.next:
prev.next.put(prev.next.get().next.get());
}
sizebox.put(sizebox.get() - 1);
return old;
}
public boolean remove(Object o)
{
boolean found = false;
Node<E> prev = null;
for (Node<E> current = head.get(); current != null; current = current.next.get())
{
if (current.value != o && !(o != null && o.equals(current.value)))
{
prev = current;
continue;
}
found = true;
if (tail.get() == current)
tail.put(prev);
if (prev == null) // removing the head
head.put(head.get().next.get());
else
// prev.next = current.next:
prev.next.put(current.next.get());
}
sizebox.put(sizebox.get() - 1);
return found;
}
@SuppressWarnings("unchecked")
public boolean removeAll(Collection<?> c)
{
boolean modified = false;
for (Object x : c)
if (remove((E)x))
modified = true;
return modified;
}
public boolean retainAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
public E set(int index, E element)
{
Node<E> node = findNode(index);
E old = node.value;
node.value = element;
return old;
}
public int size()
{
return sizebox.get();
}
public List<E> subList(int fromIndex, int toIndex)
{
throw new UnsupportedOperationException();
}
public Object[] toArray()
{
Object[] A = new Object[size()];
int i = 0;
for (Object x : this)
A[i++] = x;
return A;
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a)
{
Class<? extends T[]> type = (Class<? extends T[]>)a.getClass();
T[] copy = ((Object)type == (Object)Object[].class)
? (T[]) new Object[size()]
: (T[]) Array.newInstance(type.getComponentType(), size());
int i = 0;
for (T x : (Iterable<T>)this)
copy[i++] = x;
return copy;
}
}