/** * Creates a new instance. * * @param startCapacity the number of bits (starting from {@code 0}) that should already be held available */ public Bitmask(int startCapacity) { int numLongs = startCapacity > 0 ? getLongPos(startCapacity - 1) + 1 : 0; this.bits = new long[numLongs]; this.cardinalityCache = 0; }
/** * Makes sure that {@link #bits} is large enough to comprise the given {@code index}. * * @param index an index for a bit * @return whether {@link #bits} was enlarged */ private boolean ensureCapacity(int index) { int numRequiredLongs = getLongPos(index) + 1; if (this.bits.length < numRequiredLongs) { long[] newBits = new long[numRequiredLongs]; System.arraycopy(this.bits, 0, newBits, 0, this.bits.length); this.bits = newBits; return true; } return false; }
/** * Gets the bit at the given index. * * @param index where the bit should be set * @return whether the bit in question is set */ public boolean get(int index) { final int longPos = getLongPos(index); if (longPos >= this.bits.length) return false; final int offset = getOffset(index); return ((this.bits[longPos] >>> offset) & 1) != 0; }
/** * Finds the next set bit, starting from a given index. * * @param from index from that the search starts * @return the index of the set next bit or {@code -1} if there is no next set bit */ public int nextSetBit(int from) { int longPos = getLongPos(from); int offset = getOffset(from); while (longPos < this.bits.length) { long bits = this.bits[longPos]; int nextOffset = Long.numberOfTrailingZeros(bits & ~createAllSetBits(offset)); if (nextOffset < BITS_PER_WORD) { return longPos << WORD_ADDRESS_BITS | nextOffset; } longPos++; offset = 0; } return -1; }
/** * Flips all bits in the given range * * @param fromIndex inclusive start index of the range * @param toIndex exclusive end index of the range * @return this instance */ public Bitmask flip(int fromIndex, int toIndex) { if (fromIndex < toIndex) { this.ensureCapacity(toIndex - 1); int fromLongPos = getLongPos(fromIndex); int untilLongPos = getLongPos(toIndex - 1); for (int longPos = fromLongPos; longPos <= untilLongPos; longPos++) { int fromOffset = (longPos == fromLongPos) ? getOffset(fromIndex) : 0; int untilOffset = (longPos == untilLongPos) ? getOffset(toIndex - 1) + 1 : BITS_PER_WORD; long flipMask = createAllSetBits(untilOffset) ^ createAllSetBits(fromOffset); this.bits[longPos] ^= flipMask; } this.cardinalityCache = -1; } return this; }
/** * Sets the bit at the given index. * * @param index where the bit should be set * @return whether this instance was changed */ public boolean set(int index) { if (!this.ensureCapacity(index) && this.get(index)) { return false; } final int longPos = getLongPos(index); final int offset = getOffset(index); this.bits[longPos] = this.bits[longPos] | (1L << offset); if (this.cardinalityCache != -1) this.cardinalityCache++; return true; }