This commit is contained in:
Joel Dice 2012-07-02 14:54:59 -06:00
commit 7ab4cb0083
4 changed files with 323 additions and 0 deletions

View File

@ -80,6 +80,30 @@ public class BitSet implements Serializable, Cloneable {
bits[i] ^= otherBits.bits[i];
}
}
public void flip(int index) {
flip(index, index+1);
}
public void flip(int fromIndex, int toIndex) {
if (fromIndex > toIndex || fromIndex < 0 || toIndex < 0) {
throw new IndexOutOfBoundsException();
} else if (fromIndex != toIndex) {
int basePartition = longPosition(fromIndex);
int lastPartition = longPosition(toIndex - 1); //range is [fromIndex, toIndex)
int numPartitionsToTraverse = lastPartition - basePartition + 1;
enlarge(lastPartition);
int currentFirstIndex = fromIndex;
for (int i = 0; i < numPartitionsToTraverse; ++i) {
int currentToIndex = Math.min(toIndex, (basePartition + i + 1) * BITS_PER_LONG);
int currentRange = currentToIndex - currentFirstIndex;
long mask = (((1L << currentRange) - 1L) << (currentFirstIndex % BITS_PER_LONG));
bits[i + basePartition] ^= mask;
currentFirstIndex = currentToIndex;
}
}
}
private void enlarge(int newSize) {
if (bits == null || bits.length < newSize) {
@ -182,4 +206,12 @@ public class BitSet implements Serializable, Cloneable {
return nextBit(fromIndex, true);
}
public int cardinality() {
int numSetBits = 0;
for (int i = nextSetBit(0); i >= 0; i = nextSetBit(i+1)) {
++numSetBits;
}
return numSetBits;
}
}

View File

@ -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);
}
}
}

View File

@ -14,16 +14,19 @@ public class BitsetTest {
assertTrue("bit 5 is set", bits.get(5));
assertTrue("bit 0 is not set", !bits.get(0));
assertTrue("bit 16 is not set", !bits.get(16));
assertCardinality(bits, 2);
bits.and(other);
assertTrue("bit 5 is set", bits.get(5));
assertTrue("bit 1 is not set", !bits.get(1));
assertCardinality(bits, 1);
bits.set(100);
assertTrue("bit 100 is set", bits.get(100));
assertTrue("bit 101 is not set", !bits.get(101));
assertCardinality(bits, 2);
other.set(101);
@ -38,11 +41,39 @@ public class BitsetTest {
assertEquals("second bit is 100 from 100", 100, bits.nextSetBit(100));
assertEquals("third bit is 101", 101, bits.nextSetBit(101));
assertEquals("there is no 4th bit", -1, bits.nextSetBit(102));
assertCardinality(bits, 3);
assertEquals("first empty bit is 0", 0, bits.nextClearBit(0));
assertEquals("after 5, 6 is empty", 6, bits.nextClearBit(5));
assertEquals("after 100, 102 is empty", 102, bits.nextClearBit(100));
testFlip();
}
private static void testFlip() {
/* simple case */
BitSet bitset = new BitSet();
bitset.set(0);
bitset.flip(0, 0);
assertTrue("Should not be flipped with 0 length range", bitset.get(0));
bitset.flip(0, 1);
assertTrue("Should be false with range of one", !bitset.get(0));
bitset.flip(0);
assertTrue("Should be true again", bitset.get(0));
/* need to grow */
bitset.flip(1000);
assertTrue("1000 should be true", bitset.get(1000));
assertTrue("1001 should be false", !bitset.get(1001));
assertTrue("999 should be false", !bitset.get(999));
/* Range over 2 segments */
bitset.flip(60, 70);
assertTrue("59 should be false", !bitset.get(59));
for (int i=60; i < 70; ++i) {
assertTrue(i + " should be true", bitset.get(i));
}
assertTrue("70 should be false", !bitset.get(70));
}
static void assertTrue(String msg, boolean flag) {
@ -61,4 +92,8 @@ public class BitsetTest {
}
}
static void assertCardinality(BitSet set, int expectedCardinality) {
assertEquals("Checking cardinality", expectedCardinality, set.cardinality());
}
}

107
test/EnumSetTest.java Normal file
View File

@ -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());
}
}
}