• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /**
29  * Private implementation class for EnumSet, for "regular sized" enum types
30  * (i.e., those with 64 or fewer enum constants).
31  *
32  * @author Josh Bloch
33  * @since 1.5
34  * @serial exclude
35  */
36 class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
37     private static final long serialVersionUID = 3411599620347842686L;
38     /**
39      * Bit vector representation of this set.  The 2^k bit indicates the
40      * presence of universe[k] in this set.
41      */
42     private long elements = 0L;
43 
RegularEnumSet(Class<E>elementType, Enum[] universe)44     RegularEnumSet(Class<E>elementType, Enum[] universe) {
45         super(elementType, universe);
46     }
47 
addRange(E from, E to)48     void addRange(E from, E to) {
49         elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
50     }
51 
addAll()52     void addAll() {
53         if (universe.length != 0)
54             elements = -1L >>> -universe.length;
55     }
56 
complement()57     void complement() {
58         if (universe.length != 0) {
59             elements = ~elements;
60             elements &= -1L >>> -universe.length;  // Mask unused bits
61         }
62     }
63 
64     /**
65      * Returns an iterator over the elements contained in this set.  The
66      * iterator traverses the elements in their <i>natural order</i> (which is
67      * the order in which the enum constants are declared). The returned
68      * Iterator is a "snapshot" iterator that will never throw {@link
69      * ConcurrentModificationException}; the elements are traversed as they
70      * existed when this call was invoked.
71      *
72      * @return an iterator over the elements contained in this set
73      */
iterator()74     public Iterator<E> iterator() {
75         return new EnumSetIterator<>();
76     }
77 
78     private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
79         /**
80          * A bit vector representing the elements in the set not yet
81          * returned by this iterator.
82          */
83         long unseen;
84 
85         /**
86          * The bit representing the last element returned by this iterator
87          * but not removed, or zero if no such element exists.
88          */
89         long lastReturned = 0;
90 
EnumSetIterator()91         EnumSetIterator() {
92             unseen = elements;
93         }
94 
hasNext()95         public boolean hasNext() {
96             return unseen != 0;
97         }
98 
next()99         public E next() {
100             if (unseen == 0)
101                 throw new NoSuchElementException();
102             lastReturned = unseen & -unseen;
103             unseen -= lastReturned;
104             return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
105         }
106 
remove()107         public void remove() {
108             if (lastReturned == 0)
109                 throw new IllegalStateException();
110             elements &= ~lastReturned;
111             lastReturned = 0;
112         }
113     }
114 
115     /**
116      * Returns the number of elements in this set.
117      *
118      * @return the number of elements in this set
119      */
size()120     public int size() {
121         return Long.bitCount(elements);
122     }
123 
124     /**
125      * Returns <tt>true</tt> if this set contains no elements.
126      *
127      * @return <tt>true</tt> if this set contains no elements
128      */
isEmpty()129     public boolean isEmpty() {
130         return elements == 0;
131     }
132 
133     /**
134      * Returns <tt>true</tt> if this set contains the specified element.
135      *
136      * @param e element to be checked for containment in this collection
137      * @return <tt>true</tt> if this set contains the specified element
138      */
contains(Object e)139     public boolean contains(Object e) {
140         if (e == null)
141             return false;
142         Class eClass = e.getClass();
143         if (eClass != elementType && eClass.getSuperclass() != elementType)
144             return false;
145 
146         return (elements & (1L << ((Enum)e).ordinal())) != 0;
147     }
148 
149     // Modification Operations
150 
151     /**
152      * Adds the specified element to this set if it is not already present.
153      *
154      * @param e element to be added to this set
155      * @return <tt>true</tt> if the set changed as a result of the call
156      *
157      * @throws NullPointerException if <tt>e</tt> is null
158      */
add(E e)159     public boolean add(E e) {
160         typeCheck(e);
161 
162         long oldElements = elements;
163         elements |= (1L << ((Enum)e).ordinal());
164         return elements != oldElements;
165     }
166 
167     /**
168      * Removes the specified element from this set if it is present.
169      *
170      * @param e element to be removed from this set, if present
171      * @return <tt>true</tt> if the set contained the specified element
172      */
remove(Object e)173     public boolean remove(Object e) {
174         if (e == null)
175             return false;
176         Class eClass = e.getClass();
177         if (eClass != elementType && eClass.getSuperclass() != elementType)
178             return false;
179 
180         long oldElements = elements;
181         elements &= ~(1L << ((Enum)e).ordinal());
182         return elements != oldElements;
183     }
184 
185     // Bulk Operations
186 
187     /**
188      * Returns <tt>true</tt> if this set contains all of the elements
189      * in the specified collection.
190      *
191      * @param c collection to be checked for containment in this set
192      * @return <tt>true</tt> if this set contains all of the elements
193      *        in the specified collection
194      * @throws NullPointerException if the specified collection is null
195      */
containsAll(Collection<?> c)196     public boolean containsAll(Collection<?> c) {
197         if (!(c instanceof RegularEnumSet))
198             return super.containsAll(c);
199 
200         RegularEnumSet es = (RegularEnumSet)c;
201         if (es.elementType != elementType)
202             return es.isEmpty();
203 
204         return (es.elements & ~elements) == 0;
205     }
206 
207     /**
208      * Adds all of the elements in the specified collection to this set.
209      *
210      * @param c collection whose elements are to be added to this set
211      * @return <tt>true</tt> if this set changed as a result of the call
212      * @throws NullPointerException if the specified collection or any
213      *     of its elements are null
214      */
addAll(Collection<? extends E> c)215     public boolean addAll(Collection<? extends E> c) {
216         if (!(c instanceof RegularEnumSet))
217             return super.addAll(c);
218 
219         RegularEnumSet es = (RegularEnumSet)c;
220         if (es.elementType != elementType) {
221             if (es.isEmpty())
222                 return false;
223             else
224                 throw new ClassCastException(
225                     es.elementType + " != " + elementType);
226         }
227 
228         long oldElements = elements;
229         elements |= es.elements;
230         return elements != oldElements;
231     }
232 
233     /**
234      * Removes from this set all of its elements that are contained in
235      * the specified collection.
236      *
237      * @param c elements to be removed from this set
238      * @return <tt>true</tt> if this set changed as a result of the call
239      * @throws NullPointerException if the specified collection is null
240      */
removeAll(Collection<?> c)241     public boolean removeAll(Collection<?> c) {
242         if (!(c instanceof RegularEnumSet))
243             return super.removeAll(c);
244 
245         RegularEnumSet es = (RegularEnumSet)c;
246         if (es.elementType != elementType)
247             return false;
248 
249         long oldElements = elements;
250         elements &= ~es.elements;
251         return elements != oldElements;
252     }
253 
254     /**
255      * Retains only the elements in this set that are contained in the
256      * specified collection.
257      *
258      * @param c elements to be retained in this set
259      * @return <tt>true</tt> if this set changed as a result of the call
260      * @throws NullPointerException if the specified collection is null
261      */
retainAll(Collection<?> c)262     public boolean retainAll(Collection<?> c) {
263         if (!(c instanceof RegularEnumSet))
264             return super.retainAll(c);
265 
266         RegularEnumSet<?> es = (RegularEnumSet<?>)c;
267         if (es.elementType != elementType) {
268             boolean changed = (elements != 0);
269             elements = 0;
270             return changed;
271         }
272 
273         long oldElements = elements;
274         elements &= es.elements;
275         return elements != oldElements;
276     }
277 
278     /**
279      * Removes all of the elements from this set.
280      */
clear()281     public void clear() {
282         elements = 0;
283     }
284 
285     /**
286      * Compares the specified object with this set for equality.  Returns
287      * <tt>true</tt> if the given object is also a set, the two sets have
288      * the same size, and every member of the given set is contained in
289      * this set.
290      *
291      * @param e object to be compared for equality with this set
292      * @return <tt>true</tt> if the specified object is equal to this set
293      */
equals(Object o)294     public boolean equals(Object o) {
295         if (!(o instanceof RegularEnumSet))
296             return super.equals(o);
297 
298         RegularEnumSet es = (RegularEnumSet)o;
299         if (es.elementType != elementType)
300             return elements == 0 && es.elements == 0;
301         return es.elements == elements;
302     }
303 }
304