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