All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.collect.Sets Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2.FilteredCollection;
import com.google.common.math.IntMath;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.annotation.Nullable;

/**
 * Static utility methods pertaining to {@link Set} instances. Also see this
 * class's counterparts {@link Lists} and {@link Maps}.
 *
 * 

See the Guava User Guide article on * {@code Sets}. * * @author Kevin Bourrillion * @author Jared Levy * @author Chris Povirk * @since 2.0 (imported from Google Collections Library) */ @GwtCompatible(emulated = true) public final class Sets { private Sets() {} /** * Returns an immutable set instance containing the given enum elements. * Internally, the returned set will be backed by an {@link EnumSet}. * *

The iteration order of the returned set follows the enum's iteration * order, not the order in which the elements are provided to the method. * * @param anElement one of the elements the set should contain * @param otherElements the rest of the elements the set should contain * @return an immutable set containing those elements, minus duplicates */ // http://code.google.com/p/google-web-toolkit/issues/detail?id=3028 @GwtCompatible(serializable = true) public static > ImmutableSet immutableEnumSet( E anElement, E... otherElements) { return new ImmutableEnumSet(EnumSet.of(anElement, otherElements)); } /** * Returns an immutable set instance containing the given enum elements. * Internally, the returned set will be backed by an {@link EnumSet}. * *

The iteration order of the returned set follows the enum's iteration * order, not the order in which the elements appear in the given collection. * * @param elements the elements, all of the same {@code enum} type, that the * set should contain * @return an immutable set containing those elements, minus duplicates */ // http://code.google.com/p/google-web-toolkit/issues/detail?id=3028 @GwtCompatible(serializable = true) public static > ImmutableSet immutableEnumSet( Iterable elements) { Iterator iterator = elements.iterator(); if (!iterator.hasNext()) { return ImmutableSet.of(); } if (elements instanceof EnumSet) { EnumSet enumSetClone = EnumSet.copyOf((EnumSet) elements); return new ImmutableEnumSet(enumSetClone); } E first = iterator.next(); EnumSet set = EnumSet.of(first); while (iterator.hasNext()) { set.add(iterator.next()); } return new ImmutableEnumSet(set); } /** * Returns a new {@code EnumSet} instance containing the given elements. * Unlike {@link EnumSet#copyOf(Collection)}, this method does not produce an * exception on an empty collection, and it may be called on any iterable, not * just a {@code Collection}. */ public static > EnumSet newEnumSet(Iterable iterable, Class elementType) { /* * TODO(cpovirk): noneOf() and addAll() will both throw * NullPointerExceptions when appropriate. However, NullPointerTester will * fail on this method because it passes in Class.class instead of an enum * type. This means that, when iterable is null but elementType is not, * noneOf() will throw a ClassCastException before addAll() has a chance to * throw a NullPointerException. NullPointerTester considers this a failure. * Ideally the test would be fixed, but it would require a special case for * Class where E extends Enum. Until that happens (if ever), leave * checkNotNull() here. For now, contemplate the irony that checking * elementType, the problem argument, is harmful, while checking iterable, * the innocent bystander, is effective. */ checkNotNull(iterable); EnumSet set = EnumSet.noneOf(elementType); Iterables.addAll(set, iterable); return set; } // HashSet /** * Creates a mutable, empty {@code HashSet} instance. * *

Note: if mutability is not required, use {@link * ImmutableSet#of()} instead. * *

Note: if {@code E} is an {@link Enum} type, use {@link * EnumSet#noneOf} instead. * * @return a new, empty {@code HashSet} */ public static HashSet newHashSet() { return new HashSet(); } /** * Creates a mutable {@code HashSet} instance containing the given * elements in unspecified order. * *

Note: if mutability is not required and the elements are * non-null, use an overload of {@link ImmutableSet#of()} (for varargs) or * {@link ImmutableSet#copyOf(Object[])} (for an array) instead. * *

Note: if {@code E} is an {@link Enum} type, use {@link * EnumSet#of(Enum, Enum[])} instead. * * @param elements the elements that the set should contain * @return a new {@code HashSet} containing those elements (minus duplicates) */ public static HashSet newHashSet(E... elements) { HashSet set = newHashSetWithExpectedSize(elements.length); Collections.addAll(set, elements); return set; } /** * Creates a {@code HashSet} instance, with a high enough "initial capacity" * that it should hold {@code expectedSize} elements without growth. * This behavior cannot be broadly guaranteed, but it is observed to be true * for OpenJDK 1.6. It also can't be guaranteed that the method isn't * inadvertently oversizing the returned set. * * @param expectedSize the number of elements you expect to add to the * returned set * @return a new, empty {@code HashSet} with enough capacity to hold {@code * expectedSize} elements without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative */ public static HashSet newHashSetWithExpectedSize(int expectedSize) { return new HashSet(Maps.capacity(expectedSize)); } /** * Creates a mutable {@code HashSet} instance containing the given * elements in unspecified order. * *

Note: if mutability is not required and the elements are * non-null, use {@link ImmutableSet#copyOf(Iterable)} instead. * *

Note: if {@code E} is an {@link Enum} type, use * {@link #newEnumSet(Iterable, Class)} instead. * * @param elements the elements that the set should contain * @return a new {@code HashSet} containing those elements (minus duplicates) */ public static HashSet newHashSet(Iterable elements) { return (elements instanceof Collection) ? new HashSet(Collections2.cast(elements)) : newHashSet(elements.iterator()); } /** * Creates a mutable {@code HashSet} instance containing the given * elements in unspecified order. * *

Note: if mutability is not required and the elements are * non-null, use {@link ImmutableSet#copyOf(Iterable)} instead. * *

Note: if {@code E} is an {@link Enum} type, you should create an * {@link EnumSet} instead. * * @param elements the elements that the set should contain * @return a new {@code HashSet} containing those elements (minus duplicates) */ public static HashSet newHashSet(Iterator elements) { HashSet set = newHashSet(); while (elements.hasNext()) { set.add(elements.next()); } return set; } // LinkedHashSet /** * Creates a mutable, empty {@code LinkedHashSet} instance. * *

Note: if mutability is not required, use {@link * ImmutableSet#of()} instead. * * @return a new, empty {@code LinkedHashSet} */ public static LinkedHashSet newLinkedHashSet() { return new LinkedHashSet(); } /** * Creates a {@code LinkedHashSet} instance, with a high enough "initial * capacity" that it should hold {@code expectedSize} elements without * growth. This behavior cannot be broadly guaranteed, but it is observed to * be true for OpenJDK 1.6. It also can't be guaranteed that the method isn't * inadvertently oversizing the returned set. * * @param expectedSize the number of elements you expect to add to the * returned set * @return a new, empty {@code LinkedHashSet} with enough capacity to hold * {@code expectedSize} elements without resizing * @throws IllegalArgumentException if {@code expectedSize} is negative * @since 11.0 */ public static LinkedHashSet newLinkedHashSetWithExpectedSize( int expectedSize) { return new LinkedHashSet(Maps.capacity(expectedSize)); } /** * Creates a mutable {@code LinkedHashSet} instance containing the * given elements in order. * *

Note: if mutability is not required and the elements are * non-null, use {@link ImmutableSet#copyOf(Iterable)} instead. * * @param elements the elements that the set should contain, in order * @return a new {@code LinkedHashSet} containing those elements (minus * duplicates) */ public static LinkedHashSet newLinkedHashSet( Iterable elements) { if (elements instanceof Collection) { return new LinkedHashSet(Collections2.cast(elements)); } LinkedHashSet set = newLinkedHashSet(); for (E element : elements) { set.add(element); } return set; } // TreeSet /** * Creates a mutable, empty {@code TreeSet} instance sorted by the * natural sort ordering of its elements. * *

Note: if mutability is not required, use {@link * ImmutableSortedSet#of()} instead. * * @return a new, empty {@code TreeSet} */ public static TreeSet newTreeSet() { return new TreeSet(); } /** * Creates a mutable {@code TreeSet} instance containing the given * elements sorted by their natural ordering. * *

Note: if mutability is not required, use {@link * ImmutableSortedSet#copyOf(Iterable)} instead. * *

Note: If {@code elements} is a {@code SortedSet} with an explicit * comparator, this method has different behavior than * {@link TreeSet#TreeSet(SortedSet)}, which returns a {@code TreeSet} with * that comparator. * * @param elements the elements that the set should contain * @return a new {@code TreeSet} containing those elements (minus duplicates) */ public static TreeSet newTreeSet( Iterable elements) { TreeSet set = newTreeSet(); for (E element : elements) { set.add(element); } return set; } /** * Creates a mutable, empty {@code TreeSet} instance with the given * comparator. * *

Note: if mutability is not required, use {@code * ImmutableSortedSet.orderedBy(comparator).build()} instead. * * @param comparator the comparator to use to sort the set * @return a new, empty {@code TreeSet} * @throws NullPointerException if {@code comparator} is null */ public static TreeSet newTreeSet(Comparator comparator) { return new TreeSet(checkNotNull(comparator)); } /** * Creates an empty {@code Set} that uses identity to determine equality. It * compares object references, instead of calling {@code equals}, to * determine whether a provided object matches an element in the set. For * example, {@code contains} returns {@code false} when passed an object that * equals a set member, but isn't the same instance. This behavior is similar * to the way {@code IdentityHashMap} handles key lookups. * * @since 8.0 */ public static Set newIdentityHashSet() { return Sets.newSetFromMap(Maps.newIdentityHashMap()); } /** * Creates an empty {@code CopyOnWriteArraySet} instance. * *

Note: if you need an immutable empty {@link Set}, use * {@link Collections#emptySet} instead. * * @return a new, empty {@code CopyOnWriteArraySet} * @since 12.0 */ @Beta @GwtIncompatible("CopyOnWriteArraySet") public static CopyOnWriteArraySet newCopyOnWriteArraySet() { return new CopyOnWriteArraySet(); } /** * Creates a {@code CopyOnWriteArraySet} instance containing the given elements. * * @param elements the elements that the set should contain, in order * @return a new {@code CopyOnWriteArraySet} containing those elements * @since 12.0 */ @Beta @GwtIncompatible("CopyOnWriteArraySet") public static CopyOnWriteArraySet newCopyOnWriteArraySet( Iterable elements) { // We copy elements to an ArrayList first, rather than incurring the // quadratic cost of adding them to the COWAS directly. Collection elementsCollection = (elements instanceof Collection) ? Collections2.cast(elements) : Lists.newArrayList(elements); return new CopyOnWriteArraySet(elementsCollection); } /** * Creates an {@code EnumSet} consisting of all enum values that are not in * the specified collection. If the collection is an {@link EnumSet}, this * method has the same behavior as {@link EnumSet#complementOf}. Otherwise, * the specified collection must contain at least one element, in order to * determine the element type. If the collection could be empty, use * {@link #complementOf(Collection, Class)} instead of this method. * * @param collection the collection whose complement should be stored in the * enum set * @return a new, modifiable {@code EnumSet} containing all values of the enum * that aren't present in the given collection * @throws IllegalArgumentException if {@code collection} is not an * {@code EnumSet} instance and contains no elements */ public static > EnumSet complementOf( Collection collection) { if (collection instanceof EnumSet) { return EnumSet.complementOf((EnumSet) collection); } checkArgument(!collection.isEmpty(), "collection is empty; use the other version of this method"); Class type = collection.iterator().next().getDeclaringClass(); return makeComplementByHand(collection, type); } /** * Creates an {@code EnumSet} consisting of all enum values that are not in * the specified collection. This is equivalent to * {@link EnumSet#complementOf}, but can act on any input collection, as long * as the elements are of enum type. * * @param collection the collection whose complement should be stored in the * {@code EnumSet} * @param type the type of the elements in the set * @return a new, modifiable {@code EnumSet} initially containing all the * values of the enum not present in the given collection */ public static > EnumSet complementOf( Collection collection, Class type) { checkNotNull(collection); return (collection instanceof EnumSet) ? EnumSet.complementOf((EnumSet) collection) : makeComplementByHand(collection, type); } private static > EnumSet makeComplementByHand( Collection collection, Class type) { EnumSet result = EnumSet.allOf(type); result.removeAll(collection); return result; } /* * Regarding newSetForMap() and SetFromMap: * * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ /** * Returns a set backed by the specified map. The resulting set displays * the same ordering, concurrency, and performance characteristics as the * backing map. In essence, this factory method provides a {@link Set} * implementation corresponding to any {@link Map} implementation. There is no * need to use this method on a {@link Map} implementation that already has a * corresponding {@link Set} implementation (such as {@link java.util.HashMap} * or {@link java.util.TreeMap}). * *

Each method invocation on the set returned by this method results in * exactly one method invocation on the backing map or its {@code keySet} * view, with one exception. The {@code addAll} method is implemented as a * sequence of {@code put} invocations on the backing map. * *

The specified map must be empty at the time this method is invoked, * and should not be accessed directly after this method returns. These * conditions are ensured if the map is created empty, passed directly * to this method, and no reference to the map is retained, as illustrated * in the following code fragment:

  {@code
   *
   *   Set identityHashSet = Sets.newSetFromMap(
   *       new IdentityHashMap());}
   *
   * This method has the same behavior as the JDK 6 method
   * {@code Collections.newSetFromMap()}. The returned set is serializable if
   * the backing map is.
   *
   * @param map the backing map
   * @return the set backed by the map
   * @throws IllegalArgumentException if {@code map} is not empty
   */
  public static  Set newSetFromMap(Map map) {
    return new SetFromMap(map);
  }

  private static class SetFromMap extends AbstractSet
      implements Set, Serializable {
    private final Map m; // The backing map
    private transient Set s; // Its keySet

    SetFromMap(Map map) {
      checkArgument(map.isEmpty(), "Map is non-empty");
      m = map;
      s = map.keySet();
    }

    @Override public void clear() {
      m.clear();
    }
    @Override public int size() {
      return m.size();
    }
    @Override public boolean isEmpty() {
      return m.isEmpty();
    }
    @Override public boolean contains(Object o) {
      return m.containsKey(o);
    }
    @Override public boolean remove(Object o) {
      return m.remove(o) != null;
    }
    @Override public boolean add(E e) {
      return m.put(e, Boolean.TRUE) == null;
    }
    @Override public Iterator iterator() {
      return s.iterator();
    }
    @Override public Object[] toArray() {
      return s.toArray();
    }
    @Override public  T[] toArray(T[] a) {
      return s.toArray(a);
    }
    @Override public String toString() {
      return s.toString();
    }
    @Override public int hashCode() {
      return s.hashCode();
    }
    @Override public boolean equals(@Nullable Object object) {
      return this == object || this.s.equals(object);
    }
    @Override public boolean containsAll(Collection c) {
      return s.containsAll(c);
    }
    @Override public boolean removeAll(Collection c) {
      return s.removeAll(c);
    }
    @Override public boolean retainAll(Collection c) {
      return s.retainAll(c);
    }

    // addAll is the only inherited implementation
    @GwtIncompatible("not needed in emulated source")
    private static final long serialVersionUID = 0;

    @GwtIncompatible("java.io.ObjectInputStream")
    private void readObject(ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
      stream.defaultReadObject();
      s = m.keySet();
    }
  }

  /**
   * An unmodifiable view of a set which may be backed by other sets; this view
   * will change as the backing sets do. Contains methods to copy the data into
   * a new set which will then remain stable. There is usually no reason to
   * retain a reference of type {@code SetView}; typically, you either use it
   * as a plain {@link Set}, or immediately invoke {@link #immutableCopy} or
   * {@link #copyInto} and forget the {@code SetView} itself.
   *
   * @since 2.0 (imported from Google Collections Library)
   */
  public abstract static class SetView extends AbstractSet {
    private SetView() {} // no subclasses but our own

    /**
     * Returns an immutable copy of the current contents of this set view.
     * Does not support null elements.
     *
     * 

Warning: this may have unexpected results if a backing set of * this view uses a nonstandard notion of equivalence, for example if it is * a {@link TreeSet} using a comparator that is inconsistent with {@link * Object#equals(Object)}. */ public ImmutableSet immutableCopy() { return ImmutableSet.copyOf(this); } /** * Copies the current contents of this set view into an existing set. This * method has equivalent behavior to {@code set.addAll(this)}, assuming that * all the sets involved are based on the same notion of equivalence. * * @return a reference to {@code set}, for convenience */ // Note: S should logically extend Set but can't due to either // some javac bug or some weirdness in the spec, not sure which. public > S copyInto(S set) { set.addAll(this); return set; } } /** * Returns an unmodifiable view of the union of two sets. The returned * set contains all elements that are contained in either backing set. * Iterating over the returned set iterates first over all the elements of * {@code set1}, then over each element of {@code set2}, in order, that is not * contained in {@code set1}. * *

Results are undefined if {@code set1} and {@code set2} are sets based on * different equivalence relations (as {@link HashSet}, {@link TreeSet}, and * the {@link Map#keySet} of an {@code IdentityHashMap} all are). * *

Note: The returned view performs better when {@code set1} is the * smaller of the two sets. If you have reason to believe one of your sets * will generally be smaller than the other, pass it first. */ public static SetView union( final Set set1, final Set set2) { checkNotNull(set1, "set1"); checkNotNull(set2, "set2"); final Set set2minus1 = difference(set2, set1); return new SetView() { @Override public int size() { return set1.size() + set2minus1.size(); } @Override public boolean isEmpty() { return set1.isEmpty() && set2.isEmpty(); } @Override public Iterator iterator() { return Iterators.unmodifiableIterator( Iterators.concat(set1.iterator(), set2minus1.iterator())); } @Override public boolean contains(Object object) { return set1.contains(object) || set2.contains(object); } @Override public > S copyInto(S set) { set.addAll(set1); set.addAll(set2); return set; } @Override public ImmutableSet immutableCopy() { return new ImmutableSet.Builder() .addAll(set1).addAll(set2).build(); } }; } /** * Returns an unmodifiable view of the intersection of two sets. The * returned set contains all elements that are contained by both backing sets. * The iteration order of the returned set matches that of {@code set1}. * *

Results are undefined if {@code set1} and {@code set2} are sets based * on different equivalence relations (as {@code HashSet}, {@code TreeSet}, * and the keySet of an {@code IdentityHashMap} all are). * *

Note: The returned view performs slightly better when {@code * set1} is the smaller of the two sets. If you have reason to believe one of * your sets will generally be smaller than the other, pass it first. * Unfortunately, since this method sets the generic type of the returned set * based on the type of the first set passed, this could in rare cases force * you to make a cast, for example:

   {@code
   *
   *   Set aFewBadObjects = ...
   *   Set manyBadStrings = ...
   *
   *   // impossible for a non-String to be in the intersection
   *   SuppressWarnings("unchecked")
   *   Set badStrings = (Set) Sets.intersection(
   *       aFewBadObjects, manyBadStrings);}
   *
   * This is unfortunate, but should come up only very rarely.
   */
  public static  SetView intersection(
      final Set set1, final Set set2) {
    checkNotNull(set1, "set1");
    checkNotNull(set2, "set2");

    final Predicate inSet2 = Predicates.in(set2);
    return new SetView() {
      @Override public Iterator iterator() {
        return Iterators.filter(set1.iterator(), inSet2);
      }
      @Override public int size() {
        return Iterators.size(iterator());
      }
      @Override public boolean isEmpty() {
        return !iterator().hasNext();
      }
      @Override public boolean contains(Object object) {
        return set1.contains(object) && set2.contains(object);
      }
      @Override public boolean containsAll(Collection collection) {
        return set1.containsAll(collection)
            && set2.containsAll(collection);
      }
    };
  }

  /**
   * Returns an unmodifiable view of the difference of two sets. The
   * returned set contains all elements that are contained by {@code set1} and
   * not contained by {@code set2}. {@code set2} may also contain elements not
   * present in {@code set1}; these are simply ignored. The iteration order of
   * the returned set matches that of {@code set1}.
   *
   * 

Results are undefined if {@code set1} and {@code set2} are sets based * on different equivalence relations (as {@code HashSet}, {@code TreeSet}, * and the keySet of an {@code IdentityHashMap} all are). */ public static SetView difference( final Set set1, final Set set2) { checkNotNull(set1, "set1"); checkNotNull(set2, "set2"); final Predicate notInSet2 = Predicates.not(Predicates.in(set2)); return new SetView() { @Override public Iterator iterator() { return Iterators.filter(set1.iterator(), notInSet2); } @Override public int size() { return Iterators.size(iterator()); } @Override public boolean isEmpty() { return set2.containsAll(set1); } @Override public boolean contains(Object element) { return set1.contains(element) && !set2.contains(element); } }; } /** * Returns an unmodifiable view of the symmetric difference of two * sets. The returned set contains all elements that are contained in either * {@code set1} or {@code set2} but not in both. The iteration order of the * returned set is undefined. * *

Results are undefined if {@code set1} and {@code set2} are sets based * on different equivalence relations (as {@code HashSet}, {@code TreeSet}, * and the keySet of an {@code IdentityHashMap} all are). * * @since 3.0 */ public static SetView symmetricDifference( Set set1, Set set2) { checkNotNull(set1, "set1"); checkNotNull(set2, "set2"); // TODO(kevinb): Replace this with a more efficient implementation return difference(union(set1, set2), intersection(set1, set2)); } /** * Returns the elements of {@code unfiltered} that satisfy a predicate. The * returned set is a live view of {@code unfiltered}; changes to one affect * the other. * *

The resulting set's iterator does not support {@code remove()}, but all * other set methods are supported. When given an element that doesn't satisfy * the predicate, the set's {@code add()} and {@code addAll()} methods throw * an {@link IllegalArgumentException}. When methods such as {@code * removeAll()} and {@code clear()} are called on the filtered set, only * elements that satisfy the filter will be removed from the underlying set. * *

The returned set isn't threadsafe or serializable, even if * {@code unfiltered} is. * *

Many of the filtered set's methods, such as {@code size()}, iterate * across every element in the underlying set and determine which elements * satisfy the filter. When a live view is not needed, it may be faster * to copy {@code Iterables.filter(unfiltered, predicate)} and use the copy. * *

Warning: {@code predicate} must be consistent with equals, * as documented at {@link Predicate#apply}. Do not provide a predicate such * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent * with equals. (See {@link Iterables#filter(Iterable, Class)} for related * functionality.) */ // TODO(kevinb): how to omit that last sentence when building GWT javadoc? public static Set filter( Set unfiltered, Predicate predicate) { if (unfiltered instanceof SortedSet) { return filter((SortedSet) unfiltered, predicate); } if (unfiltered instanceof FilteredSet) { // Support clear(), removeAll(), and retainAll() when filtering a filtered // collection. FilteredSet filtered = (FilteredSet) unfiltered; Predicate combinedPredicate = Predicates.and(filtered.predicate, predicate); return new FilteredSet( (Set) filtered.unfiltered, combinedPredicate); } return new FilteredSet( checkNotNull(unfiltered), checkNotNull(predicate)); } private static class FilteredSet extends FilteredCollection implements Set { FilteredSet(Set unfiltered, Predicate predicate) { super(unfiltered, predicate); } @Override public boolean equals(@Nullable Object object) { return equalsImpl(this, object); } @Override public int hashCode() { return hashCodeImpl(this); } } /** * Returns the elements of a {@code SortedSet}, {@code unfiltered}, that * satisfy a predicate. The returned set is a live view of {@code unfiltered}; * changes to one affect the other. * *

The resulting set's iterator does not support {@code remove()}, but all * other set methods are supported. When given an element that doesn't satisfy * the predicate, the set's {@code add()} and {@code addAll()} methods throw * an {@link IllegalArgumentException}. When methods such as * {@code removeAll()} and {@code clear()} are called on the filtered set, * only elements that satisfy the filter will be removed from the underlying * set. * *

The returned set isn't threadsafe or serializable, even if * {@code unfiltered} is. * *

Many of the filtered set's methods, such as {@code size()}, iterate across * every element in the underlying set and determine which elements satisfy * the filter. When a live view is not needed, it may be faster to copy * {@code Iterables.filter(unfiltered, predicate)} and use the copy. * *

Warning: {@code predicate} must be consistent with equals, * as documented at {@link Predicate#apply}. Do not provide a predicate such as * {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent with * equals. (See {@link Iterables#filter(Iterable, Class)} for related * functionality.) * * @since 11.0 */ @Beta @SuppressWarnings("unchecked") public static SortedSet filter( SortedSet unfiltered, Predicate predicate) { if (unfiltered instanceof FilteredSet) { // Support clear(), removeAll(), and retainAll() when filtering a filtered // collection. FilteredSet filtered = (FilteredSet) unfiltered; Predicate combinedPredicate = Predicates.and(filtered.predicate, predicate); return new FilteredSortedSet( (SortedSet) filtered.unfiltered, combinedPredicate); } return new FilteredSortedSet( checkNotNull(unfiltered), checkNotNull(predicate)); } private static class FilteredSortedSet extends FilteredCollection implements SortedSet { FilteredSortedSet(SortedSet unfiltered, Predicate predicate) { super(unfiltered, predicate); } @Override public boolean equals(@Nullable Object object) { return equalsImpl(this, object); } @Override public int hashCode() { return hashCodeImpl(this); } @Override public Comparator comparator() { return ((SortedSet) unfiltered).comparator(); } @Override public SortedSet subSet(E fromElement, E toElement) { return new FilteredSortedSet(((SortedSet) unfiltered).subSet(fromElement, toElement), predicate); } @Override public SortedSet headSet(E toElement) { return new FilteredSortedSet(((SortedSet) unfiltered).headSet(toElement), predicate); } @Override public SortedSet tailSet(E fromElement) { return new FilteredSortedSet(((SortedSet) unfiltered).tailSet(fromElement), predicate); } @Override public E first() { return iterator().next(); } @Override public E last() { SortedSet sortedUnfiltered = (SortedSet) unfiltered; while (true) { E element = sortedUnfiltered.last(); if (predicate.apply(element)) { return element; } sortedUnfiltered = sortedUnfiltered.headSet(element); } } } /** * Returns every possible list that can be formed by choosing one element * from each of the given sets in order; the "n-ary * Cartesian * product" of the sets. For example:

   {@code
   *
   *   Sets.cartesianProduct(ImmutableList.of(
   *       ImmutableSet.of(1, 2),
   *       ImmutableSet.of("A", "B", "C")))}
* * returns a set containing six lists: * *
    *
  • {@code ImmutableList.of(1, "A")} *
  • {@code ImmutableList.of(1, "B")} *
  • {@code ImmutableList.of(1, "C")} *
  • {@code ImmutableList.of(2, "A")} *
  • {@code ImmutableList.of(2, "B")} *
  • {@code ImmutableList.of(2, "C")} *
* * The order in which these lists are returned is not guaranteed, however the * position of an element inside a tuple always corresponds to the position of * the set from which it came in the input list. Note that if any input set is * empty, the Cartesian product will also be empty. If no sets at all are * provided (an empty list), the resulting Cartesian product has one element, * an empty list (counter-intuitive, but mathematically consistent). * *

Performance notes: while the cartesian product of sets of size * {@code m, n, p} is a set of size {@code m x n x p}, its actual memory * consumption is much smaller. When the cartesian set is constructed, the * input sets are merely copied. Only as the resulting set is iterated are the * individual lists created, and these are not retained after iteration. * * @param sets the sets to choose elements from, in the order that * the elements chosen from those sets should appear in the resulting * lists * @param any common base class shared by all axes (often just {@link * Object}) * @return the Cartesian product, as an immutable set containing immutable * lists * @throws NullPointerException if {@code sets}, any one of the {@code sets}, * or any element of a provided set is null * @since 2.0 */ public static Set> cartesianProduct( List> sets) { for (Set set : sets) { if (set.isEmpty()) { return ImmutableSet.of(); } } CartesianSet cartesianSet = new CartesianSet(sets); return cartesianSet; } /** * Returns every possible list that can be formed by choosing one element * from each of the given sets in order; the "n-ary * Cartesian * product" of the sets. For example:

   {@code
   *
   *   Sets.cartesianProduct(
   *       ImmutableSet.of(1, 2),
   *       ImmutableSet.of("A", "B", "C"))}
* * returns a set containing six lists: * *
    *
  • {@code ImmutableList.of(1, "A")} *
  • {@code ImmutableList.of(1, "B")} *
  • {@code ImmutableList.of(1, "C")} *
  • {@code ImmutableList.of(2, "A")} *
  • {@code ImmutableList.of(2, "B")} *
  • {@code ImmutableList.of(2, "C")} *
* * The order in which these lists are returned is not guaranteed, however the * position of an element inside a tuple always corresponds to the position of * the set from which it came in the input list. Note that if any input set is * empty, the Cartesian product will also be empty. If no sets at all are * provided, the resulting Cartesian product has one element, an empty list * (counter-intuitive, but mathematically consistent). * *

Performance notes: while the cartesian product of sets of size * {@code m, n, p} is a set of size {@code m x n x p}, its actual memory * consumption is much smaller. When the cartesian set is constructed, the * input sets are merely copied. Only as the resulting set is iterated are the * individual lists created, and these are not retained after iteration. * * @param sets the sets to choose elements from, in the order that * the elements chosen from those sets should appear in the resulting * lists * @param any common base class shared by all axes (often just {@link * Object}) * @return the Cartesian product, as an immutable set containing immutable * lists * @throws NullPointerException if {@code sets}, any one of the {@code sets}, * or any element of a provided set is null * @since 2.0 */ public static Set> cartesianProduct( Set... sets) { return cartesianProduct(Arrays.asList(sets)); } private static class CartesianSet extends AbstractSet> { final ImmutableList axes; final int size; CartesianSet(List> sets) { int dividend = 1; ImmutableList.Builder builder = ImmutableList.builder(); try { for (Set set : sets) { Axis axis = new Axis(set, dividend); builder.add(axis); dividend = IntMath.checkedMultiply(dividend, axis.size()); } } catch (ArithmeticException overflow) { throw new IllegalArgumentException("cartesian product too big"); } this.axes = builder.build(); size = dividend; } @Override public int size() { return size; } @Override public UnmodifiableIterator> iterator() { return new AbstractIndexedListIterator>(size) { @Override protected List get(int index) { Object[] tuple = new Object[axes.size()]; for (int i = 0 ; i < tuple.length; i++) { tuple[i] = axes.get(i).getForIndex(index); } @SuppressWarnings("unchecked") // only B's are put in here List result = (ImmutableList) ImmutableList.copyOf(tuple); return result; } }; } @Override public boolean contains(Object element) { if (!(element instanceof List)) { return false; } List tuple = (List) element; int dimensions = axes.size(); if (tuple.size() != dimensions) { return false; } for (int i = 0; i < dimensions; i++) { if (!axes.get(i).contains(tuple.get(i))) { return false; } } return true; } @Override public boolean equals(@Nullable Object object) { // Warning: this is broken if size() == 0, so it is critical that we // substitute an empty ImmutableSet to the user in place of this if (object instanceof CartesianSet) { CartesianSet that = (CartesianSet) object; return this.axes.equals(that.axes); } return super.equals(object); } @Override public int hashCode() { // Warning: this is broken if size() == 0, so it is critical that we // substitute an empty ImmutableSet to the user in place of this // It's a weird formula, but tests prove it works. int adjust = size - 1; for (int i = 0; i < axes.size(); i++) { adjust *= 31; } return axes.hashCode() + adjust; } private class Axis { final ImmutableSet choices; final ImmutableList choicesList; final int dividend; Axis(Set set, int dividend) { choices = ImmutableSet.copyOf(set); choicesList = choices.asList(); this.dividend = dividend; } int size() { return choices.size(); } B getForIndex(int index) { return choicesList.get(index / dividend % size()); } boolean contains(Object target) { return choices.contains(target); } @Override public boolean equals(Object obj) { if (obj instanceof CartesianSet.Axis) { CartesianSet.Axis that = (CartesianSet.Axis) obj; return this.choices.equals(that.choices); // dividends must be equal or we wouldn't have gotten this far } return false; } @Override public int hashCode() { // Because Axis instances are not exposed, we can // opportunistically choose whatever bizarre formula happens // to make CartesianSet.hashCode() as simple as possible. return size / choices.size() * choices.hashCode(); } } } /** * Returns the set of all possible subsets of {@code set}. For example, * {@code powerSet(ImmutableSet.of(1, 2))} returns the set {@code {{}, * {1}, {2}, {1, 2}}}. * *

Elements appear in these subsets in the same iteration order as they * appeared in the input set. The order in which these subsets appear in the * outer set is undefined. Note that the power set of the empty set is not the * empty set, but a one-element set containing the empty set. * *

The returned set and its constituent sets use {@code equals} to decide * whether two elements are identical, even if the input set uses a different * concept of equivalence. * *

Performance notes: while the power set of a set with size {@code * n} is of size {@code 2^n}, its memory usage is only {@code O(n)}. When the * power set is constructed, the input set is merely copied. Only as the * power set is iterated are the individual subsets created, and these subsets * themselves occupy only a few bytes of memory regardless of their size. * * @param set the set of elements to construct a power set from * @return the power set, as an immutable set of immutable sets * @throws IllegalArgumentException if {@code set} has more than 30 unique * elements (causing the power set size to exceed the {@code int} range) * @throws NullPointerException if {@code set} is or contains {@code null} * @see Power set article at * Wikipedia * @since 4.0 */ @GwtCompatible(serializable = false) public static Set> powerSet(Set set) { ImmutableSet input = ImmutableSet.copyOf(set); checkArgument(input.size() <= 30, "Too many elements to create power set: %s > 30", input.size()); return new PowerSet(input); } private static final class PowerSet extends AbstractSet> { final ImmutableSet inputSet; final ImmutableList inputList; final int powerSetSize; PowerSet(ImmutableSet input) { this.inputSet = input; this.inputList = input.asList(); this.powerSetSize = 1 << input.size(); } @Override public int size() { return powerSetSize; } @Override public boolean isEmpty() { return false; } @Override public Iterator> iterator() { return new AbstractIndexedListIterator>(powerSetSize) { @Override protected Set get(final int setBits) { return new AbstractSet() { @Override public int size() { return Integer.bitCount(setBits); } @Override public Iterator iterator() { return new BitFilteredSetIterator(inputList, setBits); } }; } }; } private static final class BitFilteredSetIterator extends UnmodifiableIterator { final ImmutableList input; int remainingSetBits; BitFilteredSetIterator(ImmutableList input, int allSetBits) { this.input = input; this.remainingSetBits = allSetBits; } @Override public boolean hasNext() { return remainingSetBits != 0; } @Override public E next() { int index = Integer.numberOfTrailingZeros(remainingSetBits); if (index == 32) { throw new NoSuchElementException(); } int currentElementMask = 1 << index; remainingSetBits &= ~currentElementMask; return input.get(index); } } @Override public boolean contains(@Nullable Object obj) { if (obj instanceof Set) { Set set = (Set) obj; return inputSet.containsAll(set); } return false; } @Override public boolean equals(@Nullable Object obj) { if (obj instanceof PowerSet) { PowerSet that = (PowerSet) obj; return inputSet.equals(that.inputSet); } return super.equals(obj); } @Override public int hashCode() { /* * The sum of the sums of the hash codes in each subset is just the sum of * each input element's hash code times the number of sets that element * appears in. Each element appears in exactly half of the 2^n sets, so: */ return inputSet.hashCode() << (inputSet.size() - 1); } @Override public String toString() { return "powerSet(" + inputSet + ")"; } } /** * An implementation for {@link Set#hashCode()}. */ static int hashCodeImpl(Set s) { int hashCode = 0; for (Object o : s) { hashCode += o != null ? o.hashCode() : 0; } return hashCode; } /** * An implementation for {@link Set#equals(Object)}. */ static boolean equalsImpl(Set s, @Nullable Object object){ if (s == object) { return true; } if (object instanceof Set) { Set o = (Set) object; try { return s.size() == o.size() && s.containsAll(o); } catch (NullPointerException ignored) { return false; } catch (ClassCastException ignored) { return false; } } return false; } /** * Returns an unmodifiable view of the specified navigable set. This method * allows modules to provide users with "read-only" access to internal * navigable sets. Query operations on the returned set "read through" to the * specified set, and attempts to modify the returned set, whether direct or * via its collection views, result in an * {@code UnsupportedOperationException}. * *

The returned navigable set will be serializable if the specified * navigable set is serializable. * * @param set the navigable set for which an unmodifiable view is to be * returned * @return an unmodifiable view of the specified navigable set * @since 12.0 */ @GwtIncompatible("NavigableSet") public static NavigableSet unmodifiableNavigableSet( NavigableSet set) { if (set instanceof ImmutableSortedSet || set instanceof UnmodifiableNavigableSet) { return set; } return new UnmodifiableNavigableSet(set); } @GwtIncompatible("NavigableSet") static final class UnmodifiableNavigableSet extends ForwardingSortedSet implements NavigableSet, Serializable { private final NavigableSet delegate; UnmodifiableNavigableSet(NavigableSet delegate) { this.delegate = checkNotNull(delegate); } @Override protected SortedSet delegate() { return Collections.unmodifiableSortedSet(delegate); } @Override public E lower(E e) { return delegate.lower(e); } @Override public E floor(E e) { return delegate.floor(e); } @Override public E ceiling(E e) { return delegate.ceiling(e); } @Override public E higher(E e) { return delegate.higher(e); } @Override public E pollFirst() { throw new UnsupportedOperationException(); } @Override public E pollLast() { throw new UnsupportedOperationException(); } private transient UnmodifiableNavigableSet descendingSet; @Override public NavigableSet descendingSet() { UnmodifiableNavigableSet result = descendingSet; if (result == null) { result = descendingSet = new UnmodifiableNavigableSet( delegate.descendingSet()); result.descendingSet = this; } return result; } @Override public Iterator descendingIterator() { return Iterators.unmodifiableIterator(delegate.descendingIterator()); } @Override public NavigableSet subSet( E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { return unmodifiableNavigableSet(delegate.subSet( fromElement, fromInclusive, toElement, toInclusive)); } @Override public NavigableSet headSet(E toElement, boolean inclusive) { return unmodifiableNavigableSet(delegate.headSet(toElement, inclusive)); } @Override public NavigableSet tailSet(E fromElement, boolean inclusive) { return unmodifiableNavigableSet( delegate.tailSet(fromElement, inclusive)); } private static final long serialVersionUID = 0; } /** * Remove each element in an iterable from a set. */ static boolean removeAllImpl(Set set, Iterator iterator) { boolean changed = false; while (iterator.hasNext()) { changed |= set.remove(iterator.next()); } return changed; } static boolean removeAllImpl(Set set, Collection collection) { if (collection instanceof Multiset) { collection = ((Multiset) collection).elementSet(); } if (collection.size() < set.size()) { return removeAllImpl(set, collection.iterator()); } else { return Iterators.removeAll(set.iterator(), collection); } } @GwtIncompatible("NavigableSet") static class DescendingSet extends ForwardingNavigableSet { private final NavigableSet forward; DescendingSet(NavigableSet forward) { this.forward = forward; } @Override protected NavigableSet delegate() { return forward; } @Override public E lower(E e) { return forward.higher(e); } @Override public E floor(E e) { return forward.ceiling(e); } @Override public E ceiling(E e) { return forward.floor(e); } @Override public E higher(E e) { return forward.lower(e); } @Override public E pollFirst() { return forward.pollLast(); } @Override public E pollLast() { return forward.pollFirst(); } @Override public NavigableSet descendingSet() { return forward; } @Override public Iterator descendingIterator() { return forward.iterator(); } @Override public NavigableSet subSet( E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { return forward.subSet(toElement, toInclusive, fromElement, fromInclusive).descendingSet(); } @Override public NavigableSet headSet(E toElement, boolean inclusive) { return forward.tailSet(toElement, inclusive).descendingSet(); } @Override public NavigableSet tailSet(E fromElement, boolean inclusive) { return forward.headSet(fromElement, inclusive).descendingSet(); } @SuppressWarnings("unchecked") @Override public Comparator comparator() { Comparator forwardComparator = forward.comparator(); if (forwardComparator == null) { return (Comparator) Ordering.natural().reverse(); } else { return reverse(forwardComparator); } } // If we inline this, we get a javac error. private static Ordering reverse(Comparator forward) { return Ordering.from(forward).reverse(); } @Override public E first() { return forward.last(); } @Override public SortedSet headSet(E toElement) { return standardHeadSet(toElement); } @Override public E last() { return forward.first(); } @Override public SortedSet subSet(E fromElement, E toElement) { return standardSubSet(fromElement, toElement); } @Override public SortedSet tailSet(E fromElement) { return standardTailSet(fromElement); } @Override public Iterator iterator() { return forward.descendingIterator(); } @Override public Object[] toArray() { return standardToArray(); } @Override public T[] toArray(T[] array) { return standardToArray(array); } @Override public String toString() { return standardToString(); } } /** * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557 */ static SortedSet cast(Iterable iterable) { return (SortedSet) iterable; } }