/**
* 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 com.trifork.clj_ds;
import java.util.Collection;
import java.util.Iterator;
/**
* conses onto rear, peeks/pops from front
* See Okasaki's Batched Queues
* This differs in that it uses a PersistentArrayList as the rear, which is in-order,
* so no reversing or suspensions required for persistent use
*/
public class PersistentQueue<T> extends Obj implements IPersistentList<T>, Collection<T>{
final public static PersistentQueue EMPTY = new PersistentQueue(null, null, null);
//*
final ISeq f;
final PersistentVector r;
//static final int INITIAL_REAR_SIZE = 4;
int _hash = -1;
PersistentQueue(IPersistentMap meta, ISeq f, PersistentVector r){
super(meta);
this.f = f;
this.r = r;
}
public boolean equiv(Object obj){
if(!(obj instanceof Sequential))
return false;
ISeq ms = RT.seq(obj);
for(ISeq s = seq(); s != null; s = s.next(), ms = ms.next())
{
if(ms == null || !Util.equiv(s.first(), ms.first()))
return false;
}
return ms == null;
}
public boolean equals(Object obj){
if(!(obj instanceof Sequential))
return false;
ISeq ms = RT.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(_hash == -1)
{
int hash = 0;
for(ISeq s = seq(); s != null; s = s.next())
{
hash = Util.hashCombine(hash, Util.hash(s.first()));
}
this._hash = hash;
}
return _hash;
}
public T peek(){
return (T) RT.first(f);
}
public PersistentQueue<T> 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 = RT.seq(r);
r1 = null;
}
return new PersistentQueue<T>(meta(), f1, r1);
}
public int count(){
return RT.count(f) + RT.count(r);
}
public ISeq<T> seq(){
if(f == null)
return null;
return new Seq<T>(f, RT.seq(r));
}
public PersistentQueue<T> cons(T o){
if(f == null) //empty
return new PersistentQueue<T>(meta(), RT.list(o), null);
else
return new PersistentQueue<T>(meta(), f, (r != null ? r : PersistentVector.EMPTY).cons(o));
}
public IPersistentCollection<T> empty(){
return EMPTY.withMeta(meta());
}
public PersistentQueue<T> withMeta(IPersistentMap meta){
return new PersistentQueue<T>(meta, f, r);
}
static class Seq<T> extends ASeq<T>{
final ISeq<T> f;
final ISeq<T> rseq;
Seq(ISeq<T> f, ISeq<T> rseq){
this.f = f;
this.rseq = rseq;
}
Seq(IPersistentMap meta, ISeq<T> f, ISeq<T> rseq){
super(meta);
this.f = f;
this.rseq = rseq;
}
public T first(){
return f.first();
}
public ISeq<T> next(){
ISeq<T> f1 = f.next();
ISeq<T> r1 = rseq;
if(f1 == null)
{
if(rseq == null)
return null;
f1 = rseq;
r1 = null;
}
return new Seq<T>(f1, r1);
}
public int count(){
return RT.count(f) + RT.count(rseq);
}
public Seq<T> withMeta(IPersistentMap meta){
return new Seq<T>(meta, f, rseq);
}
}
// java.util.Collection implementation
public Object[] toArray(){
return RT.seqToArray(seq());
}
public boolean add(Object o){
throw new UnsupportedOperationException();
}
public boolean remove(Object o){
throw new UnsupportedOperationException();
}
public boolean addAll(Collection<? extends T> c){
throw new UnsupportedOperationException();
}
public void clear(){
throw new UnsupportedOperationException();
}
public boolean retainAll(Collection<?> c){
throw new UnsupportedOperationException();
}
public boolean removeAll(Collection<?> c){
throw new UnsupportedOperationException();
}
public boolean containsAll(Collection<?> c){
for(Object o : c)
{
if(contains(o))
return true;
}
return false;
}
public Object[] toArray(Object[] a){
if(a.length >= count())
{
ISeq s = seq();
for(int i = 0; s != null; ++i, s = s.next())
{
a[i] = s.first();
}
if(a.length >= count())
a[count()] = null;
return a;
}
else
return toArray();
}
public int size(){
return count();
}
public boolean isEmpty(){
return count() == 0;
}
public boolean contains(Object o){
for(ISeq<T> s = seq(); s != null; s = s.next())
{
if(Util.equiv(s.first(), o))
return true;
}
return false;
}
public Iterator<T> iterator(){
return new SeqIterator<T>(seq());
}
/*
public static void main(String[] args){
if(args.length != 1)
{
System.err.println("Usage: PersistentQueue n");
return;
}
int n = Integer.parseInt(args[0]);
long startTime, estimatedTime;
Queue list = new LinkedList();
//Queue list = new ConcurrentLinkedQueue();
System.out.println("Queue");
startTime = System.nanoTime();
for(int i = 0; i < n; i++)
{
list.add(i);
list.add(i);
list.remove();
}
for(int i = 0; i < n - 10; i++)
{
list.remove();
}
estimatedTime = System.nanoTime() - startTime;
System.out.println("time: " + estimatedTime / 1000000);
System.out.println("peek: " + list.peek());
PersistentQueue q = PersistentQueue.EMPTY;
System.out.println("PersistentQueue");
startTime = System.nanoTime();
for(int i = 0; i < n; i++)
{
q = q.cons(i);
q = q.cons(i);
q = q.pop();
}
// IPersistentList lastq = null;
// IPersistentList lastq2;
for(int i = 0; i < n - 10; i++)
{
//lastq2 = lastq;
//lastq = q;
q = q.pop();
}
estimatedTime = System.nanoTime() - startTime;
System.out.println("time: " + estimatedTime / 1000000);
System.out.println("peek: " + q.peek());
IPersistentList q2 = q;
for(int i = 0; i < 10; i++)
{
q2 = (IPersistentList) q2.cons(i);
}
// for(ISeq s = q.seq();s != null;s = s.rest())
// System.out.println("q: " + s.first().toString());
// for(ISeq s = q2.seq();s != null;s = s.rest())
// System.out.println("q2: " + s.first().toString());
}
*/
}