001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.collections4;
018
019import java.util.AbstractSet;
020import java.util.Arrays;
021import java.util.Collection;
022import java.util.Collections;
023import java.util.HashSet;
024import java.util.IdentityHashMap;
025import java.util.Iterator;
026import java.util.NavigableSet;
027import java.util.Objects;
028import java.util.Set;
029import java.util.SortedSet;
030import java.util.TreeSet;
031
032import org.apache.commons.collections4.set.ListOrderedSet;
033import org.apache.commons.collections4.set.PredicatedNavigableSet;
034import org.apache.commons.collections4.set.PredicatedSet;
035import org.apache.commons.collections4.set.PredicatedSortedSet;
036import org.apache.commons.collections4.set.TransformedNavigableSet;
037import org.apache.commons.collections4.set.TransformedSet;
038import org.apache.commons.collections4.set.TransformedSortedSet;
039import org.apache.commons.collections4.set.UnmodifiableNavigableSet;
040import org.apache.commons.collections4.set.UnmodifiableSet;
041import org.apache.commons.collections4.set.UnmodifiableSortedSet;
042
043/**
044 * Provides utility methods and decorators for
045 * {@link Set} and {@link SortedSet} instances.
046 *
047 * @since 2.1
048 */
049public class SetUtils {
050
051    /**
052     * An unmodifiable <strong>view</strong> of a set that may be backed by other sets.
053     * <p>
054     * If the decorated sets change, this view will change as well. The contents
055     * of this view can be transferred to another instance via the {@link #copyInto(Set)}
056     * and {@link #toSet()} methods.
057     * </p>
058     *
059     * @param <E> the element type
060     * @since 4.1
061     */
062    public abstract static class SetView<E> extends AbstractSet<E> {
063
064        /**
065         * Copies the contents of this view into the provided set.
066         *
067         * @param <S> the set type
068         * @param set  the set for copying the contents
069         */
070        public <S extends Set<E>> void copyInto(final S set) {
071            CollectionUtils.addAll(set, this);
072        }
073
074        /**
075         * Return an iterator for this view; the returned iterator is
076         * not required to be unmodifiable.
077         * @return a new iterator for this view
078         */
079        protected abstract Iterator<E> createIterator();
080
081        @Override
082        public Iterator<E> iterator() {
083            return IteratorUtils.unmodifiableIterator(createIterator());
084        }
085
086        @Override
087        public int size() {
088            return IteratorUtils.size(iterator());
089        }
090
091        /**
092         * Returns a new set containing the contents of this view.
093         *
094         * @return a new set containing all elements of this view
095         */
096        public Set<E> toSet() {
097            final Set<E> set = new HashSet<>(size());
098            copyInto(set);
099            return set;
100        }
101    }
102
103    /**
104     * An empty unmodifiable sorted set.
105     * This is not provided in the JDK.
106     */
107    @SuppressWarnings("rawtypes")
108    public static final SortedSet EMPTY_SORTED_SET =
109            UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet<>());
110
111    /**
112     * Returns an unmodifiable <strong>view</strong> containing the difference of the given
113     * {@link Set}s, denoted by {@code a \ b} (or {@code a - b}).
114     * <p>
115     * The returned view contains all elements of {@code a} that are not a member
116     * of {@code b}.
117     *
118     * @param <E> the generic type that is able to represent the types contained
119     *   in both input sets.
120     * @param setA  the set to subtract from, must not be null
121     * @param setB  the set to subtract, must not be null
122     * @return a view of the relative complement of the two sets
123     * @since 4.1
124     */
125    public static <E> SetView<E> difference(final Set<? extends E> setA, final Set<? extends E> setB) {
126        Objects.requireNonNull(setA, "setA");
127        Objects.requireNonNull(setB, "setB");
128
129        final Predicate<E> notContainedInB = object -> !setB.contains(object);
130
131        return new SetView<E>() {
132            @Override
133            public boolean contains(final Object o) {
134                return setA.contains(o) && !setB.contains(o);
135            }
136
137            @Override
138            public Iterator<E> createIterator() {
139                return IteratorUtils.filteredIterator(setA.iterator(), notContainedInB);
140            }
141        };
142    }
143
144    /**
145     * Returns an unmodifiable <strong>view</strong> of the symmetric difference of the given
146     * {@link Set}s.
147     * <p>
148     * The returned view contains all elements of {@code a} and {@code b} that are
149     * not a member of the other set.
150     * <p>
151     * This is equivalent to {@code union(difference(a, b), difference(b, a))}.
152     *
153     * @param <E> the generic type that is able to represent the types contained
154     *   in both input sets.
155     * @param setA  the first set, must not be null
156     * @param setB  the second set, must not be null
157     * @return a view of the symmetric difference of the two sets
158     * @since 4.1
159     */
160    public static <E> SetView<E> disjunction(final Set<? extends E> setA, final Set<? extends E> setB) {
161        Objects.requireNonNull(setA, "setA");
162        Objects.requireNonNull(setB, "setB");
163
164        final SetView<E> aMinusB = difference(setA, setB);
165        final SetView<E> bMinusA = difference(setB, setA);
166
167        return new SetView<E>() {
168            @Override
169            public boolean contains(final Object o) {
170                return setA.contains(o) ^ setB.contains(o);
171            }
172
173            @Override
174            public Iterator<E> createIterator() {
175                return IteratorUtils.chainedIterator(aMinusB.iterator(), bMinusA.iterator());
176            }
177
178            @Override
179            public boolean isEmpty() {
180                return aMinusB.isEmpty() && bMinusA.isEmpty();
181            }
182
183            @Override
184            public int size() {
185                return aMinusB.size() + bMinusA.size();
186            }
187        };
188    }
189
190    /**
191     * Returns an immutable empty set if the argument is {@code null},
192     * or the argument itself otherwise.
193     *
194     * @param <T> the element type
195     * @param set the set, possibly {@code null}
196     * @return an empty set if the argument is {@code null}
197     */
198    public static <T> Set<T> emptyIfNull(final Set<T> set) {
199        return set == null ? Collections.<T>emptySet() : set;
200    }
201
202    /**
203     * Gets a typed empty unmodifiable Set.
204     * @param <E> the element type
205     * @return an empty Set
206     */
207    public static <E> Set<E> emptySet() {
208        return Collections.<E>emptySet();
209    }
210
211    /**
212     * Gets a typed empty unmodifiable sorted set.
213     * @param <E> the element type
214     * @return an empty sorted Set
215     */
216    @SuppressWarnings("unchecked") // empty set is OK for any type
217    public static <E> SortedSet<E> emptySortedSet() {
218        return EMPTY_SORTED_SET;
219    }
220
221    /**
222     * Generates a hash code using the algorithm specified in
223     * {@link java.util.Set#hashCode()}.
224     * <p>
225     * This method is useful for implementing {@code Set} when you cannot
226     * extend AbstractSet. The method takes Collection instances to enable other
227     * collection types to use the Set implementation algorithm.
228     *
229     * @param <T> the element type
230     * @see java.util.Set#hashCode()
231     * @param set  the set to calculate the hash code for, may be null
232     * @return the hash code
233     */
234    public static <T> int hashCodeForSet(final Collection<T> set) {
235        if (set == null) {
236            return 0;
237        }
238
239        int hashCode = 0;
240        for (final T obj : set) {
241            if (obj != null) {
242                hashCode += obj.hashCode();
243            }
244        }
245        return hashCode;
246    }
247
248    /**
249     * Creates a set from the given items. If the passed var-args argument is {@code
250     * null}, then the method returns {@code null}.
251     * @param <E> the element type
252     * @param items the elements that make up the new set
253     * @return a set
254     * @since 4.3
255     */
256    public static <E> HashSet<E> hashSet(final E... items) {
257        if (items == null) {
258            return null;
259        }
260        return new HashSet<>(Arrays.asList(items));
261    }
262
263    /**
264     * Returns an unmodifiable <strong>view</strong> of the intersection of the given {@link Set}s.
265     * <p>
266     * The returned view contains all elements that are members of both input sets
267     * ({@code a} and {@code b}).
268     *
269     * @param <E> the generic type that is able to represent the types contained
270     *   in both input sets.
271     * @param setA  the first set, must not be null
272     * @param setB  the second set, must not be null
273     * @return a view of the intersection of the two sets
274     * @since 4.1
275     */
276    public static <E> SetView<E> intersection(final Set<? extends E> setA, final Set<? extends E> setB) {
277        Objects.requireNonNull(setA, "setA");
278        Objects.requireNonNull(setB, "setB");
279
280        return new SetView<E>() {
281            @Override
282            public boolean contains(final Object o) {
283                return setA.contains(o) && setB.contains(o);
284            }
285
286            @Override
287            public Iterator<E> createIterator() {
288                return IteratorUtils.filteredIterator(setA.iterator(), setB::contains);
289            }
290        };
291    }
292
293    /**
294     * Tests two sets for equality as per the {@code equals()} contract
295     * in {@link java.util.Set#equals(Object)}.
296     * <p>
297     * This method is useful for implementing {@code Set} when you cannot
298     * extend AbstractSet. The method takes Collection instances to enable other
299     * collection types to use the Set implementation algorithm.
300     * <p>
301     * The relevant text (slightly paraphrased as this is a static method) is:
302     * <blockquote>
303     * <p>Two sets are considered equal if they have
304     * the same size, and every member of the first set is contained in
305     * the second. This ensures that the {@code equals} method works
306     * properly across different implementations of the {@code Set}
307     * interface.</p>
308     *
309     * <p>
310     * This implementation first checks if the two sets are the same object:
311     * if so it returns {@code true}.  Then, it checks if the two sets are
312     * identical in size; if not, it returns false. If so, it returns
313     * {@code a.containsAll((Collection) b)}.</p>
314     * </blockquote>
315     *
316     * @see java.util.Set
317     * @param set1  the first set, may be null
318     * @param set2  the second set, may be null
319     * @return whether the sets are equal by value comparison
320     */
321    public static boolean isEqualSet(final Collection<?> set1, final Collection<?> set2) {
322        if (set1 == set2) {
323            return true;
324        }
325        if (set1 == null || set2 == null || set1.size() != set2.size()) {
326            return false;
327        }
328
329        return set1.containsAll(set2);
330    }
331
332    /**
333     * Returns a new hash set that matches elements based on {@code ==} not
334     * {@code equals()}.
335     * <p>
336     * <strong>This set will violate the detail of various Set contracts.</strong>
337     * As a general rule, don't compare this set to other sets. In particular, you can't
338     * use decorators like {@link ListOrderedSet} on it, which silently assume that these
339     * contracts are fulfilled.
340     * <p>
341     * <strong>Note that the returned set is not synchronized and is not thread-safe.</strong>
342     * If you wish to use this set from multiple threads concurrently, you must use
343     * appropriate synchronization. The simplest approach is to wrap this map
344     * using {@link java.util.Collections#synchronizedSet(Set)}. This class may throw
345     * exceptions when accessed by concurrent threads without synchronization.
346     *
347     * @param <E>  the element type
348     * @return a new identity hash set
349     * @since 4.1
350     */
351    public static <E> Set<E> newIdentityHashSet() {
352        return Collections.newSetFromMap(new IdentityHashMap<>());
353    }
354
355    /**
356     * Returns a set that maintains the order of elements that are added
357     * backed by the given set.
358     * <p>
359     * If an element is added twice, the order is determined by the first add.
360     * The order is observed through the iterator or toArray.
361     *
362     * @param <E> the element type
363     * @param set  the set to order, must not be null
364     * @return an ordered set backed by the given set
365     * @throws NullPointerException if the set is null
366     */
367    public static <E> Set<E> orderedSet(final Set<E> set) {
368        return ListOrderedSet.listOrderedSet(set);
369    }
370
371    /**
372     * Returns a predicated (validating) navigable set backed by the given navigable set.
373     * <p>
374     * Only objects that pass the test in the given predicate can be added to the set.
375     * Trying to add an invalid object results in an IllegalArgumentException.
376     * It is important not to use the original set after invoking this method,
377     * as it is a backdoor for adding invalid objects.
378     *
379     * @param <E> the element type
380     * @param set  the navigable set to predicate, must not be null
381     * @param predicate  the predicate for the navigable set, must not be null
382     * @return a predicated navigable set backed by the given navigable set
383     * @throws NullPointerException if the set or predicate is null
384     * @since 4.1
385     */
386    public static <E> SortedSet<E> predicatedNavigableSet(final NavigableSet<E> set,
387                                                          final Predicate<? super E> predicate) {
388        return PredicatedNavigableSet.predicatedNavigableSet(set, predicate);
389    }
390
391    /**
392     * Returns a predicated (validating) set backed by the given set.
393     * <p>
394     * Only objects that pass the test in the given predicate can be added to the set.
395     * Trying to add an invalid object results in an IllegalArgumentException.
396     * It is important not to use the original set after invoking this method,
397     * as it is a backdoor for adding invalid objects.
398     *
399     * @param <E> the element type
400     * @param set  the set to predicate, must not be null
401     * @param predicate  the predicate for the set, must not be null
402     * @return a predicated set backed by the given set
403     * @throws NullPointerException if the set or predicate is null
404     */
405    public static <E> Set<E> predicatedSet(final Set<E> set, final Predicate<? super E> predicate) {
406        return PredicatedSet.predicatedSet(set, predicate);
407    }
408
409    /**
410     * Returns a predicated (validating) sorted set backed by the given sorted set.
411     * <p>
412     * Only objects that pass the test in the given predicate can be added to the set.
413     * Trying to add an invalid object results in an IllegalArgumentException.
414     * It is important not to use the original set after invoking this method,
415     * as it is a backdoor for adding invalid objects.
416     *
417     * @param <E> the element type
418     * @param set  the sorted set to predicate, must not be null
419     * @param predicate  the predicate for the sorted set, must not be null
420     * @return a predicated sorted set backed by the given sorted set
421     * @throws NullPointerException if the set or predicate is null
422     */
423    public static <E> SortedSet<E> predicatedSortedSet(final SortedSet<E> set,
424                                                       final Predicate<? super E> predicate) {
425        return PredicatedSortedSet.predicatedSortedSet(set, predicate);
426    }
427
428    // Set
429    /**
430     * Returns a synchronized set backed by the given set.
431     * <p>
432     * You must manually synchronize on the returned set's iterator to
433     * avoid non-deterministic behavior:
434     *
435     * <pre>
436     * Sets s = SetUtils.synchronizedSet(mySet);
437     * synchronized (s) {
438     *     Iterator i = s.iterator();
439     *     while (i.hasNext()) {
440     *         process (i.next());
441     *     }
442     * }
443     * </pre>
444     *
445     * This method is just a wrapper for {@link Collections#synchronizedSet(Set)}.
446     *
447     * @param <E> the element type
448     * @param set  the set to synchronize, must not be null
449     * @return a synchronized set backed by the given set
450     * @throws NullPointerException if the set is null
451     */
452    public static <E> Set<E> synchronizedSet(final Set<E> set) {
453        return Collections.synchronizedSet(set);
454    }
455
456    // SortedSet
457    /**
458     * Returns a synchronized sorted set backed by the given sorted set.
459     * <p>
460     * You must manually synchronize on the returned set's iterator to
461     * avoid non-deterministic behavior:
462     *
463     * <pre>
464     * Set s = SetUtils.synchronizedSortedSet(mySet);
465     * synchronized (s) {
466     *     Iterator i = s.iterator();
467     *     while (i.hasNext()) {
468     *         process (i.next());
469     *     }
470     * }
471     * </pre>
472     *
473     * This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}.
474     *
475     * @param <E> the element type
476     * @param set  the sorted set to synchronize, must not be null
477     * @return a synchronized set backed by the given set
478     * @throws NullPointerException if the set is null
479     */
480    public static <E> SortedSet<E> synchronizedSortedSet(final SortedSet<E> set) {
481        return Collections.synchronizedSortedSet(set);
482    }
483
484    /**
485     * Returns a transformed navigable set backed by the given navigable set.
486     * <p>
487     * Each object is passed through the transformer as it is added to the
488     * Set. It is important not to use the original set after invoking this
489     * method, as it is a backdoor for adding untransformed objects.
490     * <p>
491     * Existing entries in the specified set will not be transformed.
492     * If you want that behavior, see {@link TransformedNavigableSet#transformedNavigableSet}.
493     *
494     * @param <E> the element type
495     * @param set  the navigable set to transform, must not be null
496     * @param transformer  the transformer for the set, must not be null
497     * @return a transformed set backed by the given set
498     * @throws NullPointerException if the set or transformer is null
499     * @since 4.1
500     */
501    public static <E> SortedSet<E> transformedNavigableSet(final NavigableSet<E> set,
502                                                           final Transformer<? super E, ? extends E> transformer) {
503        return TransformedNavigableSet.transformingNavigableSet(set, transformer);
504    }
505
506    /**
507     * Returns a transformed set backed by the given set.
508     * <p>
509     * Each object is passed through the transformer as it is added to the
510     * Set. It is important not to use the original set after invoking this
511     * method, as it is a backdoor for adding untransformed objects.
512     * <p>
513     * Existing entries in the specified set will not be transformed.
514     * If you want that behavior, see {@link TransformedSet#transformedSet}.
515     *
516     * @param <E> the element type
517     * @param set  the set to transform, must not be null
518     * @param transformer  the transformer for the set, must not be null
519     * @return a transformed set backed by the given set
520     * @throws NullPointerException if the set or transformer is null
521     */
522    public static <E> Set<E> transformedSet(final Set<E> set,
523                                            final Transformer<? super E, ? extends E> transformer) {
524        return TransformedSet.transformingSet(set, transformer);
525    }
526
527    /**
528     * Returns a transformed sorted set backed by the given set.
529     * <p>
530     * Each object is passed through the transformer as it is added to the
531     * Set. It is important not to use the original set after invoking this
532     * method, as it is a backdoor for adding untransformed objects.
533     * <p>
534     * Existing entries in the specified set will not be transformed.
535     * If you want that behavior, see {@link TransformedSortedSet#transformedSortedSet}.
536     *
537     * @param <E> the element type
538     * @param set  the set to transform, must not be null
539     * @param transformer  the transformer for the set, must not be null
540     * @return a transformed set backed by the given set
541     * @throws NullPointerException if the set or transformer is null
542     */
543    public static <E> SortedSet<E> transformedSortedSet(final SortedSet<E> set,
544                                                        final Transformer<? super E, ? extends E> transformer) {
545        return TransformedSortedSet.transformingSortedSet(set, transformer);
546    }
547
548    // Set operations
549
550    /**
551     * Returns an unmodifiable <strong>view</strong> of the union of the given {@link Set}s.
552     * <p>
553     * The returned view contains all elements of {@code a} and {@code b}.
554     *
555     * @param <E> the generic type that is able to represent the types contained
556     *   in both input sets.
557     * @param setA  the first set, must not be null
558     * @param setB  the second set, must not be null
559     * @return a view of the union of the two set
560     * @throws NullPointerException if either input set is null
561     * @since 4.1
562     */
563    public static <E> SetView<E> union(final Set<? extends E> setA, final Set<? extends E> setB) {
564        Objects.requireNonNull(setA, "setA");
565        Objects.requireNonNull(setB, "setB");
566
567        final SetView<E> bMinusA = difference(setB, setA);
568
569        return new SetView<E>() {
570            @Override
571            public boolean contains(final Object o) {
572                return setA.contains(o) || setB.contains(o);
573            }
574
575            @Override
576            public Iterator<E> createIterator() {
577                return IteratorUtils.chainedIterator(setA.iterator(), bMinusA.iterator());
578            }
579
580            @Override
581            public boolean isEmpty() {
582                return setA.isEmpty() && setB.isEmpty();
583            }
584
585            @Override
586            public int size() {
587                return setA.size() + bMinusA.size();
588            }
589        };
590    }
591
592    // NavigableSet
593    /**
594     * Returns an unmodifiable navigable set backed by the given navigable set.
595     * <p>
596     * This method uses the implementation in the decorators subpackage.
597     *
598     * @param <E> the element type
599     * @param set  the navigable set to make unmodifiable, must not be null
600     * @return an unmodifiable set backed by the given set
601     * @throws NullPointerException if the set is null
602     * @since 4.1
603     */
604    public static <E> SortedSet<E> unmodifiableNavigableSet(final NavigableSet<E> set) {
605        return UnmodifiableNavigableSet.unmodifiableNavigableSet(set);
606    }
607
608    /**
609     * Creates an unmodifiable set from the given items. If the passed var-args argument is {@code
610     * null}, then the method returns {@code null}.
611     * @param <E> the element type
612     * @param items the elements that make up the new set
613     * @return a set
614     * @since 4.3
615     */
616    public static <E> Set<E> unmodifiableSet(final E... items) {
617        if (items == null) {
618            return null;
619        }
620        return UnmodifiableSet.unmodifiableSet(hashSet(items));
621    }
622
623    /**
624     * Returns an unmodifiable set backed by the given set.
625     * <p>
626     * This method uses the implementation in the decorators subpackage.
627     *
628     * @param <E> the element type
629     * @param set  the set to make unmodifiable, must not be null
630     * @return an unmodifiable set backed by the given set
631     * @throws NullPointerException if the set is null
632     */
633    public static <E> Set<E> unmodifiableSet(final Set<? extends E> set) {
634        return UnmodifiableSet.unmodifiableSet(set);
635    }
636
637    /**
638     * Returns an unmodifiable sorted set backed by the given sorted set.
639     * <p>
640     * This method uses the implementation in the decorators subpackage.
641     *
642     * @param <E> the element type
643     * @param set  the sorted set to make unmodifiable, must not be null
644     * @return an unmodifiable set backed by the given set
645     * @throws NullPointerException if the set is null
646     */
647    public static <E> SortedSet<E> unmodifiableSortedSet(final SortedSet<E> set) {
648        return UnmodifiableSortedSet.unmodifiableSortedSet(set);
649    }
650
651    /**
652     * Don't allow instances.
653     */
654    private SetUtils() {
655        // empty
656    }
657
658}