package org.multiverse.collections;
import org.multiverse.api.Stm;
import org.multiverse.api.Txn;
import org.multiverse.api.collections.TxnIterator;
import org.multiverse.api.collections.TxnStack;
import org.multiverse.api.references.TxnInteger;
import org.multiverse.api.references.TxnRef;
import java.util.NoSuchElementException;
import static org.multiverse.api.TxnThreadLocal.getThreadLocalTxn;
public final class NaiveTxnStack<E> extends AbstractTxnCollection<E> implements TxnStack<E> {
private final int capacity;
private final TxnRef<Node<E>> head;
private final TxnInteger size;
public NaiveTxnStack(Stm stm) {
this(stm, Integer.MAX_VALUE);
}
public NaiveTxnStack(Stm stm, int capacity) {
super(stm);
if (capacity < 0) {
throw new IllegalArgumentException();
}
this.capacity = capacity;
this.head = stm.getDefaultRefFactory().newTxnRef(null);
this.size = stm.getDefaultRefFactory().newTxnInteger(0);
}
@Override
public int size(Txn txn) {
return size.get(txn);
}
public int getCapacity() {
return capacity;
}
@Override
public void clear(Txn txn) {
int s = size.get(txn);
if (s == 0) {
return;
}
size.set(txn, 0);
head.set(txn, null);
}
@Override
public boolean offer(E item) {
return offer(getThreadLocalTxn(), item);
}
@Override
public boolean offer(Txn txn, E item) {
if (capacity == size(txn)) {
return false;
}
push(txn, item);
return true;
}
@Override
public E poll() {
return poll(getThreadLocalTxn());
}
@Override
public E poll(Txn txn) {
if (size.get(txn) == 0) {
return null;
}
return pop(txn);
}
@Override
public E peek() {
return peek(getThreadLocalTxn());
}
@Override
public E peek(Txn txn) {
Node<E> h = head.get(txn);
return h == null ? null : h.value;
}
@Override
public void push(E item) {
push(getThreadLocalTxn(), item);
}
@Override
public void push(Txn txn, E item) {
if (item == null) {
throw new NullPointerException();
}
if (size.get(txn) == capacity) {
txn.retry();
}
head.set(txn, new Node<E>(head.get(txn), item));
size.increment(txn);
}
@Override
public E pop() {
return pop(getThreadLocalTxn());
}
@Override
public E pop(Txn txn) {
if (size.get(txn) == 0) {
txn.retry();
}
Node<E> node = head.get(txn);
head.set(txn, node.next);
size.decrement(txn);
return node.value;
}
@Override
public boolean add(Txn txn, E e) {
if (!offer(txn, e)) {
throw new IllegalStateException("NaiveTxnStack full");
}
return true;
}
@Override
public TxnIterator<E> iterator(Txn txn) {
return new It<E>(stm, head.get(txn));
}
@Override
public boolean contains(Txn txn, Object o) {
if (o == null) {
return false;
}
int s = size.get(txn);
if (s == 0) {
return false;
}
Node<E> node = head.get();
while (node != null) {
if(node.value.equals(o)){
return true;
}
node = node.next;
}
return false;
}
@Override
public boolean remove(Txn txn, Object o) {
throw new UnsupportedOperationException();
}
static class It<E> extends AbstractTxnIterator<E> {
final TxnRef<Node<E>> node;
It(Stm stm, Node<E> node) {
this.node = stm.getDefaultRefFactory().newTxnRef(node);
}
@Override
public boolean hasNext(Txn txn) {
return node.get() != null;
}
@Override
public E next(Txn txn) {
Node<E> n = node.get(txn);
if (n == null) {
throw new NoSuchElementException();
}
E value = n.value;
node.set(txn, n.next);
return value;
}
@Override
public void remove(Txn txn) {
throw new UnsupportedOperationException();
}
}
@Override
public String toString(Txn txn) {
int s = size.get(txn);
if (s == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder("[");
Node<E> node = head.get();
while (node != null) {
sb.append(node.value);
node = node.next;
if (node != null) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
static class Node<E> {
final Node<E> next;
final E value;
Node(Node<E> next, E value) {
this.next = next;
this.value = value;
}
}
}