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