001    /*
002     * Copyright (C) 2008 Google Inc.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package com.google.common.collect;
018    
019    import static com.google.common.base.Preconditions.checkArgument;
020    import static com.google.common.base.Preconditions.checkNotNull;
021    
022    import com.google.common.annotations.GwtCompatible;
023    import com.google.common.base.Function;
024    import com.google.common.base.Joiner;
025    import com.google.common.base.Predicate;
026    import com.google.common.base.Predicates;
027    
028    import java.util.AbstractCollection;
029    import java.util.Collection;
030    import java.util.Iterator;
031    
032    /**
033     * Provides static methods for working with {@code Collection} instances.
034     *
035     * @author Chris Povirk
036     * @author Mike Bostock
037     * @author Jared Levy
038     * @since 2 (imported from Google Collections Library)
039     */
040    @GwtCompatible
041    public final class Collections2 {
042      private Collections2() {}
043    
044      /**
045       * Returns the elements of {@code unfiltered} that satisfy a predicate. The
046       * returned collection is a live view of {@code unfiltered}; changes to one
047       * affect the other.
048       *
049       * <p>The resulting collection's iterator does not support {@code remove()},
050       * but all other collection methods are supported. When given an element that
051       * doesn't satisfy the predicate, the collection's {@code add()} and {@code
052       * addAll()} methods throw an {@link IllegalArgumentException}. When methods
053       * such as {@code removeAll()} and {@code clear()} are called on the filtered
054       * collection, only elements that satisfy the filter will be removed from the
055       * underlying collection.
056       *
057       * <p>The returned collection isn't threadsafe or serializable, even if
058       * {@code unfiltered} is.
059       *
060       * <p>Many of the filtered collection's methods, such as {@code size()},
061       * iterate across every element in the underlying collection and determine
062       * which elements satisfy the filter. When a live view is <i>not</i> needed,
063       * it may be faster to copy {@code Iterables.filter(unfiltered, predicate)}
064       * and use the copy.
065       *
066       * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
067       * as documented at {@link Predicate#apply}. Do not provide a predicate such
068       * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent
069       * with equals. (See {@link Iterables#filter(Iterable, Class)} for related
070       * functionality.)
071       */
072      public static <E> Collection<E> filter(
073          Collection<E> unfiltered, Predicate<? super E> predicate) {
074        if (unfiltered instanceof FilteredCollection) {
075          // Support clear(), removeAll(), and retainAll() when filtering a filtered
076          // collection.
077          return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
078        }
079    
080        return new FilteredCollection<E>(
081            checkNotNull(unfiltered), checkNotNull(predicate));
082      }
083    
084      /**
085       * Delegates to {@link Collection#contains}.  Returns {@code false} on {@code
086       * ClassCastException}
087       */
088      static boolean safeContains(Collection<?> collection, Object object) {
089        try {
090          return collection.contains(object);
091        } catch (ClassCastException e) {
092          return false;
093        }
094      }
095    
096      static class FilteredCollection<E> implements Collection<E> {
097        final Collection<E> unfiltered;
098        final Predicate<? super E> predicate;
099    
100        FilteredCollection(Collection<E> unfiltered,
101            Predicate<? super E> predicate) {
102          this.unfiltered = unfiltered;
103          this.predicate = predicate;
104        }
105    
106        FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
107          return new FilteredCollection<E>(unfiltered,
108              Predicates.<E>and(predicate, newPredicate));
109          // .<E> above needed to compile in JDK 5
110        }
111    
112        public boolean add(E element) {
113          checkArgument(predicate.apply(element));
114          return unfiltered.add(element);
115        }
116    
117        public boolean addAll(Collection<? extends E> collection) {
118          for (E element : collection) {
119            checkArgument(predicate.apply(element));
120          }
121          return unfiltered.addAll(collection);
122        }
123    
124        public void clear() {
125          Iterables.removeIf(unfiltered, predicate);
126        }
127    
128        public boolean contains(Object element) {
129          try {
130            // unsafe cast can result in a CCE from predicate.apply(), which we
131            // will catch
132            @SuppressWarnings("unchecked")
133            E e = (E) element;
134    
135            /*
136             * We check whether e satisfies the predicate, when we really mean to
137             * check whether the element contained in the set does. This is ok as
138             * long as the predicate is consistent with equals, as required.
139             */
140            return predicate.apply(e) && unfiltered.contains(element);
141          } catch (NullPointerException e) {
142            return false;
143          } catch (ClassCastException e) {
144            return false;
145          }
146        }
147    
148        public boolean containsAll(Collection<?> collection) {
149          for (Object element : collection) {
150            if (!contains(element)) {
151              return false;
152            }
153          }
154          return true;
155        }
156    
157        public boolean isEmpty() {
158          return !Iterators.any(unfiltered.iterator(), predicate);
159        }
160    
161        public Iterator<E> iterator() {
162          return Iterators.filter(unfiltered.iterator(), predicate);
163        }
164    
165        public boolean remove(Object element) {
166          try {
167            // unsafe cast can result in a CCE from predicate.apply(), which we
168            // will catch
169            @SuppressWarnings("unchecked")
170            E e = (E) element;
171    
172            // See comment in contains() concerning predicate.apply(e)
173            return predicate.apply(e) && unfiltered.remove(element);
174          } catch (NullPointerException e) {
175            return false;
176          } catch (ClassCastException e) {
177            return false;
178          }
179        }
180    
181        public boolean removeAll(final Collection<?> collection) {
182          checkNotNull(collection);
183          Predicate<E> combinedPredicate = new Predicate<E>() {
184            public boolean apply(E input) {
185              return predicate.apply(input) && collection.contains(input);
186            }
187          };
188          return Iterables.removeIf(unfiltered, combinedPredicate);
189        }
190    
191        public boolean retainAll(final Collection<?> collection) {
192          checkNotNull(collection);
193          Predicate<E> combinedPredicate = new Predicate<E>() {
194            public boolean apply(E input) {
195              // See comment in contains() concerning predicate.apply(e)
196              return predicate.apply(input) && !collection.contains(input);
197            }
198          };
199          return Iterables.removeIf(unfiltered, combinedPredicate);
200        }
201    
202        public int size() {
203          return Iterators.size(iterator());
204        }
205    
206        public Object[] toArray() {
207          // creating an ArrayList so filtering happens once
208          return Lists.newArrayList(iterator()).toArray();
209        }
210    
211        public <T> T[] toArray(T[] array) {
212          return Lists.newArrayList(iterator()).toArray(array);
213        }
214    
215        @Override public String toString() {
216          return Iterators.toString(iterator());
217        }
218      }
219    
220      /**
221       * Returns a collection that applies {@code function} to each element of
222       * {@code fromCollection}. The returned collection is a live view of {@code
223       * fromCollection}; changes to one affect the other.
224       *
225       * <p>The returned collection's {@code add()} and {@code addAll()} methods
226       * throw an {@link UnsupportedOperationException}. All other collection
227       * methods are supported, as long as {@code fromCollection} supports them.
228       *
229       * <p>The returned collection isn't threadsafe or serializable, even if
230       * {@code fromCollection} is.
231       *
232       * <p>When a live view is <i>not</i> needed, it may be faster to copy the
233       * transformed collection and use the copy.
234       */
235      public static <F, T> Collection<T> transform(Collection<F> fromCollection,
236          Function<? super F, T> function) {
237        return new TransformedCollection<F, T>(fromCollection, function);
238      }
239    
240      static class TransformedCollection<F, T> extends AbstractCollection<T> {
241        final Collection<F> fromCollection;
242        final Function<? super F, ? extends T> function;
243    
244        TransformedCollection(Collection<F> fromCollection,
245            Function<? super F, ? extends T> function) {
246          this.fromCollection = checkNotNull(fromCollection);
247          this.function = checkNotNull(function);
248        }
249    
250        @Override public void clear() {
251          fromCollection.clear();
252        }
253    
254        @Override public boolean isEmpty() {
255          return fromCollection.isEmpty();
256        }
257    
258        @Override public Iterator<T> iterator() {
259          return Iterators.transform(fromCollection.iterator(), function);
260        }
261    
262        @Override public int size() {
263          return fromCollection.size();
264        }
265      }
266    
267      /**
268       * Returns {@code true} if the collection {@code self} contains all of the
269       * elements in the collection {@code c}.
270       *
271       * <p>This method iterates over the specified collection {@code c}, checking
272       * each element returned by the iterator in turn to see if it is contained in
273       * the specified collection {@code self}. If all elements are so contained,
274       * {@code true} is returned, otherwise {@code false}.
275       *
276       * @param self a collection which might contain all elements in {@code c}
277       * @param c a collection whose elements might be contained by {@code self}
278       */
279      static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
280        checkNotNull(self);
281        for (Object o : c) {
282          if (!self.contains(o)) {
283            return false;
284          }
285        }
286        return true;
287      }
288      
289      /**
290       * An implementation of {@link Collection#toString()}.
291       */
292      static String toStringImpl(final Collection<?> collection) {
293        StringBuilder sb
294            = newStringBuilderForCollection(collection.size()).append('[');
295        STANDARD_JOINER.appendTo(
296            sb, Iterables.transform(collection, new Function<Object, Object>() {
297              @Override public Object apply(Object input) {
298                return input == collection ? "(this Collection)" : input;
299              }
300            }));
301        return sb.append(']').toString();
302      }
303    
304      /**
305       * Returns best-effort-sized StringBuilder based on the given collection size.
306       */
307      static StringBuilder newStringBuilderForCollection(int size) {
308        checkArgument(size >= 0, "size must be non-negative");
309        return new StringBuilder((int) Math.min(size * 8L, 1 << 30));
310      }
311    
312      /**
313       * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
314       */
315      static <T> Collection<T> cast(Iterable<T> iterable) {
316        return (Collection<T>) iterable;
317      }
318    
319      static final Joiner STANDARD_JOINER = Joiner.on(", ");
320    }