Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2008 The Guava Authors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.collect;
     18 
     19 import static com.google.common.base.Preconditions.checkArgument;
     20 import static com.google.common.base.Preconditions.checkNotNull;
     21 
     22 import com.google.common.annotations.GwtCompatible;
     23 import com.google.common.base.Function;
     24 import com.google.common.base.Joiner;
     25 import com.google.common.base.Predicate;
     26 import com.google.common.base.Predicates;
     27 import com.google.common.primitives.Ints;
     28 
     29 import java.util.AbstractCollection;
     30 import java.util.ArrayList;
     31 import java.util.Collection;
     32 import java.util.Collections;
     33 import java.util.Iterator;
     34 import java.util.List;
     35 
     36 /**
     37  * Provides static methods for working with {@code Collection} instances.
     38  *
     39  * @author Chris Povirk
     40  * @author Mike Bostock
     41  * @author Jared Levy
     42  * @since 2.0 (imported from Google Collections Library)
     43  */
     44 @GwtCompatible
     45 public final class Collections2 {
     46   private Collections2() {}
     47 
     48   /**
     49    * Returns the elements of {@code unfiltered} that satisfy a predicate. The
     50    * returned collection is a live view of {@code unfiltered}; changes to one
     51    * affect the other.
     52    *
     53    * <p>The resulting collection's iterator does not support {@code remove()},
     54    * but all other collection methods are supported. When given an element that
     55    * doesn't satisfy the predicate, the collection's {@code add()} and {@code
     56    * addAll()} methods throw an {@link IllegalArgumentException}. When methods
     57    * such as {@code removeAll()} and {@code clear()} are called on the filtered
     58    * collection, only elements that satisfy the filter will be removed from the
     59    * underlying collection.
     60    *
     61    * <p>The returned collection isn't threadsafe or serializable, even if
     62    * {@code unfiltered} is.
     63    *
     64    * <p>Many of the filtered collection's methods, such as {@code size()},
     65    * iterate across every element in the underlying collection and determine
     66    * which elements satisfy the filter. When a live view is <i>not</i> needed,
     67    * it may be faster to copy {@code Iterables.filter(unfiltered, predicate)}
     68    * and use the copy.
     69    *
     70    * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
     71    * as documented at {@link Predicate#apply}. Do not provide a predicate such
     72    * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent
     73    * with equals. (See {@link Iterables#filter(Iterable, Class)} for related
     74    * functionality.)
     75    */
     76   // TODO(kevinb): how can we omit that Iterables link when building gwt
     77   // javadoc?
     78   public static <E> Collection<E> filter(
     79       Collection<E> unfiltered, Predicate<? super E> predicate) {
     80     if (unfiltered instanceof FilteredCollection) {
     81       // Support clear(), removeAll(), and retainAll() when filtering a filtered
     82       // collection.
     83       return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
     84     }
     85 
     86     return new FilteredCollection<E>(
     87         checkNotNull(unfiltered), checkNotNull(predicate));
     88   }
     89 
     90   /**
     91    * Delegates to {@link Collection#contains}. Returns {@code false} if the
     92    * {@code contains} method throws a {@code ClassCastException}.
     93    */
     94   static boolean safeContains(Collection<?> collection, Object object) {
     95     try {
     96       return collection.contains(object);
     97     } catch (ClassCastException e) {
     98       return false;
     99     }
    100   }
    101 
    102   static class FilteredCollection<E> implements Collection<E> {
    103     final Collection<E> unfiltered;
    104     final Predicate<? super E> predicate;
    105 
    106     FilteredCollection(Collection<E> unfiltered,
    107         Predicate<? super E> predicate) {
    108       this.unfiltered = unfiltered;
    109       this.predicate = predicate;
    110     }
    111 
    112     FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
    113       return new FilteredCollection<E>(unfiltered,
    114           Predicates.<E>and(predicate, newPredicate));
    115       // .<E> above needed to compile in JDK 5
    116     }
    117 
    118     @Override
    119     public boolean add(E element) {
    120       checkArgument(predicate.apply(element));
    121       return unfiltered.add(element);
    122     }
    123 
    124     @Override
    125     public boolean addAll(Collection<? extends E> collection) {
    126       for (E element : collection) {
    127         checkArgument(predicate.apply(element));
    128       }
    129       return unfiltered.addAll(collection);
    130     }
    131 
    132     @Override
    133     public void clear() {
    134       Iterables.removeIf(unfiltered, predicate);
    135     }
    136 
    137     @Override
    138     public boolean contains(Object element) {
    139       try {
    140         // unsafe cast can result in a CCE from predicate.apply(), which we
    141         // will catch
    142         @SuppressWarnings("unchecked")
    143         E e = (E) element;
    144 
    145         /*
    146          * We check whether e satisfies the predicate, when we really mean to
    147          * check whether the element contained in the set does. This is ok as
    148          * long as the predicate is consistent with equals, as required.
    149          */
    150         return predicate.apply(e) && unfiltered.contains(element);
    151       } catch (NullPointerException e) {
    152         return false;
    153       } catch (ClassCastException e) {
    154         return false;
    155       }
    156     }
    157 
    158     @Override
    159     public boolean containsAll(Collection<?> collection) {
    160       for (Object element : collection) {
    161         if (!contains(element)) {
    162           return false;
    163         }
    164       }
    165       return true;
    166     }
    167 
    168     @Override
    169     public boolean isEmpty() {
    170       return !Iterators.any(unfiltered.iterator(), predicate);
    171     }
    172 
    173     @Override
    174     public Iterator<E> iterator() {
    175       return Iterators.filter(unfiltered.iterator(), predicate);
    176     }
    177 
    178     @Override
    179     public boolean remove(Object element) {
    180       try {
    181         // unsafe cast can result in a CCE from predicate.apply(), which we
    182         // will catch
    183         @SuppressWarnings("unchecked")
    184         E e = (E) element;
    185 
    186         // See comment in contains() concerning predicate.apply(e)
    187         return predicate.apply(e) && unfiltered.remove(element);
    188       } catch (NullPointerException e) {
    189         return false;
    190       } catch (ClassCastException e) {
    191         return false;
    192       }
    193     }
    194 
    195     @Override
    196     public boolean removeAll(final Collection<?> collection) {
    197       checkNotNull(collection);
    198       Predicate<E> combinedPredicate = new Predicate<E>() {
    199         @Override
    200         public boolean apply(E input) {
    201           return predicate.apply(input) && collection.contains(input);
    202         }
    203       };
    204       return Iterables.removeIf(unfiltered, combinedPredicate);
    205     }
    206 
    207     @Override
    208     public boolean retainAll(final Collection<?> collection) {
    209       checkNotNull(collection);
    210       Predicate<E> combinedPredicate = new Predicate<E>() {
    211         @Override
    212         public boolean apply(E input) {
    213           // See comment in contains() concerning predicate.apply(e)
    214           return predicate.apply(input) && !collection.contains(input);
    215         }
    216       };
    217       return Iterables.removeIf(unfiltered, combinedPredicate);
    218     }
    219 
    220     @Override
    221     public int size() {
    222       return Iterators.size(iterator());
    223     }
    224 
    225     @Override
    226     public Object[] toArray() {
    227       // creating an ArrayList so filtering happens once
    228       return Lists.newArrayList(iterator()).toArray();
    229     }
    230 
    231     @Override
    232     public <T> T[] toArray(T[] array) {
    233       return Lists.newArrayList(iterator()).toArray(array);
    234     }
    235 
    236     @Override public String toString() {
    237       return Iterators.toString(iterator());
    238     }
    239   }
    240 
    241   /**
    242    * Returns a collection that applies {@code function} to each element of
    243    * {@code fromCollection}. The returned collection is a live view of {@code
    244    * fromCollection}; changes to one affect the other.
    245    *
    246    * <p>The returned collection's {@code add()} and {@code addAll()} methods
    247    * throw an {@link UnsupportedOperationException}. All other collection
    248    * methods are supported, as long as {@code fromCollection} supports them.
    249    *
    250    * <p>The returned collection isn't threadsafe or serializable, even if
    251    * {@code fromCollection} is.
    252    *
    253    * <p>When a live view is <i>not</i> needed, it may be faster to copy the
    254    * transformed collection and use the copy.
    255    *
    256    * <p>If the input {@code Collection} is known to be a {@code List}, consider
    257    * {@link Lists#transform}. If only an {@code Iterable} is available, use
    258    * {@link Iterables#transform}.
    259    */
    260   public static <F, T> Collection<T> transform(Collection<F> fromCollection,
    261       Function<? super F, T> function) {
    262     return new TransformedCollection<F, T>(fromCollection, function);
    263   }
    264 
    265   static class TransformedCollection<F, T> extends AbstractCollection<T> {
    266     final Collection<F> fromCollection;
    267     final Function<? super F, ? extends T> function;
    268 
    269     TransformedCollection(Collection<F> fromCollection,
    270         Function<? super F, ? extends T> function) {
    271       this.fromCollection = checkNotNull(fromCollection);
    272       this.function = checkNotNull(function);
    273     }
    274 
    275     @Override public void clear() {
    276       fromCollection.clear();
    277     }
    278 
    279     @Override public boolean isEmpty() {
    280       return fromCollection.isEmpty();
    281     }
    282 
    283     @Override public Iterator<T> iterator() {
    284       return Iterators.transform(fromCollection.iterator(), function);
    285     }
    286 
    287     @Override public int size() {
    288       return fromCollection.size();
    289     }
    290   }
    291 
    292   /**
    293    * Returns {@code true} if the collection {@code self} contains all of the
    294    * elements in the collection {@code c}.
    295    *
    296    * <p>This method iterates over the specified collection {@code c}, checking
    297    * each element returned by the iterator in turn to see if it is contained in
    298    * the specified collection {@code self}. If all elements are so contained,
    299    * {@code true} is returned, otherwise {@code false}.
    300    *
    301    * @param self a collection which might contain all elements in {@code c}
    302    * @param c a collection whose elements might be contained by {@code self}
    303    */
    304   static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
    305     checkNotNull(self);
    306     for (Object o : c) {
    307       if (!self.contains(o)) {
    308         return false;
    309       }
    310     }
    311     return true;
    312   }
    313 
    314   /**
    315    * An implementation of {@link Collection#toString()}.
    316    */
    317   static String toStringImpl(final Collection<?> collection) {
    318     StringBuilder sb
    319         = newStringBuilderForCollection(collection.size()).append('[');
    320     STANDARD_JOINER.appendTo(
    321         sb, Iterables.transform(collection, new Function<Object, Object>() {
    322           @Override public Object apply(Object input) {
    323             return input == collection ? "(this Collection)" : input;
    324           }
    325         }));
    326     return sb.append(']').toString();
    327   }
    328 
    329   /**
    330    * Returns best-effort-sized StringBuilder based on the given collection size.
    331    */
    332   static StringBuilder newStringBuilderForCollection(int size) {
    333     checkArgument(size >= 0, "size must be non-negative");
    334     return new StringBuilder((int) Math.min(size * 8L, Ints.MAX_POWER_OF_TWO));
    335   }
    336 
    337   /**
    338    * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
    339    */
    340   static <T> Collection<T> cast(Iterable<T> iterable) {
    341     return (Collection<T>) iterable;
    342   }
    343 
    344   static final Joiner STANDARD_JOINER = Joiner.on(", ");
    345 
    346   // TODO(user): Maybe move the mathematical methods to a separate
    347   // package-permission class.
    348 }
    349