private static void maskInWord(JsArrayInteger array, int index, int from, int to) { // shifting by 32 is the same as shifting by 0, this check prevents that // from happening in addition to the obvious avoidance of extra work if (from != to) { // adjust "to" so it will shift out those bits to = 32 - to; // create a mask and OR it in int value = getWord(array, index); value |= ((0xffffffff >>> from) << (from + to)) >>> to; array.set(index, value); } };
private static void flipMaskedWord(JsArrayInteger array, int index, int from, int to) { if (from == to) { return; } // get the bits int word = getWord(array, index); // adjust "to" so it will shift out those bits to = 32 - to; // create a mask and XOR it in word ^= (((0xffffffff >>> from) << from) << to) >>> to; ; setWord(array, index, word); }
private static void maskOutWord(JsArrayInteger array, int index, int from, int to) { int word = getWord(array, index); // something only happens if word has bits set if (word != 0) { // create a mask int mask; if (from != 0) { mask = 0xffffffff >>> (32 - from); } else { mask = 0; } // shifting by 32 is the same as shifting by 0 if (to != 32) { mask |= 0xffffffff << to; } // mask it out word &= mask; setWord(array, index, word); } }
/** * This hash is different than the one described in Sun's documentation. The * described hash uses 64 bit integers and that's not practical in * JavaScript. */ @Override public int hashCode() { // FNV constants final int fnvOffset = 0x811c9dc5; final int fnvPrime = 0x1000193; // initialize final int last = trimToSize(array); int hash = fnvOffset ^ last; // loop over the data for (int i = 0; i <= last; i++) { int value = getWord(array, i); // hash one byte at a time using FNV1 hash = (hash * fnvPrime) ^ (value & 0xff); hash = (hash * fnvPrime) ^ ((value >>> 8) & 0xff); hash = (hash * fnvPrime) ^ ((value >>> 16) & 0xff); hash = (hash * fnvPrime) ^ (value >>> 24); } return hash; }
private static void flipWord(JsArrayInteger array, int index) { int word = getWord(array, index); if (word == 0) { array.set(index, 0xffffffff); } else { word = ~word; setWord(array, index, word); } }
private static boolean get(JsArrayInteger array, int bitIndex) { // retrieve the bits for the given index int word = getWord(array, wordIndex(bitIndex)); // shift and mask the bit out return ((word >>> (bitOffset(bitIndex))) & 1) == 1; }
public int length() { int last = trimToSize(array); if (last == -1) { return 0; } // compute the position of the leftmost bit's index int offsets[] = { 16, 8, 4, 2, 1 }; int bitMasks[] = { 0xffff0000, 0xff00, 0xf0, 0xc, 0x2 }; int position = bitIndex(last) + 1; int word = getWord(array, last); for (int i = 0; i < offsets.length; i++) { if ((word & bitMasks[i]) != 0) { word >>>= offsets[i]; position += offsets[i]; } } return position; }
@Override public boolean equals(Object obj) { if (this != obj) { if (!ClassReflection.isInstance(BitVector.class, obj)) { return false; } BitVector other = (BitVector) obj; int last = trimToSize(array); if (last != trimToSize(other.array)) { return false; } int index = 0; while ((index = nextSetWord(array, index)) != -1) { if (getWord(array, index) != getWord(other.array, index)) { return false; } index++; } } return true; }
private static void clear(JsArrayInteger array, int bitIndex) { int index = wordIndex(bitIndex); int word = getWord(array, index); if (word != 0) { // mask the correct bit out setWord(array, index, word & ~(1 << (bitOffset(bitIndex)))); } }
private static void set(JsArrayInteger array, int bitIndex) { int index = wordIndex(bitIndex); array.set(index, getWord(array, index) | (1 << (bitOffset(bitIndex)))); }
public int nextClearBit(int fromIndex) { checkIndex(fromIndex); int index = wordIndex(fromIndex); // special case for first index int fromBit = fromIndex - (bitIndex(index)); int word = getWord(array, index); for (int i = fromBit; i < 32; i++) { if ((word & (1 << i)) == 0) { return (bitIndex(index)) + i; } } // loop through the rest while (true) { index++; word = getWord(array, index); if (word != 0xffffffff) { return (bitIndex(index)) + Integer.numberOfTrailingZeros(~word); } } }
public void or(BitVector set) { // a | a is just a if (this == set) { return; } // truth table // // case | a | b | a | b | change? // 1 | false | false | false | a is already false // 2 | false | true | true | set a to true // 3 | true | false | true | a is already true // 4 | true | true | true | a is already true // // we only need to change something in case 2 // case 2 only happens when b is true, so iterate over set b int index = 0; while ((index = nextSetWord(set.array, index)) != -1) { setWord(array, index, getWord(array, index) | set.array.get(index)); index++; } }
private static void flip(JsArrayInteger array, int bitIndex) { // calculate index and offset int index = wordIndex(bitIndex); int offset = bitOffset(bitIndex); // figure out if the bit is on or off int word = getWord(array, index); if (((word >>> offset) & 1) == 1) { // if on, turn it off setWord(array, index, word & ~(1 << offset)); } else { // if off, turn it on array.set(index, word | (1 << offset)); } };
public boolean intersects(BitVector set) { int last = trimToSize(array); if (this == set) { // if it has any bits then it intersects itself return last != -1; } int length = set.array.length(); int index = 0; while ((index = nextSetWord(array, index)) != -1) { if ((array.get(index) & getWord(set.array, index)) != 0) { return true; } if (++index >= length) { // nothing further can intersect break; } } return false; }
public void xor(BitVector set) { // a ^ a is false if (this == set) { // this results in an empty BitSet clear(); return; } // truth table // // case | a | b | a ^ b | change? // 1 | false | false | false | a is already false // 2 | false | true | true | set a to true // 3 | true | false | true | a is already true // 4 | true | true | false | set a to false // // we need to change something in cases 2 and 4 // cases 2 and 4 only happen when b is true, so iterate over set b int index = 0; while ((index = nextSetWord(set.array, index)) != -1) { setWord(array, index, getWord(array, index) ^ set.array.get(index)); index++; } }
public int nextSetBit(int fromIndex) { checkIndex(fromIndex); int index = wordIndex(fromIndex); // check the current word int word = getWord(array, index); if (word != 0) { for (int i = bitOffset(fromIndex); i < 32; i++) { if ((word & (1 << i)) != 0) { return (bitIndex(index)) + i; } } } index++; // find the next set word trimToSize(array); index = nextSetWord(array, index); if (index == -1) { return -1; } // return the next set bit return (bitIndex(index)) + Integer.numberOfTrailingZeros(array.get(index)); };
public void andNot(BitVector set) { // a & !a is false if (this == set) { // all falses result in an empty BitSet clear(); return; } // trim the second set to avoid extra work trimToSize(array); int length = array.length(); // truth table // // case | a | b | !b | a & !b | change? // 1 | false | false | true | false | a is already false // 2 | false | true | false | false | a is already false // 3 | true | false | true | true | a is already true // 4 | true | true | false | false | set a to false // // we only need to change something in case 4 // whenever b is true, a should be false, so iterate over set b int index = 0; while ((index = nextSetWord(set.array, index)) != -1) { setWord(array, index, getWord(array, index) & ~set.array.get(index)); if (++index >= length) { // nothing further will affect anything break; } } }
public void and(BitVector set) { // a & a is just a if (this == set) { return; } // trim the second set to avoid extra work trimToSize(set.array); // check if the length is longer than otherLength int otherLength = set.array.length(); if (array.length() > otherLength) { // shrink the array, effectively ANDing those bits to false setLengthWords(array, otherLength); } // truth table // // case | a | b | a & b | change? // 1 | false | false | false | a is already false // 2 | false | true | false | a is already false // 3 | true | false | false | set a to false // 4 | true | true | true | a is already true // // we only need to change something in case 3, so iterate over set a int index = 0; while ((index = nextSetWord(array, index)) != -1) { setWord(array, index, array.get(index) & getWord(set.array, index)); index++; } }