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