/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.shell.syntax; import java.util.Collection; import java.util.Deque; import java.util.Iterator; import java.util.LinkedList; import java.util.NoSuchElementException; /** * This a custom stack (FIFO) class for MuParser. Each time MuParser creates a "choice point", * it needs to record the current state of its syntax stack. This is gets expensive in time * and space; e.g. if the syntax and/or choice stack is deep. This stack implementation * takes advantage of the fact that the saved stack will not normally be referred to. It * defers the actual copying until the active stack's size drops below the saved stack's * size. * <p> * This class is not a complete Deque implementation. It only implements the subset of * the interface that is required by MuParser. * * @author crawley@jnode.org * * @param <E> */ class SharedStack<E> implements Deque<E> { private int baseStackSize; private Deque<E> baseStack; private Deque<E> myStack; private static final boolean DEBUG = true; /** * Create a new working stack with an initial state taken from the supplied Deque. * It is assumed that the supplied Deque is not be changed for the lifetime of * the SharedStack. * * @param stack */ public SharedStack(Deque<E> stack) { this.baseStack = stack; this.baseStackSize = stack.size(); this.myStack = new LinkedList<E>(); } public boolean add(E e) { throw new UnsupportedOperationException(); } public void addFirst(E e) { if (DEBUG) check(); myStack.addFirst(e); } public void addLast(E e) { throw new UnsupportedOperationException(); } public boolean contains(Object o) { throw new UnsupportedOperationException(); } public Iterator<E> descendingIterator() { throw new UnsupportedOperationException(); } public E element() { throw new UnsupportedOperationException(); } public E getFirst() { if (DEBUG) check(); return myStack.getFirst(); } public E getLast() { throw new UnsupportedOperationException(); } public Iterator<E> iterator() { if (DEBUG) check(); final Iterator<E> it1 = myStack.iterator(); final Iterator<E> it2 = baseStack == null ? null : baseStack.iterator(); return new Iterator<E>() { public boolean hasNext() { return it1.hasNext() || (it2 != null && it2.hasNext()); } public E next() { if (it1.hasNext()) { return it1.next(); } else if (it2 != null) { return it2.next(); } else { throw new NoSuchElementException("iterator is tired and emotional"); } } public void remove() { throw new UnsupportedOperationException("remove"); } }; } public boolean offer(E e) { throw new UnsupportedOperationException(); } public boolean offerFirst(E e) { throw new UnsupportedOperationException(); } public boolean offerLast(E e) { throw new UnsupportedOperationException(); } public E peek() { if (DEBUG) check(); return myStack.peek(); } public E peekFirst() { if (DEBUG) check(); return myStack.peekFirst(); } public E peekLast() { throw new UnsupportedOperationException(); } public E poll() { throw new UnsupportedOperationException(); } public E pollFirst() { throw new UnsupportedOperationException(); } public E pollLast() { throw new UnsupportedOperationException(); } public E pop() { return removeFirst(); } public void push(E e) { addFirst(e); } public E remove() { return removeFirst(); } public boolean remove(Object o) { throw new UnsupportedOperationException(); } public E removeFirst() { if (DEBUG) check(); if (myStack.isEmpty() && baseStack != null) { myStack = new LinkedList<E>(baseStack); baseStack = null; baseStackSize = 0; } return myStack.removeFirst(); } public boolean removeFirstOccurrence(Object o) { throw new UnsupportedOperationException(); } public E removeLast() { throw new UnsupportedOperationException(); } public boolean removeLastOccurrence(Object o) { throw new UnsupportedOperationException(); } public int size() { if (DEBUG) check(); return myStack.size() + baseStackSize; } public boolean addAll(Collection<? extends E> c) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } public boolean containsAll(Collection<?> c) { throw new UnsupportedOperationException(); } public boolean isEmpty() { if (DEBUG) check(); return size() == 0; } public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException(); } public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException(); } public Object[] toArray() { // This method is used by copy constructors. if (DEBUG) check(); if (baseStack == null) { return myStack.toArray(); } else { int myStackSize = myStack.size(); Object[] res = new Object[baseStackSize + myStackSize]; myStack.toArray(res); Object[] tmp = baseStack.toArray(); System.arraycopy(tmp, 0, res, myStackSize, baseStackSize); return res; } } public <T> T[] toArray(T[] a) { throw new UnsupportedOperationException(); } private void check() { if (baseStack != null && baseStack.size() != baseStackSize) { throw new AssertionError("base stack has been updated!"); } } }