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