001    /*
002    Galois, a framework to exploit amorphous data-parallelism in irregular
003    programs.
004    
005    Copyright (C) 2010, The University of Texas at Austin. All rights reserved.
006    UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS SOFTWARE
007    AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR ANY
008    PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF PERFORMANCE, AND ANY
009    WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF DEALING OR USAGE OF TRADE.
010    NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH RESPECT TO THE USE OF THE
011    SOFTWARE OR DOCUMENTATION. Under no circumstances shall University be liable
012    for incidental, special, indirect, direct or consequential damages or loss of
013    profits, interruption of business, or related expenses which may arise from use
014    of Software or Documentation, including but not limited to those resulting from
015    defects in Software and/or Documentation, or loss or inaccuracy of data of any
016    kind.
017    
018    File: FnIterable.java 
019    
020    */
021    
022    
023    
024    package util.fn;
025    
026    import java.util.ArrayList;
027    import java.util.Iterator;
028    import java.util.List;
029    
030    import util.Pair;
031    
032    /**
033     * Functional programming like sequences. This class provides map-like functionality.
034     * 
035     *
036     * @param <T>  type of elements of the sequence
037     */
038    public class FnIterable<T> implements Iterable<T> {
039      private final Iterable<T> it;
040    
041      private FnIterable(Iterable<T> it) {
042        this.it = it;
043      }
044    
045      /**
046       * Creates a new functional sequence from an {@link java.lang.Iterable} object
047       * 
048       * @param <T>  type of elements of the sequence
049       * @param it   the iterable object
050       * @return     a functional sequence view of the iterable object
051       */
052      public static <T> FnIterable<T> from(Iterable<T> it) {
053        return new FnIterable<T>(it);
054      }
055    
056      /**
057       * Produces a sequence of pairs from two sequences.
058       * <pre>
059       *  {a1, a2, a3, ...}.zip({b1, b2, b3, ...}) ==> {(a1, b1), (a2, b2), (a3, b3), ...}
060       * </pre>
061       * 
062       * @param <U> type of elements of the argument sequence
063       * @param o   argument sequence to zip with
064       * @return    sequence of pairs combining this and argument sequence
065       */
066      public final <U> FnIterable<Pair<T, U>> zip(final FnIterable<U> o) {
067        return new FnIterable<Pair<T, U>>(new Iterable<Pair<T, U>>() {
068          @Override
069          public Iterator<Pair<T, U>> iterator() {
070            final Iterator<T> inner1 = it.iterator();
071            final Iterator<U> inner2 = o.iterator();
072            return new Iterator<Pair<T, U>>() {
073              @Override
074              public boolean hasNext() {
075                return inner1.hasNext() || inner2.hasNext();
076              }
077    
078              @Override
079              public Pair<T, U> next() {
080                T o1 = inner1.hasNext() ? inner1.next() : null;
081                U o2 = inner2.hasNext() ? inner2.next() : null;
082                return new Pair<T, U>(o1, o2);
083              }
084    
085              @Override
086              public void remove() {
087                throw new UnsupportedOperationException();
088              }
089            };
090          }
091        });
092      }
093    
094      /**
095       * Maps function to sequence
096       * <pre>
097       *  {a1, a2, a3, ...}.map(fn) ==> {fn(a1), fn(a2), fn(a3), ...}
098       * </pre>
099       * 
100       * @param <U>  type of elements in result sequence
101       * @param fn   function from elements in this sequence to elements of result sequence
102       * @return     a sequence of the return values of the function
103       */
104      public final <U> FnIterable<U> map(final Lambda<T, U> fn) {
105        return new FnIterable<U>(new Iterable<U>() {
106          @Override
107          public Iterator<U> iterator() {
108            final Iterator<T> inner = it.iterator();
109            return new Iterator<U>() {
110              @Override
111              public boolean hasNext() {
112                return inner.hasNext();
113              }
114    
115              @Override
116              public U next() {
117                return fn.call(inner.next());
118              }
119    
120              @Override
121              public void remove() {
122                throw new UnsupportedOperationException();
123              }
124            };
125          }
126        });
127      }
128    
129      /**
130       * Reduces this sequence to a value.
131       * <pre>
132       *  {}.reduce(fn, initial)  ==> initial
133       *  {a1, a2, a3, ...}.reduce(fn, initial) ==> fn(... fn(fn(fn(initial, a1), a2), a3) ...)
134       * </pre>
135       * 
136       * @param <U>      type of the resulting value
137       * @param fn       function to reduce sequence
138       * @param initial  initial value to pass reducing function
139       * @return         resulting value from applying function over sequence
140       */
141      public final <U> U reduce(Lambda2<U, T, U> fn, U initial) {
142        for (T item : this) {
143          initial = fn.call(initial, item);
144        }
145        return initial;
146      }
147    
148      /**
149       * @return  a copy of this sequence as a list
150       */
151      public final List<T> toList() {
152        List<T> retval = new ArrayList<T>();
153        for (T item : this) {
154          retval.add(item);
155        }
156        return retval;
157      }
158    
159      @Override
160      public Iterator<T> iterator() {
161        return it.iterator();
162      }
163    }