1 /*
2  * Copyright (c) 2003, 2019, 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 
26 package java.util;
27 
28 import jdk.internal.access.SharedSecrets;
29 
30 /**
31  * A specialized {@link Set} implementation for use with enum types.  All of
32  * the elements in an enum set must come from a single enum type that is
33  * specified, explicitly or implicitly, when the set is created.  Enum sets
34  * are represented internally as bit vectors.  This representation is
35  * extremely compact and efficient. The space and time performance of this
36  * class should be good enough to allow its use as a high-quality, typesafe
37  * alternative to traditional {@code int}-based "bit flags."  Even bulk
38  * operations (such as {@code containsAll} and {@code retainAll}) should
39  * run very quickly if their argument is also an enum set.
40  *
41  * <p>The iterator returned by the {@code iterator} method traverses the
42  * elements in their <i>natural order</i> (the order in which the enum
43  * constants are declared).  The returned iterator is <i>weakly
44  * consistent</i>: it will never throw {@link ConcurrentModificationException}
45  * and it may or may not show the effects of any modifications to the set that
46  * occur while the iteration is in progress.
47  *
48  * <p>Null elements are not permitted.  Attempts to insert a null element
49  * will throw {@link NullPointerException}.  Attempts to test for the
50  * presence of a null element or to remove one will, however, function
51  * properly.
52  *
53  * <P>Like most collection implementations, {@code EnumSet} is not
54  * synchronized.  If multiple threads access an enum set concurrently, and at
55  * least one of the threads modifies the set, it should be synchronized
56  * externally.  This is typically accomplished by synchronizing on some
57  * object that naturally encapsulates the enum set.  If no such object exists,
58  * the set should be "wrapped" using the {@link Collections#synchronizedSet}
59  * method.  This is best done at creation time, to prevent accidental
60  * unsynchronized access:
61  *
62  * <pre>
63  * Set&lt;MyEnum&gt; s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
64  * </pre>
65  *
66  * <p>Implementation note: All basic operations execute in constant time.
67  * They are likely (though not guaranteed) to be much faster than their
68  * {@link HashSet} counterparts.  Even bulk operations execute in
69  * constant time if their argument is also an enum set.
70  *
71  * <p>This class is a member of the
72  * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
73  * Java Collections Framework</a>.
74  *
75  * @author Josh Bloch
76  * @since 1.5
77  * @see EnumMap
78  */
79 public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
80     implements Cloneable, java.io.Serializable
81 {
82     // declare EnumSet.class serialization compatibility with JDK 8
83     @java.io.Serial
84     private static final long serialVersionUID = 1009687484059888093L;
85 
86     /**
87      * The class of all the elements of this set.
88      */
89     final transient Class<E> elementType;
90 
91     /**
92      * All of the values comprising E.  (Cached for performance.)
93      */
94     final transient Enum<?>[] universe;
95 
EnumSet(Class<E>elementType, Enum<?>[] universe)96     EnumSet(Class<E>elementType, Enum<?>[] universe) {
97         this.elementType = elementType;
98         this.universe    = universe;
99     }
100 
101     /**
102      * Creates an empty enum set with the specified element type.
103      *
104      * @param <E> The class of the elements in the set
105      * @param elementType the class object of the element type for this enum
106      *     set
107      * @return An empty enum set of the specified type.
108      * @throws NullPointerException if {@code elementType} is null
109      */
noneOf(Class<E> elementType)110     public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
111         Enum<?>[] universe = getUniverse(elementType);
112         if (universe == null)
113             throw new ClassCastException(elementType + " not an enum");
114 
115         if (universe.length <= 64)
116             return new RegularEnumSet<>(elementType, universe);
117         else
118             return new JumboEnumSet<>(elementType, universe);
119     }
120 
121     /**
122      * Creates an enum set containing all of the elements in the specified
123      * element type.
124      *
125      * @param <E> The class of the elements in the set
126      * @param elementType the class object of the element type for this enum
127      *     set
128      * @return An enum set containing all the elements in the specified type.
129      * @throws NullPointerException if {@code elementType} is null
130      */
allOf(Class<E> elementType)131     public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
132         EnumSet<E> result = noneOf(elementType);
133         result.addAll();
134         return result;
135     }
136 
137     /**
138      * Adds all of the elements from the appropriate enum type to this enum
139      * set, which is empty prior to the call.
140      */
addAll()141     abstract void addAll();
142 
143     /**
144      * Creates an enum set with the same element type as the specified enum
145      * set, initially containing the same elements (if any).
146      *
147      * @param <E> The class of the elements in the set
148      * @param s the enum set from which to initialize this enum set
149      * @return A copy of the specified enum set.
150      * @throws NullPointerException if {@code s} is null
151      */
copyOf(EnumSet<E> s)152     public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
153         return s.clone();
154     }
155 
156     /**
157      * Creates an enum set initialized from the specified collection.  If
158      * the specified collection is an {@code EnumSet} instance, this static
159      * factory method behaves identically to {@link #copyOf(EnumSet)}.
160      * Otherwise, the specified collection must contain at least one element
161      * (in order to determine the new enum set's element type).
162      *
163      * @param <E> The class of the elements in the collection
164      * @param c the collection from which to initialize this enum set
165      * @return An enum set initialized from the given collection.
166      * @throws IllegalArgumentException if {@code c} is not an
167      *     {@code EnumSet} instance and contains no elements
168      * @throws NullPointerException if {@code c} is null
169      */
copyOf(Collection<E> c)170     public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
171         if (c instanceof EnumSet) {
172             return ((EnumSet<E>)c).clone();
173         } else {
174             if (c.isEmpty())
175                 throw new IllegalArgumentException("Collection is empty");
176             Iterator<E> i = c.iterator();
177             E first = i.next();
178             EnumSet<E> result = EnumSet.of(first);
179             while (i.hasNext())
180                 result.add(i.next());
181             return result;
182         }
183     }
184 
185     /**
186      * Creates an enum set with the same element type as the specified enum
187      * set, initially containing all the elements of this type that are
188      * <i>not</i> contained in the specified set.
189      *
190      * @param <E> The class of the elements in the enum set
191      * @param s the enum set from whose complement to initialize this enum set
192      * @return The complement of the specified set in this set
193      * @throws NullPointerException if {@code s} is null
194      */
complementOf(EnumSet<E> s)195     public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
196         EnumSet<E> result = copyOf(s);
197         result.complement();
198         return result;
199     }
200 
201     /**
202      * Creates an enum set initially containing the specified element.
203      *
204      * Overloadings of this method exist to initialize an enum set with
205      * one through five elements.  A sixth overloading is provided that
206      * uses the varargs feature.  This overloading may be used to create
207      * an enum set initially containing an arbitrary number of elements, but
208      * is likely to run slower than the overloadings that do not use varargs.
209      *
210      * @param <E> The class of the specified element and of the set
211      * @param e the element that this set is to contain initially
212      * @throws NullPointerException if {@code e} is null
213      * @return an enum set initially containing the specified element
214      */
of(E e)215     public static <E extends Enum<E>> EnumSet<E> of(E e) {
216         EnumSet<E> result = noneOf(e.getDeclaringClass());
217         result.add(e);
218         return result;
219     }
220 
221     /**
222      * Creates an enum set initially containing the specified elements.
223      *
224      * Overloadings of this method exist to initialize an enum set with
225      * one through five elements.  A sixth overloading is provided that
226      * uses the varargs feature.  This overloading may be used to create
227      * an enum set initially containing an arbitrary number of elements, but
228      * is likely to run slower than the overloadings that do not use varargs.
229      *
230      * @param <E> The class of the parameter elements and of the set
231      * @param e1 an element that this set is to contain initially
232      * @param e2 another element that this set is to contain initially
233      * @throws NullPointerException if any parameters are null
234      * @return an enum set initially containing the specified elements
235      */
of(E e1, E e2)236     public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
237         EnumSet<E> result = noneOf(e1.getDeclaringClass());
238         result.add(e1);
239         result.add(e2);
240         return result;
241     }
242 
243     /**
244      * Creates an enum set initially containing the specified elements.
245      *
246      * Overloadings of this method exist to initialize an enum set with
247      * one through five elements.  A sixth overloading is provided that
248      * uses the varargs feature.  This overloading may be used to create
249      * an enum set initially containing an arbitrary number of elements, but
250      * is likely to run slower than the overloadings that do not use varargs.
251      *
252      * @param <E> The class of the parameter elements and of the set
253      * @param e1 an element that this set is to contain initially
254      * @param e2 another element that this set is to contain initially
255      * @param e3 another element that this set is to contain initially
256      * @throws NullPointerException if any parameters are null
257      * @return an enum set initially containing the specified elements
258      */
of(E e1, E e2, E e3)259     public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
260         EnumSet<E> result = noneOf(e1.getDeclaringClass());
261         result.add(e1);
262         result.add(e2);
263         result.add(e3);
264         return result;
265     }
266 
267     /**
268      * Creates an enum set initially containing the specified elements.
269      *
270      * Overloadings of this method exist to initialize an enum set with
271      * one through five elements.  A sixth overloading is provided that
272      * uses the varargs feature.  This overloading may be used to create
273      * an enum set initially containing an arbitrary number of elements, but
274      * is likely to run slower than the overloadings that do not use varargs.
275      *
276      * @param <E> The class of the parameter elements and of the set
277      * @param e1 an element that this set is to contain initially
278      * @param e2 another element that this set is to contain initially
279      * @param e3 another element that this set is to contain initially
280      * @param e4 another element that this set is to contain initially
281      * @throws NullPointerException if any parameters are null
282      * @return an enum set initially containing the specified elements
283      */
of(E e1, E e2, E e3, E e4)284     public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
285         EnumSet<E> result = noneOf(e1.getDeclaringClass());
286         result.add(e1);
287         result.add(e2);
288         result.add(e3);
289         result.add(e4);
290         return result;
291     }
292 
293     /**
294      * Creates an enum set initially containing the specified elements.
295      *
296      * Overloadings of this method exist to initialize an enum set with
297      * one through five elements.  A sixth overloading is provided that
298      * uses the varargs feature.  This overloading may be used to create
299      * an enum set initially containing an arbitrary number of elements, but
300      * is likely to run slower than the overloadings that do not use varargs.
301      *
302      * @param <E> The class of the parameter elements and of the set
303      * @param e1 an element that this set is to contain initially
304      * @param e2 another element that this set is to contain initially
305      * @param e3 another element that this set is to contain initially
306      * @param e4 another element that this set is to contain initially
307      * @param e5 another element that this set is to contain initially
308      * @throws NullPointerException if any parameters are null
309      * @return an enum set initially containing the specified elements
310      */
of(E e1, E e2, E e3, E e4, E e5)311     public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
312                                                     E e5)
313     {
314         EnumSet<E> result = noneOf(e1.getDeclaringClass());
315         result.add(e1);
316         result.add(e2);
317         result.add(e3);
318         result.add(e4);
319         result.add(e5);
320         return result;
321     }
322 
323     /**
324      * Creates an enum set initially containing the specified elements.
325      * This factory, whose parameter list uses the varargs feature, may
326      * be used to create an enum set initially containing an arbitrary
327      * number of elements, but it is likely to run slower than the overloadings
328      * that do not use varargs.
329      *
330      * @param <E> The class of the parameter elements and of the set
331      * @param first an element that the set is to contain initially
332      * @param rest the remaining elements the set is to contain initially
333      * @throws NullPointerException if any of the specified elements are null,
334      *     or if {@code rest} is null
335      * @return an enum set initially containing the specified elements
336      */
337     @SafeVarargs
of(E first, E... rest)338     public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
339         EnumSet<E> result = noneOf(first.getDeclaringClass());
340         result.add(first);
341         for (E e : rest)
342             result.add(e);
343         return result;
344     }
345 
346     /**
347      * Creates an enum set initially containing all of the elements in the
348      * range defined by the two specified endpoints.  The returned set will
349      * contain the endpoints themselves, which may be identical but must not
350      * be out of order.
351      *
352      * @param <E> The class of the parameter elements and of the set
353      * @param from the first element in the range
354      * @param to the last element in the range
355      * @throws NullPointerException if {@code from} or {@code to} are null
356      * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
357      * @return an enum set initially containing all of the elements in the
358      *         range defined by the two specified endpoints
359      */
range(E from, E to)360     public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
361         if (from.compareTo(to) > 0)
362             throw new IllegalArgumentException(from + " > " + to);
363         EnumSet<E> result = noneOf(from.getDeclaringClass());
364         result.addRange(from, to);
365         return result;
366     }
367 
368     /**
369      * Adds the specified range to this enum set, which is empty prior
370      * to the call.
371      */
addRange(E from, E to)372     abstract void addRange(E from, E to);
373 
374     /**
375      * Returns a copy of this set.
376      *
377      * @return a copy of this set
378      */
379     @SuppressWarnings("unchecked")
clone()380     public EnumSet<E> clone() {
381         try {
382             return (EnumSet<E>) super.clone();
383         } catch(CloneNotSupportedException e) {
384             throw new AssertionError(e);
385         }
386     }
387 
388     /**
389      * Complements the contents of this enum set.
390      */
complement()391     abstract void complement();
392 
393     /**
394      * Throws an exception if e is not of the correct type for this enum set.
395      */
typeCheck(E e)396     final void typeCheck(E e) {
397         Class<?> eClass = e.getClass();
398         if (eClass != elementType && eClass.getSuperclass() != elementType)
399             throw new ClassCastException(eClass + " != " + elementType);
400     }
401 
402     /**
403      * Returns all of the values comprising E.
404      * The result is uncloned, cached, and shared by all callers.
405      */
getUniverse(Class<E> elementType)406     private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
407         return SharedSecrets.getJavaLangAccess()
408                                         .getEnumConstantsShared(elementType);
409     }
410 
411     /**
412      * This class is used to serialize all EnumSet instances, regardless of
413      * implementation type.  It captures their "logical contents" and they
414      * are reconstructed using public static factories.  This is necessary
415      * to ensure that the existence of a particular implementation type is
416      * an implementation detail.
417      *
418      * @serial include
419      */
420     private static class SerializationProxy<E extends Enum<E>>
421         implements java.io.Serializable
422     {
423 
424         private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
425 
426         /**
427          * The element type of this enum set.
428          *
429          * @serial
430          */
431         private final Class<E> elementType;
432 
433         /**
434          * The elements contained in this enum set.
435          *
436          * @serial
437          */
438         private final Enum<?>[] elements;
439 
SerializationProxy(EnumSet<E> set)440         SerializationProxy(EnumSet<E> set) {
441             elementType = set.elementType;
442             elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
443         }
444 
445         /**
446          * Returns an {@code EnumSet} object with initial state
447          * held by this proxy.
448          *
449          * @return a {@code EnumSet} object with initial state
450          * held by this proxy
451          */
452         @SuppressWarnings("unchecked")
453         @java.io.Serial
readResolve()454         private Object readResolve() {
455             // instead of cast to E, we should perhaps use elementType.cast()
456             // to avoid injection of forged stream, but it will slow the
457             // implementation
458             EnumSet<E> result = EnumSet.noneOf(elementType);
459             for (Enum<?> e : elements)
460                 result.add((E)e);
461             return result;
462         }
463 
464         @java.io.Serial
465         private static final long serialVersionUID = 362491234563181265L;
466     }
467 
468     /**
469      * Returns a
470      * <a href="{@docRoot}/serialized-form.html#java.util.EnumSet.SerializationProxy">
471      * SerializationProxy</a>
472      * representing the state of this instance.
473      *
474      * @return a {@link SerializationProxy}
475      * representing the state of this instance
476      */
477     @java.io.Serial
writeReplace()478     Object writeReplace() {
479         return new SerializationProxy<>(this);
480     }
481 
482     /**
483      * Throws {@code InvalidObjectException}.
484      * @param s the stream
485      * @throws java.io.InvalidObjectException always
486      */
487     @java.io.Serial
readObject(java.io.ObjectInputStream s)488     private void readObject(java.io.ObjectInputStream s)
489         throws java.io.InvalidObjectException {
490         throw new java.io.InvalidObjectException("Proxy required");
491     }
492 
493     /**
494      * Throws {@code InvalidObjectException}.
495      * @throws java.io.InvalidObjectException always
496      */
497     @java.io.Serial
readObjectNoData()498     private void readObjectNoData()
499         throws java.io.InvalidObjectException {
500         throw new java.io.InvalidObjectException("Proxy required");
501     }
502 }
503