• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package java.util;
18 
19 
20 /**
21  * A concrete EnumSet for enums with 64 or fewer elements.
22  */
23 @SuppressWarnings("serial")
24 final class MiniEnumSet<E extends Enum<E>> extends EnumSet<E> {
25     private static final int MAX_ELEMENTS = 64;
26 
27     private int size;
28 
29     private final E[] enums;
30 
31     private long bits;
32 
33     /**
34      * Constructs an instance.
35      *
36      * @param elementType non-null; type of the elements
37      * @param enums non-null; pre-populated array of constants in ordinal
38      * order
39      */
MiniEnumSet(Class<E> elementType, E[] enums)40     MiniEnumSet(Class<E> elementType, E[] enums) {
41         super(elementType);
42         this.enums = enums;
43     }
44 
45     private class MiniEnumSetIterator implements Iterator<E> {
46 
47         /**
48          * The bits yet to be returned for bits. As values from the current index are returned,
49          * their bits are zeroed out.
50          */
51         private long currentBits = bits;
52 
53         /**
54          * The single bit of the next value to return.
55          */
56         private long mask = currentBits & -currentBits; // the lowest 1 bit in currentBits
57 
58         /**
59          * The candidate for removal. If null, no value may be removed.
60          */
61         private E last;
62 
hasNext()63         public boolean hasNext() {
64             return mask != 0;
65         }
66 
next()67         public E next() {
68             if (mask == 0) {
69                 throw new NoSuchElementException();
70             }
71 
72             int ordinal = Long.numberOfTrailingZeros(mask);
73             last = enums[ordinal];
74 
75             currentBits &= ~mask;
76             mask = currentBits & -currentBits; // the lowest 1 bit in currentBits
77 
78             return last;
79         }
80 
remove()81         public void remove() {
82             if (last == null) {
83                 throw new IllegalStateException();
84             }
85 
86             MiniEnumSet.this.remove(last);
87             last = null;
88         }
89     }
90 
91     @Override
iterator()92     public Iterator<E> iterator() {
93         return new MiniEnumSetIterator();
94     }
95 
96     @Override
size()97     public int size() {
98         return size;
99     }
100 
101     @Override
clear()102     public void clear() {
103         bits = 0;
104         size = 0;
105     }
106 
107     @Override
add(E element)108     public boolean add(E element) {
109         elementClass.cast(element); // Called to throw ClassCastException.
110         long oldBits = bits;
111         long newBits = oldBits | (1L << element.ordinal());
112         if (oldBits != newBits) {
113             bits = newBits;
114             size++;
115             return true;
116         }
117         return false;
118     }
119 
120     @Override
addAll(Collection<? extends E> collection)121     public boolean addAll(Collection<? extends E> collection) {
122         if (collection.isEmpty()) {
123             return false;
124         }
125         if (collection instanceof EnumSet) {
126             EnumSet<?> set = (EnumSet) collection; // raw type due to javac bug 6548436
127             set.elementClass.asSubclass(elementClass); // Called to throw ClassCastException.
128 
129             MiniEnumSet<?> miniSet = (MiniEnumSet<?>) set;
130             long oldBits = bits;
131             long newBits = oldBits | miniSet.bits;
132             bits = newBits;
133             size = Long.bitCount(newBits);
134             return (oldBits != newBits);
135         }
136         return super.addAll(collection);
137     }
138 
139     @Override
contains(Object object)140     public boolean contains(Object object) {
141         if (object == null || !isValidType(object.getClass())) {
142             return false;
143         }
144 
145         @SuppressWarnings("unchecked") // guarded by isValidType()
146         Enum<E> element = (Enum<E>) object;
147         int ordinal = element.ordinal();
148         return (bits & (1L << ordinal)) != 0;
149     }
150 
151     @Override
containsAll(Collection<?> collection)152     public boolean containsAll(Collection<?> collection) {
153         if (collection.isEmpty()) {
154             return true;
155         }
156         if (collection instanceof MiniEnumSet) {
157             MiniEnumSet<?> set = (MiniEnumSet<?>) collection;
158             long setBits = set.bits;
159             return isValidType(set.elementClass) && ((bits & setBits) == setBits);
160         }
161         return !(collection instanceof EnumSet) && super.containsAll(collection);
162     }
163 
164     @Override
removeAll(Collection<?> collection)165     public boolean removeAll(Collection<?> collection) {
166         if (collection.isEmpty()) {
167             return false;
168         }
169         if (collection instanceof EnumSet) {
170             EnumSet<?> set = (EnumSet<?>) collection;
171             if (!isValidType(set.elementClass)) {
172                 return false;
173             }
174 
175             MiniEnumSet<E> miniSet = (MiniEnumSet<E>) set;
176             long oldBits = bits;
177             long newBits = oldBits & ~miniSet.bits;
178             if (oldBits != newBits) {
179                 bits = newBits;
180                 size = Long.bitCount(newBits);
181                 return true;
182             }
183             return false;
184         }
185         return super.removeAll(collection);
186     }
187 
188     @Override
retainAll(Collection<?> collection)189     public boolean retainAll(Collection<?> collection) {
190         if (collection instanceof EnumSet) {
191             EnumSet<?> set = (EnumSet<?>) collection;
192             if (!isValidType(set.elementClass)) {
193                 if (size > 0) {
194                     clear();
195                     return true;
196                 } else {
197                     return false;
198                 }
199             }
200 
201             MiniEnumSet<E> miniSet = (MiniEnumSet<E>) set;
202             long oldBits = bits;
203             long newBits = oldBits & miniSet.bits;
204             if (oldBits != newBits) {
205                 bits = newBits;
206                 size = Long.bitCount(newBits);
207                 return true;
208             }
209             return false;
210         }
211         return super.retainAll(collection);
212     }
213 
214     @Override
remove(Object object)215     public boolean remove(Object object) {
216         if (object == null || !isValidType(object.getClass())) {
217             return false;
218         }
219 
220         @SuppressWarnings("unchecked") // guarded by isValidType()
221         Enum<E> element = (Enum<E>) object;
222         int ordinal = element.ordinal();
223         long oldBits = bits;
224         long newBits = oldBits & ~(1L << ordinal);
225         if (oldBits != newBits) {
226             bits = newBits;
227             size--;
228             return true;
229         }
230         return false;
231     }
232 
233     @Override
equals(Object object)234     public boolean equals(Object object) {
235         if (!(object instanceof EnumSet)) {
236             return super.equals(object);
237         }
238         EnumSet<?> set =(EnumSet<?>) object;
239         if (!isValidType(set.elementClass)) {
240             return size == 0 && set.isEmpty();
241         }
242         return bits == ((MiniEnumSet<?>) set).bits;
243     }
244 
245     @Override
complement()246     void complement() {
247         if (enums.length != 0) {
248             bits = ~bits;
249             bits &= (-1L >>> (MAX_ELEMENTS - enums.length));
250             size = enums.length - size;
251         }
252     }
253 
254     @Override
setRange(E start, E end)255     void setRange(E start, E end) {
256         int length = end.ordinal() - start.ordinal() + 1;
257         long range = (-1L >>> (MAX_ELEMENTS - length)) << start.ordinal();
258         bits |= range;
259         size = Long.bitCount(bits);
260     }
261 }
262