emul/compact/src/main/java/java/util/EnumSet.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sun, 22 Sep 2013 21:49:42 +0200
branchjdk7-b147
changeset 1292 9cf04876e4a5
permissions -rw-r--r--
Need EnumMap, EnumSet for the javac
     1 /*
     2  * Copyright (c) 2003, 2011, 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 }