EnumSet.java revision 983b2c6ff9ea6d35adf7ab6398dccf870b7e180a
1/*
2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.util;
27
28/**
29 * A specialized {@link Set} implementation for use with enum types.  All of
30 * the elements in an enum set must come from a single enum type that is
31 * specified, explicitly or implicitly, when the set is created.  Enum sets
32 * are represented internally as bit vectors.  This representation is
33 * extremely compact and efficient. The space and time performance of this
34 * class should be good enough to allow its use as a high-quality, typesafe
35 * alternative to traditional <tt>int</tt>-based "bit flags."  Even bulk
36 * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
37 * run very quickly if their argument is also an enum set.
38 *
39 * <p>The iterator returned by the <tt>iterator</tt> method traverses the
40 * elements in their <i>natural order</i> (the order in which the enum
41 * constants are declared).  The returned iterator is <i>weakly
42 * consistent</i>: it will never throw {@link ConcurrentModificationException}
43 * and it may or may not show the effects of any modifications to the set that
44 * occur while the iteration is in progress.
45 *
46 * <p>Null elements are not permitted.  Attempts to insert a null element
47 * will throw {@link NullPointerException}.  Attempts to test for the
48 * presence of a null element or to remove one will, however, function
49 * properly.
50 *
51 * <P>Like most collection implementations, <tt>EnumSet</tt> is not
52 * synchronized.  If multiple threads access an enum set concurrently, and at
53 * least one of the threads modifies the set, it should be synchronized
54 * externally.  This is typically accomplished by synchronizing on some
55 * object that naturally encapsulates the enum set.  If no such object exists,
56 * the set should be "wrapped" using the {@link Collections#synchronizedSet}
57 * method.  This is best done at creation time, to prevent accidental
58 * unsynchronized access:
59 *
60 * <pre>
61 * Set&lt;MyEnum&gt; s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
62 * </pre>
63 *
64 * <p>Implementation note: All basic operations execute in constant time.
65 * They are likely (though not guaranteed) to be much faster than their
66 * {@link HashSet} counterparts.  Even bulk operations execute in
67 * constant time if their argument is also an enum set.
68 *
69 * <p>This class is a member of the
70 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
71 * Java Collections Framework</a>.
72 *
73 * @author Josh Bloch
74 * @since 1.5
75 * @see EnumMap
76 * @serial exclude
77 */
78public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
79    implements Cloneable, java.io.Serializable
80{
81    /**
82     * The class of all the elements of this set.
83     */
84    final Class<E> elementType;
85
86    /**
87     * All of the values comprising T.  (Cached for performance.)
88     */
89    final Enum[] universe;
90
91    private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
92
93    EnumSet(Class<E>elementType, Enum[] universe) {
94        this.elementType = elementType;
95        this.universe    = universe;
96    }
97
98    /**
99     * Creates an empty enum set with the specified element type.
100     *
101     * @param elementType the class object of the element type for this enum
102     *     set
103     * @throws NullPointerException if <tt>elementType</tt> is null
104     */
105    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
106        Enum[] universe = getUniverse(elementType);
107        if (universe == null)
108            throw new ClassCastException(elementType + " not an enum");
109
110        if (universe.length <= 64)
111            return new RegularEnumSet<>(elementType, universe);
112        else
113            return new JumboEnumSet<>(elementType, universe);
114    }
115
116    /**
117     * Creates an enum set containing all of the elements in the specified
118     * element type.
119     *
120     * @param elementType the class object of the element type for this enum
121     *     set
122     * @throws NullPointerException if <tt>elementType</tt> is null
123     */
124    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
125        EnumSet<E> result = noneOf(elementType);
126        result.addAll();
127        return result;
128    }
129
130    /**
131     * Adds all of the elements from the appropriate enum type to this enum
132     * set, which is empty prior to the call.
133     */
134    abstract void addAll();
135
136    /**
137     * Creates an enum set with the same element type as the specified enum
138     * set, initially containing the same elements (if any).
139     *
140     * @param s the enum set from which to initialize this enum set
141     * @throws NullPointerException if <tt>s</tt> is null
142     */
143    public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
144        return s.clone();
145    }
146
147    /**
148     * Creates an enum set initialized from the specified collection.  If
149     * the specified collection is an <tt>EnumSet</tt> instance, this static
150     * factory method behaves identically to {@link #copyOf(EnumSet)}.
151     * Otherwise, the specified collection must contain at least one element
152     * (in order to determine the new enum set's element type).
153     *
154     * @param c the collection from which to initialize this enum set
155     * @throws IllegalArgumentException if <tt>c</tt> is not an
156     *     <tt>EnumSet</tt> instance and contains no elements
157     * @throws NullPointerException if <tt>c</tt> is null
158     */
159    public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
160        if (c instanceof EnumSet) {
161            return ((EnumSet<E>)c).clone();
162        } else {
163            if (c.isEmpty())
164                throw new IllegalArgumentException("Collection is empty");
165            Iterator<E> i = c.iterator();
166            E first = i.next();
167            EnumSet<E> result = EnumSet.of(first);
168            while (i.hasNext())
169                result.add(i.next());
170            return result;
171        }
172    }
173
174    /**
175     * Creates an enum set with the same element type as the specified enum
176     * set, initially containing all the elements of this type that are
177     * <i>not</i> contained in the specified set.
178     *
179     * @param s the enum set from whose complement to initialize this enum set
180     * @throws NullPointerException if <tt>s</tt> is null
181     */
182    public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
183        EnumSet<E> result = copyOf(s);
184        result.complement();
185        return result;
186    }
187
188    /**
189     * Creates an enum set initially containing the specified element.
190     *
191     * Overloadings of this method exist to initialize an enum set with
192     * one through five elements.  A sixth overloading is provided that
193     * uses the varargs feature.  This overloading may be used to create
194     * an enum set initially containing an arbitrary number of elements, but
195     * is likely to run slower than the overloadings that do not use varargs.
196     *
197     * @param e the element that this set is to contain initially
198     * @throws NullPointerException if <tt>e</tt> is null
199     * @return an enum set initially containing the specified element
200     */
201    public static <E extends Enum<E>> EnumSet<E> of(E e) {
202        EnumSet<E> result = noneOf(e.getDeclaringClass());
203        result.add(e);
204        return result;
205    }
206
207    /**
208     * Creates an enum set initially containing the specified elements.
209     *
210     * Overloadings of this method exist to initialize an enum set with
211     * one through five elements.  A sixth overloading is provided that
212     * uses the varargs feature.  This overloading may be used to create
213     * an enum set initially containing an arbitrary number of elements, but
214     * is likely to run slower than the overloadings that do not use varargs.
215     *
216     * @param e1 an element that this set is to contain initially
217     * @param e2 another element that this set is to contain initially
218     * @throws NullPointerException if any parameters are null
219     * @return an enum set initially containing the specified elements
220     */
221    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
222        EnumSet<E> result = noneOf(e1.getDeclaringClass());
223        result.add(e1);
224        result.add(e2);
225        return result;
226    }
227
228    /**
229     * Creates an enum set initially containing the specified elements.
230     *
231     * Overloadings of this method exist to initialize an enum set with
232     * one through five elements.  A sixth overloading is provided that
233     * uses the varargs feature.  This overloading may be used to create
234     * an enum set initially containing an arbitrary number of elements, but
235     * is likely to run slower than the overloadings that do not use varargs.
236     *
237     * @param e1 an element that this set is to contain initially
238     * @param e2 another element that this set is to contain initially
239     * @param e3 another element that this set is to contain initially
240     * @throws NullPointerException if any parameters are null
241     * @return an enum set initially containing the specified elements
242     */
243    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
244        EnumSet<E> result = noneOf(e1.getDeclaringClass());
245        result.add(e1);
246        result.add(e2);
247        result.add(e3);
248        return result;
249    }
250
251    /**
252     * Creates an enum set initially containing the specified elements.
253     *
254     * Overloadings of this method exist to initialize an enum set with
255     * one through five elements.  A sixth overloading is provided that
256     * uses the varargs feature.  This overloading may be used to create
257     * an enum set initially containing an arbitrary number of elements, but
258     * is likely to run slower than the overloadings that do not use varargs.
259     *
260     * @param e1 an element that this set is to contain initially
261     * @param e2 another element that this set is to contain initially
262     * @param e3 another element that this set is to contain initially
263     * @param e4 another element that this set is to contain initially
264     * @throws NullPointerException if any parameters are null
265     * @return an enum set initially containing the specified elements
266     */
267    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
268        EnumSet<E> result = noneOf(e1.getDeclaringClass());
269        result.add(e1);
270        result.add(e2);
271        result.add(e3);
272        result.add(e4);
273        return result;
274    }
275
276    /**
277     * Creates an enum set initially containing the specified elements.
278     *
279     * Overloadings of this method exist to initialize an enum set with
280     * one through five elements.  A sixth overloading is provided that
281     * uses the varargs feature.  This overloading may be used to create
282     * an enum set initially containing an arbitrary number of elements, but
283     * is likely to run slower than the overloadings that do not use varargs.
284     *
285     * @param e1 an element that this set is to contain initially
286     * @param e2 another element that this set is to contain initially
287     * @param e3 another element that this set is to contain initially
288     * @param e4 another element that this set is to contain initially
289     * @param e5 another element that this set is to contain initially
290     * @throws NullPointerException if any parameters are null
291     * @return an enum set initially containing the specified elements
292     */
293    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
294                                                    E e5)
295    {
296        EnumSet<E> result = noneOf(e1.getDeclaringClass());
297        result.add(e1);
298        result.add(e2);
299        result.add(e3);
300        result.add(e4);
301        result.add(e5);
302        return result;
303    }
304
305    /**
306     * Creates an enum set initially containing the specified elements.
307     * This factory, whose parameter list uses the varargs feature, may
308     * be used to create an enum set initially containing an arbitrary
309     * number of elements, but it is likely to run slower than the overloadings
310     * that do not use varargs.
311     *
312     * @param first an element that the set is to contain initially
313     * @param rest the remaining elements the set is to contain initially
314     * @throws NullPointerException if any of the specified elements are null,
315     *     or if <tt>rest</tt> is null
316     * @return an enum set initially containing the specified elements
317     */
318    @SafeVarargs
319    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
320        EnumSet<E> result = noneOf(first.getDeclaringClass());
321        result.add(first);
322        for (E e : rest)
323            result.add(e);
324        return result;
325    }
326
327    /**
328     * Creates an enum set initially containing all of the elements in the
329     * range defined by the two specified endpoints.  The returned set will
330     * contain the endpoints themselves, which may be identical but must not
331     * be out of order.
332     *
333     * @param from the first element in the range
334     * @param to the last element in the range
335     * @throws NullPointerException if {@code from} or {@code to} are null
336     * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
337     * @return an enum set initially containing all of the elements in the
338     *         range defined by the two specified endpoints
339     */
340    public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
341        if (from.compareTo(to) > 0)
342            throw new IllegalArgumentException(from + " > " + to);
343        EnumSet<E> result = noneOf(from.getDeclaringClass());
344        result.addRange(from, to);
345        return result;
346    }
347
348    /**
349     * Adds the specified range to this enum set, which is empty prior
350     * to the call.
351     */
352    abstract void addRange(E from, E to);
353
354    /**
355     * Returns a copy of this set.
356     *
357     * @return a copy of this set
358     */
359    public EnumSet<E> clone() {
360        try {
361            return (EnumSet<E>) super.clone();
362        } catch(CloneNotSupportedException e) {
363            throw new AssertionError(e);
364        }
365    }
366
367    /**
368     * Complements the contents of this enum set.
369     */
370    abstract void complement();
371
372    /**
373     * Throws an exception if e is not of the correct type for this enum set.
374     */
375    final void typeCheck(E e) {
376        Class eClass = e.getClass();
377        if (eClass != elementType && eClass.getSuperclass() != elementType)
378            throw new ClassCastException(eClass + " != " + elementType);
379    }
380
381    /**
382     * Returns all of the values comprising E.
383     * The result is uncloned, cached, and shared by all callers.
384     */
385    private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
386        // Android-changed: Use JavaLangAccess directly instead of going via
387        // SharedSecrets.
388        return java.lang.JavaLangAccess.getEnumConstantsShared(elementType);
389    }
390
391    /**
392     * This class is used to serialize all EnumSet instances, regardless of
393     * implementation type.  It captures their "logical contents" and they
394     * are reconstructed using public static factories.  This is necessary
395     * to ensure that the existence of a particular implementation type is
396     * an implementation detail.
397     *
398     * @serial include
399     */
400    private static class SerializationProxy <E extends Enum<E>>
401        implements java.io.Serializable
402    {
403        /**
404         * The element type of this enum set.
405         *
406         * @serial
407         */
408        private final Class<E> elementType;
409
410        /**
411         * The elements contained in this enum set.
412         *
413         * @serial
414         */
415        private final Enum[] elements;
416
417        SerializationProxy(EnumSet<E> set) {
418            elementType = set.elementType;
419            elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
420        }
421
422        private Object readResolve() {
423            EnumSet<E> result = EnumSet.noneOf(elementType);
424            for (Enum e : elements)
425                result.add((E)e);
426            return result;
427        }
428
429        private static final long serialVersionUID = 362491234563181265L;
430    }
431
432    Object writeReplace() {
433        return new SerializationProxy<>(this);
434    }
435
436    // readObject method for the serialization proxy pattern
437    // See Effective Java, Second Ed., Item 78.
438    private void readObject(java.io.ObjectInputStream stream)
439        throws java.io.InvalidObjectException {
440        throw new java.io.InvalidObjectException("Proxy required");
441    }
442}
443