package cc.mallet.pipe; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import cc.mallet.pipe.iterator.EmptyInstanceIterator; import cc.mallet.types.Instance; /** A Pipe that works like a rule list. Evaluate predicate() on each Pipe in the array; * the first one that returns true, call that one ("the called Pipe"), and ignore the * remainder in the array. The called Pipe will then get control of the source * InstanceIterator until it produces an Instance---in other words it will be able to call * next() on the source Pipe as often as necessary to produce an Instance. * You must be very careful that none of the iterators from Pipes in the rule list buffer * any Instances---in other words they shouldn't call next() to pre-gather any Instances * they they themselves don't consume and process immediately. Otherwise, Instances * that should have been processed by some other constituent Pipe could get lost in * this buffering process. * @author Andrew McCallum <mccallum@cs.umass.edu> */ @ Deprecated //Implementation not yet complete, and seems quite dangerous and error-prone. public class BranchingPipe extends Pipe { ArrayList<Pipe> pipes; public BranchingPipe () { this.pipes = new ArrayList<Pipe> (); } public BranchingPipe (Pipe[] pipes) { this.pipes = new ArrayList<Pipe> (pipes.length); for (int i = 0; i < pipes.length; i++) this.pipes.add (pipes[i]); } public BranchingPipe (Collection<Pipe> pipeList) { pipes = new ArrayList<Pipe> (pipeList); } private class PeekingInstanceIterator implements Iterator<Instance> { Iterator<Instance> source; Instance nextInstance = null; public PeekingInstanceIterator (Iterator<Instance> source) { this.source = source; } public boolean hasNext () { return source.hasNext(); } public Instance peekNext () { if (nextInstance == null && !hasNext()) return null; else if (nextInstance == null) nextInstance = next(); return nextInstance; } public Instance next () { if (nextInstance != null) { Instance tmp = nextInstance; nextInstance = null; return tmp; } else { return source.next(); } } public void remove () { throw new IllegalStateException ("This Iterator<Instance> does not support remove()."); } } private class GateKeepingInstanceIterator implements Iterator<Instance> { PeekingInstanceIterator source; Pipe testingPipe; public GateKeepingInstanceIterator (PeekingInstanceIterator source, Pipe testingPipe) { this.source = source; this.testingPipe = testingPipe; } public Instance next () { // Make sure this is not an Instance we were supposed to skip. assert (testingPipe.precondition(source.peekNext())); return source.next(); } public boolean hasNext () { return source.hasNext() && testingPipe.precondition(source.peekNext()); } public void remove () { throw new IllegalStateException ("This Iterator<Instance> does not support remove()."); } } private class BranchingInstanceIterator implements Iterator<Instance> { PeekingInstanceIterator source; ArrayList<Iterator<Instance>> iterators; public BranchingInstanceIterator (PeekingInstanceIterator source) { this.source = new PeekingInstanceIterator (source); this.iterators = new ArrayList<Iterator<Instance>>(pipes.size()); for (Pipe p : pipes) iterators.add (new GateKeepingInstanceIterator (source, p)); } public boolean hasNext () { return source.hasNext(); } public Instance next() { Instance input = source.peekNext(); for (int i = 0; i < pipes.size(); i++) { if (pipes.get(i).precondition(input)) { return iterators.get(i).next(); } } throw new IllegalStateException ("Next Instance satisfied none of the branches' preconditions."); } /** Return the @link{Pipe} that processes @link{Instance}s going through this iterator. */ public Pipe getPipe () { return null; } public Iterator<Instance> getSourceIterator () { return source; } public void remove () { throw new IllegalStateException ("This Iterator<Instance> does not support remove()."); } } public Iterator<Instance> newIteratorFrom (Iterator<Instance> source) { if (pipes.size() == 0) return source; Iterator<Instance> ret = pipes.get(0).newIteratorFrom(source); for (int i = 1; i < pipes.size(); i++) ret = pipes.get(i).newIteratorFrom(ret); return ret; } private static void test () { new BranchingPipe (new Pipe[] { new CharSequence2TokenSequence("\\w*") { public boolean skipIfFalse (Instance inst) { return ! (inst instanceof CharSequence); } } }); } }