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 */ 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 63 public boolean hasNext() { 64 return mask != 0; 65 } 66 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 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 92 public Iterator<E> iterator() { 93 return new MiniEnumSetIterator(); 94 } 95 96 @Override 97 public int size() { 98 return size; 99 } 100 101 @Override 102 public void clear() { 103 bits = 0; 104 size = 0; 105 } 106 107 @Override 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 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 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 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 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 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 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 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 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 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