/* * 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; import static net.openhft.lang.collection.SingleThreadedDirectBitSet.*; /** * DirectBitSet with input validations and ThreadSafe memory access. */ public class ATSDirectBitSet implements DirectBitSet { private final Bytes bytes; private final long longLength; private ATSDirectBitSet(Bytes bytes) { this.bytes = bytes; assert (bytes.capacity() & 7) == 0; longLength = bytes.capacity() >> 3; } public static DirectBitSet wrap(Bytes bytes) { return new ATSDirectBitSet(bytes); } private static long rightShiftOneFill(long l, long shift) { return (l >> shift) | ~(ALL_ONES >>> shift); } private static long leftShiftOneFill(long l, long shift) { return (l << shift) | ((1L << shift) - 1L); } private long readLong(long longIndex) { return bytes.readLong(firstByte(longIndex)); } private long readVolatileLong(long longIndex) { return bytes.readVolatileLong(firstByte(longIndex)); } @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); if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); long byteIndex = firstByte(longIndex); // only 6 lowest-order bits used, JLS 15.19 long mask = singleBit(bitIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); long l2 = l ^ mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return this; } } @Override public DirectBitSet flip(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); if (fromIndex < 0 || fromIndex > exclusiveToIndex || toLongIndex >= longLength) throw new IndexOutOfBoundsException(); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long fromByteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex); while (true) { long l = bytes.readVolatileLong(fromByteIndex); long l2 = l ^ mask; if (bytes.compareAndSwapLong(fromByteIndex, l, l2)) break; } firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { while (true) { long l = readVolatileLong(i); long l2 = ~l; if (bytes.compareAndSwapLong(firstByte(i), l, l2)) break; } } } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { while (true) { long l = readVolatileLong(i); long l2 = ~l; if (bytes.compareAndSwapLong(firstByte(i), l, l2)) break; } } long toByteIndex = firstByte(toLongIndex); long mask = lowerBitsIncludingThis(toIndex); while (true) { long l = bytes.readVolatileLong(toByteIndex); long l2 = l ^ mask; if (bytes.compareAndSwapLong(toByteIndex, l, l2)) return this; } } } else { long byteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); long l2 = l ^ mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return this; } } return this; } @Override public DirectBitSet set(long bitIndex) { long longIndex = longWithThisBit(bitIndex); if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); if ((l & mask) != 0) return this; long l2 = l | mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return this; } } @Override public boolean setIfClear(long bitIndex) { long longIndex = longWithThisBit(bitIndex); if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); long l2 = l | mask; if (l == l2) return false; if (bytes.compareAndSwapLong(byteIndex, l, 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); if (fromIndex < 0 || fromIndex > exclusiveToIndex || toLongIndex >= longLength) throw new IndexOutOfBoundsException(); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long fromByteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex); while (true) { long l = bytes.readVolatileLong(fromByteIndex); long l2 = l | mask; if (bytes.compareAndSwapLong(fromByteIndex, l, l2)) break; } firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { bytes.writeLong(firstByte(i), ALL_ONES); } } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { bytes.writeLong(firstByte(i), ALL_ONES); } long toByteIndex = firstByte(toLongIndex); long mask = lowerBitsIncludingThis(toIndex); while (true) { long l = bytes.readVolatileLong(toByteIndex); long l2 = l | mask; if (bytes.compareAndSwapLong(toByteIndex, l, l2)) return this; } } } else { long byteIndex = firstByte(fromLongIndex); long mask = higherBitsIncludingThis(fromIndex) & lowerBitsIncludingThis(toIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); long l2 = l | mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return this; } } return this; } @Override public DirectBitSet setAll() { for (long i = 0; i < longLength; i++) { bytes.writeLong(firstByte(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); if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); if ((l & mask) == 0) return this; long l2 = l & ~mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return this; } } @Override public boolean clearIfSet(long bitIndex) { long longIndex = longWithThisBit(bitIndex); if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); long byteIndex = firstByte(longIndex); long mask = singleBit(bitIndex); while (true) { long l = bytes.readVolatileLong(byteIndex); if ((l & mask) == 0) return false; long l2 = l & ~mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return true; } } @Override public DirectBitSet clear(long fromIndex, long exclusiveToIndex) { long fromLongIndex = longWithThisBit(fromIndex); long toIndex = exclusiveToIndex - 1; long toLongIndex = longWithThisBit(toIndex); if (fromIndex < 0 || fromIndex > exclusiveToIndex || toLongIndex >= longLength) throw new IndexOutOfBoundsException(); if (fromLongIndex != toLongIndex) { long firstFullLongIndex = fromLongIndex; if ((fromIndex & 63) != 0) { long fromByteIndex = firstByte(fromLongIndex); long mask = lowerBitsExcludingThis(fromIndex); while (true) { long l = bytes.readVolatileLong(fromByteIndex); long l2 = l & mask; if (bytes.compareAndSwapLong(fromByteIndex, l, l2)) break; } firstFullLongIndex++; } if ((exclusiveToIndex & 63) == 0) { for (long i = firstFullLongIndex; i <= toLongIndex; i++) { bytes.writeLong(firstByte(i), 0L); } } else { for (long i = firstFullLongIndex; i < toLongIndex; i++) { bytes.writeLong(firstByte(i), 0L); } long toByteIndex = firstByte(toLongIndex); long mask = higherBitsExcludingThis(toIndex); while (true) { long l = bytes.readVolatileLong(toByteIndex); long l2 = l & mask; if (bytes.compareAndSwapLong(toByteIndex, l, l2)) return this; } } } else { long byteIndex = firstByte(fromLongIndex); long mask = lowerBitsExcludingThis(fromIndex) | (higherBitsExcludingThis(toIndex)); while (true) { long l = bytes.readVolatileLong(byteIndex); long l2 = l & mask; if (bytes.compareAndSwapLong(byteIndex, l, l2)) return this; } } return this; } @Override public DirectBitSet clear() { bytes.zeroOut(); return this; } @Override public boolean get(long bitIndex) { long longIndex = longWithThisBit(bitIndex); if (bitIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); long l = readVolatileLong(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) { if (longIndex < 0 || longIndex >= longLength) throw new IndexOutOfBoundsException(); return readVolatileLong(longIndex); } @Override public long nextSetBit(long fromIndex) { return bytes.nextSetBit(fromIndex); } @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); while (true) { long w = bytes.readVolatileLong(fromByteIndex); long l = w >>> fromIndex; if (l != 0) { long indexOfSetBit = fromIndex + numberOfTrailingZeros(l); long mask = singleBit(indexOfSetBit); if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask)) return indexOfSetBit; } else { break; } } longLoop: for (long i = fromLongIndex + 1; i < longLength; i++) { long byteIndex = firstByte(i); while (true) { long l = bytes.readLong(byteIndex); if (l != 0) { long indexOfSetBit = firstBit(i) + numberOfTrailingZeros(l); long mask = singleBit(indexOfSetBit); if (bytes.compareAndSwapLong(byteIndex, l, l ^ mask)) return indexOfSetBit; } else { continue longLoop; } } } return NOT_FOUND; } @Override public long nextSetLong(long fromLongIndex) { if (fromLongIndex < 0) throw new IndexOutOfBoundsException(); if (fromLongIndex >= longLength) return NOT_FOUND; if (readVolatileLong(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 = (~readVolatileLong(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); while (true) { long w = bytes.readVolatileLong(fromByteIndex); long l = (~w) >>> fromIndex; if (l != 0) { long indexOfClearBit = fromIndex + numberOfTrailingZeros(l); long mask = singleBit(indexOfClearBit); if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask)) return indexOfClearBit; } else { break; } } longLoop: for (long i = fromLongIndex + 1; i < longLength; i++) { long byteIndex = firstByte(i); while (true) { long w = bytes.readLong(byteIndex); long l = ~w; if (l != 0) { long indexOfClearBit = firstBit(i) + numberOfTrailingZeros(l); long mask = singleBit(indexOfClearBit); if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) return indexOfClearBit; } else { continue longLoop; } } } return NOT_FOUND; } @Override public long nextClearLong(long fromLongIndex) { if (fromLongIndex < 0) throw new IndexOutOfBoundsException(); if (fromLongIndex >= longLength) return NOT_FOUND; if (readVolatileLong(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 = readVolatileLong(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 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); while (true) { long w = bytes.readVolatileLong(fromByteIndex); long l = w << ~fromIndex; if (l != 0) { long indexOfSetBit = fromIndex - numberOfLeadingZeros(l); long mask = singleBit(indexOfSetBit); if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask)) return indexOfSetBit; } else { break; } } longLoop: for (long i = fromLongIndex - 1; i >= 0; i--) { long byteIndex = firstByte(i); while (true) { long l = bytes.readLong(byteIndex); if (l != 0) { long indexOfSetBit = lastBit(i) - numberOfLeadingZeros(l); long mask = singleBit(indexOfSetBit); if (bytes.compareAndSwapLong(byteIndex, l, l ^ mask)) return indexOfSetBit; } else { continue longLoop; } } } return NOT_FOUND; } @Override public long previousSetLong(long fromLongIndex) { if (checkNotFoundIndex(fromLongIndex)) return NOT_FOUND; if (fromLongIndex >= longLength) fromLongIndex = longLength - 1; if (readVolatileLong(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 = (~readVolatileLong(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); while (true) { long w = bytes.readVolatileLong(fromByteIndex); long l = (~w) << ~fromIndex; if (l != 0) { long indexOfClearBit = fromIndex - numberOfLeadingZeros(l); long mask = singleBit(indexOfClearBit); if (bytes.compareAndSwapLong(fromByteIndex, w, w ^ mask)) return indexOfClearBit; } else { break; } } longLoop: for (long i = fromLongIndex - 1; i >= 0; i--) { long byteIndex = firstByte(i); while (true) { long w = bytes.readLong(byteIndex); long l = ~w; if (l != 0) { long indexOfClearBit = lastBit(i) - numberOfLeadingZeros(l); long mask = singleBit(indexOfClearBit); if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) return indexOfClearBit; } else { continue longLoop; } } } return NOT_FOUND; } @Override public long previousClearLong(long fromLongIndex) { if (checkNotFoundIndex(fromLongIndex)) return NOT_FOUND; if (fromLongIndex >= longLength) fromLongIndex = longLength - 1; if (readVolatileLong(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 = Long.bitCount(bytes.readVolatileLong(0)); for (long i = 1; i < longLength; i++) { count += Long.bitCount(readLong(i)); } return count; } @Override public DirectBitSet and(long longIndex, long value) { while (true) { long l = readVolatileLong(longIndex); long l2 = l & value; if (l == l2 || bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this; } } @Override public DirectBitSet or(long longIndex, long value) { while (true) { long l = readVolatileLong(longIndex); long l2 = l | value; if (l == l2 || bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this; } } @Override public DirectBitSet xor(long longIndex, long value) { while (true) { long l = readVolatileLong(longIndex); long l2 = l ^ value; if (bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this; } } @Override public DirectBitSet andNot(long longIndex, long value) { while (true) { long l = readVolatileLong(longIndex); long l2 = l & ~value; if (bytes.compareAndSwapLong(firstByte(longIndex), l, l2)) return this; } } /** * WARNING! This implementation doesn't strictly follow the contract * from {@code DirectBitSet} interface. For the sake of atomicity this * implementation couldn't find and flip the range crossing native word * boundary, e. g. bits from 55 to 75 (boundary is 64). * * @throws IllegalArgumentException if {@code numberOfBits} * is out of range {@code 0 < numberOfBits && numberOfBits <= 64} */ @Override public long setNextNContinuousClearBits(long fromIndex, int numberOfBits) { checkNumberOfBits(numberOfBits); if (numberOfBits == 1) return setNextClearBit(fromIndex); if (fromIndex < 0) throw new IndexOutOfBoundsException(); int n64Complement = 64 - numberOfBits; long nTrailingOnes = ALL_ONES >>> n64Complement; long bitIndex = fromIndex; long longIndex = longWithThisBit(bitIndex); long byteIndex = firstByte(longIndex); long w, l; if ((bitIndex & 63) > n64Complement) { if (++longIndex >= longLength) return NOT_FOUND; byteIndex += 8; bitIndex = firstBit(longIndex); l = w = bytes.readVolatileLong(byteIndex); } else { if (longIndex >= longLength) return NOT_FOUND; w = bytes.readVolatileLong(byteIndex); l = rightShiftOneFill(w, bitIndex); } // long loop while (true) { continueLongLoop: { // (1) if ((l & 1) != 0) { long x = ~l; if (x != 0) { int trailingOnes = numberOfTrailingZeros(x); bitIndex += trailingOnes; // i. e. bitIndex + numberOfBits crosses 64 boundary if ((bitIndex & 63) > n64Complement) break continueLongLoop; // (2) l = rightShiftOneFill(l, trailingOnes); } else { // all bits are ones, go to the next long break continueLongLoop; } } // bit search within a long while (true) { // CAS retry loop while ((l & nTrailingOnes) == 0) { long mask = nTrailingOnes << bitIndex; if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) { return bitIndex; } else { w = bytes.readLong(byteIndex); l = rightShiftOneFill(w, bitIndex); } } // n > trailing zeros > 0 // > 0 ensured by block (1) int trailingZeros = numberOfTrailingZeros(l); bitIndex += trailingZeros; // (3) l = rightShiftOneFill(l, trailingZeros); long x = ~l; if (x != 0) { int trailingOnes = numberOfTrailingZeros(x); bitIndex += trailingOnes; // i. e. bitIndex + numberOfBits crosses 64 boundary if ((bitIndex & 63) > n64Complement) break continueLongLoop; // already shifted with one-filling at least once // at (2) or (3), => garanteed highest bit is 1 => // "natural" one-filling l >>= trailingOnes; } else { // zeros in this long exhausted, go to the next long break continueLongLoop; } } } if (++longIndex >= longLength) return NOT_FOUND; byteIndex += 8; bitIndex = firstBit(longIndex); l = w = bytes.readLong(byteIndex); } } /** * WARNING! This implementation doesn't strictly follow the contract * from {@code DirectBitSet} interface. For the sake of atomicity this * implementation couldn't find and flip the range crossing native word * boundary, e. g. bits from 55 to 75 (boundary is 64). * * @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(); int n64Complement = 64 - numberOfBits; long nTrailingOnes = ALL_ONES >>> n64Complement; long bitIndex = fromIndex; long longIndex = longWithThisBit(bitIndex); long byteIndex = firstByte(longIndex); long w, l; if ((bitIndex & 63) > n64Complement) { if (++longIndex >= longLength) return NOT_FOUND; byteIndex += 8; bitIndex = firstBit(longIndex); l = w = bytes.readVolatileLong(byteIndex); } else { if (longIndex >= longLength) return NOT_FOUND; w = bytes.readVolatileLong(byteIndex); l = w >>> bitIndex; } // long loop while (true) { continueLongLoop: { if ((l & 1) == 0) { if (l != 0) { int trailingZeros = numberOfTrailingZeros(l); bitIndex += trailingZeros; // i. e. bitIndex + numberOfBits crosses 64 boundary if ((bitIndex & 63) > n64Complement) break continueLongLoop; l >>>= trailingZeros; } else { // all bits are zeros, go to the next long break continueLongLoop; } } // bit search within a long while (true) { // CAS retry loop while (((~l) & nTrailingOnes) == 0) { long mask = nTrailingOnes << bitIndex; if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) { return bitIndex; } else { w = bytes.readLong(byteIndex); l = w >>> bitIndex; } } // n > trailing ones > 0 int trailingOnes = numberOfTrailingZeros(~l); bitIndex += trailingOnes; l >>>= trailingOnes; if (l != 0) { int trailingZeros = numberOfTrailingZeros(l); bitIndex += trailingZeros; // i. e. bitIndex + numberOfBits crosses 64 boundary if ((bitIndex & 63) > n64Complement) break continueLongLoop; l >>>= trailingZeros; } else { // ones in this long exhausted, go to the next long break continueLongLoop; } } } if (++longIndex >= longLength) return NOT_FOUND; byteIndex += 8; bitIndex = firstBit(longIndex); l = w = bytes.readLong(byteIndex); } } /** * WARNING! This implementation doesn't strictly follow the contract * from {@code DirectBitSet} interface. For the sake of atomicity this * implementation couldn't find and flip the range crossing native word * boundary, e. g. bits from 55 to 75 (boundary is 64). * * @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 numberOfBitsMinusOne = numberOfBits - 1; long nLeadingOnes = ALL_ONES << (64 - numberOfBits); long bitIndex = fromIndex; long longIndex = longWithThisBit(bitIndex); if (longIndex >= longLength) { longIndex = longLength - 1; bitIndex = lastBit(longIndex); } long byteIndex = firstByte(longIndex); long w, l; if ((bitIndex & 63) < numberOfBitsMinusOne) { if (--longIndex < 0) return NOT_FOUND; byteIndex -= 8; bitIndex = lastBit(longIndex); l = w = bytes.readVolatileLong(byteIndex); } else { w = bytes.readVolatileLong(byteIndex); // left shift by ~bitIndex === left shift by (63 - (bitIndex & 63)) l = leftShiftOneFill(w, ~bitIndex); } // long loop while (true) { continueLongLoop: { if (l < 0) { // condition means the highest bit is one long x = ~l; if (x != 0) { int leadingOnes = numberOfLeadingZeros(x); bitIndex -= leadingOnes; if ((bitIndex & 63) < numberOfBitsMinusOne) break continueLongLoop; l = leftShiftOneFill(l, leadingOnes); } else { // all bits are ones, go to the next long break continueLongLoop; } } // bit search within a long while (true) { // CAS retry loop while ((l & nLeadingOnes) == 0) { // >>> ~bitIndex === >>> (63 - (butIndex & 63)) long mask = nLeadingOnes >>> ~bitIndex; if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) { return bitIndex - numberOfBitsMinusOne; } else { w = bytes.readLong(byteIndex); l = leftShiftOneFill(w, ~bitIndex); } } // n > leading zeros > 0 int leadingZeros = numberOfLeadingZeros(l); bitIndex -= leadingZeros; l = leftShiftOneFill(l, leadingZeros); long x = ~l; if (x != 0) { int leadingOnes = numberOfLeadingZeros(x); bitIndex -= leadingOnes; if ((bitIndex & 63) < numberOfBitsMinusOne) break continueLongLoop; l = leftShiftOneFill(l, leadingOnes); } else { // zeros in this long exhausted, go to the next long break continueLongLoop; } } } if (--longIndex < 0) return NOT_FOUND; byteIndex -= 8; bitIndex = lastBit(longIndex); l = w = bytes.readLong(byteIndex); } } /** * WARNING! This implementation doesn't strictly follow the contract * from {@code DirectBitSet} interface. For the sake of atomicity this * implementation couldn't find and flip the range crossing native word * boundary, e. g. bits from 55 to 75 (boundary is 64). * * @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 numberOfBitsMinusOne = numberOfBits - 1; long nLeadingOnes = ALL_ONES << (64 - numberOfBits); long bitIndex = fromIndex; long longIndex = longWithThisBit(bitIndex); if (longIndex >= longLength) { longIndex = longLength - 1; bitIndex = lastBit(longIndex); } long byteIndex = firstByte(longIndex); long w, l; if ((bitIndex & 63) < numberOfBitsMinusOne) { if (--longIndex < 0) return NOT_FOUND; byteIndex -= 8; bitIndex = lastBit(longIndex); l = w = bytes.readVolatileLong(byteIndex); } else { w = bytes.readVolatileLong(byteIndex); // << ~bitIndex === << (63 - (bitIndex & 63)) l = w << ~bitIndex; } // long loop while (true) { continueLongLoop: { // condition means the highest bit is zero, but not all if (l > 0) { int leadingZeros = numberOfLeadingZeros(l); bitIndex -= leadingZeros; if ((bitIndex & 63) < numberOfBitsMinusOne) break continueLongLoop; l <<= leadingZeros; } else if (l == 0) { // all bits are zeros, go to the next long break continueLongLoop; } // bit search within a long while (true) { // CAS retry loop while (((~l) & nLeadingOnes) == 0) { // >>> ~bitIndex === >>> (63 - (butIndex & 63)) long mask = nLeadingOnes >>> ~bitIndex; if (bytes.compareAndSwapLong(byteIndex, w, w ^ mask)) { return bitIndex - numberOfBitsMinusOne; } else { w = bytes.readLong(byteIndex); l = w << ~bitIndex; } } // n > leading ones > 0 int leadingOnes = numberOfLeadingZeros(~l); bitIndex -= leadingOnes; l <<= leadingOnes; if (l != 0) { int leadingZeros = numberOfLeadingZeros(l); bitIndex -= leadingZeros; if ((bitIndex & 63) < numberOfBitsMinusOne) break continueLongLoop; l <<= leadingZeros; } else { // ones in this long exhausted, go to the next long break continueLongLoop; } } } if (--longIndex < 0) return NOT_FOUND; byteIndex -= 8; bitIndex = lastBit(longIndex); l = w = bytes.readLong(byteIndex); } } private class SetBits implements Bits { private final long byteLength = longLength << 3; private long byteIndex = 0; private long bitIndex = 0; @Override public long next() { long bitIndex = this.bitIndex; if (bitIndex >= 0) { long i = byteIndex; long l = bytes.readVolatileLong(i) >>> bitIndex; if (l != 0) { int trailingZeros = numberOfTrailingZeros(l); long index = bitIndex + trailingZeros; if (((this.bitIndex = index + 1) & 63) == 0) { if ((byteIndex = i + 8) == byteLength) this.bitIndex = -1; } return index; } for (long lim = byteLength; (i += 8) < lim; ) { if ((l = bytes.readLong(i)) != 0) { int trailingZeros = numberOfTrailingZeros(l); long index = (i << 3) + trailingZeros; if (((this.bitIndex = index + 1) & 63) != 0) { byteIndex = i; } else { if ((byteIndex = i + 8) == lim) this.bitIndex = -1; } return index; } } } this.bitIndex = -1; return -1; } } }