All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pcollections.ConsPStack Maven / Gradle / Ivy

There is a newer version: 3.3.8
Show newest version
/*
 * Copyright (c) 2008 Harold Cooper. All rights reserved.
 * Licensed under the MIT License.
 * See LICENSE file in the project root for full license information.
 */

package org.pcollections;

import java.io.Serializable;
import java.util.AbstractSequentialList;
import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;

/**
 * A simple persistent stack of non-null values.
 *
 * 

This implementation is thread-safe (assuming Java's AbstractSequentialList is thread-safe), * although its iterators may not be. * * @author harold * @param */ public final class ConsPStack extends AbstractSequentialList implements PStack, Serializable { private static final long serialVersionUID = 1L; //// STATIC FACTORY METHODS //// private static final ConsPStack EMPTY = new ConsPStack(); /** * @param * @return an empty stack */ @SuppressWarnings("unchecked") public static ConsPStack empty() { return (ConsPStack) EMPTY; } /** * @param * @param e * @return empty().plus(e) */ public static ConsPStack singleton(final E e) { return ConsPStack.empty().plus(e); } /** * @param * @param list * @return a stack consisting of the elements of list in the order of list.iterator() */ @SuppressWarnings("unchecked") public static ConsPStack from(final Collection list) { if (list instanceof ConsPStack) return (ConsPStack) list; // (actually we only know it's ConsPStack) // but that's good enough for an immutable // (i.e. we can't mess someone else up by adding the wrong type to it) return ConsPStack.from(list.iterator()); } private static ConsPStack from(final Iterator i) { if (!i.hasNext()) return empty(); E e = i.next(); return ConsPStack.from(i).plus(e); } //// PRIVATE CONSTRUCTORS //// private final E first; private final ConsPStack rest; private final int size; // not externally instantiable (or subclassable): private ConsPStack() { // EMPTY constructor if (EMPTY != null) throw new RuntimeException("empty constructor should only be used once"); size = 0; first = null; rest = null; } private ConsPStack(final E first, final ConsPStack rest) { this.first = first; this.rest = rest; size = 1 + rest.size; } //// REQUIRED METHODS FROM AbstractSequentialList //// @Override public int size() { return size; } @Override public ListIterator listIterator(final int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException(); return new ListIterator() { int i = index; ConsPStack next = subList(index); public boolean hasNext() { return next.size > 0; } public boolean hasPrevious() { return i > 0; } public int nextIndex() { return index; } public int previousIndex() { return index - 1; } public E next() { E e = next.first; next = next.rest; return e; } public E previous() { System.err.println("ConsPStack.listIterator().previous() is inefficient, don't use it!"); next = subList(index - 1); // go from beginning... return next.first; } public void add(final E o) { throw new UnsupportedOperationException(); } public void remove() { throw new UnsupportedOperationException(); } public void set(final E o) { throw new UnsupportedOperationException(); } }; } //// OVERRIDDEN METHODS FROM AbstractSequentialList //// @SuppressWarnings("static-access") @Override public ConsPStack subList(final int start, final int end) { if (start < 0 || end > size || start > end) throw new IndexOutOfBoundsException(); if (start == end) return empty(); if (start > 0) // remove from beginning return subList(start).subList(0, end - start); if (end == size) return this; // remove from end (by popping off until end, and then pushing back on) ConsPStack reversed = empty(); for (final E e : this) { if (reversed.size == end) break; reversed = reversed.plus(e); } return this.empty().plusAll(reversed); // plusAll reverses again } //// IMPLEMENTED METHODS OF PStack //// public ConsPStack plus(final E e) { return new ConsPStack(e, this); } public ConsPStack plusAll(final Collection list) { ConsPStack result = this; for (E e : list) result = result.plus(e); return result; } public ConsPStack plus(final int i, final E e) { if (i < 0 || i > size) throw new IndexOutOfBoundsException(); if (i == 0) // insert at beginning return plus(e); return new ConsPStack(first, rest.plus(i - 1, e)); } public ConsPStack plusAll(final int i, final Collection list) { if (i < 0 || i > size) throw new IndexOutOfBoundsException(); if (i == 0) return plusAll(list); return new ConsPStack(first, rest.plusAll(i - 1, list)); } public ConsPStack minus(final Object e) { if (size == 0) return this; if (first.equals(e)) // found it return rest; // don't recurse (only remove one) // otherwise keep looking: ConsPStack newRest = rest.minus(e); if (newRest == rest) return this; return new ConsPStack(first, newRest); } public ConsPStack minus(final int i) { if (i < 0 || i >= size) throw new IndexOutOfBoundsException("Index: " + i + "; size: " + size); else if (i == 0) return rest; else return new ConsPStack(first, rest.minus(i - 1)); } public ConsPStack minusAll(final Collection list) { if (size == 0) return this; if (list.contains(first)) // get rid of current element return rest.minusAll(list); // recursively delete all // either way keep looking: ConsPStack newRest = rest.minusAll(list); if (newRest == rest) return this; return new ConsPStack(first, newRest); } public ConsPStack with(final int i, final E e) { if (i < 0 || i >= size) throw new IndexOutOfBoundsException(); if (i == 0) { if (first.equals(e)) return this; return new ConsPStack(e, rest); } ConsPStack newRest = rest.with(i - 1, e); if (newRest == rest) return this; return new ConsPStack(first, newRest); } public ConsPStack subList(int start) { if (start < 0 || start > size) throw new IndexOutOfBoundsException(); ConsPStack s = this; while (start > 0) { s = s.rest; start--; } return s; } }