/** * 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. **/ /* rich Mar 5, 2009 */ package clojure.lang; final public class Stream implements Seqable, Streamable, Sequential { static final ISeq NO_SEQ = new Cons(null, null); ISeq sequence = NO_SEQ; final IFn src; final IFn xform; IFn tap = null; public Stream(IFn src){ this.src = src; this.xform = null; } public Stream(IFn xform, Stream src) { this.src = src.tap(); this.xform = xform; } final public ISeq seq(){ return sequence().seq(); } final synchronized public ISeq sequence(){ if(sequence == NO_SEQ) { tap(); sequence = makeSequence(tap); } return sequence; } static ISeq makeSequence(final IFn tap){ return new LazySeq(new AFn(){ public Object invoke() throws Exception{ Object v = tap.invoke(); if(v == RT.EOS) return null; return new Cons(v, new LazySeq(this)); } }); } final synchronized public Stream stream() throws Exception { return this; } final synchronized public IFn tap() { if (tap != null) throw new IllegalStateException("Stream already tapped"); return tap = makeTap(xform, src); } static IFn makeTap(final IFn xform, final IFn src){ return new AFn(){ final synchronized public Object invoke() throws Exception{ if(xform == null) return src.invoke(); Object v; Object xv; do { v = src.invoke(); if(v == RT.EOS) return v; xv = xform.invoke(v); } while(xv == RT.SKIP); return xv; } }; } }