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     private static final long serialVersionUID = 1009687484059888093L;
  84 
  85     /**
  86      * The class of all the elements of this set.
  87      */
  88     final transient Class<E> elementType;
  89 
  90     /**
  91      * All of the values comprising E.  (Cached for performance.)
  92      */
  93     final transient Enum<?>[] universe;
  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 {@code elementType} 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 {@code elementType} 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 {@code s} 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 {@code EnumSet} 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 {@code c} is not an
 166      *     {@code EnumSet} instance and contains no elements
 167      * @throws NullPointerException if {@code c} 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 {@code s} 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 {@code e} 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 {@code rest} 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         private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
 424 
 425         /**
 426          * The element type of this enum set.
 427          *
 428          * @serial
 429          */
 430         private final Class<E> elementType;
 431 
 432         /**
 433          * The elements contained in this enum set.
 434          *
 435          * @serial
 436          */
 437         private final Enum<?>[] elements;
 438 
 439         SerializationProxy(EnumSet<E> set) {
 440             elementType = set.elementType;
 441             elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
 442         }
 443 
 444         /**
 445          * Returns an {@code EnumSet} object with initial state
 446          * held by this proxy.
 447          *
 448          * @return a {@code EnumSet} object with initial state
 449          * held by this proxy
 450          */
 451         @SuppressWarnings("unchecked")
 452         private Object readResolve() {
 453             // instead of cast to E, we should perhaps use elementType.cast()
 454             // to avoid injection of forged stream, but it will slow the
 455             // implementation
 456             EnumSet<E> result = EnumSet.noneOf(elementType);
 457             for (Enum<?> e : elements)
 458                 result.add((E)e);
 459             return result;
 460         }
 461 
 462         private static final long serialVersionUID = 362491234563181265L;
 463     }
 464 
 465     /**
 466      * Returns a
 467      * <a href="{@docRoot}/serialized-form.html#java.util.EnumSet.SerializationProxy">
 468      * SerializationProxy</a>
 469      * representing the state of this instance.
 470      *
 471      * @return a {@link SerializationProxy}
 472      * representing the state of this instance
 473      */
 474     Object writeReplace() {
 475         return new SerializationProxy<>(this);
 476     }
 477 
 478     /**
 479      * @param s the stream
 480      * @throws java.io.InvalidObjectException always
 481      */
 482     private void readObject(java.io.ObjectInputStream s)
 483         throws java.io.InvalidObjectException {
 484         throw new java.io.InvalidObjectException("Proxy required");
 485     }
 486 }