/* * (c) Copyright 2007, 2008, 2009 Hewlett-Packard Development Company, LP * All rights reserved. * [See end of file] */ package org.openjena.atlas.iterator; import java.io.PrintStream ; import java.util.* ; import org.openjena.atlas.lib.ActionKeyValue ; import org.openjena.atlas.lib.Closeable ; public class Iter implements Iterable, Iterator { // First part : the static function library. // Often with both Iterator and Iterable public static Iterator singleton(T item) { return new SingletonIterator(item) ; } public static Iterator nullIterator() { return new NullIterator() ; } public static Set toSet(Iterable stream) { return toSet(stream.iterator()); } public static Set toSet(Iterator stream) { Accumulate> action = new Accumulate>() { private Set acc = null ; public void accumulate(T item) { acc.add(item) ; } public Set get() { return acc ; } public void start() { acc = new HashSet() ; } public void finish() {} } ; return reduce(stream, action) ; } public static List toList(Iterable stream) { return toList(stream.iterator()) ; } public static List toList(Iterator stream) { Accumulate> action = new Accumulate>() { private List acc = null ; public void accumulate(T item) { acc.add(item) ; } public List get() { return acc ; } public void start() { acc = new ArrayList() ; } public void finish() {} } ; return reduce(stream, action) ; } public interface Folder { Y eval(Y acc, X arg) ; } public static R foldLeft(Iterable stream, Folder function, R value) { return foldLeft(stream.iterator(), function, value) ; } public static R foldLeft(Iterator stream, Folder function, R value) { // Tail recursion, unwound for ( ; stream.hasNext() ; ) { T item = stream.next(); value = function.eval(value, item) ; } return value ; } public static R foldRight(Iterable stream, Folder function, R value) { return foldRight(stream.iterator(), function, value) ; } public static R foldRight(Iterator stream, Folder function, R value) { // Recursive. if ( ! stream.hasNext() ) return value ; T item = stream.next() ; return function.eval( foldRight(stream, function, value) , item ) ; } // Note fold-left and fold-right // http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29 // This reduce is fold-left (take first element, apply to rest of list) // which copes with infinite lists. // Fold-left starts by combining the first element, then moves on. public static R reduce(Iterable stream, Accumulate aggregator) { return reduce(stream.iterator(), aggregator) ; } public static R reduce(Iterator stream, Accumulate aggregator) { aggregator.start(); for ( ; stream.hasNext() ; ) { T item = stream.next(); aggregator.accumulate(item) ; } aggregator.finish(); return aggregator.get(); } // map without the results - do immediately. // Also, apply with call in between? public static void apply(Iterable stream, Action action) { apply(stream.iterator(), action) ; } public static void apply(Iterator stream, Action action) { for ( ; stream.hasNext() ; ) { T item = stream.next(); action.apply(item) ; } } // -- Map specific apply. No results - do immediately. public static void apply(Map map, ActionKeyValue action) { for ( Map.Entry entry : map.entrySet() ) action.apply(entry.getKey(), entry.getValue()) ; } // ---- Filter public static Iterator filter(Iterable stream, Filter filter) { return filter(stream.iterator(), filter) ; } public static Iterator filter(final Iterator stream, final Filter filter) { final Iterator iter = new Iterator(){ boolean finished = false ; T slot ; public boolean hasNext() { if ( finished ) return false ; while ( slot == null ) { if ( ! stream.hasNext() ) { finished = true ; break ; } T nextItem = stream.next() ; if ( filter.accept(nextItem) ) { slot = nextItem ; break ; } } return slot != null ; } public T next() { if ( hasNext() ) { T returnValue = slot ; slot = null ; return returnValue ; } throw new NoSuchElementException("filter.next") ; } public void remove() { throw new UnsupportedOperationException("filter.remove") ; } } ; return iter ; } private static class InvertedFilter implements Filter { public static Filter invert(Filter filter) { return new InvertedFilter(filter) ; } private Filter baseFilter ; private InvertedFilter(Filter baseFilter) { this.baseFilter = baseFilter ; } public boolean accept(T item) { return ! baseFilter.accept(item) ; } } public static Iterator notFilter(Iterable stream, Filter filter) { return notFilter(stream.iterator(), filter) ; } public static Iterator notFilter(final Iterator stream, final Filter filter) { Filter flippedFilter = InvertedFilter.invert(filter) ; return filter(stream, flippedFilter) ; } // Filter-related /** Return true if every element of stream passes the filter (reads the stream) */ public static boolean every(Iterable stream, Filter filter) { for ( T item : stream ) if ( ! filter.accept(item) ) return false ; return true ; } /** Return true if every element of stream passes the filter (reads the stream until the first element not passing the filter) */ public static boolean every(Iterator stream, Filter filter) { for ( ; stream.hasNext() ; ) { T item = stream.next(); if ( ! filter.accept(item) ) return false ; } return true ; } /** Return true if every element of stream passes the filter (reads the stream until the first element passing the filter) */ public static boolean some(Iterable stream, Filter filter) { for ( T item : stream ) if ( filter.accept(item) ) return true ; return false ; } /** Return true if one or more elements of stream passes the filter (reads the stream to first element passing the filter) */ public static boolean some(Iterator stream, Filter filter) { for ( ; stream.hasNext() ; ) { T item = stream.next(); if ( filter.accept(item) ) return true ; } return false ; } // ---- Map public static Iterator map(Iterable stream, Transform converter) { return map(stream.iterator(), converter) ; } public static Iterator map(final Iterator stream, final Transform converter) { final Iterator iter = new Iterator(){ public boolean hasNext() { return stream.hasNext() ; } public R next() { return converter.convert(stream.next()) ; } public void remove() { throw new UnsupportedOperationException("map.remove") ; } } ; return iter ; } public static List map(List list, Transform converter) { return toList(map(list.iterator(), converter)) ; } /** Apply an action to everything in stream, yielding a stream of the same items */ public static Iterator operate(Iterable stream, Action converter) { return operate(stream.iterator(), converter) ; } /** Apply an action to everything in stream, yielding a stream of the same items */ public static Iterator operate(final Iterator stream, final Action action) { final Iterator iter = new Iterator(){ public boolean hasNext() { return stream.hasNext() ; } public T next() { T t = stream.next() ; action.apply(t) ; return t ; } public void remove() { throw new UnsupportedOperationException("operate.remove") ; } } ; return iter ; } /** Print an iterator as it gets used - this adds a printing wrapper */ public static Iterator printWrapper(final Iterator stream) { return Iter.printWrapper(System.out, stream) ; } /** Print an iterator as it gets used - this adds a printing wrapper */ public static Iterator printWrapper(final PrintStream out, final Iterator stream) { Action action = new Action(){ public void apply(T item) { out.println(item) ; } } ; return Iter.operate(stream, action) ; } public static Iterator append(Iterable iter1, Iterable iter2) { return IteratorCons.create(iterator(iter1), iterator(iter2)); } // Could try for on each arg. public static Iterator append(Iterator iter1, Iterator iter2) { return IteratorCons.create(iter1, iter2); } private static Iterator iterator(Iterable iter) { return (iter==null) ? null : iter.iterator() ; } public static Iterator distinct(Iterable iter) { return distinct(iter.iterator()) ; } public static Iterator distinct(Iterator iter) { return filter(iter, new FilterUnique()) ; } public static Iterator removeNulls(Iterable iter) { return filter(iter, new FilterOutNulls()) ; } public static Iterator removeNulls(Iterator iter) { return filter(iter, new FilterOutNulls()) ; } @SuppressWarnings("unchecked") public static Iterator convert(Iterator iterator) { return (Iterator)iterator ; } /** Count the iterable - many iterable objects have a .size() operation which shoudl be used in preference to this explicit counting operation */ public static long count(Iterable iterator) { ActionCount action = new ActionCount() ; Iter.apply(iterator, action) ; return action.getCount() ; } /** Count the iterator (this is destructive on the iterator) */ public static long count(Iterator iterator) { ActionCount action = new ActionCount() ; Iter.apply(iterator, action) ; return action.getCount() ; } // ---- String related helpers public static String asString(Iterable stream) { return asString(stream, new AccString()) ; } public static String asString(Iterator stream) { return asString(stream, new AccString()) ; } public static String asString(Iter stream) { return asString(stream, new AccString()) ; } public static String asString(Iterable stream, String sep) { return asString(stream, new AccString(sep)) ; } public static String asString(Iterator stream, String sep) { return asString(stream, new AccString(sep)) ; } public static String asString(Iter stream, String sep) { return asString(stream.iterator(), new AccString(sep)) ; } public static String asString(Iterable stream, AccString formatter) { return reduce(stream, formatter) ; } public static String asString(Iterator stream, AccString formatter) { return reduce(stream, formatter) ; } public static String asString(Iter stream, AccString formatter) { return reduce(stream.iterator(), formatter) ; } // ---- public static void close(Iterator iter) { if ( iter instanceof Closeable ) ((Closeable)iter).close() ; } public static Iterator debug(Iterator stream) { Transform x = new Transform() { //@Override public T convert(T item) { System.out.println(item) ; return item ; } } ; return map(stream, x) ; } //---- // Iter class part // And .... // Could merge in concatenated iterators - if used a lot there is reducable cost. // Just putting in a slot is free (?) because objects of one or two slots have // the same memory allocation. // And .. be an iterator framework for extension // Or dynamically with a subclass and a static constructor // List concatenated = null ; public static Iter iter(Iter iter) { return iter ; } // May not do what you expect. iter(int[]) is iter of one object (an int[]) // public static Iter iter(T...objects) // { return Iter.iter(Arrays.asList(objects)) ; } public static Iter iter(Collection collection) { return Iter.iter(collection.iterator()) ; } public static Iter iter(Iterator iterator) { if ( iterator instanceof Iter ) return (Iter)iterator ; return new Iter(iterator) ; } public static Iter iter(Iterable iterable) { if ( iterable instanceof Iter ) return (Iter)iterable ; return new Iter(iterable.iterator()) ; } /** Materializae an iterator, that is, force it to run now - useful in debugging */ public static Iterator materialize(Iterator iter) { return Iter.toList(iter).iterator() ; } public static Iter concat(Iter iter1, Iteriter2) { if ( iter1 == null ) return iter2 ; if ( iter2 == null ) return iter1 ; return iter1.append(iter2) ; } public static Iterator concat(Iterator iter1, Iteratoriter2) { if ( iter1 == null ) return iter2 ; if ( iter2 == null ) return iter1 ; return Iter.iter(iter1).append(Iter.iter(iter2)) ; } // ------------------------------------------------------ // The class. private Iterator iterator ; private Iter(Iterator iterator) { this.iterator = iterator ; } public Set toSet() { return toSet(iterator) ; } public List toList() { return toList(iterator) ; } public Iter filter(Filter filter) { return iter(filter(iterator, filter)) ; } public boolean every(Filter filter) { return every(iterator, filter) ; } public boolean some(Filter filter) { return some(iterator, filter) ; } public Iter removeNulls() { return filter(new FilterOutNulls()) ; } public Iter map(Transform converter) { return iter(map(iterator, converter)) ; } /** Apply an action to everything in the stream, yielding a stream of the same items */ public Iter operate(Action action) { return iter(operate(iterator, action)) ; } public R reduce(Accumulate aggregator) { return reduce(iterator, aggregator) ; } public void apply(Action action) { apply(iterator, action) ; } public Iter append(Iterator iter) { return new Iter(IteratorCons.create(iterator, iter)) ; } /** Count the iterator (this is destructive on the iterator) */ public long count() { ActionCount action = new ActionCount() ; apply(action) ; return action.getCount() ; } public String asString() { return asString(iterator) ; } public String asString(String sep) { return asString(iterator, sep) ; } public Iter distinct() { return new Iter(distinct(iterator())) ; } // ---- Iterable public Iterator iterator() { return iterator ; } // ---- Iterator //---- // Could merge in concatenated iterators - if used a lot there is reducable cost. // Just putting in a slot is free (?) because objects of one or two slots have // the same memory allocation. // And .. be an iterator framework for extension public boolean hasNext() { return iterator.hasNext() ; } public T next() { return iterator.next() ; } public void remove() { iterator.remove() ; } //---- // Iter class part // And .... // Could merge in concatenated iterators - if used a lot there is reducable cost. // Just putting in a slot is free (?) because objects of one or two slots have // the same memory allocation. // And .. be an iterator framework for extension // Or dynamically with a subclass and a static constructor // List concatenated = null ; public static Iter singletonIter(T item) { return new Iter(new SingletonIterator(item)) ; } public static Iter nullIter() { return new Iter(new NullIterator()) ; } } /* * (c) Copyright 2007, 2008, 2009 Hewlett-Packard Development Company, LP * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */