Coverage Report - jaggregate.Iterables
 
Classes in this File Line Coverage Branch Coverage Complexity
Iterables
100%
41/41
100%
11/11
0
Iterables$1
100%
2/2
N/A
0
Iterables$2
100%
2/2
N/A
0
Iterables$SelectingIterator
100%
21/21
100%
4/4
0
Iterables$TransformingIterator
100%
7/7
N/A
0
 
 1  
 /*
 2  
  Copyright 2004-2008 Paul R. Holser, Jr.  All rights reserved.
 3  
  Licensed under the Academic Free License version 3.0
 4  
  */
 5  
 
 6  
 package jaggregate;
 7  
 
 8  
 import java.util.Iterator;
 9  
 import java.util.NoSuchElementException;
 10  
 
 11  
 import static jaggregate.internal.ArgumentChecks.*;
 12  
 import static jaggregate.internal.UnaryConditions.*;
 13  
 
 14  
 /**
 15  
  * Functions that offer {@linkplain Collection}-like functionality for
 16  
  * {@linkplain Iterable}s.
 17  
  *
 18  
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
 19  
  * @version $Id: Iterables.java,v 1.8 2008/10/03 19:01:23 pholser Exp $
 20  
  */
 21  
 public class Iterables {
 22  
     /**
 23  
      * Discourages instantiation.
 24  
      *
 25  
      * @throws UnsupportedOperationException always
 26  
      */
 27  1
     protected Iterables() {
 28  1
         throw new UnsupportedOperationException();
 29  
     }
 30  
 
 31  
     /**
 32  
      * Answers {@code true} if the given discriminator answers {@code true} for every
 33  
      * element yielded by the given iterable, or if the iterable yields no elements;
 34  
      * otherwise answers {@code false}.
 35  
      * <p/>
 36  
      * It is unspecified whether {@code discriminator} will be evaluated with every
 37  
      * element that the iterable yields.
 38  
      *
 39  
      * @param <E> type of the items to iterate over
 40  
      * @param items the items to iterate over
 41  
      * @param discriminator the discriminator to evaluate
 42  
      * @return whether {@code discriminator} is {@code true} for every element
 43  
      * @throws NullPointerException if {@code items} or {@code discriminator}
 44  
      * is {@code null}
 45  
      * @see Collection#allSatisfy(UnaryCondition)
 46  
      */
 47  
     public static <E> boolean allSatisfy( Iterable<? extends E> items,
 48  
         UnaryCondition<? super E> discriminator ) {
 49  
 
 50  5
         ensureNotNull( discriminator, DISCRIMINATOR );
 51  
 
 52  4
         for ( E each : items ) {
 53  6
             if ( !discriminator.matches( each ) )
 54  1
                 return false;
 55  
         }
 56  
 
 57  2
         return true;
 58  
     }
 59  
 
 60  
     /**
 61  
      * Answers {@code true} if the given discriminator answers {@code true} for any
 62  
      * element yielded by the given iterable; answers {@code false} otherwise, or if the
 63  
      * iterable yields no elements.
 64  
      * <p/>
 65  
      * It is unspecified whether {@code discriminator} will be evaluated with every
 66  
      * element that the iterable yields.
 67  
      *
 68  
      * @param <E> type of the items to iterate over
 69  
      * @param items the items to iterate over
 70  
      * @param discriminator the discriminator to evaluate
 71  
      * @return whether {@code discriminator} is {@code true} for any element
 72  
      * @throws NullPointerException if {@code items} or {@code discriminator}
 73  
      * is {@code null}
 74  
      * @see Collection#anySatisfy(UnaryCondition)
 75  
      */
 76  
     public static <E> boolean anySatisfy( Iterable<? extends E> items,
 77  
         UnaryCondition<? super E> discriminator ) {
 78  
 
 79  5
         ensureNotNull( discriminator, DISCRIMINATOR );
 80  
 
 81  4
         for ( E each : items ) {
 82  6
             if ( discriminator.matches( each ) )
 83  1
                 return true;
 84  
         }
 85  
 
 86  2
         return false;
 87  
     }
 88  
 
 89  
     /**
 90  
      * Wraps the given iterable with another iterable whose iterator will transform
 91  
      * items using the given functor.
 92  
      *
 93  
      * @param <E> type of the items to iterate over
 94  
      * @param <R> type of the transformed iterated items
 95  
      * @param items the iterable to wrap
 96  
      * @param transformer functor used to transform elements
 97  
      * @return the wrapping, transforming iterable
 98  
      * @throws NullPointerException if {@code items} or {@code transformer} is
 99  
      * {@code null}
 100  
      * @see Collection#collect(UnaryFunctor)
 101  
      */
 102  
     public static <E, R> Iterable<R> collect( final Iterable<? extends E> items,
 103  
         final UnaryFunctor<? super E, ? extends R> transformer ) {
 104  
 
 105  10
         ensureNotNull( items, ITERABLE );
 106  9
         ensureNotNull( transformer, TRANSFORMER );
 107  
 
 108  8
         return new Iterable<R>() {
 109  8
             public Iterator<R> iterator() {
 110  8
                 return new TransformingIterator<E, R>( items.iterator(), transformer );
 111  
             }
 112  
         };
 113  
     }
 114  
 
 115  
     /**
 116  
      * Answers the first element yielded by the given iterable for which the given
 117  
      * discriminator answers {@code true} when given that element as an argument.
 118  
      * <p/>
 119  
      * {@code discriminator} will only be evaluated until such an object is found or
 120  
      * until the iterable yields no elements to use as arguments.  That is, there may
 121  
      * be elements that the iterable yields that are never used as arguments to
 122  
      * {@code discriminator}.
 123  
      *
 124  
      * @param <E> type of the items to iterate over
 125  
      * @param items the items to iterate over
 126  
      * @param discriminator the discriminator to evaluate
 127  
      * @return the first item that satisfies {@code discriminator}
 128  
      * @throws java.util.NoSuchElementException if no item satisfies
 129  
      * {@code discriminator}
 130  
      * @throws NullPointerException if {@code items} or {@code discriminator} is
 131  
      * {@code null}
 132  
      */
 133  
     public static <E> E detect( Iterable<? extends E> items,
 134  
         UnaryCondition<? super E> discriminator ) {
 135  
 
 136  5
         ensureNotNull( discriminator, DISCRIMINATOR );
 137  
 
 138  4
         for ( E each : items ) {
 139  5
             if ( discriminator.matches( each ) )
 140  1
                 return each;
 141  
         }
 142  
 
 143  2
         throw new NoSuchElementException();
 144  
     }
 145  
 
 146  
     /**
 147  
      * Answers the number of elements yielded by the given iterable which are equivalent
 148  
      * to the given target.
 149  
      *
 150  
      * @param <E> type of the items to iterate over
 151  
      * @param items the items to iterate over
 152  
      * @param target the object to compare against
 153  
      * @return the number of occurrences of equivalent objects yielded by the iterable
 154  
      * @throws NullPointerException if {@code items} is {@code null}
 155  
      */
 156  
     public static <E> int occurrencesOf( Iterable<? extends E> items, E target ) {
 157  5
         int occurrences = 0;
 158  
 
 159  5
         for ( E each : items ) {
 160  24
             if ( Objects.areEqual( each, target ) )
 161  6
                 ++occurrences;
 162  
         }
 163  
 
 164  4
         return occurrences;
 165  
     }
 166  
 
 167  
     /**
 168  
      * Answers the final result of evaluating the given operation using each element of
 169  
      * the given iterable and the previous evaluation result as the parameters.
 170  
      * <p/>
 171  
      * The first evaluation of {@code operation} is performed with the given initial
 172  
      * value as the first parameter, and the first element of the iterable as the second
 173  
      * parameter.  Subsequent evaluations are done with the result of the previous
 174  
      * evaluation as the first parameter, and the next element as the second parameter.
 175  
      * The result of the last evaluation is answered.
 176  
      *
 177  
      * @param <E> type of the items to iterate over
 178  
      * @param <R> type of the initial value, intermediate results, and final result
 179  
      * @param items the items to iterate over
 180  
      * @param initialValue first parameter for the first evaluation
 181  
      * @param operation the operation to evaluate
 182  
      * @return the result of the last evaluation
 183  
      * @throws NullPointerException if {@code items} or {@code operation} is {@code null}
 184  
      * @see Collection#inject(Object, BinaryFunctor)
 185  
      */
 186  
     public static <E, R> R inject( Iterable<? extends E> items, R initialValue,
 187  
         BinaryFunctor<? super R, ? super E, ? extends R> operation ) {
 188  
 
 189  4
         ensureNotNull( operation, OPERATION );
 190  
 
 191  3
         R result = initialValue;
 192  3
         for ( E each : items )
 193  4
             result = operation.evaluate( result, each );
 194  
 
 195  2
         return result;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Removes items from the given iterable which match the given predicate.
 200  
      *
 201  
      * @param <E> type of the items to iterate over
 202  
      * @param items items to iterate over
 203  
      * @param discriminator tells which items should be removed
 204  
      * @return {@code true} if any removals occurred
 205  
      * @throws NullPointerException if {@code items} or {@code discriminator}
 206  
      * is {@code null}
 207  
      * @throws UnsupportedOperationException if {@code items}'s iterator does not
 208  
      * support removal
 209  
      * @see ExtensibleCollection#removeIf(UnaryCondition)
 210  
      */
 211  
     public static <E> boolean removeIf( Iterable<? extends E> items,
 212  
         UnaryCondition<? super E> discriminator ) {
 213  
 
 214  11
         ensureNotNull( discriminator, DISCRIMINATOR );
 215  
 
 216  10
         boolean removalsOccurred = false;
 217  
 
 218  10
         for ( Iterator<? extends E> it = items.iterator(); it.hasNext(); ) {
 219  16
             if ( discriminator.matches( it.next() ) ) {
 220  9
                 it.remove();
 221  7
                 removalsOccurred = true;
 222  
             }
 223  
         }
 224  
 
 225  6
         return removalsOccurred;
 226  
     }
 227  
 
 228  
     /**
 229  
      * Removes items from the given iterable which do not match the given predicate.
 230  
      *
 231  
      * @param <E> type of the items to iterate over
 232  
      * @param items items to iterate over
 233  
      * @param discriminator tells which items should be retained
 234  
      * @return {@code true} if any removals occurred
 235  
      * @throws NullPointerException if {@code items} or {@code discriminator}
 236  
      * is {@code null}
 237  
      * @throws UnsupportedOperationException if {@code items}'s iterator does not
 238  
      * support removal
 239  
      * @see ExtensibleCollection#retainIf(UnaryCondition)
 240  
      */
 241  
     public static <E> boolean retainIf( Iterable<? extends E> items,
 242  
         UnaryCondition<? super E> discriminator ) {
 243  
 
 244  6
         return removeIf( items, not( discriminator ) );
 245  
     }
 246  
 
 247  
     /**
 248  
      * Wraps the given iterable with another iterable whose iterator will filter
 249  
      * out items which do not match the given predicate.
 250  
      *
 251  
      * @param <E> type of the items to iterate over
 252  
      * @param items the iterable to wrap
 253  
      * @param discriminator predicate used to filter elements
 254  
      * @return the wrapping, filtering iterable
 255  
      * @throws NullPointerException if {@code items} or {@code discriminator} is
 256  
      * {@code null}
 257  
      * @see Collection#select(UnaryCondition)
 258  
      */
 259  
     public static <E> Iterable<E> select( final Iterable<? extends E> items,
 260  
         final UnaryCondition<? super E> discriminator ) {
 261  
 
 262  18
         ensureNotNull( items, ITERABLE );
 263  17
         ensureNotNull( discriminator, DISCRIMINATOR );
 264  
 
 265  16
         return new Iterable<E>() {
 266  16
             public Iterator<E> iterator() {
 267  16
                 return new SelectingIterator<E>( items.iterator(), discriminator );
 268  
             }
 269  
         };
 270  
     }
 271  
 
 272  
     private static class SelectingIterator<E> implements Iterator<E> {
 273  
         private final Iterator<? extends E> wrapped;
 274  
         private final UnaryCondition<? super E> discriminator;
 275  
         private boolean askedHasNext;
 276  16
         private boolean hasNext = true;
 277  16
         private E current = null;
 278  
 
 279  
         SelectingIterator( Iterator<? extends E> wrapped,
 280  16
             UnaryCondition<? super E> discriminator ) {
 281  
 
 282  16
             this.wrapped = wrapped;
 283  16
             this.discriminator = discriminator;
 284  16
         }
 285  
 
 286  
         /**
 287  
          * {@inheritDoc}
 288  
          */
 289  
         public boolean hasNext() {
 290  20
             askedHasNext = true;
 291  
 
 292  20
             advance();
 293  
 
 294  20
             return hasNext;
 295  
         }
 296  
 
 297  
         /**
 298  
          * {@inheritDoc}
 299  
          */
 300  
         public E next() {
 301  22
             if ( !askedHasNext )
 302  10
                 advance();
 303  
 
 304  22
             if ( !hasNext )
 305  4
                 throw new NoSuchElementException();
 306  
 
 307  18
             return current;
 308  
         }
 309  
 
 310  
         /**
 311  
          * {@inheritDoc}
 312  
          */
 313  
         public void remove() {
 314  4
             throw new UnsupportedOperationException();
 315  
         }
 316  
 
 317  
         private void advance() {
 318  48
             while ( wrapped.hasNext() ) {
 319  36
                 current = wrapped.next();
 320  
 
 321  36
                 if ( discriminator.matches( current ) )
 322  18
                     return;
 323  
             }
 324  
 
 325  12
             hasNext = false;
 326  12
         }
 327  
     }
 328  
 
 329  
     private static class TransformingIterator<E, R> implements Iterator<R> {
 330  
         private Iterator<? extends E> wrapped;
 331  
         private UnaryFunctor<? super E, ? extends R> transformer;
 332  
 
 333  
         TransformingIterator( Iterator<? extends E> wrapped,
 334  8
             UnaryFunctor<? super E, ? extends R> transformer ) {
 335  
 
 336  8
             this.wrapped = wrapped;
 337  8
             this.transformer = transformer;
 338  8
         }
 339  
 
 340  
         /**
 341  
          * {@inheritDoc}
 342  
          */
 343  
         public boolean hasNext() {
 344  11
             return wrapped.hasNext();
 345  
         }
 346  
 
 347  
         /**
 348  
          * {@inheritDoc}
 349  
          */
 350  
         public R next() {
 351  13
             return transformer.evaluate( wrapped.next() );
 352  
         }
 353  
 
 354  
         /**
 355  
          * {@inheritDoc}
 356  
          */
 357  
         public void remove() {
 358  2
             throw new UnsupportedOperationException();
 359  
         }
 360  
     }
 361  
 }