consumer) {
- this.threadSafe = threadSafe;
- this.bitSetSize = size;
- this.consumer = consumer;
- }
-
- /**
- * Adds the specified range to this {@code RangeSet} (optional operation). That is, for equal range sets a and b,
- * the result of {@code a.add(range)} is that {@code a} will be the minimal range set for which both
- * {@code a.enclosesAll(b)} and {@code a.encloses(range)}.
- *
- * Note that {@code range} will merge given {@code range} with any ranges in the range set that are
- * {@linkplain Range#isConnected(Range) connected} with it. Moreover, if {@code range} is empty, this is a no-op.
- */
- @Override
- public void addOpenClosed(long lowerKey, long lowerValueOpen, long upperKey, long upperValue) {
- long lowerValue = lowerValueOpen + 1;
- if (lowerKey != upperKey) {
- // (1) set lower to last in lowerRange.getKey()
- if (isValid(lowerKey, lowerValue)) {
- BitSet rangeBitSet = rangeBitSetMap.get(lowerKey);
- // if lower and upper has different key/ledger then set ranges for lower-key only if
- // a. bitSet already exist and given value is not the last value in the bitset.
- // it will prevent setting up values which are not actually expected to set
- // eg: (2:10..4:10] in this case, don't set any value for 2:10 and set [4:0..4:10]
- if (rangeBitSet != null && (rangeBitSet.previousSetBit(rangeBitSet.size()) > lowerValueOpen)) {
- int lastValue = rangeBitSet.previousSetBit(rangeBitSet.size());
- rangeBitSet.set((int) lowerValue, (int) Math.max(lastValue, lowerValue) + 1);
- }
- }
- // (2) set 0th-index to upper-index in upperRange.getKey()
- if (isValid(upperKey, upperValue)) {
- BitSet rangeBitSet = rangeBitSetMap.computeIfAbsent(upperKey, (key) -> createNewBitSet());
- if (rangeBitSet != null) {
- rangeBitSet.set(0, (int) upperValue + 1);
- }
- }
- // No-op if values are not valid eg: if lower == LongPair.earliest or upper == LongPair.latest then nothing
- // to set
- } else {
- long key = lowerKey;
- BitSet rangeBitSet = rangeBitSetMap.computeIfAbsent(key, (k) -> createNewBitSet());
- rangeBitSet.set((int) lowerValue, (int) upperValue + 1);
- }
- updatedAfterCachedForSize = true;
- updatedAfterCachedForToString = true;
- }
-
- private boolean isValid(long key, long value) {
- return key != LongPair.earliest.getKey() && value != LongPair.earliest.getValue()
- && key != LongPair.latest.getKey() && value != LongPair.latest.getValue();
- }
-
- @Override
- public boolean contains(long key, long value) {
-
- BitSet rangeBitSet = rangeBitSetMap.get(key);
- if (rangeBitSet != null) {
- return rangeBitSet.get(getSafeEntry(value));
- }
- return false;
- }
-
- @Override
- public Range rangeContaining(long key, long value) {
- BitSet rangeBitSet = rangeBitSetMap.get(key);
- if (rangeBitSet != null) {
- if (!rangeBitSet.get(getSafeEntry(value))) {
- // if position is not part of any range then return null
- return null;
- }
- int lowerValue = rangeBitSet.previousClearBit(getSafeEntry(value)) + 1;
- final T lower = consumer.apply(key, lowerValue);
- final T upper = consumer.apply(key,
- Math.max(rangeBitSet.nextClearBit(getSafeEntry(value)) - 1, lowerValue));
- return Range.closed(lower, upper);
- }
- return null;
- }
-
- @Override
- public void removeAtMost(long key, long value) {
- this.remove(Range.atMost(new LongPair(key, value)));
- }
-
- @Override
- public boolean isEmpty() {
- if (rangeBitSetMap.isEmpty()) {
- return true;
- }
- for (BitSet rangeBitSet : rangeBitSetMap.values()) {
- if (!rangeBitSet.isEmpty()) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public void clear() {
- rangeBitSetMap.clear();
- updatedAfterCachedForSize = true;
- updatedAfterCachedForToString = true;
- }
-
- @Override
- public Range span() {
- if (rangeBitSetMap.isEmpty()) {
- return null;
- }
- Entry firstSet = rangeBitSetMap.firstEntry();
- Entry lastSet = rangeBitSetMap.lastEntry();
- int first = firstSet.getValue().nextSetBit(0);
- int last = lastSet.getValue().previousSetBit(lastSet.getValue().size());
- return Range.openClosed(consumer.apply(firstSet.getKey(), first - 1), consumer.apply(lastSet.getKey(), last));
- }
-
- @Override
- public List> asRanges() {
- List> ranges = new ArrayList<>();
- forEach((range) -> {
- ranges.add(range);
- return true;
- });
- return ranges;
- }
-
- @Override
- public void forEach(RangeProcessor action) {
- forEach(action, consumer);
- }
-
- @Override
- public void forEach(RangeProcessor action, LongPairConsumer extends T> consumerParam) {
- forEachRawRange((lowerKey, lowerValue, upperKey, upperValue) -> {
- Range range = Range.openClosed(
- consumerParam.apply(lowerKey, lowerValue),
- consumerParam.apply(upperKey, upperValue)
- );
- return action.process(range);
- });
- }
-
- @Override
- public void forEachRawRange(RawRangeProcessor processor) {
- AtomicBoolean completed = new AtomicBoolean(false);
- rangeBitSetMap.forEach((key, set) -> {
- if (completed.get()) {
- return;
- }
- if (set.isEmpty()) {
- return;
- }
- int first = set.nextSetBit(0);
- int last = set.previousSetBit(set.size());
- int currentClosedMark = first;
- while (currentClosedMark != -1 && currentClosedMark <= last) {
- int nextOpenMark = set.nextClearBit(currentClosedMark);
- if (!processor.processRawRange(key, currentClosedMark - 1,
- key, nextOpenMark - 1)) {
- completed.set(true);
- break;
- }
- currentClosedMark = set.nextSetBit(nextOpenMark);
- }
- });
- }
-
-
- @Override
- public Range firstRange() {
- if (rangeBitSetMap.isEmpty()) {
- return null;
- }
- Entry firstSet = rangeBitSetMap.firstEntry();
- int lower = firstSet.getValue().nextSetBit(0);
- int upper = Math.max(lower, firstSet.getValue().nextClearBit(lower) - 1);
- return Range.openClosed(consumer.apply(firstSet.getKey(), lower - 1), consumer.apply(firstSet.getKey(), upper));
- }
-
- @Override
- public Range lastRange() {
- if (rangeBitSetMap.isEmpty()) {
- return null;
- }
- Entry lastSet = rangeBitSetMap.lastEntry();
- int upper = lastSet.getValue().previousSetBit(lastSet.getValue().size());
- int lower = Math.min(lastSet.getValue().previousClearBit(upper), upper);
- return Range.openClosed(consumer.apply(lastSet.getKey(), lower), consumer.apply(lastSet.getKey(), upper));
- }
-
- @Override
- public int cardinality(long lowerKey, long lowerValue, long upperKey, long upperValue) {
- NavigableMap subMap = rangeBitSetMap.subMap(lowerKey, true, upperKey, true);
- MutableInt v = new MutableInt(0);
- subMap.forEach((key, bitset) -> {
- if (key == lowerKey || key == upperKey) {
- BitSet temp = (BitSet) bitset.clone();
- // Trim the bitset index which < lowerValue
- if (key == lowerKey) {
- temp.clear(0, (int) Math.max(0, lowerValue));
- }
- // Trim the bitset index which > upperValue
- if (key == upperKey) {
- temp.clear((int) Math.min(upperValue + 1, temp.length()), temp.length());
- }
- v.add(temp.cardinality());
- } else {
- v.add(bitset.cardinality());
- }
- });
- return v.intValue();
- }
-
- @Override
- public int size() {
- if (updatedAfterCachedForSize) {
- MutableInt size = new MutableInt(0);
-
- // ignore result because we just want to count
- forEachRawRange((lowerKey, lowerValue, upperKey, upperValue) -> {
- size.increment();
- return true;
- });
-
- cachedSize = size.intValue();
- updatedAfterCachedForSize = false;
- }
- return cachedSize;
- }
-
- @Override
- public String toString() {
- if (updatedAfterCachedForToString) {
- StringBuilder toString = new StringBuilder();
- AtomicBoolean first = new AtomicBoolean(true);
- if (toString != null) {
- toString.append("[");
- }
- forEach((range) -> {
- if (!first.get()) {
- toString.append(",");
- }
- toString.append(range);
- first.set(false);
- return true;
- });
- toString.append("]");
- cachedToString = toString.toString();
- updatedAfterCachedForToString = false;
- }
- return cachedToString;
- }
-
- /**
- * Adds the specified range to this {@code RangeSet} (optional operation). That is, for equal range sets a and b,
- * the result of {@code a.add(range)} is that {@code a} will be the minimal range set for which both
- * {@code a.enclosesAll(b)} and {@code a.encloses(range)}.
- *
- * Note that {@code range} will merge given {@code range} with any ranges in the range set that are
- * {@linkplain Range#isConnected(Range) connected} with it. Moreover, if {@code range} is empty/invalid, this is a
- * no-op.
- */
- public void add(Range range) {
- LongPair lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : LongPair.earliest;
- LongPair upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : LongPair.latest;
-
- long lowerValueOpen = (range.hasLowerBound() && range.lowerBoundType().equals(BoundType.CLOSED))
- ? getSafeEntry(lowerEndpoint) - 1
- : getSafeEntry(lowerEndpoint);
- long upperValueClosed = (range.hasUpperBound() && range.upperBoundType().equals(BoundType.CLOSED))
- ? getSafeEntry(upperEndpoint)
- : getSafeEntry(upperEndpoint) + 1;
-
- // #addOpenClosed doesn't create bitSet for lower-key because it avoids setting up values for non-exist items
- // into the key-ledger. so, create bitSet and initialize so, it can't be ignored at #addOpenClosed
- rangeBitSetMap.computeIfAbsent(lowerEndpoint.getKey(), (key) -> createNewBitSet())
- .set((int) lowerValueOpen + 1);
- this.addOpenClosed(lowerEndpoint.getKey(), lowerValueOpen, upperEndpoint.getKey(), upperValueClosed);
- }
-
- public boolean contains(LongPair position) {
- requireNonNull(position, "argument can't be null");
- return contains(position.getKey(), position.getValue());
- }
-
- public void remove(Range range) {
- LongPair lowerEndpoint = range.hasLowerBound() ? range.lowerEndpoint() : LongPair.earliest;
- LongPair upperEndpoint = range.hasUpperBound() ? range.upperEndpoint() : LongPair.latest;
-
- long lower = (range.hasLowerBound() && range.lowerBoundType().equals(BoundType.CLOSED))
- ? getSafeEntry(lowerEndpoint)
- : getSafeEntry(lowerEndpoint) + 1;
- long upper = (range.hasUpperBound() && range.upperBoundType().equals(BoundType.CLOSED))
- ? getSafeEntry(upperEndpoint)
- : getSafeEntry(upperEndpoint) - 1;
-
- // if lower-bound is not set then remove all the keys less than given upper-bound range
- if (lowerEndpoint.equals(LongPair.earliest)) {
- // remove all keys with
- rangeBitSetMap.forEach((key, set) -> {
- if (key < upperEndpoint.getKey()) {
- rangeBitSetMap.remove(key);
- }
- });
- }
-
- // if upper-bound is not set then remove all the keys greater than given lower-bound range
- if (upperEndpoint.equals(LongPair.latest)) {
- // remove all keys with
- rangeBitSetMap.forEach((key, set) -> {
- if (key > lowerEndpoint.getKey()) {
- rangeBitSetMap.remove(key);
- }
- });
- }
-
- // remove all the keys between two endpoint keys
- rangeBitSetMap.forEach((key, set) -> {
- if (lowerEndpoint.getKey() == upperEndpoint.getKey() && key == upperEndpoint.getKey()) {
- set.clear((int) lower, (int) upper + 1);
- } else {
- // eg: remove-range: [(3,5) - (5,5)] -> Delete all items from 3,6->3,N,4.*,5,0->5,5
- if (key == lowerEndpoint.getKey()) {
- // remove all entries from given position to last position
- set.clear((int) lower, set.previousSetBit(set.size()));
- } else if (key == upperEndpoint.getKey()) {
- // remove all entries from 0 to given position
- set.clear(0, (int) upper + 1);
- } else if (key > lowerEndpoint.getKey() && key < upperEndpoint.getKey()) {
- rangeBitSetMap.remove(key);
- }
- }
- // remove bit-set if set is empty
- if (set.isEmpty()) {
- rangeBitSetMap.remove(key);
- }
- });
-
- updatedAfterCachedForSize = true;
- updatedAfterCachedForToString = true;
- }
-
- private int getSafeEntry(LongPair position) {
- return (int) Math.max(position.getValue(), -1);
- }
-
- private int getSafeEntry(long value) {
- return (int) Math.max(value, -1);
- }
-
- private BitSet createNewBitSet() {
- return this.threadSafe ? new ConcurrentBitSet(bitSetSize) : new BitSet(bitSetSize);
- }
-
-}
\ No newline at end of file