Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding EnumSet, which is backed by a speedy BitSet.

  • Loading branch information...
commit 6e30366d07c46ba04b574268ebede00fab83d710 1 parent d419899
Mike Keesey mkeesey authored
Showing with 256 additions and 0 deletions.
  1. +149 −0 classpath/java/util/EnumSet.java
  2. +107 −0 test/EnumSetTest.java
149 classpath/java/util/EnumSet.java
View
@@ -0,0 +1,149 @@
+package java.util;
+
+public class EnumSet<T extends Enum<T>> extends AbstractSet<T> {
+
+ private BitSet bitset;
+ private Class<T> elementType;
+
+ private EnumSet(int size, Class<T> type) {
+ bitset = new BitSet(size);
+ elementType = type;
+ }
+
+ @Override
+ public boolean add(T element) {
+ int index = element.ordinal();
+ boolean contains = bitset.get(index);
+ if (!contains) {
+ bitset.set(index);
+ }
+
+ return !contains;
+ }
+
+ @Override
+ public boolean remove(Object toRemove) {
+ T element = tryToCast(toRemove);
+
+ int index = element.ordinal();
+ boolean contains = bitset.get(index);
+ if (contains) {
+ bitset.clear(index);
+ }
+
+ return contains;
+ }
+
+ @Override
+ public boolean contains(Object toCheck) {
+ T element = tryToCast(toCheck);
+ int index = element.ordinal();
+ return bitset.get(index);
+ }
+
+ @Override
+ public int size() {
+ return bitset.cardinality();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return new EnumSetIterator();
+ }
+
+ public static <T extends Enum<T>>EnumSet<T> allOf(Class<T> elementType) {
+ EnumSet<T> enumSet = createEmptyEnumSet(elementType);
+ addAllElementsToSet(Arrays.asList(elementType.getEnumConstants()), enumSet);
+
+ return enumSet;
+ }
+
+ public static <T extends Enum<T>>EnumSet<T> noneOf(Class<T> elementType) {
+ return createEmptyEnumSet(elementType);
+ }
+
+ public static <T extends Enum<T>>EnumSet<T> of(T first, T ... rest) {
+ EnumSet<T> enumSet = createEmptyEnumSet(first.getDeclaringClass());
+ enumSet.add(first);
+ addAllElementsToSet(Arrays.asList(rest), enumSet);
+
+ return enumSet;
+ }
+
+ public static <T extends Enum<T>>EnumSet<T> complementOf(EnumSet<T> s) {
+ EnumSet<T> enumSet = copyOf(s);
+ enumSet.bitset.flip(0, s.elementType.getEnumConstants().length);
+
+ return enumSet;
+ }
+
+ public static <T extends Enum<T>>EnumSet<T> copyOf(EnumSet<T> s) {
+ EnumSet<T> enumSet = createEmptyEnumSet(s.elementType);
+ enumSet.bitset.or(s.bitset);
+
+ return enumSet;
+ }
+
+ private static <T extends Enum<T>>EnumSet<T> createEmptyEnumSet(Class<T> elementType) {
+ T[] constants = elementType.getEnumConstants();
+ EnumSet<T> enumSet = new EnumSet<T>(constants.length, elementType);
+
+ return enumSet;
+ }
+
+ private static <T extends Enum<T>> void addAllElementsToSet(Iterable<T> elements, EnumSet<T> enumSet) {
+ for (T element : elements) {
+ enumSet.add(element);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private T tryToCast(Object object) throws ClassCastException {
+ //We want the class cast exception if we can't convert.
+ return (T) object;
+ }
+
+ private class EnumSetIterator implements Iterator<T> {
+ private int currentIndex = 0;
+ private boolean removeAllowed = false;
+
+ @Override
+ public T next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException("EnumSet has no more elements");
+ }
+
+ int indexOfNextValue = nextIndex();
+ T element = elementType.getEnumConstants()[indexOfNextValue];
+ currentIndex = indexOfNextValue + 1;
+ removeAllowed = true;
+
+ return element;
+ }
+
+ @Override
+ public boolean hasNext() {
+ int indexOfNextValue = nextIndex();
+ if (indexOfNextValue >= 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void remove() {
+ //TODO
+ if (!removeAllowed) {
+ throw new IllegalStateException("Cannot remove from this iterator in this state");
+ }
+
+ bitset.clear(currentIndex - 1);
+ removeAllowed = false;
+ }
+
+ private int nextIndex() {
+ return bitset.nextSetBit(currentIndex);
+ }
+ }
+}
107 test/EnumSetTest.java
View
@@ -0,0 +1,107 @@
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class EnumSetTest {
+ private enum SmallEnum {
+ ONE,
+ TWO,
+ THREE
+ }
+
+ private enum LargerEnum {
+ LARGEONE,
+ LARGETWO,
+ LARGETHREE,
+ LARGEFOUR,
+ LARGEFIVE,
+ LARGESIX
+ }
+
+ public static void main(String[] args) {
+ testAllOf();
+ testNoneOf();
+ testIterators();
+ testOf();
+ testCopyOf();
+ testComplimentOf();
+ }
+
+ private static void testComplimentOf() {
+ EnumSet<SmallEnum> one = EnumSet.of(SmallEnum.ONE, SmallEnum.THREE);
+ EnumSet<SmallEnum> two = EnumSet.complementOf(one);
+ assertElementInSet(SmallEnum.TWO, two);
+ assertSize(1, two);
+ }
+
+ private static void testCopyOf() {
+ EnumSet<SmallEnum> one = EnumSet.of(SmallEnum.ONE, SmallEnum.THREE);
+ EnumSet<SmallEnum> two = EnumSet.copyOf(one);
+ assertElementInSet(SmallEnum.ONE, two);
+ assertElementInSet(SmallEnum.THREE, two);
+ assertSize(2, two);
+ }
+
+ private static void testOf() {
+ EnumSet<LargerEnum> set = EnumSet.of(LargerEnum.LARGEONE, LargerEnum.LARGEFIVE, LargerEnum.LARGETWO);
+ assertElementInSet(LargerEnum.LARGEONE, set);
+ assertElementInSet(LargerEnum.LARGEFIVE, set);
+ assertElementInSet(LargerEnum.LARGETWO, set);
+ assertSize(3, set);
+ }
+
+ private static void testAllOf() {
+ EnumSet<SmallEnum> set = EnumSet.allOf(SmallEnum.class);
+ for (SmallEnum current : SmallEnum.values()) {
+ assertElementInSet(current, set);
+ }
+ assertSize(3, set);
+ }
+
+ private static void testNoneOf() {
+ EnumSet<SmallEnum> set = EnumSet.noneOf(SmallEnum.class);
+ assertSize(0, set);
+ }
+
+ private static void testIterators() {
+ EnumSet<SmallEnum> set = EnumSet.allOf(SmallEnum.class);
+ Iterator<SmallEnum> iterator = set.iterator();
+ boolean exceptionCaught = false;
+ try {
+ iterator.remove();
+ } catch (IllegalStateException e) {
+ exceptionCaught = true;
+ }
+ if (!exceptionCaught) {
+ throw new RuntimeException("Calling remove() before next() should throw IllegalStateException");
+ }
+
+ while (iterator.hasNext()) {
+ iterator.next();
+ iterator.remove();
+ }
+ assertSize(0, set);
+
+ exceptionCaught = false;
+ try {
+ iterator.next();
+ } catch (NoSuchElementException e) {
+ exceptionCaught = true;
+ }
+ if (!exceptionCaught) {
+ throw new RuntimeException("Calling next() when hasNext() == false should throw NoSuchElementException");
+ }
+ }
+
+ private static void assertElementInSet(Enum<?> element, EnumSet<?> set) {
+ if (!set.contains(element)) {
+ throw new RuntimeException("expected " + element + " in the set!");
+ }
+ }
+
+ private static void assertSize(int expectedSize, EnumSet<?> set) {
+ if (set.size() != expectedSize) {
+ throw new RuntimeException("expected the set to be size=" + expectedSize + ", actual=" + set.size());
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.