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