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