001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package java.util;
017:
018: /**
019: * A {@link java.util.Set} of {@link Enum}s. <a
020: * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/EnumSet.html">[Sun
021: * docs]</a>
022: *
023: * @param <E> enumeration type
024: */
025: public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> {
026:
027: /**
028: * An implementation of EnumSet that works for Enums with arbitrarily large
029: * numbers of values.
030: *
031: * TODO(tobyr) Consider implementing this like SimpleEnumSet, but backed by
032: * int[]'s instead of ints.
033: */
034: static class LargeEnumSet<E extends Enum<E>> extends EnumSet<E> {
035:
036: HashSet<E> set = new HashSet<E>();
037:
038: private E[] allEnums; // Must not be modified
039:
040: LargeEnumSet(E first, E... rest) {
041: allEnums = getEnums(first.getDeclaringClass());
042: add(first);
043: for (E e : rest) {
044: add(e);
045: }
046: }
047:
048: LargeEnumSet(E[] allValues) {
049: this .allEnums = allValues;
050: }
051:
052: @Override
053: public boolean add(E e) {
054: if (e == null) {
055: throw new NullPointerException(
056: "Can't add null to an EnumSet");
057: }
058: return set.add(e);
059: }
060:
061: public LargeEnumSet<E> clone() {
062: LargeEnumSet<E> newSet = new LargeEnumSet<E>(this .allEnums);
063: newSet.set = new HashSet<E>(this .set);
064: return newSet;
065: }
066:
067: @Override
068: public boolean contains(Object object) {
069: return set.contains(object);
070: }
071:
072: @Override
073: public Iterator<E> iterator() {
074: return set.iterator();
075: }
076:
077: @Override
078: public boolean remove(Object o) {
079: return set.remove(o);
080: }
081:
082: @Override
083: public int size() {
084: return set.size();
085: }
086:
087: @Override
088: void addRange(E from, E to) {
089: for (int i = from.ordinal(), end = to.ordinal(); i <= end; ++i) {
090: add(allEnums[i]);
091: }
092: }
093:
094: @Override
095: void complement() {
096: for (int i = 0; i < allEnums.length; ++i) {
097: E e = allEnums[i];
098: if (set.contains(e)) {
099: set.remove(e);
100: } else {
101: set.add(e);
102: }
103: }
104: }
105: }
106:
107: /**
108: * A fast implementation of EnumSet for enums with less than 32 values. A Java
109: * EnumSet can support 63 bits easily with a primitive long, but JavaScript
110: * generally represents long values as floating point numbers.
111: *
112: * LargeEnumSet is used to support enums with > 31 values using a map-backed
113: * implementation.
114: */
115: static class SimpleEnumSet<E extends Enum<E>> extends EnumSet<E> {
116:
117: // TODO(tobyr)
118: // Consider optimizing this iterator by walking the values using a
119: // combination of lowestOneBit and numberOfLeadingZeros.
120: // This is low priority as iterating over enums is not the common usecase.
121: class SimpleIterator implements Iterator<E> {
122:
123: private Iterator<E> iterator;
124:
125: private E value;
126:
127: SimpleIterator() {
128: List<E> values = new ArrayList<E>();
129: for (int i = 0; i < 31; ++i) {
130: int mask = 0x1 << i;
131: if ((enumValues & mask) != 0) {
132: values.add(allEnums[i]);
133: }
134: }
135:
136: iterator = values.iterator();
137: }
138:
139: public boolean hasNext() {
140: return iterator.hasNext();
141: }
142:
143: public E next() {
144: value = iterator.next();
145: return value;
146: }
147:
148: public void remove() {
149: SimpleEnumSet.this .remove(value);
150: }
151: }
152:
153: private static int ALL_BITS_SET = 0x7FFFFFFF;
154:
155: static <E extends Enum<E>> SimpleEnumSet<E> all(
156: Class<E> enumClass) {
157: SimpleEnumSet<E> set = new SimpleEnumSet<E>(enumClass);
158: set.enumValues = ALL_BITS_SET;
159: return set;
160: }
161:
162: static <E extends Enum<E>> SimpleEnumSet<E> none(
163: Class<E> enumClass) {
164: return new SimpleEnumSet<E>(enumClass);
165: }
166:
167: private E[] allEnums;
168:
169: private Class<E> declaringClass;
170:
171: private int enumValues;
172:
173: SimpleEnumSet(Class<E> enumClass) {
174: declaringClass = enumClass;
175: allEnums = getEnums(declaringClass);
176: }
177:
178: SimpleEnumSet(E first, E... rest) {
179: declaringClass = first.getDeclaringClass();
180: allEnums = getEnums(declaringClass);
181: add(first);
182: for (E e : rest) {
183: add(e);
184: }
185: }
186:
187: SimpleEnumSet(List<E> enums) {
188: declaringClass = enums.get(0).getDeclaringClass();
189: allEnums = getEnums(declaringClass);
190: for (E e : enums) {
191: add(e);
192: }
193: }
194:
195: // For use only by clone
196: private SimpleEnumSet() {
197: }
198:
199: @Override
200: public boolean add(E o) {
201: // Throws NullPointerException according to spec
202: int value = 1 << o.ordinal();
203: boolean exists = (enumValues & value) != 0;
204: enumValues |= value;
205: return exists;
206: }
207:
208: @Override
209: public void addRange(E from, E to) {
210: for (int i = from.ordinal(), end = to.ordinal(); i <= end; ++i) {
211: add(allEnums[i]);
212: }
213: }
214:
215: public SimpleEnumSet<E> clone() {
216: SimpleEnumSet<E> set = new SimpleEnumSet<E>();
217: set.declaringClass = this .declaringClass;
218: set.enumValues = this .enumValues;
219: set.allEnums = this .allEnums;
220: return set;
221: }
222:
223: @Override
224: public void complement() {
225: enumValues ^= ALL_BITS_SET;
226: }
227:
228: @Override
229: public boolean contains(Object obj) {
230: return contains(asE(obj));
231: }
232:
233: @Override
234: public Iterator<E> iterator() {
235: return new SimpleIterator();
236: }
237:
238: @Override
239: public boolean remove(Object obj) {
240: return remove(asE(obj));
241: }
242:
243: @Override
244: public int size() {
245: return Integer.bitCount(enumValues);
246: }
247:
248: boolean contains(E e) {
249: if (e == null) {
250: return false;
251: }
252: int value = 1 << e.ordinal();
253: return (enumValues & value) != 0;
254: }
255:
256: boolean remove(E e) {
257: if (e == null) {
258: return false;
259: }
260:
261: int value = 1 << e.ordinal();
262: boolean exists = (enumValues & value) != 0;
263: if (exists) {
264: enumValues ^= value;
265: }
266: return exists;
267: }
268:
269: /**
270: * Returns <code>obj</code> as an E if it is an E. Otherwise, returns
271: * null.
272: */
273: @SuppressWarnings("unchecked")
274: private E asE(Object obj) {
275: if (!(obj instanceof Enum)) {
276: return null;
277: }
278: Enum e = (Enum) obj;
279: return e.getDeclaringClass() == declaringClass ? (E) e
280: : null;
281: }
282: }
283:
284: public static <E extends Enum<E>> EnumSet<E> allOf(
285: Class<E> elementType) {
286: E[] enums = getEnums(elementType);
287:
288: if (enums.length < 32) {
289: return SimpleEnumSet.all(elementType);
290: }
291:
292: EnumSet<E> largeEnumSet = new LargeEnumSet<E>(enums);
293: for (E e : enums) {
294: largeEnumSet.add(e);
295: }
296:
297: return largeEnumSet;
298: }
299:
300: public static <E extends Enum<E>> EnumSet<E> complementOf(
301: EnumSet<E> s) {
302: EnumSet<E> set = copyOf(s);
303: set.complement();
304: return set;
305: }
306:
307: public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
308: if (c instanceof EnumSet) {
309: return EnumSet.copyOf((EnumSet<E>) c);
310: }
311:
312: Iterator<E> it = c.iterator();
313: E first = it.next();
314: Class<E> clazz = first.getDeclaringClass();
315: EnumSet<E> set = EnumSet.noneOf(clazz);
316: set.add(first);
317:
318: while (it.hasNext()) {
319: set.add(it.next());
320: }
321:
322: return set;
323: }
324:
325: public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
326: return s.clone();
327: }
328:
329: public static <E extends Enum<E>> EnumSet<E> noneOf(
330: Class<E> elementType) {
331: E[] enums = getEnums(elementType);
332:
333: if (enums.length < 32) {
334: return SimpleEnumSet.none(elementType);
335: }
336: return new LargeEnumSet<E>(enums);
337: }
338:
339: public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
340: Class<E> c = first.getDeclaringClass();
341: EnumSet<E> set = noneOf(c);
342: set.add(first);
343:
344: for (E e : rest) {
345: set.add(e);
346: }
347:
348: return set;
349: }
350:
351: public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
352: if (from.compareTo(to) > 0) {
353: throw new IllegalArgumentException(from + " > " + to);
354: }
355: EnumSet<E> set = noneOf(from.getDeclaringClass());
356: set.addRange(from, to);
357: return set;
358: }
359:
360: private static <T extends Enum<T>> T[] getEnums(Class<T> clazz) {
361: return clazz.getEnumConstants();
362: }
363:
364: protected EnumSet() {
365: }
366:
367: public abstract EnumSet<E> clone();
368:
369: abstract void addRange(E from, E to);
370:
371: abstract void complement();
372: }
|