1 /*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 *
5 *
6 *
7 *
8 *
9 *
10 *
11 *
12 *
13 *
14 *
15 *
16 *
17 *
18 *
19 *
20 *
21 *
22 *
23 *
24 */
25
26 package java.util;
27
28 import sun.misc.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 <tt>int</tt>-based "bit flags." Even bulk
38 * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
39 * run very quickly if their argument is also an enum set.
40 *
41 * <p>The iterator returned by the <tt>iterator</tt> 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, <tt>EnumSet</tt> 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<MyEnum> 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}/../technotes/guides/collections/index.html">
73 * Java Collections Framework</a>.
74 *
75 * @author Josh Bloch
76 * @since 1.5
77 * @see EnumMap
78 * @serial exclude
79 */
80 public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
81 implements Cloneable, java.io.Serializable
82 {
83 /**
84 * The class of all the elements of this set.
85 */
86 final Class<E> elementType;
87
88 /**
89 * All of the values comprising T. (Cached for performance.)
90 */
91 final Enum<?>[] universe;
92
93 private static Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
94
95 EnumSet(Class<E>elementType, Enum<?>[] universe) {
96 this.elementType = elementType;
97 this.universe = universe;
98 }
99
100 /**
101 * Creates an empty enum set with the specified element type.
102 *
103 * @param <E> The class of the elements in the set
104 * @param elementType the class object of the element type for this enum
105 * set
106 * @return An empty enum set of the specified type.
107 * @throws NullPointerException if <tt>elementType</tt> is null
108 */
109 public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
110 Enum<?>[] universe = getUniverse(elementType);
111 if (universe == null)
112 throw new ClassCastException(elementType + " not an enum");
113
114 if (universe.length <= 64)
115 return new RegularEnumSet<>(elementType, universe);
116 else
117 return new JumboEnumSet<>(elementType, universe);
118 }
119
120 /**
121 * Creates an enum set containing all of the elements in the specified
122 * element type.
123 *
124 * @param <E> The class of the elements in the set
125 * @param elementType the class object of the element type for this enum
126 * set
127 * @return An enum set containing all the elements in the specified type.
128 * @throws NullPointerException if <tt>elementType</tt> is null
129 */
130 public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
131 EnumSet<E> result = noneOf(elementType);
132 result.addAll();
133 return result;
134 }
135
136 /**
137 * Adds all of the elements from the appropriate enum type to this enum
138 * set, which is empty prior to the call.
139 */
140 abstract void addAll();
141
142 /**
143 * Creates an enum set with the same element type as the specified enum
144 * set, initially containing the same elements (if any).
145 *
146 * @param <E> The class of the elements in the set
147 * @param s the enum set from which to initialize this enum set
148 * @return A copy of the specified enum set.
149 * @throws NullPointerException if <tt>s</tt> is null
150 */
151 public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
152 return s.clone();
153 }
154
155 /**
156 * Creates an enum set initialized from the specified collection. If
157 * the specified collection is an <tt>EnumSet</tt> instance, this static
158 * factory method behaves identically to {@link #copyOf(EnumSet)}.
159 * Otherwise, the specified collection must contain at least one element
160 * (in order to determine the new enum set's element type).
161 *
162 * @param <E> The class of the elements in the collection
163 * @param c the collection from which to initialize this enum set
164 * @return An enum set initialized from the given collection.
165 * @throws IllegalArgumentException if <tt>c</tt> is not an
166 * <tt>EnumSet</tt> instance and contains no elements
167 * @throws NullPointerException if <tt>c</tt> is null
168 */
169 public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
170 if (c instanceof EnumSet) {
171 return ((EnumSet<E>)c).clone();
172 } else {
173 if (c.isEmpty())
174 throw new IllegalArgumentException("Collection is empty");
175 Iterator<E> i = c.iterator();
176 E first = i.next();
177 EnumSet<E> result = EnumSet.of(first);
178 while (i.hasNext())
179 result.add(i.next());
180 return result;
181 }
182 }
183
184 /**
185 * Creates an enum set with the same element type as the specified enum
186 * set, initially containing all the elements of this type that are
187 * <i>not</i> contained in the specified set.
188 *
189 * @param <E> The class of the elements in the enum set
190 * @param s the enum set from whose complement to initialize this enum set
191 * @return The complement of the specified set in this set
192 * @throws NullPointerException if <tt>s</tt> is null
193 */
194 public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
195 EnumSet<E> result = copyOf(s);
196 result.complement();
197 return result;
198 }
199
200 /**
201 * Creates an enum set initially containing the specified element.
202 *
203 * Overloadings of this method exist to initialize an enum set with
204 * one through five elements. A sixth overloading is provided that
205 * uses the varargs feature. This overloading may be used to create
206 * an enum set initially containing an arbitrary number of elements, but
207 * is likely to run slower than the overloadings that do not use varargs.
208 *
209 * @param <E> The class of the specified element and of the set
210 * @param e the element that this set is to contain initially
211 * @throws NullPointerException if <tt>e</tt> is null
212 * @return an enum set initially containing the specified element
213 */
214 public static <E extends Enum<E>> EnumSet<E> of(E e) {
215 EnumSet<E> result = noneOf(e.getDeclaringClass());
216 result.add(e);
217 return result;
218 }
219
220 /**
221 * Creates an enum set initially containing the specified elements.
222 *
223 * Overloadings of this method exist to initialize an enum set with
224 * one through five elements. A sixth overloading is provided that
225 * uses the varargs feature. This overloading may be used to create
226 * an enum set initially containing an arbitrary number of elements, but
227 * is likely to run slower than the overloadings that do not use varargs.
228 *
229 * @param <E> The class of the parameter elements and of the set
230 * @param e1 an element that this set is to contain initially
231 * @param e2 another element that this set is to contain initially
232 * @throws NullPointerException if any parameters are null
233 * @return an enum set initially containing the specified elements
234 */
235 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
236 EnumSet<E> result = noneOf(e1.getDeclaringClass());
237 result.add(e1);
238 result.add(e2);
239 return result;
240 }
241
242 /**
243 * Creates an enum set initially containing the specified elements.
244 *
245 * Overloadings of this method exist to initialize an enum set with
246 * one through five elements. A sixth overloading is provided that
247 * uses the varargs feature. This overloading may be used to create
248 * an enum set initially containing an arbitrary number of elements, but
249 * is likely to run slower than the overloadings that do not use varargs.
250 *
251 * @param <E> The class of the parameter elements and of the set
252 * @param e1 an element that this set is to contain initially
253 * @param e2 another element that this set is to contain initially
254 * @param e3 another element that this set is to contain initially
255 * @throws NullPointerException if any parameters are null
256 * @return an enum set initially containing the specified elements
257 */
258 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
259 EnumSet<E> result = noneOf(e1.getDeclaringClass());
260 result.add(e1);
261 result.add(e2);
262 result.add(e3);
263 return result;
264 }
265
266 /**
267 * Creates an enum set initially containing the specified elements.
268 *
269 * Overloadings of this method exist to initialize an enum set with
270 * one through five elements. A sixth overloading is provided that
271 * uses the varargs feature. This overloading may be used to create
272 * an enum set initially containing an arbitrary number of elements, but
273 * is likely to run slower than the overloadings that do not use varargs.
274 *
275 * @param <E> The class of the parameter elements and of the set
276 * @param e1 an element that this set is to contain initially
277 * @param e2 another element that this set is to contain initially
278 * @param e3 another element that this set is to contain initially
279 * @param e4 another element that this set is to contain initially
280 * @throws NullPointerException if any parameters are null
281 * @return an enum set initially containing the specified elements
282 */
283 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
284 EnumSet<E> result = noneOf(e1.getDeclaringClass());
285 result.add(e1);
286 result.add(e2);
287 result.add(e3);
288 result.add(e4);
289 return result;
290 }
291
292 /**
293 * Creates an enum set initially containing the specified elements.
294 *
295 * Overloadings of this method exist to initialize an enum set with
296 * one through five elements. A sixth overloading is provided that
297 * uses the varargs feature. This overloading may be used to create
298 * an enum set initially containing an arbitrary number of elements, but
299 * is likely to run slower than the overloadings that do not use varargs.
300 *
301 * @param <E> The class of the parameter elements and of the set
302 * @param e1 an element that this set is to contain initially
303 * @param e2 another element that this set is to contain initially
304 * @param e3 another element that this set is to contain initially
305 * @param e4 another element that this set is to contain initially
306 * @param e5 another element that this set is to contain initially
307 * @throws NullPointerException if any parameters are null
308 * @return an enum set initially containing the specified elements
309 */
310 public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
311 E e5)
312 {
313 EnumSet<E> result = noneOf(e1.getDeclaringClass());
314 result.add(e1);
315 result.add(e2);
316 result.add(e3);
317 result.add(e4);
318 result.add(e5);
319 return result;
320 }
321
322 /**
323 * Creates an enum set initially containing the specified elements.
324 * This factory, whose parameter list uses the varargs feature, may
325 * be used to create an enum set initially containing an arbitrary
326 * number of elements, but it is likely to run slower than the overloadings
327 * that do not use varargs.
328 *
329 * @param <E> The class of the parameter elements and of the set
330 * @param first an element that the set is to contain initially
331 * @param rest the remaining elements the set is to contain initially
332 * @throws NullPointerException if any of the specified elements are null,
333 * or if <tt>rest</tt> is null
334 * @return an enum set initially containing the specified elements
335 */
336 @SafeVarargs
337 public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
338 EnumSet<E> result = noneOf(first.getDeclaringClass());
339 result.add(first);
340 for (E e : rest)
341 result.add(e);
342 return result;
343 }
344
345 /**
346 * Creates an enum set initially containing all of the elements in the
347 * range defined by the two specified endpoints. The returned set will
348 * contain the endpoints themselves, which may be identical but must not
349 * be out of order.
350 *
351 * @param <E> The class of the parameter elements and of the set
352 * @param from the first element in the range
353 * @param to the last element in the range
354 * @throws NullPointerException if {@code from} or {@code to} are null
355 * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
356 * @return an enum set initially containing all of the elements in the
357 * range defined by the two specified endpoints
358 */
359 public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
360 if (from.compareTo(to) > 0)
361 throw new IllegalArgumentException(from + " > " + to);
362 EnumSet<E> result = noneOf(from.getDeclaringClass());
363 result.addRange(from, to);
364 return result;
365 }
366
367 /**
368 * Adds the specified range to this enum set, which is empty prior
369 * to the call.
370 */
371 abstract void addRange(E from, E to);
372
373 /**
374 * Returns a copy of this set.
375 *
376 * @return a copy of this set
377 */
378 @SuppressWarnings("unchecked")
379 public EnumSet<E> clone() {
380 try {
381 return (EnumSet<E>) super.clone();
382 } catch(CloneNotSupportedException e) {
383 throw new AssertionError(e);
384 }
385 }
386
387 /**
388 * Complements the contents of this enum set.
389 */
390 abstract void complement();
391
392 /**
393 * Throws an exception if e is not of the correct type for this enum set.
394 */
395 final void typeCheck(E e) {
396 Class<?> eClass = e.getClass();
397 if (eClass != elementType && eClass.getSuperclass() != elementType)
398 throw new ClassCastException(eClass + " != " + elementType);
399 }
400
401 /**
402 * Returns all of the values comprising E.
403 * The result is uncloned, cached, and shared by all callers.
404 */
405 private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
406 return SharedSecrets.getJavaLangAccess()
407 .getEnumConstantsShared(elementType);
408 }
409
410 /**
411 * This class is used to serialize all EnumSet instances, regardless of
412 * implementation type. It captures their "logical contents" and they
413 * are reconstructed using public static factories. This is necessary
414 * to ensure that the existence of a particular implementation type is
415 * an implementation detail.
416 *
417 * @serial include
418 */
419 private static class SerializationProxy <E extends Enum<E>>
420 implements java.io.Serializable
421 {
422 /**
423 * The element type of this enum set.
424 *
425 * @serial
426 */
427 private final Class<E> elementType;
428
429 /**
430 * The elements contained in this enum set.
431 *
432 * @serial
433 */
434 private final Enum<?>[] elements;
435
436 SerializationProxy(EnumSet<E> set) {
437 elementType = set.elementType;
438 elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
439 }
440
441 // instead of cast to E, we should perhaps use elementType.cast()
442 // to avoid injection of forged stream, but it will slow the implementation
443 @SuppressWarnings("unchecked")
444 private Object readResolve() {
445 EnumSet<E> result = EnumSet.noneOf(elementType);
446 for (Enum<?> e : elements)
447 result.add((E)e);
448 return result;
449 }
450
451 private static final long serialVersionUID = 362491234563181265L;
452 }
453
454 Object writeReplace() {
455 return new SerializationProxy<>(this);
456 }
457
458 // readObject method for the serialization proxy pattern
459 // See Effective Java, Second Ed., Item 78.
460 private void readObject(java.io.ObjectInputStream stream)
461 throws java.io.InvalidObjectException {
462 throw new java.io.InvalidObjectException("Proxy required");
463 }
464 }
465