- * In practice, calls {#link naive_and}
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap and(Iterator
- * In practice, calls {#link naive_and}
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap and(RoaringBitmap... bitmaps) {
- return naive_and(bitmaps);
- }
-
- /**
- * Calls naive_or.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- @Deprecated
- public static RoaringBitmap horizontal_or(Iterator
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #or(RoaringBitmap...)
- */
- public static RoaringBitmap horizontal_or(List
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #or(RoaringBitmap...)
- */
- public static RoaringBitmap horizontal_or(RoaringBitmap... bitmaps) {
- RoaringBitmap answer = new RoaringBitmap();
- if (bitmaps.length == 0) {
- return answer;
- }
- PriorityQueue
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #xor(RoaringBitmap...)
- */
- public static RoaringBitmap horizontal_xor(RoaringBitmap... bitmaps) {
- RoaringBitmap answer = new RoaringBitmap();
- if (bitmaps.length == 0) {
- return answer;
- }
- PriorityQueue
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap naive_and(Iterator
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap naive_and(RoaringBitmap... bitmaps) {
- if (bitmaps.length == 0) {
- return new RoaringBitmap();
- }
- RoaringBitmap answer = bitmaps[0].clone();
- for (int k = 1; k < bitmaps.length; ++k) {
- answer.and(bitmaps[k]);
- }
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap naive_or(Iterator
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap naive_or(RoaringBitmap... bitmaps) {
- RoaringBitmap answer = new RoaringBitmap();
- for (int k = 0; k < bitmaps.length; ++k) {
- answer.naivelazyor(bitmaps[k]);
- }
- answer.repairAfterLazy();
- return answer;
- }
-
- /**
- * Compute overall XOR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap naive_xor(Iterator
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap naive_xor(RoaringBitmap... bitmaps) {
- RoaringBitmap answer = new RoaringBitmap();
- for (int k = 0; k < bitmaps.length; ++k) {
- answer.xor(bitmaps[k]);
- }
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap or(Iterator
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #horizontal_or(RoaringBitmap...)
- */
- public static RoaringBitmap priorityqueue_or(Iterator
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #horizontal_or(RoaringBitmap...)
- */
- public static RoaringBitmap priorityqueue_or(RoaringBitmap... bitmaps) {
- if (bitmaps.length == 0) {
- return new RoaringBitmap();
- }
- // we buffer the call to getSizeInBytes(), hence the code complexity
- final RoaringBitmap[] buffer = Arrays.copyOf(bitmaps, bitmaps.length);
- final long[] sizes = new long[buffer.length];
- final boolean[] istmp = new boolean[buffer.length];
- for (int k = 0; k < sizes.length; ++k) {
- sizes[k] = buffer[k].getLongSizeInBytes();
- }
- PriorityQueue
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #horizontal_xor(RoaringBitmap...)
- */
- public static RoaringBitmap priorityqueue_xor(RoaringBitmap... bitmaps) {
- // TODO: This code could be faster, see priorityqueue_or
- if (bitmaps.length == 0) {
- return new RoaringBitmap();
- }
-
- PriorityQueue
- * * Usage:
- *
- * Internally, this is computed as a 64-bit counter.
- *
- * @return estimated memory usage.
- */
- public int getSizeInBytes();
-
- /**
- * Estimate of the memory usage of this data structure. Provides
- * full 64-bit number.
- *
- * @return estimated memory usage.
- */
- public long getLongSizeInBytes();
-
- /**
- * Checks whether the bitmap is empty.
- *
- * @return true if this bitmap contains no set bit
- */
- public boolean isEmpty();
-
- /**
- * Create a new bitmap of the same class, containing at most maxcardinality integers.
- *
- * @param x maximal cardinality
- * @return a new bitmap with cardinality no more than maxcardinality
- */
- public ImmutableBitmapDataProvider limit(int x);
-
- /**
- * Rank returns the number of integers that are smaller or equal to x (Rank(infinity) would be
- * GetCardinality()).
- *
- * The value is internally computed as a 64-bit number.
- *
- * @param x upper limit
- * @return the rank
- */
- public int rank(int x);
-
- /**
- * Same as "rank" but produces a full 64-bit value.
- *
- * @param x upper limit
- * @return the rank
- */
- public long rankLong(int x);
-
- /**
- * Return the jth value stored in this bitmap.
- *
- * @param j index of the value
- * @return the value
- */
- public int select(int j);
-
- /**
- * Serialize this bitmap.
- *
- * The current bitmap is not modified.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- public void serialize(DataOutput out) throws IOException;
-
- /**
- * Report the number of bytes required to serialize this bitmap. This is the number of bytes
- * written out when using the serialize method. When using the writeExternal method, the count
- * will be higher due to the overhead of Java serialization.
- *
- * @return the size in bytes
- */
- public int serializedSizeInBytes();
-
- /**
- * Return the set values as an array. The integer values are in sorted order.
- *
- * @return array representing the set values.
- */
- public int[] toArray();
-
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntConsumer.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntConsumer.java
deleted file mode 100644
index 47ff1e27d..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntConsumer.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.fr.third.bitmap.roaringbitmap;
-
-/**
- * An IntConsumer receives the int values contained in a data structure.
- * Each value is visited once.
- *
- * Usage:
- *
- *
- * For better performance, consider the {@link RoaringBitmap#forEach} method.
- *
- * @author Borislav Ivanov
- **/
-public class IntIteratorFlyweight implements PeekableIntIterator {
-
- private int hs;
-
- private PeekableShortIterator iter;
-
- private ArrayContainerShortIterator arrIter = new ArrayContainerShortIterator();
-
- private BitmapContainerShortIterator bitmapIter = new BitmapContainerShortIterator();
-
- private RunContainerShortIterator runIter = new RunContainerShortIterator();
-
- private int pos;
-
- private RoaringBitmap roaringBitmap = null;
-
- /**
- * Creates an instance that is not ready for iteration. You must first call
- * {@link #wrap(RoaringBitmap)}.
- */
- public IntIteratorFlyweight() {
-
- }
-
- /**
- * Creates an instance that is ready for iteration.
- *
- * @param r bitmap to be iterated over
- */
- public IntIteratorFlyweight(RoaringBitmap r) {
- wrap(r);
- }
-
- @Override
- public PeekableIntIterator clone() {
- try {
- IntIteratorFlyweight x = (IntIteratorFlyweight) super.clone();
- x.iter = this.iter.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return pos < this.roaringBitmap.highLowContainer.size();
- }
-
- @Override
- public int next() {
- int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- ++pos;
- nextContainer();
- }
- return x;
- }
-
- private void nextContainer() {
- if (pos < this.roaringBitmap.highLowContainer.size()) {
-
- Container container = this.roaringBitmap.highLowContainer.getContainerAtIndex(pos);
-
- if (container instanceof BitmapContainer) {
- bitmapIter.wrap(((BitmapContainer) container).bitmap);
- iter = bitmapIter;
- } else if (container instanceof ArrayContainer) {
- arrIter.wrap((ArrayContainer) container);
- iter = arrIter;
- } else {
- runIter.wrap((RunContainer) container);
- iter = runIter;
- }
- hs = Util.toIntUnsigned(this.roaringBitmap.highLowContainer.getKeyAtIndex(pos)) << 16;
- }
- }
-
- /**
- * Prepares a bitmap for iteration
- *
- * @param r bitmap to be iterated over
- */
- public void wrap(RoaringBitmap r) {
- this.hs = 0;
- this.pos = 0;
- this.roaringBitmap = r;
- this.nextContainer();
- }
-
- @Override
- public void advanceIfNeeded(final int minval) {
- while (hasNext() && ((hs >>> 16) < (minval >>> 16))) {
- ++pos;
- nextContainer();
- }
- if (hasNext() && ((hs >>> 16) == (minval >>> 16))) {
- iter.advanceIfNeeded(Util.lowbits(minval));
- if (!iter.hasNext()) {
- ++pos;
- nextContainer();
- }
- }
- }
-
- @Override
- public int peekNext() {
- return Util.toIntUnsigned(iter.peekNext()) | hs;
- }
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/PeekableIntIterator.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/PeekableIntIterator.java
deleted file mode 100644
index 906f23b73..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/PeekableIntIterator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.fr.third.bitmap.roaringbitmap;
-
-
-/**
- * Simple extension to the IntIterator interface.
- * It allows you to "skip" values using the advanceIfNeeded
- * method, and to look at the value without advancing (peekNext).
- */
-public interface PeekableIntIterator extends IntIterator {
- /**
- * If needed, advance as long as the next value is smaller than minval
- *
- * @param minval threshold
- */
- public void advanceIfNeeded(int minval);
-
- /**
- * Look at the next value without advancing
- *
- * @return next value
- */
- public int peekNext();
-
- /**
- * Creates a copy of the iterator.
- *
- * @return a clone of the current iterator
- */
- @Override
- PeekableIntIterator clone();
-}
-
-
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/PeekableShortIterator.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/PeekableShortIterator.java
deleted file mode 100644
index 278f0e20a..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/PeekableShortIterator.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-package com.fr.third.bitmap.roaringbitmap;
-
-
-/**
- * Simple extension to the ShortIterator interface
- */
-public interface PeekableShortIterator extends ShortIterator {
- /**
- * If needed, advance as long as the next value is smaller than minval (as an unsigned
- * short)
- *
- * @param minval threshold
- */
- public void advanceIfNeeded(short minval);
-
- /**
- * Look at the next value without advancing
- *
- * @return next value
- */
- public short peekNext();
-
- /**
- * Creates a copy of the iterator.
- *
- * @return a clone of the current iterator
- */
- @Override
- PeekableShortIterator clone();
-}
-
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/ReverseIntIteratorFlyweight.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/ReverseIntIteratorFlyweight.java
deleted file mode 100644
index 0475cc78d..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/ReverseIntIteratorFlyweight.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap;
-
-/**
- * Fast iterator minimizing the stress on the garbage collector. You can create one reusable
- * instance of this class and then {@link #wrap(RoaringBitmap)}
- *
- * This iterator enumerates the stored values in reverse (starting from the end).
- *
- * @author Borislav Ivanov
- **/
-public class ReverseIntIteratorFlyweight implements IntIterator {
-
- private int hs;
-
- private ShortIterator iter;
-
- private ReverseArrayContainerShortIterator arrIter = new ReverseArrayContainerShortIterator();
-
- private ReverseBitmapContainerShortIterator bitmapIter =
- new ReverseBitmapContainerShortIterator();
-
- private ReverseRunContainerShortIterator runIter = new ReverseRunContainerShortIterator();
-
- private short pos;
-
- private RoaringBitmap roaringBitmap = null;
-
-
- /**
- * Creates an instance that is not ready for iteration. You must first call
- * {@link #wrap(RoaringBitmap)}.
- */
- public ReverseIntIteratorFlyweight() {
-
- }
-
- /**
- * Creates an instance that is ready for iteration.
- *
- * @param r bitmap to be iterated over
- */
- public ReverseIntIteratorFlyweight(RoaringBitmap r) {
- wrap(r);
- }
-
- @Override
- public IntIterator clone() {
- try {
- ReverseIntIteratorFlyweight x = (ReverseIntIteratorFlyweight) super.clone();
- x.iter = this.iter.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return pos >= 0;
- }
-
-
- @Override
- public int next() {
- final int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- --pos;
- nextContainer();
- }
- return x;
- }
-
- private void nextContainer() {
-
-
- if (pos >= 0) {
-
- Container container = this.roaringBitmap.highLowContainer.getContainerAtIndex(pos);
- if (container instanceof BitmapContainer) {
- bitmapIter.wrap(((BitmapContainer) container).bitmap);
- iter = bitmapIter;
- } else if (container instanceof ArrayContainer) {
- arrIter.wrap((ArrayContainer) container);
- iter = arrIter;
- } else {
- runIter.wrap((RunContainer) container);
- iter = runIter;
- }
- hs = Util.toIntUnsigned(this.roaringBitmap.highLowContainer.getKeyAtIndex(pos)) << 16;
- }
- }
-
- /**
- * Prepares a bitmap for iteration
- *
- * @param r bitmap to be iterated over
- */
- public void wrap(RoaringBitmap r) {
- this.roaringBitmap = r;
- this.hs = 0;
- this.pos = (short) (this.roaringBitmap.highLowContainer.size() - 1);
- this.nextContainer();
- }
-
-}
-
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RoaringArray.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RoaringArray.java
deleted file mode 100644
index eebb99d77..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RoaringArray.java
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap;
-
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Arrays;
-
-
-/**
- * Specialized array to store the containers used by a RoaringBitmap. This is not meant to be used
- * by end users.
- */
-public final class RoaringArray implements Cloneable, Externalizable {
- protected static final short SERIAL_COOKIE_NO_RUNCONTAINER = 12346;
- protected static final short SERIAL_COOKIE = 12347;
- protected static final int NO_OFFSET_THRESHOLD = 4;
- static final int INITIAL_CAPACITY = 4;
- // bumped serialVersionUID with runcontainers, so default serialization
- // will not work...
- private static final long serialVersionUID = 8L;
- short[] keys = null;
-
- Container[] values = null;
-
- int size = 0;
-
- protected RoaringArray() {
- this.keys = new short[INITIAL_CAPACITY];
- this.values = new Container[INITIAL_CAPACITY];
- }
-
- /**
- * Find the smallest integer index larger than pos such that array[index].key>=x. If none can
- * be found, return size. Based on code by O. Kaser.
- *
- * @param x minimal value
- * @param pos index to exceed
- * @return the smallest index greater than pos such that array[index].key is at least as large as
- * min, or size if it is not possible.
- */
- protected int advanceUntil(short x, int pos) {
- int lower = pos + 1;
-
- // special handling for a possibly common sequential case
- if (lower >= size || Util.toIntUnsigned(keys[lower]) >= Util.toIntUnsigned(x)) {
- return lower;
- }
-
- int spansize = 1; // could set larger
- // bootstrap an upper limit
-
- while (lower + spansize < size
- && Util.toIntUnsigned(keys[lower + spansize]) < Util.toIntUnsigned(x)) {
- spansize *= 2; // hoping for compiler will reduce to shift
- }
- int upper = (lower + spansize < size) ? lower + spansize : size - 1;
-
- // maybe we are lucky (could be common case when the seek ahead
- // expected to be small and sequential will otherwise make us look bad)
- if (keys[upper] == x) {
- return upper;
- }
-
- if (Util.toIntUnsigned(keys[upper]) < Util.toIntUnsigned(x)) {// means array has no item key >=
- // x
- return size;
- }
-
- // we know that the next-smallest span was too small
- lower += (spansize / 2);
-
- // else begin binary search
- // invariant: array[lower]
- * The current bitmap is not modified.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- public void serialize(DataOutput out) throws IOException {
- int startOffset = 0;
- boolean hasrun = hasRunContainer();
- if (hasrun) {
- out.writeInt(Integer.reverseBytes(SERIAL_COOKIE | ((size - 1) << 16)));
- byte[] bitmapOfRunContainers = new byte[(size + 7) / 8];
- for (int i = 0; i < size; ++i) {
- if (this.values[i] instanceof RunContainer) {
- bitmapOfRunContainers[i / 8] |= (1 << (i % 8));
- }
- }
- out.write(bitmapOfRunContainers);
- if (this.size < NO_OFFSET_THRESHOLD) {
- startOffset = 4 + 4 * this.size + bitmapOfRunContainers.length;
- } else {
- startOffset = 4 + 8 * this.size + bitmapOfRunContainers.length;
- }
- } else { // backwards compatibility
- out.writeInt(Integer.reverseBytes(SERIAL_COOKIE_NO_RUNCONTAINER));
- out.writeInt(Integer.reverseBytes(size));
- startOffset = 4 + 4 + 4 * this.size + 4 * this.size;
- }
- for (int k = 0; k < size; ++k) {
- out.writeShort(Short.reverseBytes(this.keys[k]));
- out.writeShort(Short.reverseBytes((short) (this.values[k].getCardinality() - 1)));
- }
- if ((!hasrun) || (this.size >= NO_OFFSET_THRESHOLD)) {
- // writing the containers offsets
- for (int k = 0; k < this.size; k++) {
- out.writeInt(Integer.reverseBytes(startOffset));
- startOffset = startOffset + this.values[k].getArraySizeInBytes();
- }
- }
- for (int k = 0; k < size; ++k) {
- values[k].writeArray(out);
- }
- }
-
- /**
- * Report the number of bytes required for serialization.
- *
- * @return the size in bytes
- */
- public int serializedSizeInBytes() {
- int count = headerSize();
- for (int k = 0; k < size; ++k) {
- count += values[k].getArraySizeInBytes();
- }
- return count;
- }
-
- protected void setContainerAtIndex(int i, Container c) {
- this.values[i] = c;
- }
-
- protected int size() {
- return this.size;
- }
-
- @Override
- public void writeExternal(ObjectOutput out) throws IOException {
- serialize(out);
- }
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RoaringBitmap.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RoaringBitmap.java
deleted file mode 100644
index e300cb8b8..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RoaringBitmap.java
+++ /dev/null
@@ -1,2205 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap;
-
-import com.fr.third.bitmap.roaringbitmap.buffer.ImmutableRoaringBitmap;
-import com.fr.third.bitmap.roaringbitmap.buffer.MappeableContainerPointer;
-import com.fr.third.bitmap.roaringbitmap.buffer.MutableRoaringBitmap;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.Serializable;
-import java.util.Iterator;
-
-
-/**
- * RoaringBitmap, a compressed alternative to the BitSet.
- *
- *
- * Integers are added in unsigned sorted order. That is, they are treated as unsigned integers (see
- * Java 8's Integer.toUnsignedLong function).
- *
- * Bitmaps are limited to a maximum of Integer.MAX_VALUE entries. Trying to create larger bitmaps
- * could result in undefined behaviors.
- */
-
-
-public class RoaringBitmap implements Cloneable, Serializable, Iterable
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- * @see FastAggregation#and(RoaringBitmap...)
- */
- public static RoaringBitmap and(final RoaringBitmap x1, final RoaringBitmap x2) {
- final RoaringBitmap answer = new RoaringBitmap();
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- int pos1 = 0, pos2 = 0;
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- final Container c = c1.and(c2);
- if (c.getCardinality() > 0) {
- answer.highLowContainer.append(s1, c);
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- return answer;
- }
-
- /**
- * Cardinality of Bitwise AND (intersection) operation. The provided bitmaps are *not* modified.
- * This operation is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return as if you did and(x2,x2).getCardinality()
- * @see FastAggregation#and(RoaringBitmap...)
- */
- public static int andCardinality(final RoaringBitmap x1, final RoaringBitmap x2) {
- int answer = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- int pos1 = 0, pos2 = 0;
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- // TODO: could be made faster if we did not have to materialize container
- answer += c1.andCardinality(c2);
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- return answer;
- }
-
- /**
- * Bitwise ANDNOT (difference) operation. The provided bitmaps are *not* modified. This operation
- * is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- */
- public static RoaringBitmap andNot(final RoaringBitmap x1, final RoaringBitmap x2) {
- final RoaringBitmap answer = new RoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- final Container c = c1.andNot(c2);
- if (c.getCardinality() > 0) {
- answer.highLowContainer.append(s1, c);
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- final int nextPos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1, nextPos1);
- pos1 = nextPos1;
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- if (pos2 == length2) {
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1, length1);
- }
- return answer;
- }
-
- /**
- * Generate a bitmap with the specified values set to true. The provided integers values don't
- * have to be in sorted order, but it may be preferable to sort them from a performance point of
- * view.
- *
- * @param dat set values
- * @return a new bitmap
- */
- public static RoaringBitmap bitmapOf(final int... dat) {
- final RoaringBitmap ans = new RoaringBitmap();
- ans.add(dat);
- return ans;
- }
-
- /**
- * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The
- * given bitmap is unchanged.
- *
- * @param bm bitmap being negated
- * @param rangeStart inclusive beginning of range, in [0, 0xffffffff]
- * @param rangeEnd exclusive ending of range, in [0, 0xffffffff + 1]
- * @return a new Bitmap
- */
- public static RoaringBitmap flip(RoaringBitmap bm, final long rangeStart, final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- return bm.clone();
- }
- RoaringBitmap answer = new RoaringBitmap();
- final int hbStart = Util.toIntUnsigned(Util.highbits(rangeStart));
- final int lbStart = Util.toIntUnsigned(Util.lowbits(rangeStart));
- final int hbLast = Util.toIntUnsigned(Util.highbits(rangeEnd - 1));
- final int lbLast = Util.toIntUnsigned(Util.lowbits(rangeEnd - 1));
-
- // copy the containers before the active area
- answer.highLowContainer.appendCopiesUntil(bm.highLowContainer, (short) hbStart);
-
- for (int hb = hbStart; hb <= hbLast; ++hb) {
- final int containerStart = (hb == hbStart) ? lbStart : 0;
- final int containerLast = (hb == hbLast) ? lbLast : Util.maxLowBitAsInteger();
-
- final int i = bm.highLowContainer.getIndex((short) hb);
- final int j = answer.highLowContainer.getIndex((short) hb);
- assert j < 0;
-
- if (i >= 0) {
- Container c =
- bm.highLowContainer.getContainerAtIndex(i).not(containerStart, containerLast + 1);
- if (c.getCardinality() > 0) {
- answer.highLowContainer.insertNewKeyValueAt(-j - 1, (short) hb, c);
- }
-
- } else { // *think* the range of ones must never be
- // empty.
- answer.highLowContainer.insertNewKeyValueAt(-j - 1, (short) hb,
- Container.rangeOfOnes(containerStart, containerLast + 1));
- }
- }
- // copy the containers after the active area.
- answer.highLowContainer.appendCopiesAfter(bm.highLowContainer, (short) hbLast);
- return answer;
- }
-
- /**
- * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The
- * given bitmap is unchanged.
- *
- * @param rb bitmap being negated
- * @param rangeStart inclusive beginning of range, in [0, 0xffffffff]
- * @param rangeEnd exclusive ending of range, in [0, 0xffffffff + 1]
- * @return a new Bitmap
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public static RoaringBitmap flip(RoaringBitmap rb, final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- return flip(rb, (long) rangeStart, (long) rangeEnd);
- }
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- return flip(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
-
-
- /**
- * Checks whether the two bitmaps intersect. This can be much faster than calling "and" and
- * checking the cardinality of the result.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return true if they intersect
- */
- public static boolean intersects(final RoaringBitmap x1, final RoaringBitmap x2) {
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- int pos1 = 0, pos2 = 0;
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- if (c1.intersects(c2)) {
- return true;
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- return false;
- }
-
-
- // important: inputs should not have been computed lazily
- protected static RoaringBitmap lazyor(final RoaringBitmap x1, final RoaringBitmap x2) {
- final RoaringBitmap answer = new RoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- answer.highLowContainer.append(s1, x1.highLowContainer.getContainerAtIndex(pos1)
- .lazyOR(x2.highLowContainer.getContainerAtIndex(pos2)));
- pos1++;
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1);
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- answer.highLowContainer.appendCopy(x2.highLowContainer, pos2);
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- answer.highLowContainer.appendCopy(x2.highLowContainer, pos2, length2);
- } else if (pos2 == length2) {
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1, length1);
- }
- return answer;
- }
-
- // important: inputs should not be reused
- protected static RoaringBitmap lazyorfromlazyinputs(final RoaringBitmap x1,
- final RoaringBitmap x2) {
- final RoaringBitmap answer = new RoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- if ((c2 instanceof BitmapContainer) && (!(c1 instanceof BitmapContainer))) {
- Container tmp = c1;
- c1 = c2;
- c2 = tmp;
- }
- answer.highLowContainer.append(s1, c1.lazyIOR(c2));
- pos1++;
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- Container c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- answer.highLowContainer.append(s1, c1);
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- Container c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- answer.highLowContainer.append(s2, c2);
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- answer.highLowContainer.append(x2.highLowContainer, pos2, length2);
- } else if (pos2 == length2) {
- answer.highLowContainer.append(x1.highLowContainer, pos1, length1);
- }
- return answer;
- }
-
-
- /**
- * Compute overall OR between bitmaps.
- *
- * (Effectively calls {@link FastAggregation#or})
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap or(Iterator
- * (Effectively calls {@link FastAggregation#or})
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static RoaringBitmap or(RoaringBitmap... bitmaps) {
- return FastAggregation.or(bitmaps);
- }
-
- /**
- * Bitwise OR (union) operation. The provided bitmaps are *not* modified. This operation is
- * thread-safe as long as the provided bitmaps remain unchanged.
- *
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- * @see FastAggregation#or(RoaringBitmap...)
- * @see FastAggregation#horizontal_or(RoaringBitmap...)
- */
- public static RoaringBitmap or(final RoaringBitmap x1, final RoaringBitmap x2) {
- final RoaringBitmap answer = new RoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- answer.highLowContainer.append(s1, x1.highLowContainer.getContainerAtIndex(pos1)
- .or(x2.highLowContainer.getContainerAtIndex(pos2)));
- pos1++;
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1);
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- answer.highLowContainer.appendCopy(x2.highLowContainer, pos2);
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- answer.highLowContainer.appendCopy(x2.highLowContainer, pos2, length2);
- } else if (pos2 == length2) {
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1, length1);
- }
- return answer;
- }
-
- /**
- * Cardinality of the bitwise OR (union) operation. The provided bitmaps are *not* modified. This
- * operation is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return cardinality of the union
- * @see FastAggregation#or(RoaringBitmap...)
- * @see FastAggregation#horizontal_or(RoaringBitmap...)
- */
- public static int orCardinality(final RoaringBitmap x1, final RoaringBitmap x2) {
- // we use the fact that the cardinality of the bitmaps is known so that
- // the union is just the total cardinality minus the intersection
- return x1.getCardinality() + x2.getCardinality() - andCardinality(x1, x2);
- }
-
-
- /**
- * Generate a new bitmap with all integers in [rangeStart,rangeEnd) removed.
- *
- * @param rb initial bitmap (will not be modified)
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new bitmap
- */
- public static RoaringBitmap remove(RoaringBitmap rb, final long rangeStart, final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- return rb.clone(); // empty range
- }
-
-
- final int hbStart = Util.toIntUnsigned(Util.highbits(rangeStart));
- final int lbStart = Util.toIntUnsigned(Util.lowbits(rangeStart));
- final int hbLast = Util.toIntUnsigned(Util.highbits(rangeEnd - 1));
- final int lbLast = Util.toIntUnsigned(Util.lowbits(rangeEnd - 1));
- RoaringBitmap answer = new RoaringBitmap();
- answer.highLowContainer.appendCopiesUntil(rb.highLowContainer, (short) hbStart);
-
- if (hbStart == hbLast) {
- final int i = rb.highLowContainer.getIndex((short) hbStart);
- if (i >= 0) {
- final Container c = rb.highLowContainer.getContainerAtIndex(i).remove(lbStart, lbLast + 1);
- if (c.getCardinality() > 0) {
- answer.highLowContainer.append((short) hbStart, c);
- }
- }
- answer.highLowContainer.appendCopiesAfter(rb.highLowContainer, (short) hbLast);
- return answer;
- }
- int ifirst = rb.highLowContainer.getIndex((short) hbStart);
- int ilast = rb.highLowContainer.getIndex((short) hbLast);
- if ((ifirst >= 0) && (lbStart != 0)) {
- final Container c = rb.highLowContainer.getContainerAtIndex(ifirst).remove(lbStart,
- Util.maxLowBitAsInteger() + 1);
- if (c.getCardinality() > 0) {
- answer.highLowContainer.append((short) hbStart, c);
- }
- }
- if ((ilast >= 0) && (lbLast != Util.maxLowBitAsInteger())) {
- final Container c = rb.highLowContainer.getContainerAtIndex(ilast).remove(0, lbLast + 1);
- if (c.getCardinality() > 0) {
- answer.highLowContainer.append((short) hbLast, c);
- }
- }
- answer.highLowContainer.appendCopiesAfter(rb.highLowContainer, (short) hbLast);
- return answer;
- }
-
- /**
- * Generate a new bitmap with all integers in [rangeStart,rangeEnd) removed.
- *
- * @param rb initial bitmap (will not be modified)
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new bitmap
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public static RoaringBitmap remove(RoaringBitmap rb, final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- return remove(rb, (long) rangeStart, (long) rangeEnd);
- }
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- return remove(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
-
-
- /**
- * Bitwise XOR (symmetric difference) operation. The provided bitmaps are *not* modified. This
- * operation is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- * @see FastAggregation#xor(RoaringBitmap...)
- * @see FastAggregation#horizontal_xor(RoaringBitmap...)
- */
- public static RoaringBitmap xor(final RoaringBitmap x1, final RoaringBitmap x2) {
- final RoaringBitmap answer = new RoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- final Container c = x1.highLowContainer.getContainerAtIndex(pos1)
- .xor(x2.highLowContainer.getContainerAtIndex(pos2));
- if (c.getCardinality() > 0) {
- answer.highLowContainer.append(s1, c);
- }
- pos1++;
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1);
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- answer.highLowContainer.appendCopy(x2.highLowContainer, pos2);
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- answer.highLowContainer.appendCopy(x2.highLowContainer, pos2, length2);
- } else if (pos2 == length2) {
- answer.highLowContainer.appendCopy(x1.highLowContainer, pos1, length1);
- }
-
- return answer;
- }
-
- /**
- * Computes AND between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd
- * (exclusive)
- *
- * @param bitmaps input bitmaps, these are not modified
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new result bitmap
- */
- public static RoaringBitmap and(@SuppressWarnings("rawtypes") final Iterator bitmaps,
- final long rangeStart, final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
-
- Iterator
- * The current bitmap is overwritten.
- *
- * @param in the DataInput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- public void deserialize(DataInput in) throws IOException {
- this.highLowContainer.deserialize(in);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof RoaringBitmap) {
- final RoaringBitmap srb = (RoaringBitmap) o;
- return srb.highLowContainer.equals(this.highLowContainer);
- }
- return false;
- }
-
- /**
- * Add the value if it is not already present, otherwise remove it.
- *
- * @param x integer value
- */
- public void flip(final int x) {
- final short hb = Util.highbits(x);
- final int i = highLowContainer.getIndex(hb);
- if (i >= 0) {
- Container c = highLowContainer.getContainerAtIndex(i).flip(Util.lowbits(x));
- if (c.getCardinality() > 0) {
- highLowContainer.setContainerAtIndex(i, c);
- } else {
- highLowContainer.removeAtIndex(i);
- }
- } else {
- final ArrayContainer newac = new ArrayContainer();
- highLowContainer.insertNewKeyValueAt(-i - 1, hb, newac.add(Util.lowbits(x)));
- }
- }
-
- /**
- * Modifies the current bitmap by complementing the bits in the given range, from rangeStart
- * (inclusive) rangeEnd (exclusive).
- *
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- */
- public void flip(final long rangeStart, final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- return; // empty range
- }
-
- final int hbStart = Util.toIntUnsigned(Util.highbits(rangeStart));
- final int lbStart = Util.toIntUnsigned(Util.lowbits(rangeStart));
- final int hbLast = Util.toIntUnsigned(Util.highbits(rangeEnd - 1));
- final int lbLast = Util.toIntUnsigned(Util.lowbits(rangeEnd - 1));
-
- // TODO:this can be accelerated considerably
- for (int hb = hbStart; hb <= hbLast; ++hb) {
- // first container may contain partial range
- final int containerStart = (hb == hbStart) ? lbStart : 0;
- // last container may contain partial range
- final int containerLast = (hb == hbLast) ? lbLast : Util.maxLowBitAsInteger();
- final int i = highLowContainer.getIndex((short) hb);
-
- if (i >= 0) {
- final Container c =
- highLowContainer.getContainerAtIndex(i).inot(containerStart, containerLast + 1);
- if (c.getCardinality() > 0) {
- highLowContainer.setContainerAtIndex(i, c);
- } else {
- highLowContainer.removeAtIndex(i);
- }
- } else {
- highLowContainer.insertNewKeyValueAt(-i - 1, (short) hb,
- Container.rangeOfOnes(containerStart, containerLast + 1));
- }
- }
- }
-
- /**
- * Modifies the current bitmap by complementing the bits in the given range, from rangeStart
- * (inclusive) rangeEnd (exclusive).
- *
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public void flip(final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- flip((long) rangeStart, (long) rangeEnd);
- } else {
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- flip(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
- }
-
- /**
- * Returns the number of distinct integers added to the bitmap (e.g., number of bits set).
- *
- * @return the cardinality
- */
- @Override
- public long getLongCardinality() {
- long size = 0;
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- size += this.highLowContainer.getContainerAtIndex(i).getCardinality();
- }
- return size;
- }
-
- @Override
- public int getCardinality() {
- return (int) getLongCardinality();
- }
-
- @Override
- public void forEach(IntConsumer ic) {
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- this.highLowContainer.getContainerAtIndex(i).forEach(this.highLowContainer.keys[i], ic);
- }
- }
-
- /**
- * Return a low-level container pointer that can be used to access the underlying data structure.
- *
- * @return container pointer
- */
- public ContainerPointer getContainerPointer() {
- return this.highLowContainer.getContainerPointer();
- }
-
- /**
- * For better performance, consider the Use the {@link #forEach forEach} method.
- *
- * @return a custom iterator over set bits, the bits are traversed in ascending sorted order
- */
- @Override
- public PeekableIntIterator getIntIterator() {
- return new RoaringIntIterator();
- }
-
- /**
- * @return a custom iterator over set bits, the bits are traversed in descending sorted order
- */
- @Override
- public IntIterator getReverseIntIterator() {
- return new RoaringReverseIntIterator();
- }
-
- /**
- * Estimate of the memory usage of this data structure. This can be expected to be within 1% of
- * the true memory usage.
- *
- * @return estimated memory usage.
- */
- @Override
- public long getLongSizeInBytes() {
- long size = 8;
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- final Container c = this.highLowContainer.getContainerAtIndex(i);
- size += 2 + c.getSizeInBytes();
- }
- return size;
- }
-
- @Override
- public int getSizeInBytes() {
- return (int) getLongSizeInBytes();
- }
-
- @Override
- public int hashCode() {
- return highLowContainer.hashCode();
- }
-
- /**
- * Check whether this bitmap has had its runs compressed.
- *
- * @return whether this bitmap has run compression
- */
- public boolean hasRunCompression() {
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- Container c = this.highLowContainer.getContainerAtIndex(i);
- if (c instanceof RunContainer) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks whether the bitmap is empty.
- *
- * @return true if this bitmap contains no set bit
- */
- @Override
- public boolean isEmpty() {
- return highLowContainer.size() == 0;
- }
-
- /**
- * iterate over the positions of the true values.
- *
- * @return the iterator
- */
- @Override
- public Iterator
- * Consider calling {@link #runOptimize} before serialization to improve compression.
- *
- * The current bitmap is not modified.
- *
- * Advanced example: To serialize your bitmap to a ByteBuffer, you can do the following.
- *
- *
- * Note: Java's data structures are in big endian format. Roaring serializes to a little endian
- * format, so the bytes are flipped by the library during serialization to ensure that what is
- * stored is in little endian---despite Java's big endianness. You can defeat this process by
- * reflipping the bytes again in a custom DataOutput which could lead to serialized Roaring
- * objects with an incorrect byte order.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- @Override
- public void serialize(DataOutput out) throws IOException {
- this.highLowContainer.serialize(out);
- }
-
- /**
- * Report the number of bytes required to serialize this bitmap. This is the number of bytes
- * written out when using the serialize method. When using the writeExternal method, the count
- * will be higher due to the overhead of Java serialization.
- *
- * @return the size in bytes
- */
- @Override
- public int serializedSizeInBytes() {
- return this.highLowContainer.serializedSizeInBytes();
- }
-
- /**
- * Return the set values as an array, if the cardinality is smaller than 2147483648.
- * The integer values are in sorted order.
- *
- * @return array representing the set values.
- */
- @Override
- public int[] toArray() {
- final int[] array = new int[(int) this.getCardinality()];
- int pos = 0, pos2 = 0;
- while (pos < this.highLowContainer.size()) {
- final int hs = this.highLowContainer.getKeyAtIndex(pos) << 16;
- Container c = this.highLowContainer.getContainerAtIndex(pos++);
- c.fillLeastSignificant16bits(array, pos2, hs);
- pos2 += c.getCardinality();
- }
- return array;
- }
-
-
- /**
- * Convert (copies) to a mutable roaring bitmap.
- *
- * @return a copy of this bitmap as a MutableRoaringBitmap
- */
- public MutableRoaringBitmap toMutableRoaringBitmap() {
- return new MutableRoaringBitmap(this);
- }
-
- /**
- * A string describing the bitmap.
- *
- * @return the string
- */
- @Override
- public String toString() {
- final StringBuilder answer = new StringBuilder();
- final IntIterator i = this.getIntIterator();
- answer.append("{");
- if (i.hasNext()) {
- answer.append(i.next() & 0xFFFFFFFFL);
- }
- while (i.hasNext()) {
- answer.append(",");
- // to avoid using too much memory, we limit the size
- if (answer.length() > 0x80000) {
- answer.append("...");
- break;
- }
- answer.append(i.next() & 0xFFFFFFFFL);
-
- }
- answer.append("}");
- return answer.toString();
- }
-
- /**
- * Recover allocated but unused memory.
- */
- public void trim() {
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- this.highLowContainer.getContainerAtIndex(i).trim();
- }
- }
-
-
- @Override
- public void writeExternal(ObjectOutput out) throws IOException {
- this.highLowContainer.writeExternal(out);
- }
-
- /**
- * In-place bitwise XOR (symmetric difference) operation. The current bitmap is modified.
- *
- * @param x2 other bitmap
- */
- public void xor(final RoaringBitmap x2) {
- int pos1 = 0, pos2 = 0;
- int length1 = highLowContainer.size();
- final int length2 = x2.highLowContainer.size();
-
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- final Container c = highLowContainer.getContainerAtIndex(pos1)
- .ixor(x2.highLowContainer.getContainerAtIndex(pos2));
- if (c.getCardinality() > 0) {
- this.highLowContainer.setContainerAtIndex(pos1, c);
- pos1++;
- } else {
- highLowContainer.removeAtIndex(pos1);
- --length1;
- }
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- highLowContainer.insertNewKeyValueAt(pos1, s2,
- x2.highLowContainer.getContainerAtIndex(pos2).clone());
- pos1++;
- length1++;
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- highLowContainer.appendCopy(x2.highLowContainer, pos2, length2);
- }
- }
-
- private final class RoaringIntIterator implements PeekableIntIterator {
- private int hs = 0;
-
- private PeekableShortIterator iter;
-
- private int pos = 0;
-
- private RoaringIntIterator() {
- nextContainer();
- }
-
- @Override
- public PeekableIntIterator clone() {
- try {
- RoaringIntIterator x = (RoaringIntIterator) super.clone();
- x.iter = this.iter.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return pos < RoaringBitmap.this.highLowContainer.size();
- }
-
- @Override
- public int next() {
- final int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- ++pos;
- nextContainer();
- }
- return x;
- }
-
- private void nextContainer() {
- if (pos < RoaringBitmap.this.highLowContainer.size()) {
- iter = RoaringBitmap.this.highLowContainer.getContainerAtIndex(pos).getShortIterator();
- hs = RoaringBitmap.this.highLowContainer.getKeyAtIndex(pos) << 16;
- }
- }
-
- @Override
- public void advanceIfNeeded(int minval) {
- while (hasNext() && ((hs >>> 16) < (minval >>> 16))) {
- ++pos;
- nextContainer();
- }
- if (hasNext() && ((hs >>> 16) == (minval >>> 16))) {
- iter.advanceIfNeeded(Util.lowbits(minval));
- if (!iter.hasNext()) {
- ++pos;
- nextContainer();
- }
- }
- }
-
- @Override
- public int peekNext() {
- return Util.toIntUnsigned(iter.peekNext()) | hs;
- }
-
-
- }
-
- private final class RoaringReverseIntIterator implements IntIterator {
-
- int hs = 0;
-
- ShortIterator iter;
-
- // don't need an int because we go to 0, not Short.MAX_VALUE, and signed shorts underflow well
- // below zero
- short pos = (short) (RoaringBitmap.this.highLowContainer.size() - 1);
-
- private RoaringReverseIntIterator() {
- nextContainer();
- }
-
- @Override
- public IntIterator clone() {
- try {
- RoaringReverseIntIterator clone = (RoaringReverseIntIterator) super.clone();
- clone.iter = this.iter.clone();
- return clone;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return pos >= 0;
- }
-
- @Override
- public int next() {
- final int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- --pos;
- nextContainer();
- }
- return x;
- }
-
- private void nextContainer() {
- if (pos >= 0) {
- iter =
- RoaringBitmap.this.highLowContainer.getContainerAtIndex(pos).getReverseShortIterator();
- hs = RoaringBitmap.this.highLowContainer.getKeyAtIndex(pos) << 16;
- }
- }
-
- }
-
-
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RunContainer.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RunContainer.java
deleted file mode 100644
index c078b52a8..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/RunContainer.java
+++ /dev/null
@@ -1,2518 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-package com.fr.third.bitmap.roaringbitmap;
-
-import com.fr.third.bitmap.roaringbitmap.buffer.MappeableContainer;
-import com.fr.third.bitmap.roaringbitmap.buffer.MappeableRunContainer;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.nio.ShortBuffer;
-import java.util.Arrays;
-import java.util.Iterator;
-
-
-/**
- * This container takes the form of runs of consecutive values (effectively, run-length encoding).
- *
- * Adding and removing content from this container might make it wasteful so regular calls to
- * "runOptimize" might be warranted.
- */
-public final class RunContainer extends Container implements Cloneable {
- private static final int DEFAULT_INIT_SIZE = 4;
- private static final boolean ENABLE_GALLOPING_AND = false;
-
- private static final long serialVersionUID = 1L;
- int nbrruns = 0;// how many runs, this number should fit in 16 bits.
- private short[] valueslength;// we interleave values and lengths, so
-
- /**
- * Create a container with default capacity
- */
- public RunContainer() {
- this(DEFAULT_INIT_SIZE);
- }
-
- protected RunContainer(ArrayContainer arr, int nbrRuns) {
- this.nbrruns = nbrRuns;
- valueslength = new short[2 * nbrRuns];
- if (nbrRuns == 0) {
- return;
- }
-
- int prevVal = -2;
- int runLen = 0;
- int runCount = 0;
-
- for (int i = 0; i < arr.cardinality; i++) {
- int curVal = Util.toIntUnsigned(arr.content[i]);
- if (curVal == prevVal + 1) {
- ++runLen;
- } else {
- if (runCount > 0) {
- setLength(runCount - 1, (short) runLen);
- }
- setValue(runCount, (short) curVal);
- runLen = 0;
- ++runCount;
- }
- prevVal = curVal;
- }
- setLength(runCount - 1, (short) runLen);
- }
-
- // convert a bitmap container to a run container somewhat efficiently.
- protected RunContainer(BitmapContainer bc, int nbrRuns) {
- this.nbrruns = nbrRuns;
- valueslength = new short[2 * nbrRuns];
- if (nbrRuns == 0) {
- return;
- }
-
- int longCtr = 0; // index of current long in bitmap
- long curWord = bc.bitmap[0]; // its value
- int runCount = 0;
- while (true) {
- // potentially multiword advance to first 1 bit
- while (curWord == 0L && longCtr < bc.bitmap.length - 1) {
- curWord = bc.bitmap[++longCtr];
- }
-
- if (curWord == 0L) {
- // wrap up, no more runs
- return;
- }
- int localRunStart = Long.numberOfTrailingZeros(curWord);
- int runStart = localRunStart + 64 * longCtr;
- // stuff 1s into number's LSBs
- long curWordWith1s = curWord | (curWord - 1);
-
- // find the next 0, potentially in a later word
- int runEnd = 0;
- while (curWordWith1s == -1L && longCtr < bc.bitmap.length - 1) {
- curWordWith1s = bc.bitmap[++longCtr];
- }
-
- if (curWordWith1s == -1L) {
- // a final unterminated run of 1s (32 of them)
- runEnd = 64 + longCtr * 64;
- setValue(runCount, (short) runStart);
- setLength(runCount, (short) (runEnd - runStart - 1));
- return;
- }
- int localRunEnd = Long.numberOfTrailingZeros(~curWordWith1s);
- runEnd = localRunEnd + longCtr * 64;
- setValue(runCount, (short) runStart);
- setLength(runCount, (short) (runEnd - runStart - 1));
- runCount++;
- // now, zero out everything right of runEnd.
- curWord = curWordWith1s & (curWordWith1s + 1);
- // We've lathered and rinsed, so repeat...
- }
- }
- // that if you have the values 11,12,13,14,15, you store that as 11,4 where 4 means that beyond 11
- // itself, there are
- // 4 contiguous values that follows.
- // Other example: e.g., 1, 10, 20,0, 31,2 would be a concise representation of 1, 2, ..., 11, 20,
- // 31, 32, 33
-
- /**
- * Create an array container with specified capacity
- *
- * @param capacity The capacity of the container
- */
- public RunContainer(final int capacity) {
- valueslength = new short[2 * capacity];
- }
-
-
- private RunContainer(int nbrruns, short[] valueslength) {
- this.nbrruns = nbrruns;
- this.valueslength = Arrays.copyOf(valueslength, valueslength.length);
- }
-
-
- /**
- * Creates a new non-mappeable container from a mappeable one. This copies the data.
- *
- * @param bc the original container
- */
- public RunContainer(MappeableRunContainer bc) {
- this.nbrruns = bc.numberOfRuns();
- this.valueslength = bc.toShortArray();
- }
-
- /**
- * Construct a new RunContainer backed by the provided array. Note that if you modify the
- * RunContainer a new array may be produced.
- *
- * @param array array where the data is stored
- * @param numRuns number of runs (each using 2 shorts in the buffer)
- */
- public RunContainer(final short[] array, final int numRuns) {
- if (array.length < 2 * numRuns) {
- throw new RuntimeException("Mismatch between buffer and numRuns");
- }
- this.nbrruns = numRuns;
- this.valueslength = array;
- }
-
- private static int branchyUnsignedInterleavedBinarySearch(final short[] array, final int begin,
- final int end, final short k) {
- int ikey = Util.toIntUnsigned(k);
- int low = begin;
- int high = end - 1;
- while (low <= high) {
- final int middleIndex = (low + high) >>> 1;
- final int middleValue = Util.toIntUnsigned(array[2 * middleIndex]);
- if (middleValue < ikey) {
- low = middleIndex + 1;
- } else if (middleValue > ikey) {
- high = middleIndex - 1;
- } else {
- return middleIndex;
- }
- }
- return -(low + 1);
- }
-
- // starts with binary search and finishes with a sequential search
- private static int hybridUnsignedInterleavedBinarySearch(final short[] array, final int begin,
- final int end, final short k) {
- int ikey = Util.toIntUnsigned(k);
- int low = begin;
- int high = end - 1;
- // 16 in the next line matches the size of a cache line
- while (low + 16 <= high) {
- final int middleIndex = (low + high) >>> 1;
- final int middleValue = Util.toIntUnsigned(array[2 * middleIndex]);
- if (middleValue < ikey) {
- low = middleIndex + 1;
- } else if (middleValue > ikey) {
- high = middleIndex - 1;
- } else {
- return middleIndex;
- }
- }
- // we finish the job with a sequential search
- int x = low;
- for (; x <= high; ++x) {
- final int val = Util.toIntUnsigned(array[2 * x]);
- if (val >= ikey) {
- if (val == ikey) {
- return x;
- }
- break;
- }
- }
- return -(x + 1);
- }
-
- protected static int serializedSizeInBytes(int numberOfRuns) {
- return 2 + 2 * 2 * numberOfRuns; // each run requires 2 2-byte entries.
- }
-
- private static int unsignedInterleavedBinarySearch(final short[] array, final int begin,
- final int end, final short k) {
- if (Util.USE_HYBRID_BINSEARCH) {
- return hybridUnsignedInterleavedBinarySearch(array, begin, end, k);
- } else {
- return branchyUnsignedInterleavedBinarySearch(array, begin, end, k);
- }
-
- }
-
- @Override
- public Container add(int begin, int end) {
- RunContainer rc = (RunContainer) clone();
- return rc.iadd(begin, end);
- }
-
- @Override
- public Container add(short k) {
- // TODO: it might be better and simpler to do return
- // toBitmapOrArrayContainer(getCardinality()).add(k)
- // but note that some unit tests use this method to build up test runcontainers without calling
- // runOptimize
- int index = unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, k);
- if (index >= 0) {
- return this;// already there
- }
- index = -index - 2;// points to preceding value, possibly -1
- if (index >= 0) {// possible match
- int offset = Util.toIntUnsigned(k) - Util.toIntUnsigned(getValue(index));
- int le = Util.toIntUnsigned(getLength(index));
- if (offset <= le) {
- return this;
- }
- if (offset == le + 1) {
- // we may need to fuse
- if (index + 1 < nbrruns) {
- if (Util.toIntUnsigned(getValue(index + 1)) == Util.toIntUnsigned(k) + 1) {
- // indeed fusion is needed
- setLength(index,
- (short) (getValue(index + 1) + getLength(index + 1) - getValue(index)));
- recoverRoomAtIndex(index + 1);
- return this;
- }
- }
- incrementLength(index);
- return this;
- }
- if (index + 1 < nbrruns) {
- // we may need to fuse
- if (Util.toIntUnsigned(getValue(index + 1)) == Util.toIntUnsigned(k) + 1) {
- // indeed fusion is needed
- setValue(index + 1, k);
- setLength(index + 1, (short) (getLength(index + 1) + 1));
- return this;
- }
- }
- }
- if (index == -1) {
- // we may need to extend the first run
- if (0 < nbrruns) {
- if (getValue(0) == k + 1) {
- incrementLength(0);
- decrementValue(0);
- return this;
- }
- }
- }
- makeRoomAtIndex(index + 1);
- setValue(index + 1, k);
- setLength(index + 1, (short) 0);
- return this;
- }
-
- @Override
- public Container and(ArrayContainer x) {
- ArrayContainer ac = new ArrayContainer(x.cardinality);
- if (this.nbrruns == 0) {
- return ac;
- }
- int rlepos = 0;
- int arraypos = 0;
-
- int rleval = Util.toIntUnsigned(this.getValue(rlepos));
- int rlelength = Util.toIntUnsigned(this.getLength(rlepos));
- while (arraypos < x.cardinality) {
- int arrayval = Util.toIntUnsigned(x.content[arraypos]);
- while (rleval + rlelength < arrayval) {// this will frequently be false
- ++rlepos;
- if (rlepos == this.nbrruns) {
- return ac;// we are done
- }
- rleval = Util.toIntUnsigned(this.getValue(rlepos));
- rlelength = Util.toIntUnsigned(this.getLength(rlepos));
- }
- if (rleval > arrayval) {
- arraypos = Util.advanceUntil(x.content, arraypos, x.cardinality, (short) rleval);
- } else {
- ac.content[ac.cardinality] = (short) arrayval;
- ac.cardinality++;
- arraypos++;
- }
- }
- return ac;
- }
-
-
- @Override
- public Container and(BitmapContainer x) {
- // could be implemented as return toBitmapOrArrayContainer().iand(x);
- int card = this.getCardinality();
- if (card <= ArrayContainer.DEFAULT_MAX_SIZE) {
- // result can only be an array (assuming that we never make a RunContainer)
- if (card > x.cardinality) {
- card = x.cardinality;
- }
- ArrayContainer answer = new ArrayContainer(card);
- answer.cardinality = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = Util.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + Util.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (x.contains((short) runValue)) {// it looks like contains() should be cheap enough if
- // accessed sequentially
- answer.content[answer.cardinality++] = (short) runValue;
- }
- }
- }
- return answer;
- }
- // we expect the answer to be a bitmap (if we are lucky)
- BitmapContainer answer = x.clone();
- int start = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int end = Util.toIntUnsigned(this.getValue(rlepos));
- Util.resetBitmapRange(answer.bitmap, start, end); // had been x.bitmap
- start = end + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- Util.resetBitmapRange(answer.bitmap, start, Util.maxLowBitAsInteger() + 1); // had been x.bitmap
- answer.computeCardinality();
- if (answer.getCardinality() > ArrayContainer.DEFAULT_MAX_SIZE) {
- return answer;
- } else {
- return answer.toArrayContainer();
- }
- }
-
- @Override
- public Container and(RunContainer x) {
- RunContainer answer = new RunContainer(new short[2 * (this.nbrruns + x.nbrruns)], 0);
- int rlepos = 0;
- int xrlepos = 0;
- int start = Util.toIntUnsigned(this.getValue(rlepos));
- int end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- if (ENABLE_GALLOPING_AND) {
- rlepos = skipAhead(this, rlepos, xstart); // skip over runs until we have end > xstart (or
- // rlepos is advanced beyond end)
- } else {
- ++rlepos;
- }
-
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- if (ENABLE_GALLOPING_AND) {
- xrlepos = skipAhead(x, xrlepos, start);
- } else {
- ++xrlepos;
- }
-
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {// they overlap
- final int lateststart = start > xstart ? start : xstart;
- int earliestend;
- if (end == xend) {// improbable
- earliestend = end;
- rlepos++;
- xrlepos++;
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else if (end < xend) {
- earliestend = end;
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
-
- } else {// end > xend
- earliestend = xend;
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- }
- answer.valueslength[2 * answer.nbrruns] = (short) lateststart;
- answer.valueslength[2 * answer.nbrruns + 1] = (short) (earliestend - lateststart - 1);
- answer.nbrruns++;
- }
- }
- return answer.toEfficientContainer(); // subsequent trim() may be required to avoid wasted
- // space.
- }
-
- @Override
- public int andCardinality(ArrayContainer x) {
- if (this.nbrruns == 0) {
- return x.cardinality;
- }
- int rlepos = 0;
- int arraypos = 0;
- int andCardinality = 0;
- int rleval = Util.toIntUnsigned(this.getValue(rlepos));
- int rlelength = Util.toIntUnsigned(this.getLength(rlepos));
- while (arraypos < x.cardinality) {
- int arrayval = Util.toIntUnsigned(x.content[arraypos]);
- while (rleval + rlelength < arrayval) {// this will frequently be false
- ++rlepos;
- if (rlepos == this.nbrruns) {
- return andCardinality;// we are done
- }
- rleval = Util.toIntUnsigned(this.getValue(rlepos));
- rlelength = Util.toIntUnsigned(this.getLength(rlepos));
- }
- if (rleval > arrayval) {
- arraypos = Util.advanceUntil(x.content, arraypos, x.cardinality, this.getValue(rlepos));
- } else {
- andCardinality++;
- arraypos++;
- }
- }
- return andCardinality;
- }
-
-
- @Override
- public int andCardinality(BitmapContainer x) {
- // could be implemented as return toBitmapOrArrayContainer().iand(x);
- int cardinality = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = Util.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + Util.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (x.contains((short) runValue)) {// it looks like contains() should be cheap enough if
- // accessed sequentially
- cardinality++;
- }
- }
- }
- return cardinality;
- }
-
- @Override
- public int andCardinality(RunContainer x) {
- int cardinality = 0;
- int rlepos = 0;
- int xrlepos = 0;
- int start = Util.toIntUnsigned(this.getValue(rlepos));
- int end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- if (ENABLE_GALLOPING_AND) {
- rlepos = skipAhead(this, rlepos, xstart); // skip over runs until we have end > xstart (or
- // rlepos is advanced beyond end)
- } else {
- ++rlepos;
- }
-
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- if (ENABLE_GALLOPING_AND) {
- xrlepos = skipAhead(x, xrlepos, start);
- } else {
- ++xrlepos;
- }
-
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {// they overlap
- final int lateststart = start > xstart ? start : xstart;
- int earliestend;
- if (end == xend) {// improbable
- earliestend = end;
- rlepos++;
- xrlepos++;
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else if (end < xend) {
- earliestend = end;
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
-
- } else {// end > xend
- earliestend = xend;
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- }
- // earliestend - lateststart are all values that are true.
- cardinality += (short) (earliestend - lateststart);
- }
- }
- return cardinality;
- }
-
- @Override
- public Container andNot(ArrayContainer x) {
- // when x is small, we guess that the result will still be a run container
- final int arbitrary_threshold = 32; // this is arbitrary
- if (x.getCardinality() < arbitrary_threshold) {
- return lazyandNot(x).toEfficientContainer();
- }
- // otherwise we generate either an array or bitmap container
- final int card = getCardinality();
- if (card <= ArrayContainer.DEFAULT_MAX_SIZE) {
- // if the cardinality is small, we construct the solution in place
- ArrayContainer ac = new ArrayContainer(card);
- ac.cardinality =
- Util.unsignedDifference(this.getShortIterator(), x.getShortIterator(), ac.content);
- return ac;
- }
- // otherwise, we generate a bitmap
- return toBitmapOrArrayContainer(card).iandNot(x);
- }
-
- @Override
- public Container andNot(BitmapContainer x) {
- // could be implemented as toTemporaryBitmap().iandNot(x);
- int card = this.getCardinality();
- if (card <= ArrayContainer.DEFAULT_MAX_SIZE) {
- // result can only be an array (assuming that we never make a RunContainer)
- ArrayContainer answer = new ArrayContainer(card);
- answer.cardinality = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = Util.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + Util.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (!x.contains((short) runValue)) {// it looks like contains() should be cheap enough if
- // accessed sequentially
- answer.content[answer.cardinality++] = (short) runValue;
- }
- }
- }
- return answer;
- }
- // we expect the answer to be a bitmap (if we are lucky)
- BitmapContainer answer = x.clone();
- int lastPos = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int start = Util.toIntUnsigned(this.getValue(rlepos));
- int end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- Util.resetBitmapRange(answer.bitmap, lastPos, start);
- Util.flipBitmapRange(answer.bitmap, start, end);
- lastPos = end;
- }
- Util.resetBitmapRange(answer.bitmap, lastPos, answer.bitmap.length * 64);
- answer.computeCardinality();
- if (answer.getCardinality() > ArrayContainer.DEFAULT_MAX_SIZE) {
- return answer;
- } else {
- return answer.toArrayContainer();
- }
- }
-
- @Override
- public Container andNot(RunContainer x) {
- RunContainer answer = new RunContainer(new short[2 * (this.nbrruns + x.nbrruns)], 0);
- int rlepos = 0;
- int xrlepos = 0;
- int start = Util.toIntUnsigned(this.getValue(rlepos));
- int end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- // output the first run
- answer.valueslength[2 * answer.nbrruns] = (short) start;
- answer.valueslength[2 * answer.nbrruns + 1] = (short) (end - start - 1);
- answer.nbrruns++;
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {
- if (start < xstart) {
- answer.valueslength[2 * answer.nbrruns] = (short) start;
- answer.valueslength[2 * answer.nbrruns + 1] = (short) (xstart - start - 1);
- answer.nbrruns++;
- }
- if (xend < end) {
- start = xend;
- } else {
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- }
- }
- }
- if (rlepos < this.nbrruns) {
- answer.valueslength[2 * answer.nbrruns] = (short) start;
- answer.valueslength[2 * answer.nbrruns + 1] = (short) (end - start - 1);
- answer.nbrruns++;
- rlepos++;
- if (rlepos < this.nbrruns) {
- System.arraycopy(this.valueslength, 2 * rlepos, answer.valueslength, 2 * answer.nbrruns,
- 2 * (this.nbrruns - rlepos));
- answer.nbrruns = answer.nbrruns + this.nbrruns - rlepos;
- }
- }
- return answer.toEfficientContainer();
- }
-
- // Append a value length with all values until a given value
- private void appendValueLength(int value, int index) {
- int previousValue = Util.toIntUnsigned(getValue(index));
- int length = Util.toIntUnsigned(getLength(index));
- int offset = value - previousValue;
- if (offset > length) {
- setLength(index, (short) offset);
- }
- }
-
- // To check if a value length can be prepended with a given value
- private boolean canPrependValueLength(int value, int index) {
- if (index < this.nbrruns) {
- int nextValue = Util.toIntUnsigned(getValue(index));
- return nextValue == value + 1;
- }
- return false;
- }
-
- @Override
- public void clear() {
- nbrruns = 0;
- }
-
- @Override
- public Container clone() {
- return new RunContainer(nbrruns, valueslength);
- }
-
- // To set the last value of a value length
- private void closeValueLength(int value, int index) {
- int initialValue = Util.toIntUnsigned(getValue(index));
- setLength(index, (short) (value - initialValue));
- }
-
- @Override
- public boolean contains(short x) {
- int index = unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, x);
- if (index >= 0) {
- return true;
- }
- index = -index - 2; // points to preceding value, possibly -1
- if (index != -1) {// possible match
- int offset = Util.toIntUnsigned(x) - Util.toIntUnsigned(getValue(index));
- int le = Util.toIntUnsigned(getLength(index));
- return offset <= le;
- }
- return false;
- }
-
-
- // a very cheap check... if you have more than 4096, then you should use a bitmap container.
- // this function avoids computing the cardinality
- private Container convertToLazyBitmapIfNeeded() {
- // when nbrruns exceed ArrayContainer.DEFAULT_MAX_SIZE, then we know it should be stored as a
- // bitmap, always
- if (this.nbrruns > ArrayContainer.DEFAULT_MAX_SIZE) {
- BitmapContainer answer = new BitmapContainer();
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int start = Util.toIntUnsigned(this.getValue(rlepos));
- int end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- Util.setBitmapRange(answer.bitmap, start, end);
- }
- answer.cardinality = -1;
- return answer;
- }
- return this;
- }
-
-
- // Push all values length to the end of the array (resize array if needed)
- private void copyToOffset(int offset) {
- final int minCapacity = 2 * (offset + nbrruns);
- if (valueslength.length < minCapacity) {
- // expensive case where we need to reallocate
- int newCapacity = valueslength.length;
- while (newCapacity < minCapacity) {
- newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE
- : newCapacity < 64 ? newCapacity * 2
- : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4;
- }
- short[] newvalueslength = new short[newCapacity];
- copyValuesLength(this.valueslength, 0, newvalueslength, offset, nbrruns);
- this.valueslength = newvalueslength;
- } else {
- // efficient case where we just copy
- copyValuesLength(this.valueslength, 0, this.valueslength, offset, nbrruns);
- }
- }
-
- private void copyValuesLength(short[] src, int srcIndex, short[] dst, int dstIndex, int length) {
- System.arraycopy(src, 2 * srcIndex, dst, 2 * dstIndex, 2 * length);
- }
-
- private void decrementLength(int index) {
- valueslength[2 * index + 1]--;// caller is responsible to ensure that value is non-zero
- }
-
-
- private void decrementValue(int index) {
- valueslength[2 * index]--;
- }
-
- @Override
- public void deserialize(DataInput in) throws IOException {
- nbrruns = Short.reverseBytes(in.readShort());
- if (valueslength.length < 2 * nbrruns) {
- valueslength = new short[2 * nbrruns];
- }
- for (int k = 0; k < 2 * nbrruns; ++k) {
- this.valueslength[k] = Short.reverseBytes(in.readShort());
- }
- }
-
- // not actually used anywhere, but potentially useful
- protected void ensureCapacity(int minNbRuns) {
- final int minCapacity = 2 * minNbRuns;
- if (valueslength.length < minCapacity) {
- int newCapacity = valueslength.length;
- while (newCapacity < minCapacity) {
- newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE
- : newCapacity < 64 ? newCapacity * 2
- : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4;
- }
- short[] nv = new short[newCapacity];
- copyValuesLength(valueslength, 0, nv, 0, nbrruns);
- valueslength = nv;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof RunContainer) {
- RunContainer srb = (RunContainer) o;
- if (srb.nbrruns != this.nbrruns) {
- return false;
- }
- for (int i = 0; i < nbrruns; ++i) {
- if (this.getValue(i) != srb.getValue(i)) {
- return false;
- }
- if (this.getLength(i) != srb.getLength(i)) {
- return false;
- }
- }
- return true;
- } else if (o instanceof Container) {
- if (((Container) o).getCardinality() != this.getCardinality()) {
- return false; // should be a frequent branch if they differ
- }
- // next bit could be optimized if needed:
- ShortIterator me = this.getShortIterator();
- ShortIterator you = ((Container) o).getShortIterator();
- while (me.hasNext()) {
- if (me.next() != you.next()) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void fillLeastSignificant16bits(int[] x, int i, int mask) {
- int pos = i;
- for (int k = 0; k < this.nbrruns; ++k) {
- final int limit = Util.toIntUnsigned(this.getLength(k));
- final int base = Util.toIntUnsigned(this.getValue(k));
- for (int le = 0; le <= limit; ++le) {
- x[pos++] = (base + le) | mask;
- }
- }
- }
-
- @Override
- public Container flip(short x) {
- if (this.contains(x)) {
- return this.remove(x);
- } else {
- return this.add(x);
- }
- }
-
- @Override
- protected int getArraySizeInBytes() {
- return 2 + 4 * this.nbrruns; // "array" includes its size
- }
-
-
- @Override
- public int getCardinality() {
- int sum = nbrruns;// lengths are returned -1
- for (int k = 0; k < nbrruns; ++k) {
- sum = sum + Util.toIntUnsigned(getLength(k))/* + 1 */;
- }
- return sum;
- }
-
- short getLength(int index) {
- return valueslength[2 * index + 1];
- }
-
- @Override
- public ShortIterator getReverseShortIterator() {
- return new ReverseRunContainerShortIterator(this);
- }
-
- @Override
- public PeekableShortIterator getShortIterator() {
- return new RunContainerShortIterator(this);
- }
-
- @Override
- public int getSizeInBytes() {
- return this.nbrruns * 4 + 4;
- }
-
- short getValue(int index) {
- return valueslength[2 * index];
- }
-
- @Override
- public int hashCode() {
- int hash = 0;
- for (int k = 0; k < nbrruns * 2; ++k) {
- hash += 31 * hash + valueslength[k];
- }
- return hash;
- }
-
- @Override
- public Container iadd(int begin, int end) {
- // TODO: it might be better and simpler to do return
- // toBitmapOrArrayContainer(getCardinality()).iadd(begin,end)
- if (end == begin) {
- return this;
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
-
- if (begin == end - 1) {
- add((short) begin);
- return this;
- }
-
- int bIndex = unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (short) begin);
- int eIndex =
- unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (short) (end - 1));
-
- if (bIndex >= 0 && eIndex >= 0) {
- mergeValuesLength(bIndex, eIndex);
- return this;
-
- } else if (bIndex >= 0 && eIndex < 0) {
- eIndex = -eIndex - 2;
-
- if (canPrependValueLength(end - 1, eIndex + 1)) {
- mergeValuesLength(bIndex, eIndex + 1);
- return this;
- }
-
- appendValueLength(end - 1, eIndex);
- mergeValuesLength(bIndex, eIndex);
- return this;
-
- } else if (bIndex < 0 && eIndex >= 0) {
- bIndex = -bIndex - 2;
-
- if (bIndex >= 0) {
- if (valueLengthContains(begin - 1, bIndex)) {
- mergeValuesLength(bIndex, eIndex);
- return this;
- }
- }
- prependValueLength(begin, bIndex + 1);
- mergeValuesLength(bIndex + 1, eIndex);
- return this;
-
- } else {
- bIndex = -bIndex - 2;
- eIndex = -eIndex - 2;
-
- if (eIndex >= 0) {
- if (bIndex >= 0) {
- if (!valueLengthContains(begin - 1, bIndex)) {
- if (bIndex == eIndex) {
- if (canPrependValueLength(end - 1, eIndex + 1)) {
- prependValueLength(begin, eIndex + 1);
- return this;
- }
- makeRoomAtIndex(eIndex + 1);
- setValue(eIndex + 1, (short) begin);
- setLength(eIndex + 1, (short) (end - 1 - begin));
- return this;
-
- } else {
- bIndex++;
- prependValueLength(begin, bIndex);
- }
- }
- } else {
- bIndex = 0;
- prependValueLength(begin, bIndex);
- }
-
- if (canPrependValueLength(end - 1, eIndex + 1)) {
- mergeValuesLength(bIndex, eIndex + 1);
- return this;
- }
-
- appendValueLength(end - 1, eIndex);
- mergeValuesLength(bIndex, eIndex);
- return this;
-
- } else {
- if (canPrependValueLength(end - 1, 0)) {
- prependValueLength(begin, 0);
- } else {
- makeRoomAtIndex(0);
- setValue(0, (short) begin);
- setLength(0, (short) (end - 1 - begin));
- }
- return this;
- }
- }
- }
-
- @Override
- public Container iand(ArrayContainer x) {
- return and(x);
- }
-
- @Override
- public Container iand(BitmapContainer x) {
- return and(x);
- }
-
-
- @Override
- public Container iand(RunContainer x) {
- return and(x);
- }
-
-
- @Override
- public Container iandNot(ArrayContainer x) {
- return andNot(x);
- }
-
- @Override
- public Container iandNot(BitmapContainer x) {
- return andNot(x);
- }
-
- @Override
- public Container iandNot(RunContainer x) {
- return andNot(x);
- }
-
- protected Container ilazyor(ArrayContainer x) {
- if (isFull()) {
- return this; // this can sometimes solve a lot of computation!
- }
- return ilazyorToRun(x);
- }
-
- private Container ilazyorToRun(ArrayContainer x) {
- if (isFull()) {
- return this.clone();
- }
- final int nbrruns = this.nbrruns;
- final int offset = Math.max(nbrruns, x.getCardinality());
- copyToOffset(offset);
- int rlepos = 0;
- this.nbrruns = 0;
- PeekableShortIterator i = x.getShortIterator();
- while (i.hasNext() && (rlepos < nbrruns)) {
- if (Util.compareUnsigned(getValue(rlepos + offset), i.peekNext()) <= 0) {
- smartAppend(getValue(rlepos + offset), getLength(rlepos + offset));
- rlepos++;
- } else {
- smartAppend(i.next());
- }
- }
- if (i.hasNext()) {
- /*
- * if(this.nbrruns>0) { // this might be useful if the run container has just one very large
- * run int lastval = Util.toIntUnsigned(getValue(nbrruns + offset - 1)) +
- * Util.toIntUnsigned(getLength(nbrruns + offset - 1)) + 1; i.advanceIfNeeded((short)
- * lastval); }
- */
- while (i.hasNext()) {
- smartAppend(i.next());
- }
- } else {
- while (rlepos < nbrruns) {
- smartAppend(getValue(rlepos + offset), getLength(rlepos + offset));
- rlepos++;
- }
- }
- return convertToLazyBitmapIfNeeded();
- }
-
- private void increaseCapacity() {
- int newCapacity = (valueslength.length == 0) ? DEFAULT_INIT_SIZE
- : valueslength.length < 64 ? valueslength.length * 2
- : valueslength.length < 1024 ? valueslength.length * 3 / 2
- : valueslength.length * 5 / 4;
- short[] nv = new short[newCapacity];
- System.arraycopy(valueslength, 0, nv, 0, 2 * nbrruns);
- valueslength = nv;
- }
-
-
- private void incrementLength(int index) {
- valueslength[2 * index + 1]++;
- }
-
-
- private void incrementValue(int index) {
- valueslength[2 * index]++;
- }
-
- // To set the first value of a value length
- private void initValueLength(int value, int index) {
- int initialValue = Util.toIntUnsigned(getValue(index));
- int length = Util.toIntUnsigned(getLength(index));
- setValue(index, (short) (value));
- setLength(index, (short) (length - (value - initialValue)));
- }
-
- @Override
- public Container inot(int rangeStart, int rangeEnd) {
- if (rangeEnd <= rangeStart) {
- return this;
- }
-
- // TODO: write special case code for rangeStart=0; rangeEnd=65535
- // a "sliding" effect where each range records the gap adjacent it
- // can probably be quite fast. Probably have 2 cases: start with a
- // 0 run vs start with a 1 run. If you both start and end with 0s,
- // you will require room for expansion.
-
- // the +1 below is needed in case the valueslength.length is odd
- if (valueslength.length <= 2 * nbrruns + 1) {
- // no room for expansion
- // analyze whether this is a case that will require expansion (that we cannot do)
- // this is a bit costly now (4 "contains" checks)
-
- boolean lastValueBeforeRange = false;
- boolean firstValueInRange = false;
- boolean lastValueInRange = false;
- boolean firstValuePastRange = false;
-
- // contains is based on a binary search and is hopefully fairly fast.
- // however, one binary search could *usually* suffice to find both
- // lastValueBeforeRange AND firstValueInRange. ditto for
- // lastVaueInRange and firstValuePastRange
-
- // find the start of the range
- if (rangeStart > 0) {
- lastValueBeforeRange = contains((short) (rangeStart - 1));
- }
- firstValueInRange = contains((short) rangeStart);
-
- if (lastValueBeforeRange == firstValueInRange) {
- // expansion is required if also lastValueInRange==firstValuePastRange
-
- // tougher to optimize out, but possible.
- lastValueInRange = contains((short) (rangeEnd - 1));
- if (rangeEnd != 65536) {
- firstValuePastRange = contains((short) rangeEnd);
- }
-
- // there is definitely one more run after the operation.
- if (lastValueInRange == firstValuePastRange) {
- return not(rangeStart, rangeEnd); // can't do in-place: true space limit
- }
- }
- }
- // either no expansion required, or we have room to handle any required expansion for it.
-
- // remaining code is just a minor variation on not()
- int myNbrRuns = nbrruns;
-
- RunContainer ans = this; // copy on top of self.
- int k = 0;
- ans.nbrruns = 0; // losing this.nbrruns, which is stashed in myNbrRuns.
-
- // could try using unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, rangeStart) instead
- // of sequential scan
- // to find the starting location
-
- for (; (k < myNbrRuns) && (Util.toIntUnsigned(this.getValue(k)) < rangeStart); ++k) {
- // since it is atop self, there is no copying needed
- // ans.valueslength[2 * k] = this.valueslength[2 * k];
- // ans.valueslength[2 * k + 1] = this.valueslength[2 * k + 1];
- ans.nbrruns++;
- }
- // We will work left to right, with a read pointer that always stays
- // left of the write pointer. However, we need to give the read pointer a head start.
- // use local variables so we are always reading 1 location ahead.
-
- short bufferedValue = 0, bufferedLength = 0; // 65535 start and 65535 length would be illegal,
- // could use as sentinel
- short nextValue = 0, nextLength = 0;
- if (k < myNbrRuns) { // prime the readahead variables
- bufferedValue = getValue(k);
- bufferedLength = getLength(k);
- }
-
- ans.smartAppendExclusive((short) rangeStart, (short) (rangeEnd - rangeStart - 1));
-
- for (; k < myNbrRuns; ++k) {
- if (ans.nbrruns > k + 1) {
- throw new RuntimeException(
- "internal error in inot, writer has overtaken reader!! " + k + " " + ans.nbrruns);
- }
- if (k + 1 < myNbrRuns) {
- nextValue = getValue(k + 1); // readahead for next iteration
- nextLength = getLength(k + 1);
- }
- ans.smartAppendExclusive(bufferedValue, bufferedLength);
- bufferedValue = nextValue;
- bufferedLength = nextLength;
- }
- // the number of runs can increase by one, meaning (rarely) a bitmap will become better
- // or the cardinality can decrease by a lot, making an array better
- return ans.toEfficientContainer();
- }
-
- @Override
- public boolean intersects(ArrayContainer x) {
- if (this.nbrruns == 0) {
- return false;
- }
- int rlepos = 0;
- int arraypos = 0;
- int rleval = Util.toIntUnsigned(this.getValue(rlepos));
- int rlelength = Util.toIntUnsigned(this.getLength(rlepos));
- while (arraypos < x.cardinality) {
- int arrayval = Util.toIntUnsigned(x.content[arraypos]);
- while (rleval + rlelength < arrayval) {// this will frequently be false
- ++rlepos;
- if (rlepos == this.nbrruns) {
- return false;
- }
- rleval = Util.toIntUnsigned(this.getValue(rlepos));
- rlelength = Util.toIntUnsigned(this.getLength(rlepos));
- }
- if (rleval > arrayval) {
- arraypos = Util.advanceUntil(x.content, arraypos, x.cardinality, this.getValue(rlepos));
- } else {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean intersects(BitmapContainer x) {
- // TODO: this is probably not optimally fast
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = Util.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + Util.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (x.contains((short) runValue)) {
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public boolean intersects(RunContainer x) {
- int rlepos = 0;
- int xrlepos = 0;
- int start = Util.toIntUnsigned(this.getValue(rlepos));
- int end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- if (ENABLE_GALLOPING_AND) {
- rlepos = skipAhead(this, rlepos, xstart); // skip over runs until we have end > xstart (or
- // rlepos is advanced beyond end)
- } else {
- ++rlepos;
- }
-
- if (rlepos < this.nbrruns) {
- start = Util.toIntUnsigned(this.getValue(rlepos));
- end = start + Util.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- if (ENABLE_GALLOPING_AND) {
- xrlepos = skipAhead(x, xrlepos, start);
- } else {
- ++xrlepos;
- }
-
- if (xrlepos < x.nbrruns) {
- xstart = Util.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + Util.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {// they overlap
- return true;
- }
- }
- return false;
- }
-
- @Override
- public Container ior(ArrayContainer x) {
- if (isFull()) {
- return this;
- }
- final int nbrruns = this.nbrruns;
- final int offset = Math.max(nbrruns, x.getCardinality());
- copyToOffset(offset);
- int rlepos = 0;
- this.nbrruns = 0;
- PeekableShortIterator i = x.getShortIterator();
- while (i.hasNext() && (rlepos < nbrruns)) {
- if (Util.compareUnsigned(getValue(rlepos + offset), i.peekNext()) <= 0) {
- smartAppend(getValue(rlepos + offset), getLength(rlepos + offset));
- rlepos++;
- } else {
- smartAppend(i.next());
- }
- }
- if (i.hasNext()) {
- /*
- * if(this.nbrruns>0) { // this might be useful if the run container has just one very large
- * run int lastval = Util.toIntUnsigned(getValue(nbrruns + offset - 1)) +
- * Util.toIntUnsigned(getLength(nbrruns + offset - 1)) + 1; i.advanceIfNeeded((short)
- * lastval); }
- */
- while (i.hasNext()) {
- smartAppend(i.next());
- }
- } else {
- while (rlepos < nbrruns) {
- smartAppend(getValue(rlepos + offset), getLength(rlepos + offset));
- rlepos++;
- }
- }
- return toEfficientContainer();
- }
-
- @Override
- public Container ior(BitmapContainer x) {
- if (isFull()) {
- return this;
- }
- return or(x);
- }
-
- @Override
- public Container ior(RunContainer x) {
- if (isFull()) {
- return this;
- }
-
- final int nbrruns = this.nbrruns;
- final int xnbrruns = x.nbrruns;
- final int offset = Math.max(nbrruns, xnbrruns);
-
- // Push all values length to the end of the array (resize array if needed)
- copyToOffset(offset);
- // Aggregate and store the result at the beginning of the array
- this.nbrruns = 0;
- int rlepos = 0;
- int xrlepos = 0;
-
- // Add values length (smaller first)
- while ((rlepos < nbrruns) && (xrlepos < xnbrruns)) {
- final short value = this.getValue(offset + rlepos);
- final short xvalue = x.getValue(xrlepos);
- final short length = this.getLength(offset + rlepos);
- final short xlength = x.getLength(xrlepos);
-
- if (Util.compareUnsigned(value, xvalue) <= 0) {
- this.smartAppend(value, length);
- ++rlepos;
- } else {
- this.smartAppend(xvalue, xlength);
- ++xrlepos;
- }
- }
-
- while (rlepos < nbrruns) {
- this.smartAppend(this.getValue(offset + rlepos), this.getLength(offset + rlepos));
- ++rlepos;
- }
-
- while (xrlepos < xnbrruns) {
- this.smartAppend(x.getValue(xrlepos), x.getLength(xrlepos));
- ++xrlepos;
- }
- return this.toBitmapIfNeeded();
- }
-
- @Override
- public Container iremove(int begin, int end) {
- // TODO: it might be better and simpler to do return
- // toBitmapOrArrayContainer(getCardinality()).iremove(begin,end)
- if (end == begin) {
- return this;
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
- if (begin == end - 1) {
- remove((short) begin);
- return this;
- }
-
- int bIndex = unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (short) begin);
- int eIndex =
- unsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (short) (end - 1));
-
- // note, eIndex is looking for (end-1)
-
- if (bIndex >= 0) { // beginning marks beginning of a run
- if (eIndex < 0) {
- eIndex = -eIndex - 2;
- }
- // eIndex could be a run that begins exactly at "end"
- // or it might be an earlier run
-
- // if the end is before the first run, we'd have eIndex==-1. But bIndex makes this impossible.
-
- if (valueLengthContains(end, eIndex)) {
- initValueLength(end, eIndex); // there is something left in the run
- recoverRoomsInRange(bIndex - 1, eIndex - 1);
- } else {
- recoverRoomsInRange(bIndex - 1, eIndex); // nothing left in the run
- }
-
- } else if (bIndex < 0 && eIndex >= 0) {
- // start does not coincide to a run start, but end does.
- bIndex = -bIndex - 2;
-
- if (bIndex >= 0) {
- if (valueLengthContains(begin, bIndex)) {
- closeValueLength(begin - 1, bIndex);
- }
- }
-
- // last run is one shorter
- if (getLength(eIndex) == 0) {// special case where we remove last run
- recoverRoomsInRange(eIndex, eIndex + 1);
- } else {
- incrementValue(eIndex);
- decrementLength(eIndex);
- }
- recoverRoomsInRange(bIndex, eIndex - 1);
-
- } else {
- bIndex = -bIndex - 2;
- eIndex = -eIndex - 2;
-
- if (eIndex >= 0) { // end-1 is not before first run.
- if (bIndex >= 0) { // nor is begin
- if (bIndex == eIndex) { // all removal nested properly between
- // one run start and the next
- if (valueLengthContains(begin, bIndex)) {
- if (valueLengthContains(end, eIndex)) {
- // proper nesting within a run, generates 2 sub-runs
- makeRoomAtIndex(bIndex);
- closeValueLength(begin - 1, bIndex);
- initValueLength(end, bIndex + 1);
- return this;
- }
- // removed area extends beyond run.
- closeValueLength(begin - 1, bIndex);
- }
- } else { // begin in one run area, end in a later one.
- if (valueLengthContains(begin, bIndex)) {
- closeValueLength(begin - 1, bIndex);
- // this cannot leave the bIndex run empty.
- }
- if (valueLengthContains(end, eIndex)) {
- // there is additional stuff in the eIndex run
- initValueLength(end, eIndex);
- eIndex--;
- } else {
- // run ends at or before the range being removed, can deleteById it
- }
- recoverRoomsInRange(bIndex, eIndex);
- }
-
- } else {
- // removed range begins before the first run
- if (valueLengthContains(end, eIndex)) { // had been end-1
- initValueLength(end, eIndex);
- recoverRoomsInRange(bIndex, eIndex - 1);
- } else { // removed range includes all the last run
- recoverRoomsInRange(bIndex, eIndex);
- }
- }
-
- } else {
- // eIndex == -1: whole range is before first run, nothing to deleteById...
- }
-
- }
- return this;
- }
-
- protected boolean isFull() {
- return (this.nbrruns == 1) && (this.getValue(0) == 0) && (this.getLength(0) == -1);
- }
-
- @Override
- public Iterator
- * In practice, calls {#link naive_and}
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap and(ImmutableRoaringBitmap... bitmaps) {
- return naive_and(bitmaps);
- }
-
- /**
- * Compute the AND aggregate.
- *
- * In practice, calls {#link naive_and}
- *
- * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap)
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap and(@SuppressWarnings("rawtypes") Iterator bitmaps) {
- return naive_and(bitmaps);
- }
-
- /**
- * Compute the AND aggregate.
- *
- * In practice, calls {#link naive_and}
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap and(MutableRoaringBitmap... bitmaps) {
- return and(convertToImmutable(bitmaps));
- }
-
- /**
- * Convenience method converting one type of iterator into another, to avoid unnecessary warnings.
- *
- * @param i input bitmaps
- * @return an iterator over the provided iterator, with a different type
- */
- public static Iterator
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #or(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap horizontal_or(ImmutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- if (bitmaps.length == 0) {
- return answer;
- }
- PriorityQueue
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #or(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap horizontal_or(MutableRoaringBitmap... bitmaps) {
- return horizontal_or(convertToImmutable(bitmaps));
- }
-
- /**
- * Minimizes memory usage while computing the xor aggregate on a moderate number of bitmaps.
- *
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #xor(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap horizontal_xor(ImmutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- if (bitmaps.length == 0) {
- return answer;
- }
- PriorityQueue
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #xor(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap horizontal_xor(MutableRoaringBitmap... bitmaps) {
- return horizontal_xor(convertToImmutable(bitmaps));
- }
-
- /**
- * Compute overall AND between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_and(ImmutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer;
-
- if (bitmaps.length > 0) {
- answer = (bitmaps[0]).toMutableRoaringBitmap();
- for (int k = 1; k < bitmaps.length; ++k) {
- answer = ImmutableRoaringBitmap.and(answer, bitmaps[k]);
- }
- } else {
- answer = new MutableRoaringBitmap();
- }
-
- return answer;
- }
-
- /**
- * Compute overall AND between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap)
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_and(@SuppressWarnings("rawtypes") Iterator bitmaps) {
- if (!bitmaps.hasNext()) {
- return new MutableRoaringBitmap();
- }
- MutableRoaringBitmap answer =
- ((ImmutableRoaringBitmap) bitmaps.next()).toMutableRoaringBitmap();
- while (bitmaps.hasNext()) {
- answer.and((ImmutableRoaringBitmap) bitmaps.next());
- }
- return answer;
- }
-
- /**
- * Compute overall AND between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_and(MutableRoaringBitmap... bitmaps) {
- if (bitmaps.length == 0) {
- return new MutableRoaringBitmap();
- }
- MutableRoaringBitmap answer = bitmaps[0].clone();
- for (int k = 1; k < bitmaps.length; ++k) {
- answer.and(bitmaps[k]);
- }
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_or(ImmutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- for (int k = 0; k < bitmaps.length; ++k) {
- answer.naivelazyor(bitmaps[k]);
- }
- answer.repairAfterLazy();
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap)
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_or(@SuppressWarnings("rawtypes") Iterator bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- while (bitmaps.hasNext()) {
- answer.naivelazyor((ImmutableRoaringBitmap) bitmaps.next());
- }
- answer.repairAfterLazy();
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_or(MutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- for (int k = 0; k < bitmaps.length; ++k) {
- answer.lazyor(bitmaps[k]);
- }
- answer.repairAfterLazy();
- return answer;
- }
-
- /**
- * Compute overall XOR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_xor(ImmutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- for (int k = 0; k < bitmaps.length; ++k) {
- answer.xor(bitmaps[k]);
- }
- return answer;
- }
-
- /**
- * Compute overall XOR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap)
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_xor(@SuppressWarnings("rawtypes") Iterator bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- while (bitmaps.hasNext()) {
- answer.xor((ImmutableRoaringBitmap) bitmaps.next());
- }
- return answer;
- }
-
- /**
- * Compute overall XOR between bitmaps two-by-two.
- *
- * This function runs in linear time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap naive_xor(MutableRoaringBitmap... bitmaps) {
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- for (int k = 0; k < bitmaps.length; ++k) {
- answer.xor(bitmaps[k]);
- }
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) {
- return naive_or(bitmaps);
- }
-
- /**
- * Compute overall OR between bitmaps.
- *
- * @param bitmaps input bitmaps (ImmutableRoaringBitmap or MutableRoaringBitmap)
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap or(@SuppressWarnings("rawtypes") Iterator bitmaps) {
- return naive_or(bitmaps);
- }
-
- /**
- * Compute overall OR between bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap or(MutableRoaringBitmap... bitmaps) {
- return naive_or(bitmaps);
- }
-
- /**
- * Uses a priority queue to compute the or aggregate.
- *
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #horizontal_or(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap priorityqueue_or(ImmutableRoaringBitmap... bitmaps) {
- if (bitmaps.length == 0) {
- return new MutableRoaringBitmap();
- } else if (bitmaps.length == 1) {
- return bitmaps[0].toMutableRoaringBitmap();
- }
- // we buffer the call to getLongSizeInBytes(), hence the code complexity
- final ImmutableRoaringBitmap[] buffer = Arrays.copyOf(bitmaps, bitmaps.length);
- final int[] sizes = new int[buffer.length];
- final boolean[] istmp = new boolean[buffer.length];
- for (int k = 0; k < sizes.length; ++k) {
- sizes[k] = buffer[k].serializedSizeInBytes();
- }
- PriorityQueue
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #horizontal_or(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap priorityqueue_or(
- @SuppressWarnings("rawtypes") Iterator bitmaps) {
- if (!bitmaps.hasNext()) {
- return new MutableRoaringBitmap();
- }
- // we buffer the call to getLongSizeInBytes(), hence the code complexity
- ArrayList
- * This function runs in linearithmic (O(n log n)) time with respect to the number of bitmaps.
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- * @see #horizontal_xor(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap priorityqueue_xor(ImmutableRoaringBitmap... bitmaps) {
- // code could be faster, see priorityqueue_or
- if (bitmaps.length < 2) {
- throw new IllegalArgumentException("Expecting at least 2 bitmaps");
- }
- final PriorityQueue
- * For better performance, consider the {@link ImmutableRoaringBitmap#forEach} method.
- *
- * @author Borislav Ivanov
- **/
-public class BufferIntIteratorFlyweight implements PeekableIntIterator {
-
- private int hs;
-
- private PeekableShortIterator iter;
-
- private MappeableArrayContainerShortIterator arrIter = new MappeableArrayContainerShortIterator();
-
- private MappeableBitmapContainerShortIterator bitmapIter =
- new MappeableBitmapContainerShortIterator();
-
- private MappeableRunContainerShortIterator runIter = new MappeableRunContainerShortIterator();
-
-
- private int pos;
-
- private ImmutableRoaringBitmap roaringBitmap = null;
-
- /**
- * Creates an instance that is not ready for iteration. You must first call
- * {@link #wrap(ImmutableRoaringBitmap)}.
- */
- public BufferIntIteratorFlyweight() {
-
- }
-
- /**
- * Creates an instance that is ready for iteration.
- *
- * @param r bitmap to be iterated over
- */
- public BufferIntIteratorFlyweight(ImmutableRoaringBitmap r) {
- wrap(r);
- }
-
- @Override
- public PeekableIntIterator clone() {
- try {
- BufferIntIteratorFlyweight x = (BufferIntIteratorFlyweight) super.clone();
- x.iter = this.iter.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return pos < this.roaringBitmap.highLowContainer.size();
- }
-
- @Override
- public int next() {
- int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- ++pos;
- nextContainer();
- }
- return x;
- }
-
- private void nextContainer() {
- if (pos < this.roaringBitmap.highLowContainer.size()) {
-
- MappeableContainer container = this.roaringBitmap.highLowContainer.getContainerAtIndex(pos);
-
- if (container instanceof MappeableBitmapContainer) {
- bitmapIter.wrap((MappeableBitmapContainer) container);
- iter = bitmapIter;
- } else if (container instanceof MappeableRunContainer) {
- runIter.wrap((MappeableRunContainer) container);
- iter = runIter;
- } else {
- arrIter.wrap((MappeableArrayContainer) container);
- iter = arrIter;
- }
-
- hs = BufferUtil.toIntUnsigned(this.roaringBitmap.highLowContainer.getKeyAtIndex(pos)) << 16;
- }
- }
-
- /**
- * Prepares a bitmap for iteration
- *
- * @param r bitmap to be iterated over
- */
- public void wrap(ImmutableRoaringBitmap r) {
- this.hs = 0;
- this.pos = 0;
- this.roaringBitmap = r;
- this.nextContainer();
- }
-
- @Override
- public void advanceIfNeeded(int minval) {
- while (hasNext() && ((hs >>> 16) < (minval >>> 16))) {
- ++pos;
- nextContainer();
- }
- if (hasNext() && ((hs >>> 16) == (minval >>> 16))) {
- iter.advanceIfNeeded(BufferUtil.lowbits(minval));
- if (!iter.hasNext()) {
- ++pos;
- nextContainer();
- }
- }
- }
-
- @Override
- public int peekNext() {
- return BufferUtil.toIntUnsigned(iter.peekNext()) | hs;
- }
-
-
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java
deleted file mode 100644
index 677aba388..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/BufferReverseIntIteratorFlyweight.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap.buffer;
-
-import com.fr.third.bitmap.roaringbitmap.IntIterator;
-import com.fr.third.bitmap.roaringbitmap.ShortIterator;
-
-/**
- * Fast iterator minimizing the stress on the garbage collector. You can create one reusable
- * instance of this class and then {@link #wrap(ImmutableRoaringBitmap)}
- *
- * This iterator enumerates the stored values in reverse (starting from the end).
- *
- * @author Borislav Ivanov
- **/
-public class BufferReverseIntIteratorFlyweight implements IntIterator {
-
- private int hs;
-
- private ShortIterator iter;
-
- private ReverseMappeableArrayContainerShortIterator arrIter =
- new ReverseMappeableArrayContainerShortIterator();
-
- private ReverseMappeableBitmapContainerShortIterator bitmapIter =
- new ReverseMappeableBitmapContainerShortIterator();
-
- private ReverseMappeableRunContainerShortIterator runIter =
- new ReverseMappeableRunContainerShortIterator();
-
- private short pos;
-
- private ImmutableRoaringBitmap roaringBitmap = null;
-
-
- /**
- * Creates an instance that is not ready for iteration. You must first call
- * {@link #wrap(ImmutableRoaringBitmap)}.
- */
- public BufferReverseIntIteratorFlyweight() {
-
- }
-
- /**
- * Creates an instance that is ready for iteration.
- *
- * @param r bitmap to be iterated over
- */
- public BufferReverseIntIteratorFlyweight(ImmutableRoaringBitmap r) {
- wrap(r);
- }
-
- @Override
- public IntIterator clone() {
- try {
- BufferReverseIntIteratorFlyweight x = (BufferReverseIntIteratorFlyweight) super.clone();
- x.iter = this.iter.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return pos >= 0;
- }
-
-
- @Override
- public int next() {
- final int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- --pos;
- nextContainer();
- }
- return x;
- }
-
- private void nextContainer() {
-
- if (pos >= 0) {
-
- MappeableContainer container = this.roaringBitmap.highLowContainer.getContainerAtIndex(pos);
-
- if (container instanceof MappeableBitmapContainer) {
- bitmapIter.wrap((MappeableBitmapContainer) container);
- iter = bitmapIter;
- } else if (container instanceof MappeableRunContainer) {
- runIter.wrap((MappeableRunContainer) container);
- iter = runIter;
- } else {
- arrIter.wrap((MappeableArrayContainer) container);
- iter = arrIter;
- }
-
- hs = BufferUtil.toIntUnsigned(this.roaringBitmap.highLowContainer.getKeyAtIndex(pos)) << 16;
- }
- }
-
- /**
- * Prepares a bitmap for iteration
- *
- * @param r bitmap to be iterated over
- */
- public void wrap(ImmutableRoaringBitmap r) {
- this.roaringBitmap = r;
- this.hs = 0;
- this.pos = (short) (this.roaringBitmap.highLowContainer.size() - 1);
- this.nextContainer();
- }
-
-}
-
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/BufferUtil.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/BufferUtil.java
deleted file mode 100644
index 7fd96590a..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/BufferUtil.java
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap.buffer;
-
-import com.fr.third.bitmap.roaringbitmap.Util;
-
-import java.nio.Buffer;
-import java.nio.LongBuffer;
-import java.nio.ShortBuffer;
-
-/**
- * Various useful methods for roaring bitmaps.
- *
- * This class is similar to Util but meant to be used with memory mapping.
- */
-public final class BufferUtil {
-
-
- /**
- * Private constructor to prevent instantiation of utility class
- */
- private BufferUtil() {
- }
-
- /**
- * Find the smallest integer larger than pos such that array[pos]>= min. If none can be found,
- * return length. Based on code by O. Kaser.
- *
- * @param array container where we search
- * @param pos initial position
- * @param min minimal threshold
- * @param length how big should the array consider to be
- * @return x greater than pos such that array[pos] is at least as large as min, pos is is equal to
- * length if it is not possible.
- */
- protected static int advanceUntil(ShortBuffer array, int pos, int length, short min) {
- int lower = pos + 1;
-
- // special handling for a possibly common sequential case
- if (lower >= length || toIntUnsigned(array.get(lower)) >= toIntUnsigned(min)) {
- return lower;
- }
-
- int spansize = 1; // could set larger
- // bootstrap an upper limit
-
- while (lower + spansize < length
- && toIntUnsigned(array.get(lower + spansize)) < toIntUnsigned(min)) {
- spansize *= 2; // hoping for compiler will reduce to
- }
- // shift
- int upper = (lower + spansize < length) ? lower + spansize : length - 1;
-
- // maybe we are lucky (could be common case when the seek ahead
- // expected
- // to be small and sequential will otherwise make us look bad)
- if (array.get(upper) == min) {
- return upper;
- }
-
- if (toIntUnsigned(array.get(upper)) < toIntUnsigned(min)) {// means
- // array
- // has no
- // item
- // >= min
- // pos = array.length;
- return length;
- }
-
- // we know that the next-smallest span was too small
- lower += (spansize / 2);
-
- // else begin binary search
- // invariant: array[lower]
- * The current bitmap is not modified.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- @Override
- public void serialize(DataOutput out) throws IOException {
- if (buffer.hasArray()) {
- out.write(buffer.array(), buffer.arrayOffset(), buffer.limit());
- } else {
- ByteBuffer tmp = buffer.duplicate();
- tmp.position(0);
- WritableByteChannel channel = Channels.newChannel((OutputStream) out);
- channel.write(tmp);
- }
- }
-
- /**
- * @return the size that the data structure occupies on disk
- */
- @Override
- public int serializedSizeInBytes() {
- return buffer.limit();
- }
-
- @Override
- public int size() {
- return this.size;
- }
-
- private int unsignedBinarySearch(short k) {
- return branchyUnsignedBinarySearch(k);
- }
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/ImmutableRoaringBitmap.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/ImmutableRoaringBitmap.java
deleted file mode 100644
index d631a142d..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/ImmutableRoaringBitmap.java
+++ /dev/null
@@ -1,1320 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap.buffer;
-
-import com.fr.third.bitmap.roaringbitmap.ImmutableBitmapDataProvider;
-import com.fr.third.bitmap.roaringbitmap.IntConsumer;
-import com.fr.third.bitmap.roaringbitmap.IntIterator;
-import com.fr.third.bitmap.roaringbitmap.PeekableIntIterator;
-import com.fr.third.bitmap.roaringbitmap.PeekableShortIterator;
-import com.fr.third.bitmap.roaringbitmap.RoaringBitmap;
-import com.fr.third.bitmap.roaringbitmap.ShortIterator;
-import com.fr.third.bitmap.roaringbitmap.Util;
-
-import java.io.DataOutput;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Iterator;
-
-/**
- * ImmutableRoaringBitmap provides a compressed immutable (cannot be modified) bitmap. It is meant
- * to be used with MutableRoaringBitmap, a derived class that adds methods
- * to modify the bitmap.
- *
- *
- * It can also be constructed from a ByteBuffer (useful for memory mapping).
- *
- * Objects of this class may reside almost entirely in memory-map files.
- *
- * @see MutableRoaringBitmap
- */
-public class ImmutableRoaringBitmap
- implements Iterable
- * It is not necessary that limit() on the input ByteBuffer indicates the end of the serialized
- * data.
- *
- * After creating this ImmutableRoaringBitmap, you can advance to the rest of the data (if there
- * is more) by setting b.position(b.position() + bitmap.serializedSizeInBytes());
- *
- * Note that the input ByteBuffer is effectively copied (with the slice operation) so you should
- * expect the provided ByteBuffer to remain unchanged.
- *
- * @param b data source
- */
- public ImmutableRoaringBitmap(final ByteBuffer b) {
- highLowContainer = new ImmutableRoaringArray(b);
- }
-
- /**
- * Computes AND between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd
- * (exclusive)
- *
- * @param bitmaps input bitmaps, these are not modified
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new result bitmap
- */
- public static MutableRoaringBitmap and(@SuppressWarnings("rawtypes") final Iterator bitmaps,
- final long rangeStart, final long rangeEnd) {
- MutableRoaringBitmap.rangeSanityCheck(rangeStart, rangeEnd);
- Iterator
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- * @see BufferFastAggregation#and(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap and(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2) {
- final MutableRoaringBitmap answer = new MutableRoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- if (s1 == s2) {
- final MappeableContainer c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final MappeableContainer c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- final MappeableContainer c = c1.and(c2);
- if (c.getCardinality() > 0) {
- answer.getMappeableRoaringArray().append(s1, c);
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- return answer;
- }
-
- /**
- * Cardinality of Bitwise AND (intersection) operation. The provided bitmaps are *not* modified.
- * This operation is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return as if you did and(x2,x2).getCardinality()
- * @see BufferFastAggregation#and(ImmutableRoaringBitmap...)
- */
- public static int andCardinality(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2) {
- int answer = 0;
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- if (s1 == s2) {
- final MappeableContainer c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final MappeableContainer c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- answer += c1.andCardinality(c2);
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- return answer;
- }
-
- /**
- * Bitwise ANDNOT (difference) operation for the given range, rangeStart (inclusive) and rangeEnd
- * (exclusive). The provided bitmaps are *not* modified. This operation is thread-safe as long as
- * the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @param rangeStart beginning of the range (inclusive)
- * @param rangeEnd end of range (exclusive)
- * @return result of the operation
- */
- public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2, long rangeStart, long rangeEnd) {
- MutableRoaringBitmap.rangeSanityCheck(rangeStart, rangeEnd);
- MutableRoaringBitmap rb1 = selectRangeWithoutCopy(x1, rangeStart, rangeEnd);
- MutableRoaringBitmap rb2 = selectRangeWithoutCopy(x2, rangeStart, rangeEnd);
- return andNot(rb1, rb2);
- }
-
- /**
- * Bitwise ANDNOT (difference) operation for the given range, rangeStart (inclusive) and rangeEnd
- * (exclusive). The provided bitmaps are *not* modified. This operation is thread-safe as long as
- * the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @param rangeStart beginning of the range (inclusive)
- * @param rangeEnd end of range (exclusive)
- * @return result of the operation
- * @deprecated use the version where longs specify the range. Negative values for range
- * endpoints are not allowed.
- */
- @Deprecated
- public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2,
- final int rangeStart, final int rangeEnd) {
- return andNot(x1, x2, (long) rangeStart, (long) rangeEnd);
- }
-
- /**
- * Bitwise ANDNOT (difference) operation. The provided bitmaps are *not* modified. This operation
- * is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- */
- public static MutableRoaringBitmap andNot(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2) {
- final MutableRoaringBitmap answer = new MutableRoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final MappeableContainer c1 = x1.highLowContainer.getContainerAtIndex(pos1);
- final MappeableContainer c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- final MappeableContainer c = c1.andNot(c2);
- if (c.getCardinality() > 0) {
- answer.getMappeableRoaringArray().append(s1, c);
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- final int nextPos1 = x1.highLowContainer.advanceUntil(s2, pos1);
- answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer, pos1, nextPos1);
- pos1 = nextPos1;
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- if (pos2 == length2) {
- answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer, pos1, length1);
- }
- return answer;
- }
-
- /**
- * Generate a bitmap with the specified values set to true. The provided integers values don't
- * have to be in sorted order, but it may be preferable to sort them from a performance point of
- * view.
- *
- * This function is equivalent to :
- *
- *
- * (Effectively calls {@link BufferFastAggregation#or})
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) {
- return BufferFastAggregation.or(bitmaps);
- }
-
- /**
- * Bitwise OR (union) operation. The provided bitmaps are *not* modified. This operation is
- * thread-safe as long as the provided bitmaps remain unchanged.
- *
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- * @see BufferFastAggregation#or(ImmutableRoaringBitmap...)
- * @see BufferFastAggregation#horizontal_or(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap or(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2) {
- final MutableRoaringBitmap answer = new MutableRoaringBitmap();
- MappeableContainerPointer i1 = x1.highLowContainer.getContainerPointer();
- MappeableContainerPointer i2 = x2.highLowContainer.getContainerPointer();
- main:
- if (i1.hasContainer() && i2.hasContainer()) {
- while (true) {
- if (i1.key() == i2.key()) {
- answer.getMappeableRoaringArray().append(i1.key(),
- i1.getContainer().or(i2.getContainer()));
- i1.advance();
- i2.advance();
- if (!i1.hasContainer() || !i2.hasContainer()) {
- break main;
- }
- } else if (Util.compareUnsigned(i1.key(), i2.key()) < 0) { // i1.key() < i2.key()
- answer.getMappeableRoaringArray().appendCopy(i1.key(), i1.getContainer());
- i1.advance();
- if (!i1.hasContainer()) {
- break main;
- }
- } else { // i1.key() > i2.key()
- answer.getMappeableRoaringArray().appendCopy(i2.key(), i2.getContainer());
- i2.advance();
- if (!i2.hasContainer()) {
- break main;
- }
- }
- }
- }
- if (!i1.hasContainer()) {
- while (i2.hasContainer()) {
- answer.getMappeableRoaringArray().appendCopy(i2.key(), i2.getContainer());
- i2.advance();
- }
- } else if (!i2.hasContainer()) {
- while (i1.hasContainer()) {
- answer.getMappeableRoaringArray().appendCopy(i1.key(), i1.getContainer());
- i1.advance();
- }
- }
- return answer;
- }
-
- /**
- * Compute overall OR between bitmaps.
- *
- * (Effectively calls {@link BufferFastAggregation#or})
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap or(@SuppressWarnings("rawtypes") Iterator bitmaps) {
- return BufferFastAggregation.or(bitmaps);
- }
-
- /**
- * Computes OR between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd
- * (exclusive)
- *
- * @param bitmaps input bitmaps, these are not modified
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new result bitmap
- */
- public static MutableRoaringBitmap or(@SuppressWarnings("rawtypes") final Iterator bitmaps,
- final long rangeStart, final long rangeEnd) {
- MutableRoaringBitmap.rangeSanityCheck(rangeStart, rangeEnd);
- Iterator
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return cardinality of the union
- * @see BufferFastAggregation#or(ImmutableRoaringBitmap...)
- * @see BufferFastAggregation#horizontal_or(ImmutableRoaringBitmap...)
- */
- public static int orCardinality(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2) {
- // we use the fact that the cardinality of the bitmaps is known so that
- // the union is just the total cardinality minus the intersection
- return x1.getCardinality() + x2.getCardinality() - andCardinality(x1, x2);
- }
-
- /**
- * Computes XOR between input bitmaps in the given range, from rangeStart (inclusive) to rangeEnd
- * (exclusive)
- *
- * @param bitmaps input bitmaps, these are not modified
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new result bitmap
- */
- public static MutableRoaringBitmap xor(@SuppressWarnings("rawtypes") final Iterator bitmaps,
- final long rangeStart, final long rangeEnd) {
- Iterator
- * If you have more than 2 bitmaps, consider using the FastAggregation class.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- * @see BufferFastAggregation#xor(ImmutableRoaringBitmap...)
- * @see BufferFastAggregation#horizontal_xor(ImmutableRoaringBitmap...)
- */
- public static MutableRoaringBitmap xor(final ImmutableRoaringBitmap x1,
- final ImmutableRoaringBitmap x2) {
- final MutableRoaringBitmap answer = new MutableRoaringBitmap();
- MappeableContainerPointer i1 = x1.highLowContainer.getContainerPointer();
- MappeableContainerPointer i2 = x2.highLowContainer.getContainerPointer();
- main:
- if (i1.hasContainer() && i2.hasContainer()) {
- while (true) {
- if (i1.key() == i2.key()) {
- final MappeableContainer c = i1.getContainer().xor(i2.getContainer());
- if (c.getCardinality() > 0) {
- answer.getMappeableRoaringArray().append(i1.key(), c);
- }
- i1.advance();
- i2.advance();
- if (!i1.hasContainer() || !i2.hasContainer()) {
- break main;
- }
- } else if (Util.compareUnsigned(i1.key(), i2.key()) < 0) { // i1.key() < i2.key()
- answer.getMappeableRoaringArray().appendCopy(i1.key(), i1.getContainer());
- i1.advance();
- if (!i1.hasContainer()) {
- break main;
- }
- } else { // i1.key() < i2.key()
- answer.getMappeableRoaringArray().appendCopy(i2.key(), i2.getContainer());
- i2.advance();
- if (!i2.hasContainer()) {
- break main;
- }
- }
- }
- }
- if (!i1.hasContainer()) {
- while (i2.hasContainer()) {
- answer.getMappeableRoaringArray().appendCopy(i2.key(), i2.getContainer());
- i2.advance();
- }
- } else if (!i2.hasContainer()) {
- while (i1.hasContainer()) {
- answer.getMappeableRoaringArray().appendCopy(i1.key(), i1.getContainer());
- i1.advance();
- }
- }
-
- return answer;
- }
-
- @Override
- public ImmutableRoaringBitmap clone() {
- try {
- final ImmutableRoaringBitmap x = (ImmutableRoaringBitmap) super.clone();
- x.highLowContainer = highLowContainer.clone();
- return x;
- } catch (final CloneNotSupportedException e) {
- throw new RuntimeException("shouldn't happen with clone", e);
- }
- }
-
- /**
- * Checks whether the value in included, which is equivalent to checking if the corresponding bit
- * is set (get in BitSet class).
- *
- * @param x integer value
- * @return whether the integer value is included.
- */
- @Override
- public boolean contains(final int x) {
- final short hb = BufferUtil.highbits(x);
- final MappeableContainer c = highLowContainer.getContainer(hb);
- return c != null && c.contains(BufferUtil.lowbits(x));
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof ImmutableRoaringBitmap) {
- if (this.highLowContainer.size() != ((ImmutableRoaringBitmap) o).highLowContainer.size()) {
- return false;
- }
- MappeableContainerPointer mp1 = this.highLowContainer.getContainerPointer();
- MappeableContainerPointer mp2 =
- ((ImmutableRoaringBitmap) o).highLowContainer.getContainerPointer();
- while (mp1.hasContainer()) {
- if (mp1.key() != mp2.key()) {
- return false;
- }
- if (mp1.getCardinality() != mp2.getCardinality()) {
- return false;
- }
- if (!mp1.getContainer().equals(mp2.getContainer())) {
- return false;
- }
- mp1.advance();
- mp2.advance();
- }
- return true;
- }
- return false;
- }
-
- /**
- * Returns the number of distinct integers added to the bitmap (e.g., number of bits set).
- *
- * @return the cardinality
- */
- @Override
- public long getLongCardinality() {
- long size = 0;
- for (int i = 0; i < this.highLowContainer.size(); ++i) {
- size += this.highLowContainer.getCardinality(i);
- }
- return size;
- }
-
- @Override
- public int getCardinality() {
- return (int) getLongCardinality();
- }
-
- @Override
- public void forEach(IntConsumer ic) {
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- highLowContainer.getContainerAtIndex(i).forEach(highLowContainer.getKeyAtIndex(i), ic);
- }
- }
-
- /**
- * Return a low-level container pointer that can be used to access the underlying data structure.
- *
- * @return container pointer
- */
- public MappeableContainerPointer getContainerPointer() {
- return this.highLowContainer.getContainerPointer();
- }
-
- /**
- * For better performance, consider the Use the {@link #forEach forEach} method.
- *
- * @return a custom iterator over set bits, the bits are traversed in ascending sorted order
- */
- @Override
- public PeekableIntIterator getIntIterator() {
- return new ImmutableRoaringIntIterator();
- }
-
- /**
- * @return a custom iterator over set bits, the bits are traversed in descending sorted order
- */
- @Override
- public IntIterator getReverseIntIterator() {
- return new ImmutableRoaringReverseIntIterator();
- }
-
- /**
- * Estimate of the memory usage of this data structure. This can be expected to be within 1% of
- * the true memory usage. If exact measures are needed, we recommend using dedicated libraries
- * such as SizeOf.
- *
- * When the bitmap is constructed from a ByteBuffer from a memory-mapped file, this estimate is
- * invalid: we can expect the actual memory usage to be significantly (e.g., 10x) less.
- *
- * @return estimated memory usage.
- */
- @Override
- public long getLongSizeInBytes() {
- long size = 4;
- for (int i = 0; i < this.highLowContainer.size(); ++i) {
- if (this.highLowContainer.getContainerAtIndex(i) instanceof MappeableRunContainer) {
- MappeableRunContainer thisRunContainer =
- (MappeableRunContainer) this.highLowContainer.getContainerAtIndex(i);
- size += 4 + BufferUtil.getSizeInBytesFromCardinalityEtc(0, thisRunContainer.nbrruns, true);
- } else {
- size += 4 + BufferUtil
- .getSizeInBytesFromCardinalityEtc(this.highLowContainer.getCardinality(i), 0, false);
- }
- }
- return size;
- }
-
- @Override
- public int getSizeInBytes() {
- return (int) getLongSizeInBytes();
- }
-
- @Override
- public int hashCode() {
- return highLowContainer.hashCode();
- }
-
- /**
- * Check whether this bitmap has had its runs compressed.
- *
- * @return whether this bitmap has run compression
- */
- public boolean hasRunCompression() {
- return this.highLowContainer.hasRunCompression();
- }
-
- /**
- * Checks whether the bitmap is empty.
- *
- * @return true if this bitmap contains no set bit
- */
- @Override
- public boolean isEmpty() {
- return highLowContainer.size() == 0;
- }
-
- /**
- * iterate over the positions of the true values.
- *
- * @return the iterator
- */
- @Override
- public Iterator
- * Consider calling {@link MutableRoaringBitmap#runOptimize} before serialization to improve
- * compression if this is a MutableRoaringBitmap instance.
- *
- * The current bitmap is not modified.
- *
- * Advanced example: To serialize your bitmap to a ByteBuffer, you can do the following.
- *
- *
- * Note: Java's data structures are in big endian format. Roaring serializes to a little endian
- * format, so the bytes are flipped by the library during serialization to ensure that what is
- * stored is in little endian---despite Java's big endianness. You can defeat this process by
- * reflipping the bytes again in a custom DataOutput which could lead to serialized Roaring
- * objects with an incorrect byte order.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- @Override
- public void serialize(DataOutput out) throws IOException {
- this.highLowContainer.serialize(out);
- }
-
- /**
- * Report the number of bytes required for serialization. This count will match the bytes written
- * when calling the serialize method.
- *
- * @return the size in bytes
- */
- @Override
- public int serializedSizeInBytes() {
- return this.highLowContainer.serializedSizeInBytes();
- }
-
- /**
- * Return the set values as an array if the cardinality is less
- * than 2147483648. The integer values are in sorted order.
- *
- * @return array representing the set values.
- */
- @Override
- public int[] toArray() {
- final int[] array = new int[(int) this.getCardinality()];
- int pos = 0, pos2 = 0;
- while (pos < this.highLowContainer.size()) {
- final int hs = BufferUtil.toIntUnsigned(this.highLowContainer.getKeyAtIndex(pos)) << 16;
- final MappeableContainer c = this.highLowContainer.getContainerAtIndex(pos++);
- c.fillLeastSignificant16bits(array, pos2, hs);
- pos2 += c.getCardinality();
- }
- return array;
- }
-
- /**
- * Copies the content of this bitmap to a bitmap that can be modified.
- *
- * @return a mutable bitmap.
- */
- public MutableRoaringBitmap toMutableRoaringBitmap() {
- MutableRoaringBitmap c = new MutableRoaringBitmap();
- MappeableContainerPointer mcp = highLowContainer.getContainerPointer();
- while (mcp.hasContainer()) {
- c.getMappeableRoaringArray().appendCopy(mcp.key(), mcp.getContainer());
- mcp.advance();
- }
- return c;
- }
-
- /**
- * Copies this bitmap to a mutable RoaringBitmap.
- *
- * @return a copy of this bitmap as a RoaringBitmap.
- */
- public RoaringBitmap toRoaringBitmap() {
- return new RoaringBitmap(this);
- }
-
- /**
- * A string describing the bitmap.
- *
- * @return the string
- */
- @Override
- public String toString() {
- final StringBuilder answer = new StringBuilder();
- final IntIterator i = this.getIntIterator();
- answer.append("{");
- if (i.hasNext()) {
- answer.append(i.next() & 0xFFFFFFFFL);
- }
- while (i.hasNext()) {
- answer.append(",");
- // to avoid using too much memory, we limit the size
- if (answer.length() > 0x80000) {
- answer.append("...");
- break;
- }
- answer.append(i.next() & 0xFFFFFFFFL);
- }
- answer.append("}");
- return answer.toString();
- }
-
- private final class ImmutableRoaringIntIterator implements PeekableIntIterator {
- private MappeableContainerPointer cp =
- ImmutableRoaringBitmap.this.highLowContainer.getContainerPointer();
-
- private int hs = 0;
-
- private PeekableShortIterator iter;
-
- private boolean ok;
-
- public ImmutableRoaringIntIterator() {
- nextContainer();
- }
-
- @Override
- public PeekableIntIterator clone() {
- try {
- ImmutableRoaringIntIterator x = (ImmutableRoaringIntIterator) super.clone();
- x.iter = this.iter.clone();
- x.cp = this.cp.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return ok;
- }
-
- @Override
- public int next() {
- int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- cp.advance();
- nextContainer();
- }
- return x;
- }
-
-
- private void nextContainer() {
- ok = cp.hasContainer();
- if (ok) {
- iter = cp.getContainer().getShortIterator();
- hs = BufferUtil.toIntUnsigned(cp.key()) << 16;
- }
- }
-
- @Override
- public void advanceIfNeeded(int minval) {
- while (hasNext() && ((hs >>> 16) < (minval >>> 16))) {
- cp.advance();
- nextContainer();
- }
- if (ok && ((hs >>> 16) == (minval >>> 16))) {
- iter.advanceIfNeeded(BufferUtil.lowbits(minval));
- if (!iter.hasNext()) {
- cp.advance();
- nextContainer();
- }
- }
- }
-
- @Override
- public int peekNext() {
- return BufferUtil.toIntUnsigned(iter.peekNext()) | hs;
- }
-
-
- }
-
- private final class ImmutableRoaringReverseIntIterator implements IntIterator {
- private MappeableContainerPointer cp = ImmutableRoaringBitmap.this.highLowContainer
- .getContainerPointer(ImmutableRoaringBitmap.this.highLowContainer.size() - 1);
-
- private int hs = 0;
-
- private ShortIterator iter;
-
- private boolean ok;
-
- public ImmutableRoaringReverseIntIterator() {
- nextContainer();
- }
-
- @Override
- public IntIterator clone() {
- try {
- ImmutableRoaringReverseIntIterator x = (ImmutableRoaringReverseIntIterator) super.clone();
- x.iter = this.iter.clone();
- x.cp = this.cp.clone();
- return x;
- } catch (CloneNotSupportedException e) {
- return null;// will not happen
- }
- }
-
- @Override
- public boolean hasNext() {
- return ok;
- }
-
- @Override
- public int next() {
- int x = iter.nextAsInt() | hs;
- if (!iter.hasNext()) {
- cp.previous();
- nextContainer();
- }
- return x;
- }
-
-
- private void nextContainer() {
- ok = cp.hasContainer();
- if (ok) {
- iter = cp.getContainer().getReverseShortIterator();
- hs = BufferUtil.toIntUnsigned(cp.key()) << 16;
- }
- }
-
-
- }
-
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/MappeableArrayContainer.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/MappeableArrayContainer.java
deleted file mode 100644
index 5a68357b1..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/MappeableArrayContainer.java
+++ /dev/null
@@ -1,1688 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap.buffer;
-
-import com.fr.third.bitmap.roaringbitmap.ArrayContainer;
-import com.fr.third.bitmap.roaringbitmap.Container;
-import com.fr.third.bitmap.roaringbitmap.IntConsumer;
-import com.fr.third.bitmap.roaringbitmap.PeekableShortIterator;
-import com.fr.third.bitmap.roaringbitmap.ShortIterator;
-import com.fr.third.bitmap.roaringbitmap.Util;
-
-import java.io.DataOutput;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.nio.ShortBuffer;
-import java.util.Arrays;
-import java.util.Iterator;
-
-/**
- * Simple container made of an array of 16-bit integers. Unlike ArrayContainer,
- * this class uses a ShortBuffer to store data.
- */
-public final class MappeableArrayContainer extends MappeableContainer implements Cloneable {
- protected static final int DEFAULT_MAX_SIZE = 4096; // containers with DEFAULT_MAX_SZE or less
- private static final int DEFAULT_INIT_SIZE = 4;
- private static final int ARRAY_LAZY_LOWERBOUND = 1024;
- // integers should be ArrayContainers
- private static final long serialVersionUID = 1L;
- protected int cardinality = 0;
- protected ShortBuffer content;
-
- /**
- * Create an array container with default capacity
- */
- public MappeableArrayContainer() {
- this(DEFAULT_INIT_SIZE);
- }
-
-
- /**
- * Creates a new container from a non-mappeable one. This copies the data.
- *
- * @param bc the original container
- */
- public MappeableArrayContainer(ArrayContainer bc) {
- this.cardinality = bc.getCardinality();
- this.content = bc.toShortBuffer();
- }
-
-
- /**
- * Create an array container with specified capacity
- *
- * @param capacity The capacity of the container
- */
- public MappeableArrayContainer(final int capacity) {
- content = ShortBuffer.allocate(capacity);
- }
-
- /**
- * Create an array container with a run of ones from firstOfRun to lastOfRun, exclusive. Caller is
- * responsible for making sure the range is small enough that ArrayContainer is appropriate.
- *
- * @param firstOfRun first index
- * @param lastOfRun last index (range is exclusive)
- */
- public MappeableArrayContainer(final int firstOfRun, final int lastOfRun) {
- // TODO: this can be optimized for performance
- final int valuesInRange = lastOfRun - firstOfRun;
- content = ShortBuffer.allocate(valuesInRange);
- short[] sarray = content.array();
- for (int i = 0; i < valuesInRange; ++i) {
- sarray[i] = (short) (firstOfRun + i);
- }
- cardinality = valuesInRange;
- }
-
-
- private MappeableArrayContainer(int newCard, ShortBuffer newContent) {
- this.cardinality = newCard;
- ShortBuffer tmp = newContent.duplicate();// for thread-safety
- this.content = ShortBuffer.allocate(Math.max(newCard, tmp.limit()));
- tmp.rewind();
- this.content.put(tmp);
- }
-
- /**
- * Construct a new ArrayContainer backed by the provided ShortBuffer. Note that if you modify the
- * ArrayContainer a new ShortBuffer may be produced.
- *
- * @param array ShortBuffer where the data is stored
- * @param cardinality cardinality (number of values stored)
- */
- public MappeableArrayContainer(final ShortBuffer array, final int cardinality) {
- if (array.limit() != cardinality) {
- throw new RuntimeException("Mismatch between buffer and cardinality");
- }
- this.cardinality = cardinality;
- this.content = array;
- }
-
- protected static int getArraySizeInBytes(int cardinality) {
- return cardinality * 2;
- }
-
- protected static int serializedSizeInBytes(int cardinality) {
- return cardinality * 2 + 2;
- }
-
- @Override
- public MappeableContainer add(int begin, int end) {
- // TODO: may need to convert to a RunContainer
- if (end == begin) {
- return clone();
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
- int indexstart = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) begin);
- if (indexstart < 0) {
- indexstart = -indexstart - 1;
- }
- int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (end - 1));
- if (indexend < 0) {
- indexend = -indexend - 1;
- } else {
- indexend++;
- }
- int rangelength = end - begin;
- int newcardinality = indexstart + (cardinality - indexend) + rangelength;
- if (newcardinality > DEFAULT_MAX_SIZE) {
- MappeableBitmapContainer a = this.toBitmapContainer();
- return a.iadd(begin, end);
- }
- MappeableArrayContainer answer = new MappeableArrayContainer(newcardinality, content);
- if (!BufferUtil.isBackedBySimpleArray(answer.content)) {
- throw new RuntimeException("Should not happen. Internal bug.");
- }
- BufferUtil.arraycopy(content, indexend, answer.content, indexstart + rangelength,
- cardinality - indexend);
- short[] answerarray = answer.content.array();
- for (int k = 0; k < rangelength; ++k) {
- answerarray[k + indexstart] = (short) (begin + k);
- }
- answer.cardinality = newcardinality;
- return answer;
- }
-
- /**
- * running time is in O(n) time if insert is not in order.
- */
- @Override
- // not thread-safe
- public MappeableContainer add(final short x) {
- if (BufferUtil.isBackedBySimpleArray(this.content)) {
- short[] sarray = content.array();
-
- int loc = Util.unsignedBinarySearch(sarray, 0, cardinality, x);
- if (loc < 0) {
- // Transform the ArrayContainer to a BitmapContainer
- // when cardinality exceeds DEFAULT_MAX_SIZE
- if (cardinality >= DEFAULT_MAX_SIZE) {
- final MappeableBitmapContainer a = this.toBitmapContainer();
- a.add(x);
- return a;
- }
- if (cardinality >= sarray.length) {
- increaseCapacity();
- sarray = content.array();
- }
- // insertion : shift the elements > x by one
- // position to
- // the right
- // and put x in it's appropriate place
- System.arraycopy(sarray, -loc - 1, sarray, -loc, cardinality + loc + 1);
- sarray[-loc - 1] = x;
- ++cardinality;
- }
- } else {
-
- final int loc = BufferUtil.unsignedBinarySearch(content, 0, cardinality, x);
- if (loc < 0) {
- // Transform the ArrayContainer to a BitmapContainer
- // when cardinality exceeds DEFAULT_MAX_SIZE
- if (cardinality >= DEFAULT_MAX_SIZE) {
- final MappeableBitmapContainer a = this.toBitmapContainer();
- a.add(x);
- return a;
- }
- if (cardinality >= this.content.limit()) {
- increaseCapacity();
- }
- // insertion : shift the elements > x by one
- // position to
- // the right
- // and put x in it's appropriate place
- for (int k = cardinality; k > -loc - 1; --k) {
- content.put(k, content.get(k - 1));
- }
- content.put(-loc - 1, x);
-
- ++cardinality;
- }
- }
- return this;
- }
-
- private int advance(ShortIterator it) {
- if (it.hasNext()) {
- return BufferUtil.toIntUnsigned(it.next());
- } else {
- return -1;
- }
- }
-
-
- @Override
- public MappeableArrayContainer and(final MappeableArrayContainer value2) {
-
- MappeableArrayContainer value1 = this;
- final int desiredCapacity = Math.min(value1.getCardinality(), value2.getCardinality());
- MappeableArrayContainer answer = new MappeableArrayContainer(desiredCapacity);
- if (BufferUtil.isBackedBySimpleArray(this.content)
- && BufferUtil.isBackedBySimpleArray(value2.content)) {
- answer.cardinality = Util.unsignedIntersect2by2(value1.content.array(),
- value1.getCardinality(), value2.content.array(), value2.getCardinality(),
- answer.content.array());
- } else {
- answer.cardinality = BufferUtil.unsignedIntersect2by2(value1.content, value1.getCardinality(),
- value2.content, value2.getCardinality(), answer.content.array());
- }
- return answer;
- }
-
- @Override
- public MappeableContainer and(MappeableBitmapContainer x) {
- return x.and(this);
- }
-
- @Override
- public MappeableContainer and(final MappeableRunContainer value2) {
- return value2.and(this);
- }
-
-
- @Override
- public MappeableArrayContainer andNot(final MappeableArrayContainer value2) {
- final MappeableArrayContainer value1 = this;
- final int desiredCapacity = value1.getCardinality();
- final MappeableArrayContainer answer = new MappeableArrayContainer(desiredCapacity);
- if (BufferUtil.isBackedBySimpleArray(value1.content)
- && BufferUtil.isBackedBySimpleArray(value2.content)) {
- answer.cardinality =
- Util.unsignedDifference(value1.content.array(), value1.getCardinality(),
- value2.content.array(), value2.getCardinality(), answer.content.array());
- } else {
- answer.cardinality = BufferUtil.unsignedDifference(value1.content, value1.getCardinality(),
- value2.content, value2.getCardinality(), answer.content.array());
- }
- return answer;
- }
-
- @Override
- public MappeableArrayContainer andNot(MappeableBitmapContainer value2) {
-
- final MappeableArrayContainer answer = new MappeableArrayContainer(content.limit());
- int pos = 0;
- short[] sarray = answer.content.array();
- if (BufferUtil.isBackedBySimpleArray(this.content)) {
- short[] c = content.array();
- for (int k = 0; k < cardinality; ++k) {
- short v = c[k];
- if (!value2.contains(v)) {
- sarray[pos++] = v;
- }
- }
- } else {
- for (int k = 0; k < cardinality; ++k) {
- short v = this.content.get(k);
- if (!value2.contains(v)) {
- sarray[pos++] = v;
- }
- }
- }
- answer.cardinality = pos;
- return answer;
- }
-
- @Override
- public MappeableContainer andNot(final MappeableRunContainer x) {
- int writeLocation = 0;
- int runStart, runEnd; // the current or upcoming run.
- if (x.nbrruns == 0) {
- return clone();
- }
-
- ShortBuffer buffer = ShortBuffer.allocate(cardinality);
-
- runStart = BufferUtil.toIntUnsigned(x.getValue(0));
- runEnd = runStart + BufferUtil.toIntUnsigned(x.getLength(0));
- int whichRun = 0;
-
- short val;
- for (int i = 0; i < cardinality; ++i) {
- val = content.get(i);
- int valInt = BufferUtil.toIntUnsigned(val);
- if (valInt < runStart) {
- buffer.put(writeLocation++, val);
- } else if (valInt <= runEnd) {
- ; // don't want item
- } else {
- // greater than this run, need to do an advanceUntil on runs
- // done sequentially for now (no galloping attempts).
- do {
- if (whichRun + 1 < x.nbrruns) {
- whichRun++;
- runStart = BufferUtil.toIntUnsigned(x.getValue(whichRun));
- runEnd = runStart + BufferUtil.toIntUnsigned(x.getLength(whichRun));
- } else {
- runStart = runEnd = (1 << 16) + 1; // infinity....
- }
- } while (valInt > runEnd);
- --i; // need to re-process this val
- }
- }
- return new MappeableArrayContainer(writeLocation, buffer);
- }
-
- @Override
- public void clear() {
- cardinality = 0;
- }
-
- @Override
- public MappeableArrayContainer clone() {
- return new MappeableArrayContainer(this.cardinality, this.content);
- }
-
- @Override
- public boolean contains(final short x) {
- return BufferUtil.unsignedBinarySearch(content, 0, cardinality, x) >= 0;
- }
-
- // in order
- // not thread-safe
- private void emit(short val) {
- if (cardinality == content.limit()) {
- increaseCapacity(true);
- }
- content.put(cardinality++, val);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof MappeableArrayContainer) {
- final MappeableArrayContainer srb = (MappeableArrayContainer) o;
- if (srb.cardinality != this.cardinality) {
- return false;
- }
- if (BufferUtil.isBackedBySimpleArray(this.content)
- && BufferUtil.isBackedBySimpleArray(srb.content)) {
- short[] t = this.content.array();
- short[] sr = srb.content.array();
-
- for (int i = 0; i < this.cardinality; ++i) {
- if (t[i] != sr[i]) {
- return false;
- }
- }
-
- } else {
- for (int i = 0; i < this.cardinality; ++i) {
- if (this.content.get(i) != srb.content.get(i)) {
- return false;
- }
- }
- }
- return true;
- } else if (o instanceof MappeableRunContainer) {
- return o.equals(this);
- }
- return false;
- }
-
-
- @Override
- public void fillLeastSignificant16bits(int[] x, int i, int mask) {
- if (BufferUtil.isBackedBySimpleArray(this.content)) {
- short[] c = this.content.array();
- for (int k = 0; k < this.cardinality; ++k) {
- x[k + i] = BufferUtil.toIntUnsigned(c[k]) | mask;
- }
-
- } else {
- for (int k = 0; k < this.cardinality; ++k) {
- x[k + i] = BufferUtil.toIntUnsigned(this.content.get(k)) | mask;
- }
- }
- }
-
- @Override
- // not thread-safe
- public MappeableContainer flip(short x) {
- if (BufferUtil.isBackedBySimpleArray(this.content)) {
- short[] sarray = content.array();
- int loc = Util.unsignedBinarySearch(sarray, 0, cardinality, x);
- if (loc < 0) {
- // Transform the ArrayContainer to a BitmapContainer
- // when cardinality = DEFAULT_MAX_SIZE
- if (cardinality >= DEFAULT_MAX_SIZE) {
- MappeableBitmapContainer a = this.toBitmapContainer();
- a.add(x);
- return a;
- }
- if (cardinality >= sarray.length) {
- increaseCapacity();
- sarray = content.array();
- }
- // insertion : shift the elements > x by one position to
- // the right
- // and put x in it's appropriate place
- System.arraycopy(sarray, -loc - 1, sarray, -loc, cardinality + loc + 1);
- sarray[-loc - 1] = x;
- ++cardinality;
- } else {
- System.arraycopy(sarray, loc + 1, sarray, loc, cardinality - loc - 1);
- --cardinality;
- }
- return this;
-
- } else {
- int loc = BufferUtil.unsignedBinarySearch(content, 0, cardinality, x);
- if (loc < 0) {
- // Transform the ArrayContainer to a BitmapContainer
- // when cardinality = DEFAULT_MAX_SIZE
- if (cardinality >= DEFAULT_MAX_SIZE) {
- MappeableBitmapContainer a = this.toBitmapContainer();
- a.add(x);
- return a;
- }
- if (cardinality >= content.limit()) {
- increaseCapacity();
- }
- // insertion : shift the elements > x by one position to
- // the right
- // and put x in it's appropriate place
- for (int k = cardinality; k > -loc - 1; --k) {
- content.put(k, content.get(k - 1));
- }
- content.put(-loc - 1, x);
- ++cardinality;
- } else {
- for (int k = loc + 1; k < cardinality; --k) {
- content.put(k - 1, content.get(k));
- }
- --cardinality;
- }
- return this;
- }
- }
-
- @Override
- protected int getArraySizeInBytes() {
- return getArraySizeInBytes(cardinality);
- }
-
- @Override
- public int getCardinality() {
- return cardinality;
- }
-
- @Override
- public ShortIterator getReverseShortIterator() {
- if (this.isArrayBacked()) {
- return new RawReverseArrayContainerShortIterator(this);
- }
- return new ReverseMappeableArrayContainerShortIterator(this);
- }
-
- @Override
- public PeekableShortIterator getShortIterator() {
- if (this.isArrayBacked()) {
- return new RawArrayContainerShortIterator(this);
- }
- return new MappeableArrayContainerShortIterator(this);
- }
-
- @Override
- public int getSizeInBytes() {
- return this.cardinality * 2;
- }
-
- @Override
- public int hashCode() {
- int hash = 0;
- for (int k = 0; k < cardinality; ++k) {
- hash += 31 * hash + content.get(k);
- }
- return hash;
- }
-
- @Override
- // not thread-safe
- public MappeableContainer iadd(int begin, int end) {
- // TODO: may need to convert to a RunContainer
- if (end == begin) {
- return this;
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
- int indexstart = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) begin);
- if (indexstart < 0) {
- indexstart = -indexstart - 1;
- }
- int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (end - 1));
- if (indexend < 0) {
- indexend = -indexend - 1;
- } else {
- indexend++;
- }
- int rangelength = end - begin;
- int newcardinality = indexstart + (cardinality - indexend) + rangelength;
- if (newcardinality > DEFAULT_MAX_SIZE) {
- MappeableBitmapContainer a = this.toBitmapContainer();
- return a.iadd(begin, end);
- }
- if (newcardinality >= this.content.limit()) {
- increaseCapacity(newcardinality);
- }
- BufferUtil.arraycopy(content, indexend, content, indexstart + rangelength,
- cardinality - indexend);
- if (BufferUtil.isBackedBySimpleArray(content)) {
- short[] contentarray = content.array();
- for (int k = 0; k < rangelength; ++k) {
- contentarray[k + indexstart] = (short) (begin + k);
- }
- } else {
- for (int k = 0; k < rangelength; ++k) {
- content.put(k + indexstart, (short) (begin + k));
- }
- }
- cardinality = newcardinality;
- return this;
- }
-
- @Override
- public MappeableArrayContainer iand(final MappeableArrayContainer value2) {
- final MappeableArrayContainer value1 = this;
- if (!BufferUtil.isBackedBySimpleArray(value1.content)) {
- throw new RuntimeException("Should not happen. Internal bug.");
- }
- value1.cardinality = BufferUtil.unsignedIntersect2by2(value1.content, value1.getCardinality(),
- value2.content, value2.getCardinality(), value1.content.array());
- return this;
- }
-
-
- @Override
- public MappeableContainer iand(MappeableBitmapContainer value2) {
- int pos = 0;
- for (int k = 0; k < cardinality; ++k) {
- short v = this.content.get(k);
- if (value2.contains(v)) {
- this.content.put(pos++, v);
- }
- }
- cardinality = pos;
- return this;
- }
-
-
- // Note it is never inplace, may wish to fix
- @Override
- public MappeableContainer iand(final MappeableRunContainer value2) {
- return value2.and(this);
- }
-
- @Override
- public MappeableArrayContainer iandNot(final MappeableArrayContainer value2) {
- if (!BufferUtil.isBackedBySimpleArray(this.content)) {
- throw new RuntimeException("Should not happen. Internal bug.");
- }
- if (BufferUtil.isBackedBySimpleArray(value2.content)) {
- this.cardinality =
- Util.unsignedDifference(this.content.array(), this.getCardinality(),
- value2.content.array(), value2.getCardinality(), this.content.array());
- } else {
- this.cardinality = BufferUtil.unsignedDifference(this.content, this.getCardinality(),
- value2.content, value2.getCardinality(), this.content.array());
- }
-
- return this;
- }
-
- @Override
- public MappeableArrayContainer iandNot(MappeableBitmapContainer value2) {
- if (!BufferUtil.isBackedBySimpleArray(this.content)) {
- throw new RuntimeException("Should not happen. Internal bug.");
- }
- short[] c = this.content.array();
- int pos = 0;
- for (int k = 0; k < cardinality; ++k) {
- short v = c[k];
- if (!value2.contains(v)) {
- c[pos++] = v;
- }
- }
- this.cardinality = pos;
- return this;
- }
-
- @Override
- public MappeableContainer iandNot(final MappeableRunContainer value2) { // not inplace, revisit?
- return andNot(value2);
- }
-
- private void increaseCapacity() {
- increaseCapacity(false);
- }
-
- // temporarily allow an illegally large size, as long as the operation creating
- // the illegal container does not return it.
- // not thread safe!
- private void increaseCapacity(boolean allowIllegalSize) {
- int len = this.content.limit();
- int newCapacity = (len == 0) ? DEFAULT_INIT_SIZE
- : len < 64 ? len * 2 : this.content.limit() < 1067 ? len * 3 / 2 : len * 5 / 4;
- // do not allocate more than we will ever need
- if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE && !allowIllegalSize) {
- newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE;
- }
- // if we are within 1/16th of the max., go to max right away to avoid further reallocations
- if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE
- - MappeableArrayContainer.DEFAULT_MAX_SIZE / 16 && !allowIllegalSize) {
- newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE;
- }
- final ShortBuffer newContent = ShortBuffer.allocate(newCapacity);
- this.content.rewind();
- newContent.put(this.content);
- this.content = newContent;
- }
-
-
- // not thread safe!
- private void increaseCapacity(int min) {
- int len = this.content.limit();
- int newCapacity = (len == 0) ? DEFAULT_INIT_SIZE
- : len < 64 ? len * 2 : len < 1024 ? len * 3 / 2 : len * 5 / 4;
- if (newCapacity < min) {
- newCapacity = min;
- }
- if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE;
- }
- if (newCapacity > MappeableArrayContainer.DEFAULT_MAX_SIZE
- - MappeableArrayContainer.DEFAULT_MAX_SIZE / 16) {
- newCapacity = MappeableArrayContainer.DEFAULT_MAX_SIZE;
- }
- final ShortBuffer newContent = ShortBuffer.allocate(newCapacity);
- this.content.rewind();
- newContent.put(this.content);
- this.content = newContent;
- }
-
- @Override
- // not thread safe! (duh!)
- public MappeableContainer inot(final int firstOfRange, final int lastOfRange) {
- // TODO: may need to convert to a RunContainer
- // TODO: this can be optimized for performance
- // determine the span of array indices to be affected
- int startIndex = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) firstOfRange);
- if (startIndex < 0) {
- startIndex = -startIndex - 1;
- }
- int lastIndex =
- BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (lastOfRange - 1));
- if (lastIndex < 0) {
- lastIndex = -lastIndex - 1 - 1;
- }
- final int currentValuesInRange = lastIndex - startIndex + 1;
- final int spanToBeFlipped = lastOfRange - firstOfRange;
- final int newValuesInRange = spanToBeFlipped - currentValuesInRange;
- final ShortBuffer buffer = ShortBuffer.allocate(newValuesInRange);
- final int cardinalityChange = newValuesInRange - currentValuesInRange;
- final int newCardinality = cardinality + cardinalityChange;
-
- if (cardinalityChange > 0) { // expansion, right shifting needed
- if (newCardinality > content.limit()) {
- // so big we need a bitmap?
- if (newCardinality > DEFAULT_MAX_SIZE) {
- return toBitmapContainer().inot(firstOfRange, lastOfRange);
- }
- final ShortBuffer co = ShortBuffer.allocate(newCardinality);
- content.rewind();
- co.put(content);
- content = co;
- }
- // slide right the contents after the range
- for (int pos = cardinality - 1; pos > lastIndex; --pos) {
- content.put(pos + cardinalityChange, content.get(pos));
- }
- negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange);
- } else { // no expansion needed
- negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange);
- if (cardinalityChange < 0) {
- // Leave array oversize
- for (int i = startIndex + newValuesInRange; i < newCardinality; ++i) {
- content.put(i, content.get(i - cardinalityChange));
- }
- }
- }
- cardinality = newCardinality;
- return this;
- }
-
- @Override
- public boolean intersects(MappeableArrayContainer value2) {
- MappeableArrayContainer value1 = this;
- return BufferUtil.unsignedIntersects(value1.content, value1.getCardinality(), value2.content,
- value2.getCardinality());
- }
-
- @Override
- public boolean intersects(MappeableBitmapContainer x) {
- return x.intersects(this);
- }
-
- @Override
- public boolean intersects(MappeableRunContainer x) {
- return x.intersects(this);
- }
-
- @Override
- public MappeableContainer ior(final MappeableArrayContainer value2) {
- return this.or(value2);
- }
-
- @Override
- public MappeableContainer ior(MappeableBitmapContainer x) {
- return x.or(this);
- }
-
- @Override
- public MappeableContainer ior(final MappeableRunContainer value2) {
- // not inplace
- return value2.or(this);
- }
-
- @Override
- public MappeableContainer iremove(int begin, int end) {
- if (end == begin) {
- return this;
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
- int indexstart = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) begin);
- if (indexstart < 0) {
- indexstart = -indexstart - 1;
- }
- int indexend = BufferUtil.unsignedBinarySearch(content, 0, cardinality, (short) (end - 1));
- if (indexend < 0) {
- indexend = -indexend - 1;
- } else {
- indexend++;
- }
- int rangelength = indexend - indexstart;
- BufferUtil.arraycopy(content, indexstart + rangelength, content, indexstart,
- cardinality - indexstart - rangelength);
- cardinality -= rangelength;
- return this;
- }
-
- @Override
- protected boolean isArrayBacked() {
- return BufferUtil.isBackedBySimpleArray(this.content);
- }
-
-
- @Override
- public Iterator
- *
- * Adding and removing content from this container might make it wasteful so regular calls to
- * "runOptimize" might be warranted.
- */
-public final class MappeableRunContainer extends MappeableContainer implements Cloneable {
- private static final int DEFAULT_INIT_SIZE = 4;
- private static final long serialVersionUID = 1L;
- protected ShortBuffer valueslength;
- protected int nbrruns = 0;// how many runs, this number should fit in 16 bits.
-
- /**
- * Create a container with default capacity
- */
- public MappeableRunContainer() {
- this(DEFAULT_INIT_SIZE);
- }
-
- /**
- * Create an array container with specified capacity
- *
- * @param capacity The capacity of the container
- */
- public MappeableRunContainer(final int capacity) {
- valueslength = ShortBuffer.allocate(2 * capacity);
- }
-
-
- private MappeableRunContainer(int nbrruns, final ShortBuffer valueslength) {
- this.nbrruns = nbrruns;
- ShortBuffer tmp = valueslength.duplicate();// for thread safety
- this.valueslength = ShortBuffer.allocate(Math.max(2 * nbrruns, tmp.limit()));
- tmp.rewind();
- this.valueslength.put(tmp); // may copy more than it needs to??
- }
-
- protected MappeableRunContainer(MappeableArrayContainer arr, int nbrRuns) {
- this.nbrruns = nbrRuns;
- valueslength = ShortBuffer.allocate(2 * nbrRuns);
- short[] vl = valueslength.array();
- if (nbrRuns == 0) {
- return;
- }
-
- int prevVal = -2;
- int runLen = 0;
- int runCount = 0;
- if (BufferUtil.isBackedBySimpleArray(arr.content)) {
- short[] a = arr.content.array();
- for (int i = 0; i < arr.cardinality; i++) {
- int curVal = BufferUtil.toIntUnsigned(a[i]);
- if (curVal == prevVal + 1) {
- ++runLen;
- } else {
- if (runCount > 0) {
- vl[2 * (runCount - 1) + 1] = (short) runLen;
- }
- // setLength(runCount - 1, (short) runLen);
- vl[2 * runCount] = (short) curVal;
- // setValue(runCount, (short) curVal);
- runLen = 0;
- ++runCount;
- }
- prevVal = curVal;
- }
-
- } else {
- for (int i = 0; i < arr.cardinality; i++) {
- int curVal = BufferUtil.toIntUnsigned(arr.content.get(i));
- if (curVal == prevVal + 1) {
- ++runLen;
- } else {
- if (runCount > 0) {
- vl[2 * (runCount - 1) + 1] = (short) runLen;
- }
- // setLength(runCount - 1, (short) runLen);
- vl[2 * runCount] = (short) curVal;
- // setValue(runCount, (short) curVal);
- runLen = 0;
- ++runCount;
- }
- prevVal = curVal;
- }
- }
- // setLength(runCount-1, (short) runLen);
- vl[2 * (runCount - 1) + 1] = (short) runLen;
- }
-
- // convert a bitmap container to a run container somewhat efficiently.
- protected MappeableRunContainer(MappeableBitmapContainer bc, int nbrRuns) {
- this.nbrruns = nbrRuns;
- valueslength = ShortBuffer.allocate(2 * nbrRuns);
- if (!BufferUtil.isBackedBySimpleArray(valueslength)) {
- throw new RuntimeException("Unexpected internal error.");
- }
- short[] vl = valueslength.array();
- if (nbrRuns == 0) {
- return;
- }
- if (bc.isArrayBacked()) {
- long[] b = bc.bitmap.array();
- int longCtr = 0; // index of current long in bitmap
- long curWord = b[0]; // its value
- int runCount = 0;
- final int len = bc.bitmap.limit();
- while (true) {
- // potentially multiword advance to first 1 bit
- while (curWord == 0L && longCtr < len - 1) {
- curWord = b[++longCtr];
- }
-
- if (curWord == 0L) {
- // wrap up, no more runs
- return;
- }
- int localRunStart = Long.numberOfTrailingZeros(curWord);
- int runStart = localRunStart + 64 * longCtr;
- // stuff 1s into number's LSBs
- long curWordWith1s = curWord | (curWord - 1);
-
- // find the next 0, potentially in a later word
- int runEnd = 0;
- while (curWordWith1s == -1L && longCtr < len - 1) {
- curWordWith1s = b[++longCtr];
- }
-
- if (curWordWith1s == -1L) {
- // a final unterminated run of 1s (32 of them)
- runEnd = 64 + longCtr * 64;
- // setValue(runCount, (short) runStart);
- vl[2 * runCount] = (short) runStart;
- // setLength(runCount, (short) (runEnd-runStart-1));
- vl[2 * runCount + 1] = (short) (runEnd - runStart - 1);
- return;
- }
- int localRunEnd = Long.numberOfTrailingZeros(~curWordWith1s);
- runEnd = localRunEnd + longCtr * 64;
- // setValue(runCount, (short) runStart);
- vl[2 * runCount] = (short) runStart;
- // setLength(runCount, (short) (runEnd-runStart-1));
- vl[2 * runCount + 1] = (short) (runEnd - runStart - 1);
- runCount++;
- // now, zero out everything right of runEnd.
- curWord = curWordWith1s & (curWordWith1s + 1);
- // We've lathered and rinsed, so repeat...
- }
- } else {
- int longCtr = 0; // index of current long in bitmap
- long curWord = bc.bitmap.get(0); // its value
- int runCount = 0;
- final int len = bc.bitmap.limit();
- while (true) {
- // potentially multiword advance to first 1 bit
- while (curWord == 0L && longCtr < len - 1) {
- curWord = bc.bitmap.get(++longCtr);
- }
-
- if (curWord == 0L) {
- // wrap up, no more runs
- return;
- }
- int localRunStart = Long.numberOfTrailingZeros(curWord);
- int runStart = localRunStart + 64 * longCtr;
- // stuff 1s into number's LSBs
- long curWordWith1s = curWord | (curWord - 1);
-
- // find the next 0, potentially in a later word
- int runEnd = 0;
- while (curWordWith1s == -1L && longCtr < len - 1) {
- curWordWith1s = bc.bitmap.get(++longCtr);
- }
-
- if (curWordWith1s == -1L) {
- // a final unterminated run of 1s (32 of them)
- runEnd = 64 + longCtr * 64;
- // setValue(runCount, (short) runStart);
- vl[2 * runCount] = (short) runStart;
- // setLength(runCount, (short) (runEnd-runStart-1));
- vl[2 * runCount + 1] = (short) (runEnd - runStart - 1);
- return;
- }
- int localRunEnd = Long.numberOfTrailingZeros(~curWordWith1s);
- runEnd = localRunEnd + longCtr * 64;
- // setValue(runCount, (short) runStart);
- vl[2 * runCount] = (short) runStart;
- // setLength(runCount, (short) (runEnd-runStart-1));
- vl[2 * runCount + 1] = (short) (runEnd - runStart - 1);
- runCount++;
- // now, zero out everything right of runEnd.
-
- curWord = curWordWith1s & (curWordWith1s + 1);
- // We've lathered and rinsed, so repeat...
- }
-
- }
- }
-
- /**
- * Creates a new container from a non-mappeable one. This copies the data.
- *
- * @param bc the original container
- */
- public MappeableRunContainer(RunContainer bc) {
- this.nbrruns = bc.numberOfRuns();
- this.valueslength = bc.toShortBuffer();
- }
-
-
- /**
- * Construct a new RunContainer backed by the provided ShortBuffer. Note that if you modify the
- * RunContainer a new ShortBuffer may be produced.
- *
- * @param array ShortBuffer where the data is stored
- * @param numRuns number of runs (each using 2 shorts in the buffer)
- */
- public MappeableRunContainer(final ShortBuffer array, final int numRuns) {
- if (array.limit() < 2 * numRuns) {
- throw new RuntimeException("Mismatch between buffer and numRuns");
- }
- this.nbrruns = numRuns;
- this.valueslength = array;
- }
-
- private static int branchyBufferedUnsignedInterleavedBinarySearch(final ShortBuffer sb,
- final int begin, final int end, final short k) {
- int ikey = BufferUtil.toIntUnsigned(k);
- int low = begin;
- int high = end - 1;
- while (low <= high) {
- final int middleIndex = (low + high) >>> 1;
- final int middleValue = BufferUtil.toIntUnsigned(sb.get(2 * middleIndex));
- if (middleValue < ikey) {
- low = middleIndex + 1;
- } else if (middleValue > ikey) {
- high = middleIndex - 1;
- } else {
- return middleIndex;
- }
- }
- return -(low + 1);
- }
-
- private static int bufferedUnsignedInterleavedBinarySearch(final ShortBuffer sb, final int begin,
- final int end, final short k) {
- return branchyBufferedUnsignedInterleavedBinarySearch(sb, begin, end, k);
- }
-
- protected static int getArraySizeInBytes(int nbrruns) {
- return 2 + 4 * nbrruns;
- }
-
- static short getLength(short[] vl, int index) {
- return vl[2 * index + 1];
- }
-
- static short getValue(short[] vl, int index) {
- return vl[2 * index];
- }
-
- protected static int serializedSizeInBytes(int numberOfRuns) {
- return 2 + 2 * 2 * numberOfRuns; // each run requires 2 2-byte entries.
- }
-
- @Override
- public MappeableContainer add(int begin, int end) {
- MappeableRunContainer rc = (MappeableRunContainer) clone();
- return rc.iadd(begin, end);
- }
-
- @Override
- // not thread-safe
- public MappeableContainer add(short k) {
- // TODO: it might be better and simpler to do return
- // toBitmapOrArrayContainer(getCardinality()).add(k)
- int index = bufferedUnsignedInterleavedBinarySearch(valueslength, 0, nbrruns, k);
- if (index >= 0) {
- return this;// already there
- }
- index = -index - 2;// points to preceding value, possibly -1
- if (index >= 0) {// possible match
- int offset = BufferUtil.toIntUnsigned(k) - BufferUtil.toIntUnsigned(getValue(index));
- int le = BufferUtil.toIntUnsigned(getLength(index));
- if (offset <= le) {
- return this;
- }
- if (offset == le + 1) {
- // we may need to fuse
- if (index + 1 < nbrruns) {
- if (BufferUtil.toIntUnsigned(getValue(index + 1)) == BufferUtil.toIntUnsigned(k) + 1) {
- // indeed fusion is needed
- setLength(index,
- (short) (getValue(index + 1) + getLength(index + 1) - getValue(index)));
- recoverRoomAtIndex(index + 1);
- return this;
- }
- }
- incrementLength(index);
- return this;
- }
- if (index + 1 < nbrruns) {
- // we may need to fuse
- if (BufferUtil.toIntUnsigned(getValue(index + 1)) == BufferUtil.toIntUnsigned(k) + 1) {
- // indeed fusion is needed
- setValue(index + 1, k);
- setLength(index + 1, (short) (getLength(index + 1) + 1));
- return this;
- }
- }
- }
- if (index == -1) {
- // we may need to extend the first run
- if (0 < nbrruns) {
- if (getValue(0) == k + 1) {
- incrementLength(0);
- decrementValue(0);
- return this;
- }
- }
- }
- makeRoomAtIndex(index + 1);
- setValue(index + 1, k);
- setLength(index + 1, (short) 0);
- return this;
- }
-
-
- @Override
- public MappeableContainer and(MappeableArrayContainer x) {
- MappeableArrayContainer ac = new MappeableArrayContainer(x.cardinality);
- if (this.nbrruns == 0) {
- return ac;
- }
- int rlepos = 0;
- int arraypos = 0;
-
- int rleval = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int rlelength = BufferUtil.toIntUnsigned(this.getLength(rlepos));
- while (arraypos < x.cardinality) {
- int arrayval = BufferUtil.toIntUnsigned(x.content.get(arraypos));
- while (rleval + rlelength < arrayval) {// this will frequently be false
- ++rlepos;
- if (rlepos == this.nbrruns) {
- return ac;// we are done
- }
- rleval = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- rlelength = BufferUtil.toIntUnsigned(this.getLength(rlepos));
- }
- if (rleval > arrayval) {
- arraypos =
- BufferUtil.advanceUntil(x.content, arraypos, x.cardinality, (short) rleval);
- } else {
- ac.content.put(ac.cardinality, (short) arrayval);
- ac.cardinality++;
- arraypos++;
- }
- }
- return ac;
- }
-
- @Override
- public MappeableContainer and(MappeableBitmapContainer x) {
- int card = this.getCardinality();
- if (card <= MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- // result can only be an array (assuming that we never make a RunContainer)
- if (card > x.cardinality) {
- card = x.cardinality;
- }
- MappeableArrayContainer answer = new MappeableArrayContainer(card);
- answer.cardinality = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + BufferUtil.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (x.contains((short) runValue)) {
- answer.content.put(answer.cardinality++, (short) runValue);
- }
- }
- }
- return answer;
- }
- // we expect the answer to be a bitmap (if we are lucky)
-
- MappeableBitmapContainer answer = x.clone();
- int start = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int end = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- BufferUtil.resetBitmapRange(answer.bitmap, start, end);
- start = end + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- BufferUtil.resetBitmapRange(answer.bitmap, start, BufferUtil.maxLowBitAsInteger() + 1);
- answer.computeCardinality();
- if (answer.getCardinality() > MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- return answer;
- } else {
- return answer.toArrayContainer();
- }
-
- }
-
- @Override
- public MappeableContainer and(MappeableRunContainer x) {
- MappeableRunContainer answer =
- new MappeableRunContainer(ShortBuffer.allocate(2 * (this.nbrruns + x.nbrruns)), 0);
- short[] vl = answer.valueslength.array();
- int rlepos = 0;
- int xrlepos = 0;
- int start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- // exit the first run
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {// they overlap
- final int lateststart = start > xstart ? start : xstart;
- int earliestend;
- if (end == xend) {// improbable
- earliestend = end;
- rlepos++;
- xrlepos++;
- if (rlepos < this.nbrruns) {
- start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- if (xrlepos < x.nbrruns) {
- xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else if (end < xend) {
- earliestend = end;
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
-
- } else {// end > xend
- earliestend = xend;
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- }
- vl[2 * answer.nbrruns] = (short) lateststart;
- vl[2 * answer.nbrruns + 1] = (short) (earliestend - lateststart - 1);
- answer.nbrruns++;
- }
- }
- return answer;
- }
-
- @Override
- public MappeableContainer andNot(MappeableArrayContainer x) {
- // when x is small, we guess that the result will still be a run container
- final int arbitrary_threshold = 32; // this is arbitrary
- if (x.getCardinality() < arbitrary_threshold) {
- return lazyandNot(x).toEfficientContainer();
- }
- // otherwise we generate either an array or bitmap container
- final int card = getCardinality();
- if (card <= MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- // if the cardinality is small, we construct the solution in place
- MappeableArrayContainer ac = new MappeableArrayContainer(card);
- ac.cardinality = Util.unsignedDifference(this.getShortIterator(),
- x.getShortIterator(), ac.content.array());
- return ac;
- }
- // otherwise, we generate a bitmap
- return toBitmapOrArrayContainer(card).iandNot(x);
- }
-
- @Override
- public MappeableContainer andNot(MappeableBitmapContainer x) {
- int card = this.getCardinality();
- if (card <= MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- // result can only be an array (assuming that we never make a RunContainer)
- MappeableArrayContainer answer = new MappeableArrayContainer(card);
- answer.cardinality = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + BufferUtil.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (!x.contains((short) runValue)) {
- answer.content.put(answer.cardinality++, (short) runValue);
- }
- }
- }
- return answer;
- }
- // we expect the answer to be a bitmap (if we are lucky)
- MappeableBitmapContainer answer = x.clone();
- int lastPos = 0;
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- BufferUtil.resetBitmapRange(answer.bitmap, lastPos, start);
- BufferUtil.flipBitmapRange(answer.bitmap, start, end);
- lastPos = end;
- }
- BufferUtil.resetBitmapRange(answer.bitmap, lastPos, answer.bitmap.capacity() * 64);
- answer.computeCardinality();
- if (answer.getCardinality() > MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- return answer;
- } else {
- return answer.toArrayContainer();
- }
- }
-
- @Override
- public MappeableContainer andNot(MappeableRunContainer x) {
- MappeableRunContainer answer =
- new MappeableRunContainer(ShortBuffer.allocate(2 * (this.nbrruns + x.nbrruns)), 0);
- short[] vl = answer.valueslength.array();
- int rlepos = 0;
- int xrlepos = 0;
- int start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- // output the first run
- vl[2 * answer.nbrruns] = (short) start;
- vl[2 * answer.nbrruns + 1] = (short) (end - start - 1);
- answer.nbrruns++;
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {
- if (start < xstart) {
- vl[2 * answer.nbrruns] = (short) start;
- vl[2 * answer.nbrruns + 1] = (short) (xstart - start - 1);
- answer.nbrruns++;
- }
- if (xend < end) {
- start = xend;
- } else {
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- }
- }
- }
- if (rlepos < this.nbrruns) {
- vl[2 * answer.nbrruns] = (short) start;
- vl[2 * answer.nbrruns + 1] = (short) (end - start - 1);
- answer.nbrruns++;
- rlepos++;
- for (; rlepos < this.nbrruns; ++rlepos) {
- vl[2 * answer.nbrruns] = this.valueslength.get(2 * rlepos);
- vl[2 * answer.nbrruns + 1] = this.valueslength.get(2 * rlepos + 1);
- answer.nbrruns++;
- }
- // next bit would be faster but not thread-safe because of the "position"
- // if(rlepos < this.nbrruns) {
- // this.valueslength.position(2 * rlepos);
- // this.valueslength.get(vl, 2 * answer.nbrruns, 2*(this.nbrruns-rlepos ));
- // answer.nbrruns = answer.nbrruns + this.nbrruns - rlepos;
- // }
- }
- return answer;
- }
-
- // Append a value length with all values until a given value
- private void appendValueLength(int value, int index) {
- int previousValue = BufferUtil.toIntUnsigned(getValue(index));
- int length = BufferUtil.toIntUnsigned(getLength(index));
- int offset = value - previousValue;
- if (offset > length) {
- setLength(index, (short) offset);
- }
- }
-
-
- // To check if a value length can be prepended with a given value
- private boolean canPrependValueLength(int value, int index) {
- if (index < this.nbrruns) {
- int nextValue = BufferUtil.toIntUnsigned(getValue(index));
- if (nextValue == value + 1) {
- return true;
- }
- }
- return false;
- }
-
-
- @Override
- public void clear() {
- nbrruns = 0;
- }
-
-
- @Override
- public MappeableContainer clone() {
- return new MappeableRunContainer(nbrruns, valueslength);
- }
-
-
- // To set the last value of a value length
- private void closeValueLength(int value, int index) {
- int initialValue = BufferUtil.toIntUnsigned(getValue(index));
- setLength(index, (short) (value - initialValue));
- }
-
- @Override
- public boolean contains(short x) {
- int index = bufferedUnsignedInterleavedBinarySearch(valueslength, 0, nbrruns, x);
- if (index >= 0) {
- return true;
- }
- index = -index - 2; // points to preceding value, possibly -1
- if (index != -1) {// possible match
- int offset = BufferUtil.toIntUnsigned(x) - BufferUtil.toIntUnsigned(getValue(index));
- int le = BufferUtil.toIntUnsigned(getLength(index));
- if (offset <= le) {
- return true;
- }
- }
- return false;
- }
-
- // a very cheap check... if you have more than 4096, then you should use a bitmap container.
- // this function avoids computing the cardinality
- private MappeableContainer convertToLazyBitmapIfNeeded() {
- // when nbrruns exceed MappeableArrayContainer.DEFAULT_MAX_SIZE, then we know it should be
- // stored as a bitmap, always
- if (this.nbrruns > MappeableArrayContainer.DEFAULT_MAX_SIZE) {
- MappeableBitmapContainer answer = new MappeableBitmapContainer();
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- BufferUtil.setBitmapRange(answer.bitmap, start, end);
- }
- answer.cardinality = -1;
- return answer;
- }
- return this;
- }
-
- // Push all values length to the end of the array (resize array if needed)
- private void copyToOffset(int offset) {
- final int minCapacity = 2 * (offset + nbrruns);
- if (valueslength.capacity() < minCapacity) {
- // expensive case where we need to reallocate
- int newCapacity = valueslength.capacity();
- while (newCapacity < minCapacity) {
- newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE
- : newCapacity < 64 ? newCapacity * 2
- : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4;
- }
- ShortBuffer newvalueslength = ShortBuffer.allocate(newCapacity);
- copyValuesLength(this.valueslength, 0, newvalueslength, offset, nbrruns);
- this.valueslength = newvalueslength;
- } else {
- // efficient case where we just copy
- copyValuesLength(this.valueslength, 0, this.valueslength, offset, nbrruns);
- }
- }
-
- private void copyValuesLength(ShortBuffer src, int srcIndex, ShortBuffer dst, int dstIndex,
- int length) {
- if (BufferUtil.isBackedBySimpleArray(src) && BufferUtil.isBackedBySimpleArray(dst)) {
- // common case.
- System.arraycopy(src.array(), 2 * srcIndex, dst.array(), 2 * dstIndex, 2 * length);
- return;
- }
- // source and destination may overlap
- // consider specialized code for various cases, rather than using a second buffer
- ShortBuffer temp = ShortBuffer.allocate(2 * length);
- for (int i = 0; i < 2 * length; ++i) {
- temp.put(src.get(2 * srcIndex + i));
- }
- temp.flip();
- for (int i = 0; i < 2 * length; ++i) {
- dst.put(2 * dstIndex + i, temp.get());
- }
- }
-
- private void decrementLength(int index) {
- // caller is responsible to ensure that value is non-zero
- valueslength.put(2 * index + 1, (short) (valueslength.get(2 * index + 1) - 1));
- }
-
-
- private void decrementValue(int index) {
- valueslength.put(2 * index, (short) (valueslength.get(2 * index) - 1));
- }
-
- // not thread safe!
- // not actually used anywhere, but potentially useful
- protected void ensureCapacity(int minNbRuns) {
- final int minCapacity = 2 * minNbRuns;
- if (valueslength.capacity() < minCapacity) {
- int newCapacity = valueslength.capacity();
- while (newCapacity < minCapacity) {
- newCapacity = (newCapacity == 0) ? DEFAULT_INIT_SIZE
- : newCapacity < 64 ? newCapacity * 2
- : newCapacity < 1024 ? newCapacity * 3 / 2 : newCapacity * 5 / 4;
- }
- final ShortBuffer nv = ShortBuffer.allocate(newCapacity);
- valueslength.rewind();
- nv.put(valueslength);
- valueslength = nv;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof MappeableRunContainer) {
- MappeableRunContainer srb = (MappeableRunContainer) o;
- if (srb.nbrruns != this.nbrruns) {
- return false;
- }
- for (int i = 0; i < nbrruns; ++i) {
- if (this.getValue(i) != srb.getValue(i)) {
- return false;
- }
- if (this.getLength(i) != srb.getLength(i)) {
- return false;
- }
- }
- return true;
- } else if (o instanceof MappeableContainer) {
- if (((MappeableContainer) o).getCardinality() != this.getCardinality()) {
- return false; // should be a frequent branch if they differ
- }
- // next bit could be optimized if needed:
- ShortIterator me = this.getShortIterator();
- ShortIterator you = ((MappeableContainer) o).getShortIterator();
- while (me.hasNext()) {
- if (me.next() != you.next()) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public void fillLeastSignificant16bits(int[] x, int i, int mask) {
- int pos = i;
- for (int k = 0; k < this.nbrruns; ++k) {
- final int limit = BufferUtil.toIntUnsigned(this.getLength(k));
- final int base = BufferUtil.toIntUnsigned(this.getValue(k));
- for (int le = 0; le <= limit; ++le) {
- x[pos++] = (base + le) | mask;
- }
- }
- }
-
-
- @Override
- public MappeableContainer flip(short x) {
- if (this.contains(x)) {
- return this.remove(x);
- } else {
- return this.add(x);
- }
- }
-
- @Override
- protected int getArraySizeInBytes() {
- return 2 + 4 * this.nbrruns; // "array" includes its size
- }
-
- @Override
- public int getCardinality() {
- int sum = nbrruns; // lengths are stored -1
- if (isArrayBacked()) {
- short[] vl = valueslength.array();
- for (int k = 0; k < nbrruns; ++k) {
- sum = sum + BufferUtil.toIntUnsigned(vl[2 * k + 1])/* + 1 */;
- }
- } else {
- for (int k = 0; k < nbrruns; ++k) {
- sum = sum + BufferUtil.toIntUnsigned(getLength(k))/* + 1 */;
- }
- }
- return sum;
- }
-
- short getLength(int index) {
- return valueslength.get(2 * index + 1);
- }
-
- @Override
- public ShortIterator getReverseShortIterator() {
- if (isArrayBacked()) {
- return new RawReverseMappeableRunContainerShortIterator(this);
- }
- return new ReverseMappeableRunContainerShortIterator(this);
- }
-
- @Override
- public PeekableShortIterator getShortIterator() {
- if (isArrayBacked()) {
- return new RawMappeableRunContainerShortIterator(this);
- }
- return new MappeableRunContainerShortIterator(this);
- }
-
- @Override
- public int getSizeInBytes() {
- return this.nbrruns * 4 + 4; // not sure about how exact it will be
- }
-
- short getValue(int index) {
- return valueslength.get(2 * index);
- }
-
- @Override
- public int hashCode() {
- int hash = 0;
- for (int k = 0; k < nbrruns * 2; ++k) {
- hash += 31 * hash + valueslength.get(k);
- }
- return hash;
- }
-
- @Override
- // not thread-safe
- public MappeableContainer iadd(int begin, int end) {
- // TODO: it might be better and simpler to do return
- // toBitmapOrArrayContainer(getCardinality()).iadd(begin,end)
- if (end == begin) {
- return this;
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
- if (begin == end - 1) {
- add((short) begin);
- return this;
- }
-
- int bIndex =
- bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (short) begin);
- int eIndex = bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns,
- (short) (end - 1));
-
- if (bIndex >= 0 && eIndex >= 0) {
- mergeValuesLength(bIndex, eIndex);
- return this;
-
- } else if (bIndex >= 0 && eIndex < 0) {
- eIndex = -eIndex - 2;
-
- if (canPrependValueLength(end - 1, eIndex + 1)) {
- mergeValuesLength(bIndex, eIndex + 1);
- return this;
- }
-
- appendValueLength(end - 1, eIndex);
- mergeValuesLength(bIndex, eIndex);
- return this;
-
- } else if (bIndex < 0 && eIndex >= 0) {
- bIndex = -bIndex - 2;
-
- if (bIndex >= 0) {
- if (valueLengthContains(begin - 1, bIndex)) {
- mergeValuesLength(bIndex, eIndex);
- return this;
- }
- }
- prependValueLength(begin, bIndex + 1);
- mergeValuesLength(bIndex + 1, eIndex);
- return this;
-
- } else {
- bIndex = -bIndex - 2;
- eIndex = -eIndex - 2;
-
- if (eIndex >= 0) {
- if (bIndex >= 0) {
- if (!valueLengthContains(begin - 1, bIndex)) {
- if (bIndex == eIndex) {
- if (canPrependValueLength(end - 1, eIndex + 1)) {
- prependValueLength(begin, eIndex + 1);
- return this;
- }
- makeRoomAtIndex(eIndex + 1);
- setValue(eIndex + 1, (short) begin);
- setLength(eIndex + 1, (short) (end - 1 - begin));
- return this;
-
- } else {
- bIndex++;
- prependValueLength(begin, bIndex);
- }
- }
- } else {
- bIndex = 0;
- prependValueLength(begin, bIndex);
- }
-
- if (canPrependValueLength(end - 1, eIndex + 1)) {
- mergeValuesLength(bIndex, eIndex + 1);
- return this;
- }
-
- appendValueLength(end - 1, eIndex);
- mergeValuesLength(bIndex, eIndex);
- return this;
-
- } else {
- if (canPrependValueLength(end - 1, 0)) {
- prependValueLength(begin, 0);
- } else {
- makeRoomAtIndex(0);
- setValue(0, (short) begin);
- setLength(0, (short) (end - 1 - begin));
- }
- return this;
- }
- }
- }
-
-
- @Override
- public MappeableContainer iand(MappeableArrayContainer x) {
- return and(x);
- }
-
- @Override
- public MappeableContainer iand(MappeableBitmapContainer x) {
- return and(x);
- }
-
-
- @Override
- public MappeableContainer iand(MappeableRunContainer x) {
- return and(x);
- }
-
- @Override
- public MappeableContainer iandNot(MappeableArrayContainer x) {
- return andNot(x);
- }
-
- @Override
- public MappeableContainer iandNot(MappeableBitmapContainer x) {
- return andNot(x);
- }
-
- @Override
- public MappeableContainer iandNot(MappeableRunContainer x) {
- return andNot(x);
- }
-
- protected MappeableContainer ilazyor(MappeableArrayContainer x) {
- if (isFull()) {
- return this; // this can sometimes solve a lot of computation!
- }
- return ilazyorToRun(x);
- }
-
-
- private MappeableContainer ilazyorToRun(MappeableArrayContainer x) {
- if (isFull()) {
- return this.clone();
- }
- final int nbrruns = this.nbrruns;
- final int offset = Math.max(nbrruns, x.getCardinality());
- copyToOffset(offset);
- short[] vl = valueslength.array();
- int rlepos = 0;
- this.nbrruns = 0;
- PeekableShortIterator i = (PeekableShortIterator) x.getShortIterator();
- while (i.hasNext() && (rlepos < nbrruns)) {
- if (BufferUtil.compareUnsigned(getValue(vl, rlepos + offset), i.peekNext()) <= 0) {
- smartAppend(vl, getValue(vl, rlepos + offset), getLength(vl, rlepos + offset));
- rlepos++;
- } else {
- smartAppend(vl, i.next());
- }
- }
- if (i.hasNext()) {
- /*
- * if(this.nbrruns>0) { // this might be useful if the run container has just one very large
- * run int lastval = BufferUtil.toIntUnsigned(getValue(vl,nbrruns + offset - 1)) +
- * BufferUtil.toIntUnsigned(getLength(vl,nbrruns + offset - 1)) + 1; i.advanceIfNeeded((short)
- * lastval); }
- */
- while (i.hasNext()) {
- smartAppend(vl, i.next());
- }
- } else {
- while (rlepos < nbrruns) {
- smartAppend(vl, getValue(vl, rlepos + offset), getLength(vl, rlepos + offset));
- rlepos++;
- }
- }
- return convertToLazyBitmapIfNeeded();
- }
-
- // not thread safe!
- private void increaseCapacity() {
- int newCapacity = (valueslength.capacity() == 0) ? DEFAULT_INIT_SIZE
- : valueslength.capacity() < 64 ? valueslength.capacity() * 2
- : valueslength.capacity() < 1024 ? valueslength.capacity() * 3 / 2
- : valueslength.capacity() * 5 / 4;
-
- final ShortBuffer nv = ShortBuffer.allocate(newCapacity);
- valueslength.rewind();
- nv.put(valueslength);
- valueslength = nv;
- }
-
- private void incrementLength(int index) {
- valueslength.put(2 * index + 1, (short) (1 + valueslength.get(2 * index + 1)));
- }
-
- private void incrementValue(int index) {
- valueslength.put(2 * index, (short) (1 + valueslength.get(2 * index)));
- }
-
- // To set the first value of a value length
- private void initValueLength(int value, int index) {
- int initialValue = BufferUtil.toIntUnsigned(getValue(index));
- int length = BufferUtil.toIntUnsigned(getLength(index));
- setValue(index, (short) (value));
- setLength(index, (short) (length - (value - initialValue)));
- }
-
-
- @Override
- public MappeableContainer inot(int rangeStart, int rangeEnd) {
- if (rangeEnd <= rangeStart) {
- return this;
- }
- short[] vl = this.valueslength.array();
-
- // TODO: write special case code for rangeStart=0; rangeEnd=65535
- // a "sliding" effect where each range records the gap adjacent it
- // can probably be quite fast. Probably have 2 cases: start with a
- // 0 run vs start with a 1 run. If you both start and end with 0s,
- // you will require room for expansion.
-
- // the +1 below is needed in case the valueslength.length is odd
- if (vl.length <= 2 * nbrruns + 1) {
- // no room for expansion
- // analyze whether this is a case that will require expansion (that we cannot do)
- // this is a bit costly now (4 "contains" checks)
-
- boolean lastValueBeforeRange = false;
- boolean firstValueInRange = false;
- boolean lastValueInRange = false;
- boolean firstValuePastRange = false;
-
- // contains is based on a binary search and is hopefully fairly fast.
- // however, one binary search could *usually* suffice to find both
- // lastValueBeforeRange AND firstValueInRange. ditto for
- // lastVaueInRange and firstValuePastRange
-
- // find the start of the range
- if (rangeStart > 0) {
- lastValueBeforeRange = contains((short) (rangeStart - 1));
- }
- firstValueInRange = contains((short) rangeStart);
-
- if (lastValueBeforeRange == firstValueInRange) {
- // expansion is required if also lastValueInRange==firstValuePastRange
-
- // tougher to optimize out, but possible.
- lastValueInRange = contains((short) (rangeEnd - 1));
- if (rangeEnd != 65536) {
- firstValuePastRange = contains((short) rangeEnd);
- }
-
- // there is definitely one more run after the operation.
- if (lastValueInRange == firstValuePastRange) {
- return not(rangeStart, rangeEnd); // can't do in-place: true space limit
- }
- }
- }
- // either no expansion required, or we have room to handle any required expansion for it.
-
- // remaining code is just a minor variation on not()
- int myNbrRuns = nbrruns;
-
- MappeableRunContainer ans = this; // copy on top of self.
- int k = 0;
- ans.nbrruns = 0; // losing this.nbrruns, which is stashed in myNbrRuns.
-
- // could try using unsignedInterleavedBinarySearch(valueslength, 0, nbrruns, rangeStart) instead
- // of sequential scan
- // to find the starting location
-
- for (; k < myNbrRuns && BufferUtil.toIntUnsigned(this.getValue(k)) < rangeStart; ++k) {
- // since it is atop self, there is no copying needed
- // ans.valueslength[2 * k] = this.valueslength[2 * k];
- // ans.valueslength[2 * k + 1] = this.valueslength[2 * k + 1];
- ans.nbrruns++;
- }
- // We will work left to right, with a read pointer that always stays
- // left of the write pointer. However, we need to give the read pointer a head start.
- // use local variables so we are always reading 1 location ahead.
-
- short bufferedValue = 0, bufferedLength = 0; // 65535 start and 65535 length would be illegal,
- // could use as sentinel
- short nextValue = 0, nextLength = 0;
- if (k < myNbrRuns) { // prime the readahead variables
- bufferedValue = vl[2 * k];// getValue(k);
- bufferedLength = vl[2 * k + 1];// getLength(k);
- }
-
- ans.smartAppendExclusive(vl, (short) rangeStart, (short) (rangeEnd - rangeStart - 1));
-
- for (; k < myNbrRuns; ++k) {
- if (ans.nbrruns > k + 1) {
- throw new RuntimeException(
- "internal error in inot, writer has overtaken reader!! " + k + " " + ans.nbrruns);
- }
- if (k + 1 < myNbrRuns) {
- nextValue = vl[2 * (k + 1)];// getValue(k+1); // readahead for next iteration
- nextLength = vl[2 * (k + 1) + 1];// getLength(k+1);
- }
- ans.smartAppendExclusive(vl, bufferedValue, bufferedLength);
- bufferedValue = nextValue;
- bufferedLength = nextLength;
- }
- // the number of runs can increase by one, meaning (rarely) a bitmap will become better
- // or the cardinality can decrease by a lot, making an array better
- return ans.toEfficientContainer();
- }
-
- @Override
- public boolean intersects(MappeableArrayContainer x) {
- if (this.nbrruns == 0) {
- return false;
- }
- int rlepos = 0;
- int arraypos = 0;
-
- int rleval = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int rlelength = BufferUtil.toIntUnsigned(this.getLength(rlepos));
- while (arraypos < x.cardinality) {
- int arrayval = BufferUtil.toIntUnsigned(x.content.get(arraypos));
- while (rleval + rlelength < arrayval) {// this will frequently be false
- ++rlepos;
- if (rlepos == this.nbrruns) {
- return false;
- }
- rleval = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- rlelength = BufferUtil.toIntUnsigned(this.getLength(rlepos));
- }
- if (rleval > arrayval) {
- arraypos =
- BufferUtil.advanceUntil(x.content, arraypos, x.cardinality, this.getValue(rlepos));
- } else {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public boolean intersects(MappeableBitmapContainer x) {
- // possibly inefficient
- for (int rlepos = 0; rlepos < this.nbrruns; ++rlepos) {
- int runStart = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int runEnd = runStart + BufferUtil.toIntUnsigned(this.getLength(rlepos));
- for (int runValue = runStart; runValue <= runEnd; ++runValue) {
- if (x.contains((short) runValue)) {
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public boolean intersects(MappeableRunContainer x) {
- int rlepos = 0;
- int xrlepos = 0;
- int start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- int end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- int xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- int xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- while ((rlepos < this.nbrruns) && (xrlepos < x.nbrruns)) {
- if (end <= xstart) {
- // exit the first run
- rlepos++;
- if (rlepos < this.nbrruns) {
- start = BufferUtil.toIntUnsigned(this.getValue(rlepos));
- end = start + BufferUtil.toIntUnsigned(this.getLength(rlepos)) + 1;
- }
- } else if (xend <= start) {
- // exit the second run
- xrlepos++;
- if (xrlepos < x.nbrruns) {
- xstart = BufferUtil.toIntUnsigned(x.getValue(xrlepos));
- xend = xstart + BufferUtil.toIntUnsigned(x.getLength(xrlepos)) + 1;
- }
- } else {// they overlap
- return true;
- }
- }
- return false;
- }
-
- @Override
- public MappeableContainer ior(MappeableArrayContainer x) {
- if (isFull()) {
- return this;
- }
- final int nbrruns = this.nbrruns;
- final int offset = Math.max(nbrruns, x.getCardinality());
- copyToOffset(offset);
- short[] vl = this.valueslength.array();
- int rlepos = 0;
- this.nbrruns = 0;
- PeekableShortIterator i = (PeekableShortIterator) x.getShortIterator();
- while (i.hasNext() && (rlepos < nbrruns)) {
- if (BufferUtil.compareUnsigned(getValue(vl, rlepos + offset), i.peekNext()) <= 0) {
- smartAppend(vl, getValue(vl, rlepos + offset), getLength(vl, rlepos + offset));
- rlepos++;
- } else {
- smartAppend(vl, i.next());
- }
- }
- if (i.hasNext()) {
- /*
- * if(this.nbrruns>0) { // this might be useful if the run container has just one very large
- * run int lastval = BufferUtil.toIntUnsigned(getValue(nbrruns + offset - 1)) +
- * BufferUtil.toIntUnsigned(getLength(nbrruns + offset - 1)) + 1; i.advanceIfNeeded((short)
- * lastval); }
- */
- while (i.hasNext()) {
- smartAppend(vl, i.next());
- }
- } else {
- while (rlepos < nbrruns) {
- smartAppend(vl, getValue(vl, rlepos + offset), getLength(vl, rlepos + offset));
- rlepos++;
- }
- }
- return toEfficientContainer();
- }
-
- @Override
- public MappeableContainer ior(MappeableBitmapContainer x) {
- if (isFull()) {
- return this;
- }
- return or(x);
- }
-
- @Override
- public MappeableContainer ior(MappeableRunContainer x) {
- if (isFull()) {
- return this;
- }
-
- final int nbrruns = this.nbrruns;
- final int xnbrruns = x.nbrruns;
- final int offset = Math.max(nbrruns, xnbrruns);
-
- // Push all values length to the end of the array (resize array if needed)
- copyToOffset(offset);
-
- // Aggregate and store the result at the beginning of the array
- this.nbrruns = 0;
- int rlepos = 0;
- int xrlepos = 0;
- short[] vl = this.valueslength.array();
-
- // Add values length (smaller first)
- while ((rlepos < nbrruns) && (xrlepos < xnbrruns)) {
- final short value = getValue(vl, offset + rlepos);
- final short xvalue = x.getValue(xrlepos);
- final short length = getLength(vl, offset + rlepos);
- final short xlength = x.getLength(xrlepos);
-
- if (BufferUtil.compareUnsigned(value, xvalue) <= 0) {
- this.smartAppend(vl, value, length);
- ++rlepos;
- } else {
- this.smartAppend(vl, xvalue, xlength);
- ++xrlepos;
- }
- }
- while (rlepos < nbrruns) {
- this.smartAppend(vl, getValue(vl, offset + rlepos), getLength(vl, offset + rlepos));
- ++rlepos;
- }
- while (xrlepos < xnbrruns) {
- this.smartAppend(vl, x.getValue(xrlepos), x.getLength(xrlepos));
- ++xrlepos;
- }
- return this.toBitmapIfNeeded();
- }
-
- @Override
- // not thread-safe
- public MappeableContainer iremove(int begin, int end) {
- // TODO: it might be better and simpler to do return
- // toBitmapOrArrayContainer(getCardinality()).iremove(begin,end)
- if (end == begin) {
- return this;
- }
- if ((begin > end) || (end > (1 << 16))) {
- throw new IllegalArgumentException("Invalid range [" + begin + "," + end + ")");
- }
- if (begin == end - 1) {
- remove((short) begin);
- return this;
- }
-
- int bIndex =
- bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns, (short) begin);
- int eIndex = bufferedUnsignedInterleavedBinarySearch(this.valueslength, 0, this.nbrruns,
- (short) (end - 1));
-
- if (bIndex >= 0) {
- if (eIndex < 0) {
- eIndex = -eIndex - 2;
- }
-
- if (valueLengthContains(end, eIndex)) {
- initValueLength(end, eIndex);
- recoverRoomsInRange(bIndex - 1, eIndex - 1);
- } else {
- recoverRoomsInRange(bIndex - 1, eIndex);
- }
-
- } else if (bIndex < 0 && eIndex >= 0) {
- bIndex = -bIndex - 2;
-
- if (bIndex >= 0) {
- if (valueLengthContains(begin, bIndex)) {
- closeValueLength(begin - 1, bIndex);
- }
- }
- // last run is one shorter
- if (getLength(eIndex) == 0) {// special case where we remove last run
- recoverRoomsInRange(eIndex, eIndex + 1);
- } else {
- incrementValue(eIndex);
- decrementLength(eIndex);
- }
- recoverRoomsInRange(bIndex, eIndex - 1);
-
- } else {
- bIndex = -bIndex - 2;
- eIndex = -eIndex - 2;
-
- if (eIndex >= 0) {
- if (bIndex >= 0) {
- if (bIndex == eIndex) {
- if (valueLengthContains(begin, bIndex)) {
- if (valueLengthContains(end, eIndex)) {
- makeRoomAtIndex(bIndex);
- closeValueLength(begin - 1, bIndex);
- initValueLength(end, bIndex + 1);
- return this;
- }
- closeValueLength(begin - 1, bIndex);
- }
- } else {
- if (valueLengthContains(begin, bIndex)) {
- closeValueLength(begin - 1, bIndex);
- }
- if (valueLengthContains(end, eIndex)) {
- initValueLength(end, eIndex);
- eIndex--;
- }
- recoverRoomsInRange(bIndex, eIndex);
- }
-
- } else {
- if (valueLengthContains(end, eIndex)) { // was end-1
- initValueLength(end, eIndex);
- recoverRoomsInRange(bIndex, eIndex - 1);
- } else {
- recoverRoomsInRange(bIndex, eIndex);
- }
- }
-
- }
-
- }
- return this;
- }
-
- @Override
- protected boolean isArrayBacked() {
- return BufferUtil.isBackedBySimpleArray(this.valueslength);
- }
-
- protected boolean isFull() {
- return (this.nbrruns == 1) && (this.getValue(0) == 0) && (this.getLength(0) == -1);
- }
-
- @Override
- public Iterator
- * Objects of this class reside in RAM.
- */
-public final class MutableRoaringArray implements Cloneable, Externalizable, PointableRoaringArray {
-
- protected static final int INITIAL_CAPACITY = 4;
-
- protected static final short SERIAL_COOKIE_NO_RUNCONTAINER = 12346;
- protected static final short SERIAL_COOKIE = 12347;
-
- protected static final int NO_OFFSET_THRESHOLD = 4;
-
- private static final long serialVersionUID = 5L; // TODO: OFK was 4L, not sure
- protected boolean mayHaveRunContainers = false; // does not necessarily have them, after
- // optimization
-
-
- short[] keys = null;
- MappeableContainer[] values = null;
-
- int size = 0;
-
- protected MutableRoaringArray() {
- this.keys = new short[INITIAL_CAPACITY];
- this.values = new MappeableContainer[INITIAL_CAPACITY];
- }
-
-
- @Override
- public int advanceUntil(short x, int pos) {
- int lower = pos + 1;
-
- // special handling for a possibly common sequential case
- if (lower >= size || BufferUtil.toIntUnsigned(keys[lower]) >= BufferUtil.toIntUnsigned(x)) {
- return lower;
- }
-
- int spansize = 1; // could set larger
- // bootstrap an upper limit
-
- while (lower + spansize < size
- && BufferUtil.toIntUnsigned(keys[lower + spansize]) < BufferUtil.toIntUnsigned(x)) {
- spansize *= 2; // hoping for compiler will reduce to shift
- }
- int upper = (lower + spansize < size) ? lower + spansize : size - 1;
-
- // maybe we are lucky (could be common case when the seek ahead
- // expected to be small and sequential will otherwise make us look bad)
- if (keys[upper] == x) {
- return upper;
- }
-
- if (BufferUtil.toIntUnsigned(keys[upper]) < BufferUtil.toIntUnsigned(x)) {// means array has no
- // item key >= x
- return size;
- }
-
- // we know that the next-smallest span was too small
- lower += (spansize / 2);
-
- // else begin binary search
- // invariant: array[lower]
- * The current bitmap is not modified.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- @Override
- public void serialize(DataOutput out) throws IOException {
- int startOffset = 0;
- boolean hasrun = hasRunCompression();
- if (hasrun) {
- out.writeInt(Integer.reverseBytes(SERIAL_COOKIE | ((this.size - 1) << 16)));
- byte[] bitmapOfRunContainers = new byte[(size + 7) / 8];
- for (int i = 0; i < size; ++i) {
- if (this.values[i] instanceof MappeableRunContainer) {
- bitmapOfRunContainers[i / 8] |= (1 << (i % 8));
- }
- }
- out.write(bitmapOfRunContainers);
- if (this.size < NO_OFFSET_THRESHOLD) {
- startOffset = 4 + 4 * this.size + bitmapOfRunContainers.length;
- } else {
- startOffset = 4 + 8 * this.size + bitmapOfRunContainers.length;
- }
- } else { // backwards compatibilility
- out.writeInt(Integer.reverseBytes(SERIAL_COOKIE_NO_RUNCONTAINER));
- out.writeInt(Integer.reverseBytes(size));
- startOffset = 4 + 4 + this.size * 4 + this.size * 4;
- }
- for (int k = 0; k < size; ++k) {
- out.writeShort(Short.reverseBytes(this.keys[k]));
- out.writeShort(Short.reverseBytes((short) (this.values[k].getCardinality() - 1)));
- }
- if ((!hasrun) || (this.size >= NO_OFFSET_THRESHOLD)) {
- for (int k = 0; k < this.size; k++) {
- out.writeInt(Integer.reverseBytes(startOffset));
- startOffset = startOffset + values[k].getArraySizeInBytes();
- }
- }
- for (int k = 0; k < size; ++k) {
- values[k].writeArray(out);
- }
-
- }
-
- /**
- * Report the number of bytes required for serialization.
- *
- * @return the size in bytes
- */
- @Override
- public int serializedSizeInBytes() {
- int count = headerSize();
- // for each container, we store cardinality (16 bits), key (16 bits) and location offset (32
- // bits).
- for (int k = 0; k < this.size; ++k) {
- count += values[k].getArraySizeInBytes();
- }
- return count;
- }
-
- protected void setContainerAtIndex(int i, MappeableContainer c) {
- this.values[i] = c;
- }
-
- @Override
- public int size() {
- return this.size;
- }
-
- @Override
- public void writeExternal(ObjectOutput out) throws IOException {
- serialize(out);
- }
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/MutableRoaringBitmap.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/MutableRoaringBitmap.java
deleted file mode 100644
index 902e421a7..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/MutableRoaringBitmap.java
+++ /dev/null
@@ -1,1420 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap.buffer;
-
-import com.fr.third.bitmap.roaringbitmap.BitmapDataProvider;
-import com.fr.third.bitmap.roaringbitmap.ContainerPointer;
-import com.fr.third.bitmap.roaringbitmap.RoaringBitmap;
-import com.fr.third.bitmap.roaringbitmap.ShortIterator;
-import com.fr.third.bitmap.roaringbitmap.Util;
-
-import java.io.DataInput;
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.Serializable;
-import java.util.Iterator;
-
-/**
- * MutableRoaringBitmap, a compressed alternative to the BitSet. It is similar to
- * RoaringBitmap, but it differs in that it can interact with
- * ImmutableRoaringBitmap objects.
- *
- * A MutableRoaringBitmap is an instance of an ImmutableRoaringBitmap (where methods like
- * "serialize" are implemented). That is, they both share the same core (immutable) methods, but a
- * MutableRoaringBitmap adds methods that allow you to modify the object. This design allows us to
- * use MutableRoaringBitmap as ImmutableRoaringBitmap instances when needed.
- *
- * A MutableRoaringBitmap can be used much like an RoaringBitmap instance, and
- * they serialize to the same output. The RoaringBitmap instance will be faster since it does not
- * carry the overhead of a ByteBuffer back-end, but the MutableRoaringBitmap can be used as an
- * ImmutableRoaringBitmap instance. Thus, if you use ImmutableRoaringBitmap, you probably need to
- * use MutableRoaringBitmap instances as well; if you do not use ImmutableRoaringBitmap, you
- * probably want to use only RoaringBitmap instances.
- *
- *
- * (Effectively calls {@link BufferFastAggregation#or})
- *
- * @param bitmaps input bitmaps
- * @return aggregated bitmap
- */
- public static MutableRoaringBitmap or(ImmutableRoaringBitmap... bitmaps) {
- return BufferFastAggregation.or(bitmaps);
- }
-
- /**
- * Bitwise OR (union) operation. The provided bitmaps are *not* modified. This operation is
- * thread-safe as long as the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- */
- public static MutableRoaringBitmap or(final MutableRoaringBitmap x1,
- final MutableRoaringBitmap x2) {
- final MutableRoaringBitmap answer = new MutableRoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- answer.getMappeableRoaringArray().append(s1, x1.highLowContainer.getContainerAtIndex(pos1)
- .or(x2.highLowContainer.getContainerAtIndex(pos2)));
- pos1++;
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer.getKeyAtIndex(pos1),
- x1.highLowContainer.getContainerAtIndex(pos1));
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- answer.getMappeableRoaringArray().appendCopy(x2.highLowContainer.getKeyAtIndex(pos2),
- x2.highLowContainer.getContainerAtIndex(pos2));
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- answer.getMappeableRoaringArray().appendCopy(x2.highLowContainer, pos2, length2);
- } else if (pos2 == length2) {
- answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer, pos1, length1);
- }
- return answer;
- }
-
- /**
- * Generate a new bitmap with all integers in [rangeStart,rangeEnd) removed.
- *
- * @param rb initial bitmap (will not be modified)
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new bitmap
- */
- public static MutableRoaringBitmap remove(MutableRoaringBitmap rb, final long rangeStart,
- final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- return rb.clone(); // empty range
- }
- final int hbStart = BufferUtil.toIntUnsigned(BufferUtil.highbits(rangeStart));
- final int lbStart = BufferUtil.toIntUnsigned(BufferUtil.lowbits(rangeStart));
- final int hbLast = BufferUtil.toIntUnsigned(BufferUtil.highbits(rangeEnd - 1));
- final int lbLast = BufferUtil.toIntUnsigned(BufferUtil.lowbits(rangeEnd - 1));
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- ((MutableRoaringArray) answer.highLowContainer).appendCopiesUntil(rb.highLowContainer,
- (short) hbStart);
-
- if (hbStart == hbLast) {
- final int i = rb.highLowContainer.getIndex((short) hbStart);
- if (i >= 0) {
- final MappeableContainer c =
- rb.highLowContainer.getContainerAtIndex(i).remove(lbStart, lbLast + 1);
- if (c.getCardinality() > 0) {
- ((MutableRoaringArray) answer.highLowContainer).append((short) hbStart, c);
- }
- }
- ((MutableRoaringArray) answer.highLowContainer).appendCopiesAfter(rb.highLowContainer,
- (short) hbLast);
- return answer;
- }
- int ifirst = rb.highLowContainer.getIndex((short) hbStart);
- int ilast = rb.highLowContainer.getIndex((short) hbLast);
- if ((ifirst >= 0) && (lbStart != 0)) {
- final MappeableContainer c = rb.highLowContainer.getContainerAtIndex(ifirst).remove(lbStart,
- BufferUtil.maxLowBitAsInteger() + 1);
- if (c.getCardinality() > 0) {
- ((MutableRoaringArray) answer.highLowContainer).append((short) hbStart, c);
- }
- }
- if ((ilast >= 0) && (lbLast != BufferUtil.maxLowBitAsInteger())) {
- final MappeableContainer c =
- rb.highLowContainer.getContainerAtIndex(ilast).remove(0, lbLast + 1);
- if (c.getCardinality() > 0) {
- ((MutableRoaringArray) answer.highLowContainer).append((short) hbLast, c);
- }
- }
- ((MutableRoaringArray) answer.highLowContainer).appendCopiesAfter(rb.highLowContainer,
- (short) hbLast);
- return answer;
- }
-
- /**
- * Generate a new bitmap with all integers in [rangeStart,rangeEnd) removed.
- *
- * @param rb initial bitmap (will not be modified)
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return new bitmap
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public static MutableRoaringBitmap remove(MutableRoaringBitmap rb,
- final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- return remove(rb, (long) rangeStart, (long) rangeEnd);
- }
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- return remove(rb, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
-
- /**
- * Bitwise XOR (symmetric difference) operation. The provided bitmaps are *not* modified. This
- * operation is thread-safe as long as the provided bitmaps remain unchanged.
- *
- * @param x1 first bitmap
- * @param x2 other bitmap
- * @return result of the operation
- */
- public static MutableRoaringBitmap xor(final MutableRoaringBitmap x1,
- final MutableRoaringBitmap x2) {
- final MutableRoaringBitmap answer = new MutableRoaringBitmap();
- int pos1 = 0, pos2 = 0;
- final int length1 = x1.highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- final MappeableContainer c = x1.highLowContainer.getContainerAtIndex(pos1)
- .xor(x2.highLowContainer.getContainerAtIndex(pos2));
- if (c.getCardinality() > 0) {
- answer.getMappeableRoaringArray().append(s1, c);
- }
- pos1++;
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer.getKeyAtIndex(pos1),
- x1.highLowContainer.getContainerAtIndex(pos1));
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = x1.highLowContainer.getKeyAtIndex(pos1);
- } else if (s1 > s2) {
- answer.getMappeableRoaringArray().appendCopy(x2.highLowContainer.getKeyAtIndex(pos2),
- x2.highLowContainer.getContainerAtIndex(pos2));
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- answer.getMappeableRoaringArray().appendCopy(x2.highLowContainer, pos2, length2);
- } else if (pos2 == length2) {
- answer.getMappeableRoaringArray().appendCopy(x1.highLowContainer, pos1, length1);
- }
-
- return answer;
- }
-
- /**
- * Assume that one wants to store "cardinality" integers in [0, universe_size),
- * this function returns an upper bound on the serialized size in bytes.
- *
- * This function is identical to RoaringBitmap.maximumSerializedSize.
- *
- * @param cardinality maximal cardinality
- * @param universe_size maximal value
- * @return upper bound on the serialized size in bytes of the bitmap
- */
- public static long maximumSerializedSize(int cardinality, int universe_size) {
- return RoaringBitmap.maximumSerializedSize(cardinality, universe_size);
- }
-
- /**
- * Set all the specified values to true. This can be expected to be slightly
- * faster than calling "add" repeatedly. The provided integers values don't
- * have to be in sorted order, but it may be preferable to sort them from a performance point of
- * view.
- *
- * @param dat set values
- */
- public void add(final int... dat) {
- MutableRoaringArray mra = (MutableRoaringArray) highLowContainer;
- MappeableContainer currentcont = null;
- short currenthb = 0;
- int currentcontainerindex = 0;
- int j = 0;
- if (j < dat.length) {
- int val = dat[j];
- currenthb = BufferUtil.highbits(val);
- currentcontainerindex = highLowContainer.getIndex(currenthb);
- if (currentcontainerindex >= 0) {
- currentcont = highLowContainer.getContainerAtIndex(currentcontainerindex);
- MappeableContainer newcont = currentcont.add(BufferUtil.lowbits(val));
- if (newcont != currentcont) {
- mra.setContainerAtIndex(currentcontainerindex, newcont);
- currentcont = newcont;
- }
- } else {
- currentcontainerindex = -currentcontainerindex - 1;
- final MappeableArrayContainer newac = new MappeableArrayContainer();
- currentcont = newac.add(BufferUtil.lowbits(val));
- mra.insertNewKeyValueAt(currentcontainerindex, currenthb, currentcont);
- }
- j++;
- }
- for (; j < dat.length; ++j) {
- int val = dat[j];
- short newhb = BufferUtil.highbits(val);
- if (currenthb == newhb) {// easy case
- // this could be quite frequent
- MappeableContainer newcont = currentcont.add(BufferUtil.lowbits(val));
- if (newcont != currentcont) {
- mra.setContainerAtIndex(currentcontainerindex, newcont);
- currentcont = newcont;
- }
- } else {
- currenthb = newhb;
- currentcontainerindex = highLowContainer.getIndex(currenthb);
- if (currentcontainerindex >= 0) {
- currentcont = highLowContainer.getContainerAtIndex(currentcontainerindex);
- MappeableContainer newcont = currentcont.add(BufferUtil.lowbits(val));
- if (newcont != currentcont) {
- mra.setContainerAtIndex(currentcontainerindex, newcont);
- currentcont = newcont;
- }
- } else {
- currentcontainerindex = -currentcontainerindex - 1;
- final MappeableArrayContainer newac = new MappeableArrayContainer();
- currentcont = newac.add(BufferUtil.lowbits(val));
- mra.insertNewKeyValueAt(currentcontainerindex, currenthb, currentcont);
- }
- }
- }
- }
-
- /**
- * Add the value to the container (set the value to "true"), whether it already appears or not.
- *
- * @param x integer value
- */
- @Override
- public void add(final int x) {
- final short hb = BufferUtil.highbits(x);
- final int i = highLowContainer.getIndex(hb);
- if (i >= 0) {
- getMappeableRoaringArray().setContainerAtIndex(i,
- highLowContainer.getContainerAtIndex(i).add(BufferUtil.lowbits(x)));
- } else {
- final MappeableArrayContainer newac = new MappeableArrayContainer();
- getMappeableRoaringArray().insertNewKeyValueAt(-i - 1, hb, newac.add(BufferUtil.lowbits(x)));
- }
- }
-
- /**
- * Add to the current bitmap all integers in [rangeStart,rangeEnd).
- *
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- */
- public void add(final long rangeStart, final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- return; // empty range
- }
-
- final int hbStart = BufferUtil.toIntUnsigned(BufferUtil.highbits(rangeStart));
- final int lbStart = BufferUtil.toIntUnsigned(BufferUtil.lowbits(rangeStart));
- final int hbLast = BufferUtil.toIntUnsigned(BufferUtil.highbits(rangeEnd - 1));
- final int lbLast = BufferUtil.toIntUnsigned(BufferUtil.lowbits(rangeEnd - 1));
- for (int hb = hbStart; hb <= hbLast; ++hb) {
-
- // first container may contain partial range
- final int containerStart = (hb == hbStart) ? lbStart : 0;
- // last container may contain partial range
- final int containerLast = (hb == hbLast) ? lbLast : BufferUtil.maxLowBitAsInteger();
- final int i = highLowContainer.getIndex((short) hb);
-
- if (i >= 0) {
- final MappeableContainer c =
- highLowContainer.getContainerAtIndex(i).iadd(containerStart, containerLast + 1);
- ((MutableRoaringArray) highLowContainer).setContainerAtIndex(i, c);
- } else {
- ((MutableRoaringArray) highLowContainer).insertNewKeyValueAt(-i - 1, (short) hb,
- MappeableContainer.rangeOfOnes(containerStart, containerLast + 1));
- }
- }
- }
-
- /**
- * Add to the current bitmap all integers in [rangeStart,rangeEnd).
- *
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public void add(final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- add((long) rangeStart, (long) rangeEnd);
- }
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- add(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
-
- /**
- * In-place bitwise AND (intersection) operation. The current bitmap is modified.
- *
- * @param array other bitmap
- */
- public void and(final ImmutableRoaringBitmap array) {
- int pos1 = 0, pos2 = 0, intersectionSize = 0;
- final int length1 = highLowContainer.size(), length2 = array.highLowContainer.size();
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = highLowContainer.getKeyAtIndex(pos1);
- final short s2 = array.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final MappeableContainer c1 = highLowContainer.getContainerAtIndex(pos1);
- final MappeableContainer c2 = array.highLowContainer.getContainerAtIndex(pos2);
- final MappeableContainer c = c1.iand(c2);
- if (c.getCardinality() > 0) {
- getMappeableRoaringArray().replaceKeyAndContainerAtIndex(intersectionSize++, s1, c);
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1 = highLowContainer.advanceUntil(s2, pos1);
- } else { // s1 > s2
- pos2 = array.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- getMappeableRoaringArray().resize(intersectionSize);
- }
-
- /**
- * In-place bitwise ANDNOT (difference) operation. The current bitmap is modified.
- *
- * @param x2 other bitmap
- */
- public void andNot(final ImmutableRoaringBitmap x2) {
- int pos1 = 0, pos2 = 0, intersectionSize = 0;
- final int length1 = highLowContainer.size(), length2 = x2.highLowContainer.size();
-
- while (pos1 < length1 && pos2 < length2) {
- final short s1 = highLowContainer.getKeyAtIndex(pos1);
- final short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- if (s1 == s2) {
- final MappeableContainer c1 = highLowContainer.getContainerAtIndex(pos1);
- final MappeableContainer c2 = x2.highLowContainer.getContainerAtIndex(pos2);
- final MappeableContainer c = c1.iandNot(c2);
- if (c.getCardinality() > 0) {
- getMappeableRoaringArray().replaceKeyAndContainerAtIndex(intersectionSize++, s1, c);
- }
- ++pos1;
- ++pos2;
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- if (pos1 != intersectionSize) {
- final MappeableContainer c1 = highLowContainer.getContainerAtIndex(pos1);
- getMappeableRoaringArray().replaceKeyAndContainerAtIndex(intersectionSize, s1, c1);
- }
- ++intersectionSize;
- ++pos1;
- } else { // s1 > s2
- pos2 = x2.highLowContainer.advanceUntil(s1, pos2);
- }
- }
- if (pos1 < length1) {
- getMappeableRoaringArray().copyRange(pos1, length1, intersectionSize);
- intersectionSize += length1 - pos1;
- }
- getMappeableRoaringArray().resize(intersectionSize);
- }
-
- /**
- * Add the value to the container (set the value to "true"), whether it already appears or not.
- *
- * @param x integer value
- * @return true if the added int wasn't already contained in the bitmap. False otherwise.
- */
- public boolean checkedAdd(final int x) {
- final short hb = BufferUtil.highbits(x);
- final int i = highLowContainer.getIndex(hb);
- if (i >= 0) {
- MappeableContainer C = highLowContainer.getContainerAtIndex(i);
- int oldcard = C.getCardinality();
- C = C.add(BufferUtil.lowbits(x));
- getMappeableRoaringArray().setContainerAtIndex(i, C);
- return C.getCardinality() > oldcard;
- } else {
- final MappeableArrayContainer newac = new MappeableArrayContainer();
- getMappeableRoaringArray().insertNewKeyValueAt(-i - 1, hb, newac.add(BufferUtil.lowbits(x)));
- return true;
- }
- }
-
- /**
- * If present remove the specified integer (effectively, sets its bit value to false)
- *
- * @param x integer value representing the index in a bitmap
- * @return true if the unset bit was already in the bitmap
- */
- public boolean checkedRemove(final int x) {
- final short hb = BufferUtil.highbits(x);
- final int i = highLowContainer.getIndex(hb);
- if (i < 0) {
- return false;
- }
- MappeableContainer C = highLowContainer.getContainerAtIndex(i);
- int oldcard = C.getCardinality();
- C.remove(BufferUtil.lowbits(x));
- int newcard = C.getCardinality();
- if (newcard == oldcard) {
- return false;
- }
- if (newcard > 0) {
- ((MutableRoaringArray) highLowContainer).setContainerAtIndex(i, C);
- } else {
- ((MutableRoaringArray) highLowContainer).removeAtIndex(i);
- }
- return true;
- }
-
- /**
- * reset to an empty bitmap; result occupies as much space a newly created bitmap.
- */
- public void clear() {
- highLowContainer = new MutableRoaringArray(); // lose references
- }
-
- @Override
- public MutableRoaringBitmap clone() {
- final MutableRoaringBitmap x = (MutableRoaringBitmap) super.clone();
- x.highLowContainer = highLowContainer.clone();
- return x;
-
- }
-
- /**
- * Deserialize the bitmap (retrieve from the input stream). The current bitmap is overwritten.
- *
- * @param in the DataInput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- public void deserialize(DataInput in) throws IOException {
- getMappeableRoaringArray().deserialize(in);
- }
-
- /**
- * Add the value if it is not already present, otherwise remove it.
- *
- * @param x integer value
- */
- public void flip(final int x) {
- final short hb = BufferUtil.highbits(x);
- final int i = highLowContainer.getIndex(hb);
- if (i >= 0) {
- MappeableContainer c = highLowContainer.getContainerAtIndex(i);
- c = c.flip(BufferUtil.lowbits(x));
- if (c.getCardinality() > 0) {
- ((MutableRoaringArray) highLowContainer).setContainerAtIndex(i, c);
- } else {
- ((MutableRoaringArray) highLowContainer).removeAtIndex(i);
- }
- } else {
- final MappeableArrayContainer newac = new MappeableArrayContainer();
- ((MutableRoaringArray) highLowContainer).insertNewKeyValueAt(-i - 1, hb,
- newac.add(BufferUtil.lowbits(x)));
- }
- }
-
- /**
- * Modifies the current bitmap by complementing the bits in the given range, from rangeStart
- * (inclusive) rangeEnd (exclusive).
- *
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- */
- public void flip(final long rangeStart, final long rangeEnd) {
- rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- return; // empty range
- }
-
- final int hbStart = BufferUtil.toIntUnsigned(BufferUtil.highbits(rangeStart));
- final int lbStart = BufferUtil.toIntUnsigned(BufferUtil.lowbits(rangeStart));
- final int hbLast = BufferUtil.toIntUnsigned(BufferUtil.highbits(rangeEnd - 1));
- final int lbLast = BufferUtil.toIntUnsigned(BufferUtil.lowbits(rangeEnd - 1));
-
- for (int hb = hbStart; hb <= hbLast; ++hb) {
- // first container may contain partial range
- final int containerStart = (hb == hbStart) ? lbStart : 0;
- // last container may contain partial range
- final int containerLast = (hb == hbLast) ? lbLast : BufferUtil.maxLowBitAsInteger();
- final int i = highLowContainer.getIndex((short) hb);
-
- if (i >= 0) {
- final MappeableContainer c =
- highLowContainer.getContainerAtIndex(i).inot(containerStart, containerLast + 1);
- if (c.getCardinality() > 0) {
- getMappeableRoaringArray().setContainerAtIndex(i, c);
- } else {
- getMappeableRoaringArray().removeAtIndex(i);
- }
- } else {
- getMappeableRoaringArray().insertNewKeyValueAt(-i - 1, (short) hb,
- MappeableContainer.rangeOfOnes(containerStart, containerLast + 1));
- }
- }
- }
-
- /**
- * Modifies the current bitmap by complementing the bits in the given range, from rangeStart
- * (inclusive) rangeEnd (exclusive).
- *
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public void flip(final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- flip((long) rangeStart, (long) rangeEnd);
- } else {
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- flip(rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
- }
-
- /**
- * @return a mutable copy of this bitmap
- */
- public MutableRoaringArray getMappeableRoaringArray() {
- return (MutableRoaringArray) highLowContainer;
- }
-
- @Override
- public int hashCode() {
- return highLowContainer.hashCode();
- }
-
- /**
- * iterate over the positions of the true values.
- *
- * @return the iterator
- */
- @Override
- public Iterator
- *
- * This function is equivalent to :
- *
- *
- * The current bitmap is not modified.
- *
- * @param out the DataOutput stream
- * @throws IOException Signals that an I/O exception has occurred.
- */
- public void serialize(DataOutput out) throws IOException;
-
- /**
- * @return the size that the data structure occupies on disk
- */
- public int serializedSizeInBytes();
-
-
- /**
- * @return number of keys
- */
- int size();
-}
- * {@code
- * bitmap.forEach(new IntConsumer() {
- *
- * {@literal @}Override
- * public void accept(int value) {
- * // do something here
- *
- * }});
- * }
- * }
- *
- *
- * @param ic the consumer
- */
- public void forEach(IntConsumer ic);
-
- /**
- * For better performance, consider the Use the {@link #forEach forEach} method.
- *
- * @return a custom iterator over set bits, the bits are traversed in ascending sorted order
- */
- public PeekableIntIterator getIntIterator();
-
- /**
- * @return a custom iterator over set bits, the bits are traversed in descending sorted order
- */
- public IntIterator getReverseIntIterator();
-
- /**
- * Estimate of the memory usage of this data structure.
- *
- * {@code
- * bitmap.forEach(new IntConsumer() {
- *
- * @Override
- * public void accept(int value) {
- * // do something here
- *
- * }});
- * }
- * }
- *
- */
-public interface IntConsumer {
- /**
- * Receives the integer
- *
- * @param value the integer value
- */
- void accept(int value);
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntIterator.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntIterator.java
deleted file mode 100644
index ef86f6611..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntIterator.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap;
-
-/**
- * A simple iterator over integer values
- */
-public interface IntIterator extends Cloneable {
- /**
- * Creates a copy of the iterator.
- *
- * @return a clone of the current iterator
- */
- IntIterator clone();
-
- /**
- * @return whether there is another value
- */
- boolean hasNext();
-
- /**
- * @return next integer value
- */
- int next();
-
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntIteratorFlyweight.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntIteratorFlyweight.java
deleted file mode 100644
index 36a91b168..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/IntIteratorFlyweight.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap;
-
-/**
- * Fast iterator minimizing the stress on the garbage collector. You can create one reusable
- * instance of this class and then {@link #wrap(RoaringBitmap)}
- *
- * {@code
- * import com.fr.swift.bitmap.roaringbitmap.*;
- *
- * //...
- *
- * RoaringBitmap rr = RoaringBitmap.bitmapOf(1,2,3,1000);
- * RoaringBitmap rr2 = new RoaringBitmap();
- * for(int k = 4000; k<4255;++k) rr2.add(k);
- * RoaringBitmap rror = RoaringBitmap.or(rr, rr2);
- *
- * //...
- * DataOutputStream wheretoserialize = ...
- * rr.runOptimize(); // can help compression
- * rr.serialize(wheretoserialize);
- * }
- *
- *
- * {@code
- * //r is your bitmap
- *
- * r.runOptimize(); // might improve compression
- * // next we create the ByteBuffer where the data will be stored
- * ByteBuffer outbb = ByteBuffer.allocate(r.serializedSizeInBytes());
- * // then we can serialize on a custom OutputStream
- * mrb.serialize(new DataOutputStream(new OutputStream(){
- * ByteBuffer mBB;
- * OutputStream init(ByteBuffer mbb) {mBB=mbb; return this;}
- * public void close() {}
- * public void flush() {}
- * public void write(int b) {
- * mBB.put((byte) b);}
- * public void write(byte[] b) {mBB.put(b);}
- * public void write(byte[] b, int off, int l) {mBB.put(b,off,l);}
- * }.init(outbb)));
- * // outbuff will now contain a serialized version of your bitmap
- * }
- *
- *
- * {@code
- * import com.fr.swift.bitmap.roaringbitmap.buffer.*;
- *
- * //...
- *
- * MutableRoaringBitmap rr1 = MutableRoaringBitmap.bitmapOf(1, 2, 3, 1000);
- * MutableRoaringBitmap rr2 = MutableRoaringBitmap.bitmapOf( 2, 3, 1010);
- * ByteArrayOutputStream bos = new ByteArrayOutputStream();
- * DataOutputStream dos = new DataOutputStream(bos);
- * // could call "rr1.runOptimize()" and "rr2.runOptimize" if there
- * // there were runs to compress
- * rr1.serialize(dos);
- * rr2.serialize(dos);
- * dos.close();
- * ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
- * ImmutableRoaringBitmap rrback1 = new ImmutableRoaringBitmap(bb);
- * bb.position(bb.position() + rrback1.serializedSizeInBytes());
- * ImmutableRoaringBitmap rrback2 = new ImmutableRoaringBitmap(bb);
- * }
- *
- *
- * {@code
- * (ImmutableRoaringBitmap) MutableRoaringBitmap.bitmapOf(data)
- * }
- *
- *
- * @param data set values
- * @return a new bitmap
- */
- public static ImmutableRoaringBitmap bitmapOf(final int... data) {
- return MutableRoaringBitmap.bitmapOf(data);
- }
-
- /**
- * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The
- * given bitmap is unchanged.
- *
- * @param bm bitmap being negated
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return a new Bitmap
- */
- public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm, final long rangeStart,
- final long rangeEnd) {
- MutableRoaringBitmap.rangeSanityCheck(rangeStart, rangeEnd);
- if (rangeStart >= rangeEnd) {
- throw new RuntimeException("Invalid range " + rangeStart + " -- " + rangeEnd);
- }
-
- MutableRoaringBitmap answer = new MutableRoaringBitmap();
- final short hbStart = BufferUtil.highbits(rangeStart);
- final short lbStart = BufferUtil.lowbits(rangeStart);
- final short hbLast = BufferUtil.highbits(rangeEnd - 1);
- final short lbLast = BufferUtil.lowbits(rangeEnd - 1);
-
- // copy the containers before the active area
- answer.getMappeableRoaringArray().appendCopiesUntil(bm.highLowContainer, hbStart);
-
- final int max = BufferUtil.toIntUnsigned(BufferUtil.maxLowBit());
- for (short hb = hbStart; hb <= hbLast; ++hb) {
- final int containerStart = (hb == hbStart) ? BufferUtil.toIntUnsigned(lbStart) : 0;
- final int containerLast = (hb == hbLast) ? BufferUtil.toIntUnsigned(lbLast) : max;
-
- final int i = bm.highLowContainer.getIndex(hb);
- final int j = answer.getMappeableRoaringArray().getIndex(hb);
- assert j < 0;
-
- if (i >= 0) {
- final MappeableContainer c =
- bm.highLowContainer.getContainerAtIndex(i).not(containerStart, containerLast + 1);
- if (c.getCardinality() > 0) {
- answer.getMappeableRoaringArray().insertNewKeyValueAt(-j - 1, hb, c);
- }
-
- } else { // *think* the range of ones must never be
- // empty.
- answer.getMappeableRoaringArray().insertNewKeyValueAt(-j - 1, hb,
- MappeableContainer.rangeOfOnes(containerStart, containerLast + 1));
- }
- }
- // copy the containers after the active area.
- answer.getMappeableRoaringArray().appendCopiesAfter(bm.highLowContainer, hbLast);
-
- return answer;
- }
-
- /**
- * Complements the bits in the given range, from rangeStart (inclusive) rangeEnd (exclusive). The
- * given bitmap is unchanged.
- *
- * @param bm bitmap being negated
- * @param rangeStart inclusive beginning of range
- * @param rangeEnd exclusive ending of range
- * @return a new Bitmap
- * @deprecated use the version where longs specify the range
- */
- @Deprecated
- public static MutableRoaringBitmap flip(ImmutableRoaringBitmap bm,
- final int rangeStart, final int rangeEnd) {
- if (rangeStart >= 0) {
- return flip(bm, (long) rangeStart, (long) rangeEnd);
- }
- // rangeStart being -ve and rangeEnd being positive is not expected)
- // so assume both -ve
- return flip(bm, rangeStart & 0xFFFFFFFFL, rangeEnd & 0xFFFFFFFFL);
- }
-
- /**
- * Return new iterator with only values from rangeStart (inclusive) to rangeEnd (exclusive)
- *
- * @param input bitmaps iterator
- * @param rangeStart inclusive
- * @param rangeEnd exclusive
- * @return new iterator of bitmaps
- */
- private static Iterator
- * {
- * @code
- * // r is your bitmap
- *
- * // r.runOptimize(); // might improve compression, only if you have a
- * // MutableRoaringBitmap instance.
- * // next we create the ByteBuffer where the data will be stored
- * ByteBuffer outbb = ByteBuffer.allocate(r.serializedSizeInBytes());
- * // then we can serialize on a custom OutputStream
- * mrb.serialize(new DataOutputStream(new OutputStream() {
- * ByteBuffer mBB;
- *
- * OutputStream init(ByteBuffer mbb) {
- * mBB = mbb;
- * return this;
- * }
- *
- * public void close() {}
- *
- * public void flush() {}
- *
- * public void write(int b) {
- * mBB.put((byte) b);
- * }
- *
- * public void write(byte[] b) {
- * mBB.put(b);
- * }
- *
- * public void write(byte[] b, int off, int l) {
- * mBB.put(b, off, l);
- * }
- * }.init(outbb)));
- * // outbuff will now contain a serialized version of your bitmap
- * }
- *
- *
- * {@code
- * import com.fr.swift.bitmap.roaringbitmap.buffer.*;
- *
- * //...
- *
- * MutableRoaringBitmap rr = MutableRoaringBitmap.bitmapOf(1,2,3,1000);
- * MutableRoaringBitmap rr2 = new MutableRoaringBitmap();
- * for(int k = 4000; k<4255;++k) rr2.add(k);
- *
- * RoaringBitmap rror = RoaringBitmap.or(rr, rr2);
- *
- * //...
- * DataOutputStream wheretoserialize = ...
- * rr.runOptimize(); // can help compression
- * rr.serialize(wheretoserialize);
- * }
- *
- *
- * @see ImmutableRoaringBitmap
- * @see RoaringBitmap
- */
-public class MutableRoaringBitmap extends ImmutableRoaringBitmap
- implements Cloneable, Serializable, Iterable
- * {@code
- * (ImmutableRoaringBitmap) bitmap
- * }
- *
- *
- * @return a cast of this object
- */
- public ImmutableRoaringBitmap toImmutableRoaringBitmap() {
- return this;
-
- }
-
- /**
- * Recover allocated but unused memory.
- */
- @Override
- public void trim() {
- for (int i = 0; i < this.highLowContainer.size(); i++) {
- this.highLowContainer.getContainerAtIndex(i).trim();
- }
- }
-
- @Override
- public void writeExternal(ObjectOutput out) throws IOException {
- getMappeableRoaringArray().writeExternal(out);
- }
-
- /**
- * In-place bitwise XOR (symmetric difference) operation. The current bitmap is modified.
- *
- * @param x2 other bitmap
- */
- public void xor(final ImmutableRoaringBitmap x2) {
- int pos1 = 0, pos2 = 0;
- int length1 = highLowContainer.size();
- final int length2 = x2.highLowContainer.size();
-
- main:
- if (pos1 < length1 && pos2 < length2) {
- short s1 = highLowContainer.getKeyAtIndex(pos1);
- short s2 = x2.highLowContainer.getKeyAtIndex(pos2);
-
- while (true) {
- if (s1 == s2) {
- final MappeableContainer c = highLowContainer.getContainerAtIndex(pos1)
- .ixor(x2.highLowContainer.getContainerAtIndex(pos2));
- if (c.getCardinality() > 0) {
- this.getMappeableRoaringArray().setContainerAtIndex(pos1, c);
- pos1++;
- } else {
- getMappeableRoaringArray().removeAtIndex(pos1);
- --length1;
- }
- pos2++;
- if ((pos1 == length1) || (pos2 == length2)) {
- break main;
- }
- s1 = highLowContainer.getKeyAtIndex(pos1);
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- } else if (Util.compareUnsigned(s1, s2) < 0) { // s1 < s2
- pos1++;
- if (pos1 == length1) {
- break main;
- }
- s1 = highLowContainer.getKeyAtIndex(pos1);
- } else { // s1 > s2
- getMappeableRoaringArray().insertNewKeyValueAt(pos1, s2,
- x2.highLowContainer.getContainerAtIndex(pos2).clone());
- pos1++;
- length1++;
- pos2++;
- if (pos2 == length2) {
- break main;
- }
- s2 = x2.highLowContainer.getKeyAtIndex(pos2);
- }
- }
- }
- if (pos1 == length1) {
- getMappeableRoaringArray().appendCopy(x2.highLowContainer, pos2, length2);
- }
- }
-
-
-}
diff --git a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/PointableRoaringArray.java b/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/PointableRoaringArray.java
deleted file mode 100644
index c9cd8fa7d..000000000
--- a/fine-roaringbitmap/src/main/java/com/fr/third/bitmap/roaringbitmap/buffer/PointableRoaringArray.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * (c) the authors Licensed under the Apache License, Version 2.0.
- */
-
-package com.fr.third.bitmap.roaringbitmap.buffer;
-
-import java.io.DataOutput;
-import java.io.IOException;
-
-/**
- * Generic interface for the array underlying roaring bitmap classes.
- */
-public interface PointableRoaringArray extends Cloneable {
- /**
- * Find the smallest integer index larger than pos such that getKeyAtIndex(index)>=x. If none
- * can be found, return size.
- *
- * @param x minimal value
- * @param pos index to exceed
- * @return the smallest index greater than pos such that getKeyAtIndex(index) is at least as large
- * as min, or size if it is not possible.
- */
- int advanceUntil(short x, int pos);
-
- /**
- * Create an independent copy of the underlying array
- *
- * @return a copy
- */
- PointableRoaringArray clone();
-
- /**
- * Returns the cardinality of the container at the given index. This method is expected to be
- * fast.
- *
- * @param i index
- * @return the cardinality
- */
- public int getCardinality(int i);
-
- /**
- * @param x 16-bit key
- * @return matching container
- */
- MappeableContainer getContainer(short x);
-
- /**
- * @param i index
- * @return matching container
- */
- MappeableContainer getContainerAtIndex(int i);
-
- /**
- * @return a ContainerPointer to iterator over the array
- */
- MappeableContainerPointer getContainerPointer();
-
- /**
- * @param startIndex starting index
- * @return a ContainerPointer to iterator over the array initially positioned at startIndex
- */
- MappeableContainerPointer getContainerPointer(int startIndex);
-
- /**
- * @param x 16-bit key
- * @return corresponding index
- */
- int getIndex(short x);
-
- /**
- * @param i the index
- * @return 16-bit key at the index
- */
- short getKeyAtIndex(int i);
-
- /**
- * Check whether this bitmap has had its runs compressed.
- *
- * @return whether this bitmap has run compression
- */
- public boolean hasRunCompression();
-
- /**
- * Serialize.
- *