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

org.pure4j.collections.PersistentQueue Maven / Gradle / Ivy

There is a newer version: 0.3.1
Show newest version
/**
 *   Copyright (c) Rich Hickey. All rights reserved.
 *   The use and distribution terms for this software are covered by the
 *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
 *   which can be found in the file epl-v10.html at the root of this distribution.
 *   By using this software in any fashion, you are agreeing to be bound by
 * 	 the terms of this license.
 *   You must not remove this notice, or any other, from this software.
 **/

package org.pure4j.collections;

import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.pure4j.Pure4J;
import org.pure4j.annotations.immutable.IgnoreImmutableTypeCheck;
import org.pure4j.annotations.pure.Enforcement;
import org.pure4j.annotations.pure.Pure;

//import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * conses onto rear, peeks/pops from front See Okasaki's Batched Queues This
 * differs in that it uses a PersistentVector as the rear, which is in-order, so
 * no reversing or suspensions required for persistent use
 */

public class PersistentQueue implements IPersistentStack {

	final private static PersistentQueue EMPTY = new PersistentQueue(0,null, null);

	final int cnt;
	final ISeq f;
	final PersistentVector r;
	// static final int INITIAL_REAR_SIZE = 4;
	
	@IgnoreImmutableTypeCheck
	private int _hasheq = -1;

	PersistentQueue(int cnt, ISeq f, PersistentVector r) {
		this.cnt = cnt;
		this.f = f;
		this.r = r;
	}

	public boolean equals(Object obj) {
		if (!(obj instanceof ISeq))
			return false;
		ISeq ms = PureCollections.seq(obj);
		for (ISeq s = seq(); s != null; s = s.next(), ms = ms.next()) {
			if (ms == null || !Util.equals(s.first(), ms.first()))
				return false;
		}
		return ms == null;

	}
	
	public int hashCode() {
		if (_hasheq == -1) {
			_hasheq = Hasher.hashOrdered(this);
		}
		return _hasheq;
	}

	@SuppressWarnings("unchecked")
	public K peek() {
		return (K) PureCollections.first(f);
	}

	public PersistentQueue pop() {
		if (f == null) // hmmm... pop of empty queue -> empty queue?
			return this;
		// throw new IllegalStateException("popping empty queue");
		ISeq f1 = f.next();
		PersistentVector r1 = r;
		if (f1 == null) {
			f1 = PureCollections.seq(r);
			r1 = null;
		}
		return new PersistentQueue(cnt - 1, f1, r1);
	}

	public int count() {
		return cnt;
	}

	@SuppressWarnings("unchecked")
	public ISeq seq() {
		if (f == null)
			return null;
		return new Seq(f, (ISeq) PureCollections.seq(r));
	}

	@SuppressWarnings("unchecked")
	public PersistentQueue cons(K o) {
		Pure4J.immutable(o);
		if (f == null) // empty
			return new PersistentQueue(cnt + 1,  PureCollections.list(o), null);
		else {
			PersistentVector rr = (PersistentVector) ((r != null) ? r : PersistentVector.emptyVector());
			return new PersistentQueue(cnt + 1, f, rr.cons(o));
		}
	}

	@SuppressWarnings("unchecked")
	public PersistentQueue empty() {
		return (PersistentQueue) EMPTY;
	}
	
	@SuppressWarnings("unchecked")
	public static  PersistentQueue emptyQueue() {
		return (PersistentQueue) EMPTY;
	}

	static class Seq extends ASeq {
		final ISeq f;
		final ISeq rseq;

		Seq(ISeq f, ISeq rseq) {
			this.f = f;
			this.rseq = rseq;
		}

		public K first() {
			return f.first();
		}

		public ISeq next() {
			ISeq f1 = f.next();
			ISeq r1 = rseq;
			if (f1 == null) {
				if (rseq == null)
					return null;
				f1 = rseq;
				r1 = null;
			}
			return new Seq(f1, r1);
		}

		public int count() {
			return PureCollections.count(f) + PureCollections.count(rseq);
		}
	}

	// java.util.Collection implementation

	public Object[] toArray() {
		return PureCollections.seqToArray(seq());
	}

	public boolean add(Object o) {
		Pure4J.unsupported();
		return false;
	}

	public boolean remove(Object o) {
		Pure4J.unsupported();
		return false;
	}

	public boolean addAll(Collection c) {
		Pure4J.unsupported();
		return false;
	}

	public void clear() {
		Pure4J.unsupported();
	}

	public boolean retainAll(Collection c) {
		Pure4J.unsupported();
		return false;
	}

	public boolean removeAll(Collection c) {
		Pure4J.unsupported();
		return false;
	}

	public boolean containsAll(Collection c) {
		Pure4J.immutable(c);
		for (Object o : c) {
			if (contains(o))
				return true;
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	@Pure(Enforcement.FORCE)
	public  E[] toArray(E[] a) {
		return (E[]) PureCollections.seqToNewArray(seq(), a);
	}

	public int size() {
		return count();
	}

	public boolean isEmpty() {
		return count() == 0;
	}

	public boolean contains(Object o) {
		Pure4J.immutable(o);
		for (ISeq s = seq(); s != null; s = s.next()) {
			if (Util.equals(s.first(), o))
				return true;
		}
		return false;
	}

	public Iterator iterator() {
		return new IPureIterator() {
			private ISeq fseq = f;
			private final Iterator riter = r != null ? r.iterator() : null;

			public boolean hasNext() {
				return ((fseq != null) || (riter != null && riter
						.hasNext()));
			}

			public K next() {
				if (fseq != null) {
					K ret = fseq.first();
					fseq = fseq.next();
					return ret;
				} else if (riter != null && riter.hasNext())
					return riter.next();
				else
					throw new NoSuchElementException();
			}

			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}

	public String toString() {
		return ToStringFunctions.toString(this);
	}

	@Override
	public ITransientQueue asTransient() {
		return new TransientQueue(this.seq());
	}
	

}