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