/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.openhft.lang.collection; import net.openhft.lang.io.Bytes; import static java.lang.Long.numberOfLeadingZeros; import static java.lang.Long.numberOfTrailingZeros; /** * DirectBitSet with input validations, This class is not thread safe */ public class SingleThreadedDirectBitSet implements DirectBitSet { public static final long ALL_ONES = ~0L; // masks private Bytes bytes; private long longLength; public SingleThreadedDirectBitSet(Bytes bytes) { reuse(bytes); } static long singleBit(long bitIndex) { return 1L << bitIndex; } static long singleBit(int bitIndex) { return 1L << bitIndex; } static long higherBitsIncludingThis(long bitIndex) { return ALL_ONES << bitIndex; } // conversions static long lowerBitsIncludingThis(long bitIndex) { return ALL_ONES >>> ~bitIndex; } static long higherBitsExcludingThis(long bitIndex) { return ~(ALL_ONES >>> ~bitIndex); } static long lowerBitsExcludingThis(long bitIndex) { return ~(ALL_ONES << bitIndex); } static long longWithThisBit(long bitIndex) { return bitIndex >> 6; } static long firstByte(long longIndex) { return longIndex << 3; } static long firstBit(long longIndex) { return longIndex << 6; } static long lastBit(long longIndex) { return firstBit(longIndex) + 63; } static void checkNumberOfBits(int numberOfBits) { if (numberOfBits <= 0 || numberOfBits > 64) throw new IllegalArgumentException("Illegal number of bits: " + numberOfBits); } // checks static boolean checkNotFoundIndex(long fromIndex) { if (fromIndex < 0) { if (fromIndex == NOT_FOUND) return true; throw new IndexOutOfBoundsException(); } return false; } public void reuse(Bytes bytes) { this.bytes = bytes; longLength = bytes.capacity() >> 3; } private void checkIndex(long bitIndex, long longIndex) { if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); } private void checkFromTo(long fromIndex, long exclusiveToIndex, long toLongIndex) { if (fromIndex < 0 || fromIndex > exclusiveToIndex || toLongIndex >= longLength) throw new IndexOutOfBoundsException(); } private long readLong(long longIndex) { return bytes.readLong(firstByte(longIndex)); } private void writeLong(long longIndex, long toWrite) { bytes.writeLong(firstByte(longIndex), toWrite); } @Override public void reserve() { bytes.reserve(); } @Override public boolean release() { return bytes.release(); } @Override public int refCount() { return bytes.refCount(); } @Override public DirectBitSet flip(long bitIndex) { long longIndex = longWithThisBit(bitIndex); checkIndex(bitIndex, longIndex); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); long l = bytes.readLong(byteIndex); long l2 = l ^ mask; bytes.writeLong(byteIndex, l2); return this; } @Override public DirectBitSet flip(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); checkFromTo(fromIndex, exclusiveToIndex, toLongIndex); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long fromByteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex); long l = bytes.readLong(fromByteIndex); long l2 = l ^ mask; bytes.writeLong(fromByteIndex, l2); firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { writeLong(i, ~readLong(i)); } } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { writeLong(i, ~readLong(i)); } long toByteIndex = firstByte(toLongIndex); long mask = lowerBitsIncludingThis(toIndex); long l = bytes.readLong(toByteIndex); long l2 = l ^ mask; bytes.writeLong(toByteIndex, l2); } } else { long byteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); long l = bytes.readLong(byteIndex); long l2 = l ^ mask; bytes.writeLong(byteIndex, l2); } return this; } @Override public DirectBitSet set(long bitIndex) { long longIndex = longWithThisBit(bitIndex); checkIndex(bitIndex, longIndex); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); long l = bytes.readLong(byteIndex); if ((l & mask) != 0) return this; long l2 = l | mask; bytes.writeLong(byteIndex, l2); return this; } @Override public boolean setIfClear(long bitIndex) { long longIndex = longWithThisBit(bitIndex); checkIndex(bitIndex, longIndex); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); long l = bytes.readLong(byteIndex); long l2 = l | mask; if (l == l2) return false; bytes.writeLong(byteIndex, l2); return true; } @Override public DirectBitSet set(long bitIndex, boolean value) { return value ? set(bitIndex) : clear(bitIndex); } @Override public DirectBitSet set(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); checkFromTo(fromIndex, exclusiveToIndex, toLongIndex); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long fromByteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex); long l = bytes.readLong(fromByteIndex); long l2 = l | mask; bytes.writeLong(fromByteIndex, l2); firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { writeLong(i, ALL_ONES); } } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { writeLong(i, ALL_ONES); } long toByteIndex = firstByte(toLongIndex); long mask = lowerBitsIncludingThis(toIndex); long l = bytes.readLong(toByteIndex); long l2 = l | mask; bytes.writeLong(toByteIndex, l2); } } else { long byteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); long l = bytes.readLong(byteIndex); long l2 = l | mask; bytes.writeLong(byteIndex, l2); } return this; } @Override public DirectBitSet setAll() { for (long i = 0; i < longLength; i++) { writeLong(i, ALL_ONES); } return this; } @Override public DirectBitSet set(long fromIndex, long toIndex, boolean value) { return value ? set(fromIndex, toIndex) : clear(fromIndex, toIndex); } @Override public DirectBitSet clear(long bitIndex) { long longIndex = longWithThisBit(bitIndex); checkIndex(bitIndex, longIndex); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); long l = bytes.readLong(byteIndex); if ((l & mask) == 0) return this; long l2 = l & ~mask; bytes.writeLong(byteIndex, l2); return this; } @Override public boolean clearIfSet(long bitIndex) { long longIndex = longWithThisBit(bitIndex); checkIndex(bitIndex, longIndex); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); long l = bytes.readLong(byteIndex); if ((l & mask) == 0) return false; long l2 = l & ~mask; bytes.writeLong(byteIndex, l2); return true; } @Override public DirectBitSet clear(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); checkFromTo(fromIndex, exclusiveToIndex, toLongIndex); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long fromByteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex); long l = bytes.readLong(fromByteIndex); long l2 = l & ~mask; bytes.writeLong(fromByteIndex, l2); firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { writeLong(i, 0L); } } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { writeLong(i, 0L); } long toByteIndex = firstByte(toLongIndex); long mask = lowerBitsIncludingThis(toIndex); long l = bytes.readLong(toByteIndex); long l2 = l & ~mask; bytes.writeLong(toByteIndex, l2); } } else { long byteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); long l = bytes.readLong(byteIndex); long l2 = l & ~mask; bytes.writeLong(byteIndex, l2); } return this; } /** * Checks if each bit from the specified {@code fromIndex} (inclusive) to the specified {@code * exclusiveToIndex} is set to {@code true}. * * @param fromIndex index of the first bit to check * @param exclusiveToIndex index after the last bit to check * @return {@code true} if all bits in the specified range are set to {@code true}, {@code * false} otherwise * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code fromIndex} is * larger than {@code toIndex}, or {@code exclusiveToIndex} is * larger or equal to {@code size()} */ public boolean allSet(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); checkFromTo(fromIndex, exclusiveToIndex, toLongIndex); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long mask = higherBitsIncludingThis(fromIndex); if ((~(readLong(fromLongIndex)) & mask) != 0L) return false; firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { if (~readLong(i) != 0L) return false; } return true; } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { if (~readLong(i) != 0L) return false; } long mask = lowerBitsIncludingThis(toIndex); return ((~readLong(toLongIndex)) & mask) == 0L; } } else { long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); return ((~readLong(fromLongIndex)) & mask) == 0L; } } /** * Checks if each bit from the specified {@code fromIndex} (inclusive) to the specified {@code * exclusiveToIndex} is set to {@code false}. * * @param fromIndex index of the first bit to check * @param exclusiveToIndex index after the last bit to check * @return {@code true} if all bits in the specified range are set to {@code false}, {@code * false} otherwise * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, or {@code fromIndex} is * larger than {@code toIndex}, or {@code exclusiveToIndex} is * larger or equal to {@code size()} */ public boolean allClear(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); checkFromTo(fromIndex, exclusiveToIndex, toLongIndex); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long mask = higherBitsIncludingThis(fromIndex); if ((readLong(fromLongIndex) & mask) != 0L) return false; firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { if (readLong(i) != 0L) return false; } return true; } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { if (readLong(i) != 0L) return false; } long mask = lowerBitsIncludingThis(toIndex); return (readLong(toLongIndex) & mask) == 0L; } } else { long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); return (readLong(fromLongIndex) & mask) == 0L; } } @Override public DirectBitSet clear() { bytes.zeroOut(); return this; } @Override public boolean get(long bitIndex) { long longIndex = longWithThisBit(bitIndex); checkIndex(bitIndex, longIndex); long l = readLong(longIndex); return (l & (singleBit(bitIndex))) != 0; } @Override public boolean isSet(long bitIndex) { return get(bitIndex); } @Override public boolean isClear(long bitIndex) { return !get(bitIndex); } @Override public long getLong(long longIndex) { checkIndex(longIndex, longIndex); return readLong(longIndex); } @Override public long nextSetBit(long fromIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException(); long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) return NOT_FOUND; long l = readLong(fromLongIndex) >>> fromIndex; if (l != 0) { return fromIndex + numberOfTrailingZeros(l); } for (long i = fromLongIndex + 1; i < longLength; i++) { l = readLong(i); if (l != 0) return firstBit(i) + numberOfTrailingZeros(l); } return NOT_FOUND; } @Override public Bits setBits() { return new SetBits(); } @Override public long clearNextSetBit(long fromIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException(); long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) return NOT_FOUND; long fromByteIndex = firstByte(fromLongIndex); long w = bytes.readLong(fromByteIndex); long l = w >>> fromIndex; if (l != 0) { long indexOfSetBit = fromIndex + numberOfTrailingZeros(l); long mask = singleBit(indexOfSetBit); bytes.writeLong(fromByteIndex, w ^ mask); return indexOfSetBit; } for (long i = fromLongIndex + 1; i < longLength; i++) { long byteIndex = firstByte(i); l = bytes.readLong(byteIndex); if (l != 0) { long indexOfSetBit = firstBit(i) + numberOfTrailingZeros(l); long mask = singleBit(indexOfSetBit); bytes.writeLong(byteIndex, l ^ mask); return indexOfSetBit; } } return NOT_FOUND; } @Override public long nextSetLong(long fromLongIndex) { if (fromLongIndex < 0) throw new IndexOutOfBoundsException(); if (fromLongIndex >= longLength) return NOT_FOUND; if (readLong(fromLongIndex) != 0) return fromLongIndex; for (long i = fromLongIndex + 1; i < longLength; i++) { if (readLong(i) != 0) return i; } return NOT_FOUND; } @Override public long nextClearBit(long fromIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException(); long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) return NOT_FOUND; long l = (~readLong(fromLongIndex)) >>> fromIndex; if (l != 0) { return fromIndex + numberOfTrailingZeros(l); } for (long i = fromLongIndex + 1; i < longLength; i++) { l = ~readLong(i); if (l != 0) return firstBit(i) + numberOfTrailingZeros(l); } return NOT_FOUND; } @Override public long setNextClearBit(long fromIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException(); long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) return NOT_FOUND; long fromByteIndex = firstByte(fromLongIndex); long w = bytes.readLong(fromByteIndex); long l = (~w) >>> fromIndex; if (l != 0) { long indexOfClearBit = fromIndex + numberOfTrailingZeros(l); long mask = singleBit(indexOfClearBit); bytes.writeLong(fromByteIndex, w ^ mask); return indexOfClearBit; } for (long i = fromLongIndex + 1; i < longLength; i++) { long byteIndex = firstByte(i); w = bytes.readLong(byteIndex); l = ~w; if (l != 0) { long indexOfClearBit = firstBit(i) + numberOfTrailingZeros(l); long mask = singleBit(indexOfClearBit); bytes.writeLong(byteIndex, w ^ mask); return indexOfClearBit; } } return NOT_FOUND; } @Override public long nextClearLong(long fromLongIndex) { if (fromLongIndex < 0) throw new IndexOutOfBoundsException(); if (fromLongIndex >= longLength) return NOT_FOUND; if (readLong(fromLongIndex) != ALL_ONES) return fromLongIndex; for (long i = fromLongIndex + 1; i < longLength; i++) { if (readLong(i) != ALL_ONES) return i; } return NOT_FOUND; } @Override public long previousSetBit(long fromIndex) { if (checkNotFoundIndex(fromIndex)) return NOT_FOUND; long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) { // the same policy for this "index out of bounds" situation // as in j.u.BitSet fromLongIndex = longLength - 1; fromIndex = size() - 1; } // << ~fromIndex === << (63 - (fromIndex & 63)) long l = readLong(fromLongIndex) << ~fromIndex; if (l != 0) return fromIndex - numberOfLeadingZeros(l); for (long i = fromLongIndex - 1; i >= 0; i--) { l = readLong(i); if (l != 0) return lastBit(i) - numberOfLeadingZeros(l); } return NOT_FOUND; } private long previousSetBit(long fromIndex, long inclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toLongIndex = longWithThisBit(inclusiveToIndex); checkFromTo(inclusiveToIndex, fromIndex + 1, toLongIndex); if (fromLongIndex >= longLength) { // the same policy for this "index out of bounds" situation // as in j.u.BitSet fromLongIndex = longLength - 1; fromIndex = size() - 1; } if (fromLongIndex != toLongIndex) { // << ~fromIndex === << (63 - (fromIndex & 63)) long l = readLong(fromLongIndex) << ~fromIndex; if (l != 0) return fromIndex - numberOfLeadingZeros(l); for (long i = fromLongIndex - 1; i > toLongIndex; i--) { l = readLong(i); if (l != 0) return lastBit(i) - numberOfLeadingZeros(l); } fromIndex = lastBit(toLongIndex); } long w = readLong(toLongIndex); long mask = higherBitsIncludingThis(inclusiveToIndex) & lowerBitsIncludingThis(fromIndex); long l = w & mask; if (l != 0) { return lastBit(toLongIndex) - numberOfLeadingZeros(l); } return NOT_FOUND; } @Override public long clearPreviousSetBit(long fromIndex) { if (checkNotFoundIndex(fromIndex)) return NOT_FOUND; long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) { fromLongIndex = longLength - 1; fromIndex = size() - 1; } long fromByteIndex = firstByte(fromLongIndex); long w = bytes.readLong(fromByteIndex); long l = w << ~fromIndex; if (l != 0) { long indexOfSetBit = fromIndex - numberOfLeadingZeros(l); long mask = singleBit(indexOfSetBit); bytes.writeLong(fromByteIndex, w ^ mask); return indexOfSetBit; } for (long i = fromLongIndex - 1; i >= 0; i--) { long byteIndex = firstByte(i); l = bytes.readLong(byteIndex); if (l != 0) { long indexOfSetBit = lastBit(i) - numberOfLeadingZeros(l); long mask = singleBit(indexOfSetBit); bytes.writeLong(byteIndex, l ^ mask); return indexOfSetBit; } } return NOT_FOUND; } @Override public long previousSetLong(long fromLongIndex) { if (checkNotFoundIndex(fromLongIndex)) return NOT_FOUND; if (fromLongIndex >= longLength) fromLongIndex = longLength - 1; if (readLong(fromLongIndex) != 0) return fromLongIndex; for (long i = fromLongIndex - 1; i >= 0; i--) { if (readLong(i) != 0) return i; } return NOT_FOUND; } @Override public long previousClearBit(long fromIndex) { if (checkNotFoundIndex(fromIndex)) return NOT_FOUND; long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) { fromLongIndex = longLength - 1; fromIndex = size() - 1; } long l = (~readLong(fromLongIndex)) << ~fromIndex; if (l != 0) return fromIndex - numberOfLeadingZeros(l); for (long i = fromLongIndex - 1; i >= 0; i--) { l = ~readLong(i); if (l != 0) return lastBit(i) - numberOfLeadingZeros(l); } return NOT_FOUND; } @Override public long setPreviousClearBit(long fromIndex) { if (checkNotFoundIndex(fromIndex)) return NOT_FOUND; long fromLongIndex = longWithThisBit(fromIndex); if (fromLongIndex >= longLength) { fromLongIndex = longLength - 1; fromIndex = size() - 1; } long fromByteIndex = firstByte(fromLongIndex); long w = bytes.readLong(fromByteIndex); long l = (~w) << ~fromIndex; if (l != 0) { long indexOfClearBit = fromIndex - numberOfLeadingZeros(l); long mask = singleBit(indexOfClearBit); bytes.writeLong(fromByteIndex, w ^ mask); return indexOfClearBit; } for (long i = fromLongIndex - 1; i >= 0; i--) { long byteIndex = firstByte(i); w = bytes.readLong(byteIndex); l = ~w; if (l != 0) { long indexOfClearBit = lastBit(i) - numberOfLeadingZeros(l); long mask = singleBit(indexOfClearBit); bytes.writeLong(byteIndex, w ^ mask); return indexOfClearBit; } } return NOT_FOUND; } @Override public long previousClearLong(long fromLongIndex) { if (checkNotFoundIndex(fromLongIndex)) return NOT_FOUND; if (fromLongIndex >= longLength) fromLongIndex = longLength - 1; if (readLong(fromLongIndex) != ALL_ONES) return fromLongIndex; for (long i = fromLongIndex - 1; i >= 0; i--) { if (readLong(i) != ALL_ONES) return i; } return NOT_FOUND; } @Override public long size() { return longLength << 6; } @Override public long cardinality() { long count = 0; for (long i = 0; i < longLength; i++) { count += Long.bitCount(readLong(i)); } return count; } @Override public DirectBitSet and(long longIndex, long value) { long l = readLong(longIndex); long l2 = l & value; writeLong(longIndex, l2); return this; } @Override public DirectBitSet or(long longIndex, long value) { long l = readLong(longIndex); long l2 = l | value; writeLong(longIndex, l2); return this; } @Override public DirectBitSet xor(long longIndex, long value) { long l = readLong(longIndex); long l2 = l ^ value; writeLong(longIndex, l2); return this; } @Override public DirectBitSet andNot(long longIndex, long value) { long l = readLong(longIndex); long l2 = l & ~value; writeLong(longIndex, l2); return this; } /** * @throws IllegalArgumentException if {@code numberOfBits} is negative */ @Override public long setNextNContinuousClearBits(long fromIndex, int numberOfBits) { if (numberOfBits > 64) return setNextManyContinuousClearBits(fromIndex, numberOfBits); checkNumberOfBits(numberOfBits); if (numberOfBits == 1) return setNextClearBit(fromIndex); if (fromIndex < 0) throw new IndexOutOfBoundsException(); long nTrailingOnes = ALL_ONES >>> (64 - numberOfBits); long bitIndex = fromIndex; long longIndex2 = longWithThisBit(bitIndex); if (longIndex2 >= longLength) return NOT_FOUND; int bitsFromFirstWord = 64 - (((int) bitIndex) & 63); long byteIndex2 = firstByte(longIndex2); long w1, w2 = bytes.readLong(byteIndex2); longLoop: while (true) { w1 = w2; byteIndex2 += 8; if (++longIndex2 < longLength) { w2 = bytes.readLong(byteIndex2); } else if (longIndex2 == longLength) { w2 = ALL_ONES; } else { return NOT_FOUND; } long l; // (1) if (bitsFromFirstWord != 64) { l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); } else { // special case, because if bitsFromFirstWord is 64 // w2 shift is overflowed l = w1; } // (2) if ((l & 1) != 0) { long x = ~l; if (x != 0) { int trailingOnes = numberOfTrailingZeros(x); bitIndex += trailingOnes; // (3) if ((bitsFromFirstWord -= trailingOnes) <= 0) { bitsFromFirstWord += 64; continue; // long loop } l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); } else { // all bits are ones, skip a whole word, // bitsFromFirstWord not changed bitIndex += 64; continue; // long loop } } while (true) { if ((l & nTrailingOnes) == 0) { long mask1 = nTrailingOnes << bitIndex; bytes.writeLong(byteIndex2 - 8, w1 ^ mask1); int bitsFromSecondWordToSwitch = numberOfBits - bitsFromFirstWord; if (bitsFromSecondWordToSwitch > 0) { long mask2 = (singleBit(bitsFromSecondWordToSwitch)) - 1; bytes.writeLong(byteIndex2, w2 ^ mask2); } return bitIndex; } // n > trailing zeros > 0 // > 0 ensured by block (2) int trailingZeros = numberOfTrailingZeros(l); bitIndex += trailingZeros; // (4) if ((bitsFromFirstWord -= trailingZeros) <= 0) { bitsFromFirstWord += 64; continue longLoop; } // (5) // subtractions (3) and (4) together ensure that // bitsFromFirstWord != 64, => no need in condition like (1) l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); long x = ~l; if (x != 0) { int trailingOnes = numberOfTrailingZeros(x); bitIndex += trailingOnes; if ((bitsFromFirstWord -= trailingOnes) <= 0) { bitsFromFirstWord += 64; continue longLoop; } // same as (5) l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); } else { // all bits are ones, skip a whole word, // bitsFromFirstWord not changed bitIndex += 64; continue longLoop; } } } } private long setNextManyContinuousClearBits(long fromIndex, int numberOfBits) { long size = size(); long testFromIndex = fromIndex; while (true) { long limit = fromIndex + numberOfBits; if (limit > size) return NOT_FOUND; long needToBeZerosUntil = limit - 1; long lastSetBit = previousSetBit(needToBeZerosUntil, testFromIndex); if (lastSetBit == NOT_FOUND) { set(fromIndex, limit); return fromIndex; } fromIndex = lastSetBit + 1; testFromIndex = limit; } } /** * @throws IllegalArgumentException if {@code numberOfBits} is out of range {@code 0 < * numberOfBits && numberOfBits <= 64} */ @Override public long clearNextNContinuousSetBits(long fromIndex, int numberOfBits) { checkNumberOfBits(numberOfBits); if (numberOfBits == 1) return clearNextSetBit(fromIndex); if (fromIndex < 0) throw new IndexOutOfBoundsException(); long nTrailingOnes = ALL_ONES >>> (64 - numberOfBits); long bitIndex = fromIndex; long longIndex2 = longWithThisBit(bitIndex); if (longIndex2 >= longLength) return NOT_FOUND; int bitsFromFirstWord = 64 - (((int) bitIndex) & 63); long byteIndex2 = firstByte(longIndex2); long w1, w2 = bytes.readLong(byteIndex2); longLoop: while (true) { w1 = w2; byteIndex2 += 8; if (++longIndex2 < longLength) { w2 = bytes.readLong(byteIndex2); } else if (longIndex2 == longLength) { w2 = 0L; } else { return NOT_FOUND; } long l; // (1) if (bitsFromFirstWord != 64) { l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); } else { // special case, because if bitsFromFirstWord is 64 // w2 shift is overflowed l = w1; } // (2) if ((l & 1) == 0) { if (l != 0) { int trailingZeros = numberOfTrailingZeros(l); bitIndex += trailingZeros; // (3) if ((bitsFromFirstWord -= trailingZeros) <= 0) { bitsFromFirstWord += 64; continue; // long loop } l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); } else { // all bits are zeros, skip a whole word, // bitsFromFirstWord not changed bitIndex += 64; continue; // long loop } } while (true) { if (((~l) & nTrailingOnes) == 0) { long mask1 = nTrailingOnes << bitIndex; bytes.writeLong(byteIndex2 - 8, w1 ^ mask1); int bitsFromSecondWordToSwitch = numberOfBits - bitsFromFirstWord; if (bitsFromSecondWordToSwitch > 0) { long mask2 = (singleBit(bitsFromSecondWordToSwitch)) - 1; bytes.writeLong(byteIndex2, w2 ^ mask2); } return bitIndex; } // n > trailing ones > 0 // > 0 ensured by block (2) int trailingOnes = numberOfTrailingZeros(~l); bitIndex += trailingOnes; // (4) if ((bitsFromFirstWord -= trailingOnes) <= 0) { bitsFromFirstWord += 64; continue longLoop; } // (5) // subtractions (3) and (4) together ensure that // bitsFromFirstWord != 64, => no need in condition like (1) l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); if (l != 0) { int trailingZeros = numberOfTrailingZeros(l); bitIndex += trailingZeros; if ((bitsFromFirstWord -= trailingZeros) <= 0) { bitsFromFirstWord += 64; continue longLoop; } // same as (5) l = (w1 >>> bitIndex) | (w2 << bitsFromFirstWord); } else { // all bits are zeros, skip a whole word, // bitsFromFirstWord not changed bitIndex += 64; continue longLoop; } } } } /** * @throws IllegalArgumentException if {@code numberOfBits} is out of range {@code 0 < * numberOfBits && numberOfBits <= 64} */ @Override public long setPreviousNContinuousClearBits( long fromIndex, int numberOfBits) { checkNumberOfBits(numberOfBits); if (numberOfBits == 1) return setPreviousClearBit(fromIndex); if (checkNotFoundIndex(fromIndex)) return NOT_FOUND; int n64Complement = 64 - numberOfBits; long nLeadingOnes = higherBitsIncludingThis(n64Complement); long higherBitBound = fromIndex + 1; long lowLongIndex = longWithThisBit(fromIndex); if (lowLongIndex >= longLength) { lowLongIndex = longLength - 1; higherBitBound = longLength << 6; } int bitsFromLowWord = (64 - (((int) higherBitBound) & 63)) & 63; long lowByteIndex = firstByte(lowLongIndex); // low word, high word long hw, lw = bytes.readLong(lowByteIndex); longLoop: while (true) { hw = lw; lowByteIndex -= 8; if (--lowLongIndex >= 0) { lw = bytes.readLong(lowByteIndex); } else if (lowLongIndex == -1) { lw = ALL_ONES; } else { return NOT_FOUND; } long l; if (bitsFromLowWord != 0) { // (1) l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); } else { // all bits from high word, special case needed because // higherBitBound is multiple of 64 and lw not shifted away l = hw; } // (2) if (l < 0) { // condition means the highest bit is one long x = ~l; if (x != 0) { int leadingOnes = numberOfLeadingZeros(x); higherBitBound -= leadingOnes; bitsFromLowWord += leadingOnes; // (3) int flw; if ((flw = bitsFromLowWord - 64) >= 0) { bitsFromLowWord = flw; continue; // long loop } l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); } else { // all bits are ones, skip a whole word, // bitsFromLowWord not changed higherBitBound -= 64; continue; // long loop } } while (true) { if ((l & nLeadingOnes) == 0) { long hMask = nLeadingOnes >>> bitsFromLowWord; bytes.writeLong(lowByteIndex + 8, hw ^ hMask); // bitsFromLow - (64 - n) = n - (64 - bitsFromLow) = // = n - bitsFromHigh int bitsFromLowWordToSwitch = bitsFromLowWord - n64Complement; if (bitsFromLowWordToSwitch > 0) { long lMask = ~(ALL_ONES >>> bitsFromLowWordToSwitch); bytes.writeLong(lowByteIndex, lw ^ lMask); } return higherBitBound - numberOfBits; } // n > leading zeros > 0 // > 0 ensured by block (2) int leadingZeros = numberOfLeadingZeros(l); higherBitBound -= leadingZeros; bitsFromLowWord += leadingZeros; // (4) int flw; if ((flw = bitsFromLowWord - 64) >= 0) { bitsFromLowWord = flw; continue longLoop; } // (5) // additions (3) and (4) together ensure that // bitsFromFirstWord > 0, => no need in condition like (1) l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); long x = ~l; if (x != 0) { int leadingOnes = numberOfLeadingZeros(x); higherBitBound -= leadingOnes; bitsFromLowWord += leadingOnes; if ((flw = bitsFromLowWord - 64) >= 0) { bitsFromLowWord = flw; continue longLoop; } // same as (5) l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); } else { // all bits are ones, skip a whole word, // bitsFromLowWord not changed higherBitBound -= 64; continue longLoop; } } } } /** * @throws IllegalArgumentException if {@code numberOfBits} is out of range {@code 0 < * numberOfBits && numberOfBits <= 64} */ @Override public long clearPreviousNContinuousSetBits( long fromIndex, int numberOfBits) { checkNumberOfBits(numberOfBits); if (numberOfBits == 1) return clearPreviousSetBit(fromIndex); if (checkNotFoundIndex(fromIndex)) return NOT_FOUND; int n64Complement = 64 - numberOfBits; long nLeadingOnes = higherBitsIncludingThis(n64Complement); long higherBitBound = fromIndex + 1; long lowLongIndex = longWithThisBit(fromIndex); if (lowLongIndex >= longLength) { lowLongIndex = longLength - 1; higherBitBound = longLength << 6; } int bitsFromLowWord = (64 - (((int) higherBitBound) & 63)) & 63; long lowByteIndex = firstByte(lowLongIndex); // low word, high word long hw, lw = bytes.readLong(lowByteIndex); longLoop: while (true) { hw = lw; lowByteIndex -= 8; if (--lowLongIndex >= 0) { lw = bytes.readLong(lowByteIndex); } else if (lowLongIndex == -1) { lw = 0L; } else { return NOT_FOUND; } long l; if (bitsFromLowWord != 0) { // (1) l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); } else { // all bits from high word, special case needed because // higherBitBound is multiple of 64 and lw not shifted away l = hw; } // (2) if (l > 0) { // condition means the highest bit is zero, but not all int leadingZeros = numberOfLeadingZeros(l); higherBitBound -= leadingZeros; bitsFromLowWord += leadingZeros; // (3) int flw; if ((flw = bitsFromLowWord - 64) >= 0) { bitsFromLowWord = flw; continue; // long loop } l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); } else if (l == 0) { // all bits are zeros, skip a whole word, // bitsFromLowWord not changed higherBitBound -= 64; continue; // long loop } while (true) { if (((~l) & nLeadingOnes) == 0) { long hMask = nLeadingOnes >>> bitsFromLowWord; bytes.writeLong(lowByteIndex + 8, hw ^ hMask); // bitsFromLow - (64 - n) = n - (64 - bitsFromLow) = // = n - bitsFromHigh int bitsFromLowWordToSwitch = bitsFromLowWord - n64Complement; if (bitsFromLowWordToSwitch > 0) { long lMask = ~(ALL_ONES >>> bitsFromLowWordToSwitch); bytes.writeLong(lowByteIndex, lw ^ lMask); } return higherBitBound - numberOfBits; } // n > leading ones > 0 // > 0 ensured by block (2) int leadingOnes = numberOfLeadingZeros(~l); higherBitBound -= leadingOnes; bitsFromLowWord += leadingOnes; // (4) int flw; if ((flw = bitsFromLowWord - 64) >= 0) { bitsFromLowWord = flw; continue longLoop; } // (5) // additions (3) and (4) together ensure that // bitsFromFirstWord > 0, => no need in condition like (1) l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); if (l != 0) { int leadingZeros = numberOfLeadingZeros(l); higherBitBound -= leadingZeros; bitsFromLowWord += leadingZeros; if ((flw = bitsFromLowWord - 64) >= 0) { bitsFromLowWord = flw; continue longLoop; } // same as (5) l = (lw >>> higherBitBound) | (hw << bitsFromLowWord); } else { // all bits are zeros, skip a whole word, // bitsFromLowWord not changed higherBitBound -= 64; continue longLoop; } } } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("SingleThreadedBitSet{"); sb.append("size=" + size()); sb.append(", cardinality=" + cardinality()); sb.append(", bits=["); for (long i = 0L; i < longLength; i++) { sb.append(Long.toBinaryString(readLong(i))); } sb.append("]}"); return sb.toString(); } private class SetBits implements Bits { private final long byteLength = longLength << 3; private long byteIndex = 0; private long bitIndex = -1; private long currentWord = bytes.readLong(0); @Override public long next() { long l; if ((l = currentWord) != 0) { int trailingZeros = numberOfTrailingZeros(l); currentWord = (l >>> trailingZeros) >>> 1; return bitIndex += trailingZeros + 1; } for (long i = byteIndex, lim = byteLength; (i += 8) < lim; ) { if ((l = bytes.readLong(i)) != 0) { byteIndex = i; int trailingZeros = numberOfTrailingZeros(l); currentWord = (l >>> trailingZeros) >>> 1; return bitIndex = (i << 3) + trailingZeros; } } currentWord = 0; byteIndex = byteLength; return -1; } } }