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