boolean validate(BitmapContainer bc, ArrayContainer ac) { // Checking the cardinalities of each container if (bc.getCardinality() != ac.getCardinality()) { System.out.println("cardinality differs"); return false; } // Checking that the two containers contain the same values int counter = 0; int i = bc.nextSetBit(0); while (i >= 0) { ++counter; if (!ac.contains((short) i)) { System.out.println("content differs"); System.out.println(bc); System.out.println(ac); return false; } i = bc.nextSetBit(i + 1); } // checking the cardinality of the BitmapContainer if (counter != bc.getCardinality()) return false; return true; }
@Override public Container add(int begin, int end) { BitmapContainer answer = clone(); Util.setBitmapRange(answer.bitmap, begin, end); answer.computeCardinality(); return answer; }
protected Container lazyor(BitmapContainer x) { BitmapContainer answer = new BitmapContainer(); answer.cardinality = -1; // invalid for (int k = 0; k < this.bitmap.length; k++) { answer.bitmap[k] = this.bitmap[k] | x.bitmap[k]; } return answer; }
@Override public Container remove(int begin, int end) { BitmapContainer answer = clone(); Util.resetBitmapRange(answer.bitmap, begin, end); answer.computeCardinality(); if (answer.getCardinality() <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer(); return answer; }
protected Container lazyor(ArrayContainer value2) { BitmapContainer answer = this.clone(); answer.cardinality = -1; // invalid for (int k = 0; k < value2.cardinality; ++k) { final int i = Util.toIntUnsigned(value2.content[k]) >>> 6; answer.bitmap[i] |= (1l << value2.content[k]); } return answer; }
protected Container lazyor(RunContainer x) { BitmapContainer bc = clone(); bc.cardinality = -1; // invalid for (int rlepos = 0; rlepos < x.nbrruns; ++rlepos) { int start = Util.toIntUnsigned(x.getValue(rlepos)); int end = start + Util.toIntUnsigned(x.getLength(rlepos)) + 1; Util.setBitmapRange(bc.bitmap, start, end); } return bc; }
@Override public BitmapContainer or(final ArrayContainer value2) { final BitmapContainer answer = clone(); for (int k = 0; k < value2.cardinality; ++k) { final int i = Util.toIntUnsigned(value2.content[k]) >>> 6; answer.cardinality += ((~answer.bitmap[i]) & (1l << value2.content[k])) >>> value2.content[k]; answer.bitmap[i] = answer.bitmap[i] | (1l << value2.content[k]); } return answer; }
@Override public Container andNot(final ArrayContainer value2) { final BitmapContainer answer = clone(); for (int k = 0; k < value2.cardinality; ++k) { final int i = Util.toIntUnsigned(value2.content[k]) >>> 6; answer.bitmap[i] = answer.bitmap[i] & (~(1l << value2.content[k])); answer.cardinality -= (answer.bitmap[i] ^ this.bitmap[i]) >>> value2.content[k]; } if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer(); return answer; }
@Override public Container xor(final ArrayContainer value2) { final BitmapContainer answer = clone(); for (int k = 0; k < value2.getCardinality(); ++k) { final int index = Util.toIntUnsigned(value2.content[k]) >>> 6; answer.cardinality += 1 - 2 * ((answer.bitmap[index] & (1l << value2.content[k])) >>> value2.content[k]); answer.bitmap[index] = answer.bitmap[index] ^ (1l << value2.content[k]); } if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer(); return answer; }
@Test public void BitmapContainerCardinalityTest() { final BitmapContainer ac = new BitmapContainer(); for (short k = 0; k < 100; ++k) { ac.add(k); Assert.assertEquals(ac.getCardinality(), k + 1); } for (short k = 0; k < 100; ++k) { ac.add(k); Assert.assertEquals(ac.getCardinality(), 100); } }
@Override public Container andNot(RunContainer x) { // could be rewritten as return andNot(x.toBitmapOrArrayContainer()); BitmapContainer answer = this.clone(); for (int rlepos = 0; rlepos < x.nbrruns; ++rlepos) { int start = Util.toIntUnsigned(x.getValue(rlepos)); int end = start + Util.toIntUnsigned(x.getLength(rlepos)) + 1; Util.resetBitmapRange(answer.bitmap, start, end); } answer.computeCardinality(); if (answer.getCardinality() > ArrayContainer.DEFAULT_MAX_SIZE) return answer; else return answer.toArrayContainer(); }
@Test public void bitmaptest() { final BitmapContainer rr = new BitmapContainer(); rr.add((short) 110); rr.add((short) 114); rr.add((short) 115); final short[] array = new short[3]; int pos = 0; for (final short i : rr) array[pos++] = i; Assert.assertEquals(array[0], (short) 110); Assert.assertEquals(array[1], (short) 114); Assert.assertEquals(array[2], (short) 115); }
@Override public Container or(final BitmapContainer value2) { if (USE_IN_PLACE) { BitmapContainer value1 = this.clone(); return value1.ior(value2); } final BitmapContainer answer = new BitmapContainer(); answer.cardinality = 0; for (int k = 0; k < answer.bitmap.length; ++k) { answer.bitmap[k] = this.bitmap[k] | value2.bitmap[k]; answer.cardinality += Long.bitCount(answer.bitmap[k]); } return answer; }
@Override public Container xor(BitmapContainer value2) { int newCardinality = 0; for (int k = 0; k < this.bitmap.length; ++k) { newCardinality += Long.bitCount(this.bitmap[k] ^ value2.bitmap[k]); } if (newCardinality > ArrayContainer.DEFAULT_MAX_SIZE) { final BitmapContainer answer = new BitmapContainer(); for (int k = 0; k < answer.bitmap.length; ++k) { answer.bitmap[k] = this.bitmap[k] ^ value2.bitmap[k]; } answer.cardinality = newCardinality; return answer; } ArrayContainer ac = new ArrayContainer(newCardinality); Util.fillArrayXOR(ac.content, this.bitmap, value2.bitmap); ac.cardinality = newCardinality; return ac; }
@Test public void ContainerFactory() { BitmapContainer bc1, bc2, bc3; ArrayContainer ac1, ac2, ac3; bc1 = new BitmapContainer(); bc2 = new BitmapContainer(); bc3 = new BitmapContainer(); ac1 = new ArrayContainer(); ac2 = new ArrayContainer(); ac3 = new ArrayContainer(); for (short i = 0; i < 5000; i++) bc1.add((short) (i * 70)); for (short i = 0; i < 5000; i++) bc2.add((short) (i * 70)); for (short i = 0; i < 5000; i++) bc3.add((short) (i * 70)); for (short i = 0; i < 4000; i++) ac1.add((short) (i * 50)); for (short i = 0; i < 4000; i++) ac2.add((short) (i * 50)); for (short i = 0; i < 4000; i++) ac3.add((short) (i * 50)); BitmapContainer rbc; rbc = ac1.clone().toBitmapContainer(); Assert.assertTrue(validate(rbc, ac1)); rbc = ac2.clone().toBitmapContainer(); Assert.assertTrue(validate(rbc, ac2)); rbc = ac3.clone().toBitmapContainer(); Assert.assertTrue(validate(rbc, ac3)); }
// answer could be a new BitmapContainer, or (for inplace) it can be // "this" private Container not(BitmapContainer answer, final int firstOfRange, final int lastOfRange) { assert bitmap.length == MAX_CAPACITY / 64; // checking assumption // that partial // bitmaps are not // allowed // an easy case for full range, should be common if (lastOfRange - firstOfRange == MAX_CAPACITY) { final int newCardinality = MAX_CAPACITY - cardinality; for (int k = 0; k < this.bitmap.length; ++k) answer.bitmap[k] = ~this.bitmap[k]; answer.cardinality = newCardinality; if (newCardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer(); return answer; } // could be optimized to first determine the answer cardinality, // rather than update/create bitmap and then possibly convert int cardinalityChange = 0; final int rangeFirstWord = firstOfRange / 64; final int rangeFirstBitPos = firstOfRange & 63; final int rangeLastWord = (lastOfRange - 1) / 64; final long rangeLastBitPos = (lastOfRange - 1) & 63; // if not in place, we need to duplicate stuff before // rangeFirstWord and after rangeLastWord if (answer != this) { System.arraycopy(bitmap, 0, answer.bitmap, 0, rangeFirstWord); System.arraycopy( bitmap, rangeLastWord + 1, answer.bitmap, rangeLastWord + 1, bitmap.length - (rangeLastWord + 1)); } // unfortunately, the simple expression gives the wrong mask for // rangeLastBitPos==63 // no branchless way comes to mind final long maskOnLeft = (rangeLastBitPos == 63) ? -1L : (1L << (rangeLastBitPos + 1)) - 1; long mask = -1L; // now zero out stuff in the prefix mask ^= ((1L << rangeFirstBitPos) - 1); if (rangeFirstWord == rangeLastWord) { // range starts and ends in same word (may have // unchanged bits on both left and right) mask &= maskOnLeft; cardinalityChange = -Long.bitCount(bitmap[rangeFirstWord]); answer.bitmap[rangeFirstWord] = bitmap[rangeFirstWord] ^ mask; cardinalityChange += Long.bitCount(answer.bitmap[rangeFirstWord]); answer.cardinality = cardinality + cardinalityChange; if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer(); return answer; } // range spans words cardinalityChange += -Long.bitCount(bitmap[rangeFirstWord]); answer.bitmap[rangeFirstWord] = bitmap[rangeFirstWord] ^ mask; cardinalityChange += Long.bitCount(answer.bitmap[rangeFirstWord]); cardinalityChange += -Long.bitCount(bitmap[rangeLastWord]); answer.bitmap[rangeLastWord] = bitmap[rangeLastWord] ^ maskOnLeft; cardinalityChange += Long.bitCount(answer.bitmap[rangeLastWord]); // negate the words, if any, strictly between first and last for (int i = rangeFirstWord + 1; i < rangeLastWord; ++i) { cardinalityChange += (64 - 2 * Long.bitCount(bitmap[i])); answer.bitmap[i] = ~bitmap[i]; } answer.cardinality = cardinality + cardinalityChange; if (answer.cardinality <= ArrayContainer.DEFAULT_MAX_SIZE) return answer.toArrayContainer(); return answer; }