org.roaringbitmap.buffer.BufferUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of RoaringBitmap Show documentation
Show all versions of RoaringBitmap Show documentation
Roaring bitmaps are compressed bitmaps (also called bitsets) which tend to outperform
conventional compressed bitmaps such as WAH or Concise.
/*
* (c) the authors Licensed under the Apache License, Version 2.0.
*/
package org.roaringbitmap.buffer;
import org.roaringbitmap.Util;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.LongBuffer;
import java.util.Arrays;
import static java.lang.Long.numberOfTrailingZeros;
/**
* Various useful methods for roaring bitmaps.
*
* This class is similar to org.roaringbitmap.Util but meant to be used with memory mapping.
*/
public final class BufferUtil {
/**
* Add value "offset" to all values in the container, producing
* two new containers. The existing container remains unchanged.
* The new container are not converted, so they need to be checked:
* e.g., we could produce two bitmap containers having low cardinality.
* @param source source container
* @param offsets value to add to each value in the container
* @return return an array made of two containers
*/
public static MappeableContainer[] addOffset(MappeableContainer source, char offsets) {
// could be a whole lot faster, this is a simple implementation
if(source instanceof MappeableArrayContainer) {
MappeableArrayContainer c = (MappeableArrayContainer) source;
MappeableArrayContainer low = new MappeableArrayContainer(c.cardinality);
MappeableArrayContainer high = new MappeableArrayContainer(c.cardinality);
for(int k = 0; k < c.cardinality; k++) {
int val = (c.content.get(k));
val += (int) (offsets);
if(val <= 0xFFFF) {
low.content.put(low.cardinality++, (char) val);
} else {
high.content.put(high.cardinality++, (char) val);
}
}
return new MappeableContainer[] {low, high};
} else if (source instanceof MappeableBitmapContainer) {
MappeableBitmapContainer c = (MappeableBitmapContainer) source;
MappeableBitmapContainer low = new MappeableBitmapContainer();
MappeableBitmapContainer high = new MappeableBitmapContainer();
low.cardinality = -1;
high.cardinality = -1;
final int b = (int) (offsets) >>> 6;
final int i = (int) (offsets) % 64;
if(i == 0) {
for(int k = 0; k < 1024 - b; k++) {
low.bitmap.put(b + k, c.bitmap.get(k));
}
for(int k = 1024 - b; k < 1024 ; k++) {
high.bitmap.put(k - (1024 - b),c.bitmap.get(k));
}
} else {
low.bitmap.put(b + 0, c.bitmap.get(0) << i);
for(int k = 1; k < 1024 - b; k++) {
low.bitmap.put(b + k, (c.bitmap.get(k) << i)
| (c.bitmap.get(k - 1) >>> (64-i)));
}
for(int k = 1024 - b; k < 1024 ; k++) {
high.bitmap.put(k - (1024 - b),
(c.bitmap.get(k) << i)
| (c.bitmap.get(k - 1) >>> (64-i)));
}
high.bitmap.put(b, (c.bitmap.get(1024 - 1) >>> (64-i)));
}
return new MappeableContainer[] {low.repairAfterLazy(), high.repairAfterLazy()};
} else if (source instanceof MappeableRunContainer) {
MappeableRunContainer c = (MappeableRunContainer) source;
MappeableRunContainer low = new MappeableRunContainer();
MappeableRunContainer high = new MappeableRunContainer();
for(int k = 0 ; k < c.nbrruns; k++) {
int val = (c.getValue(k));
val += (int) (offsets);
int finalval = val + (c.getLength(k));
if(val <= 0xFFFF) {
if(finalval <= 0xFFFF) {
low.smartAppend((char)val,c.getLength(k));
} else {
low.smartAppend((char)val,(char)(0xFFFF-val));
high.smartAppend((char) 0,(char)finalval);
}
} else {
high.smartAppend((char)val,c.getLength(k));
}
}
return new MappeableContainer[] {low, high};
}
throw new RuntimeException("unknown container type"); // never happens
}
/**
* 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(CharBuffer array, int pos, int length, char min) {
int lower = pos + 1;
// special handling for a possibly common sequential case
if (lower >= length || (array.get(lower)) >= (min)) {
return lower;
}
int spansize = 1; // could set larger
// bootstrap an upper limit
while (lower + spansize < length
&& (array.get(lower + spansize)) < (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 ((array.get(upper)) < (min)) {// means
// array
// has no
// item
// >= min
// pos = array.length;
return length;
}
// we know that the next-smallest span was too small
lower += (spansize >>> 1);
// else begin binary search
// invariant: array[lower]min
while (lower + 1 != upper) {
int mid = (lower + upper) >>> 1;
char arraymid = array.get(mid);
if (arraymid == min) {
return mid;
} else if ((arraymid) < (min)) {
lower = mid;
} else {
upper = mid;
}
}
return upper;
}
/**
* Find the smallest integer larger than pos such that array[pos]>= min. If none can be found,
* return length.
*
* @param array array to search within
* @param pos starting position of the search
* @param length length of the array to search
* @param min minimum value
* @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.
*/
public static int iterateUntil(CharBuffer array, int pos, int length, int min) {
while (pos < length && (array.get(pos)) < min) {
pos++;
}
return pos;
}
protected static void arraycopy(CharBuffer src, int srcPos, CharBuffer dest, int destPos,
int length) {
if (BufferUtil.isBackedBySimpleArray(src) && BufferUtil.isBackedBySimpleArray(dest)) {
System.arraycopy(src.array(), srcPos, dest.array(), destPos, length);
} else {
if (srcPos < destPos) {
for (int k = length - 1; k >= 0; --k) {
dest.put(destPos + k, src.get(k + srcPos));
}
} else {
for (int k = 0; k < length; ++k) {
dest.put(destPos + k, src.get(k + srcPos));
}
}
}
}
protected static int branchyUnsignedBinarySearch(final CharBuffer array, final int begin,
final int end, final char k) {
// next line accelerates the possibly common case where the value would be inserted at the end
if ((end > 0) && ((array.get(end - 1)) < (int) (k))) {
return -end - 1;
}
int low = begin;
int high = end - 1;
while (low <= high) {
final int middleIndex = (low + high) >>> 1;
final int middleValue = (array.get(middleIndex));
if (middleValue < (int) (k)) {
low = middleIndex + 1;
} else if (middleValue > (int) (k)) {
high = middleIndex - 1;
} else {
return middleIndex;
}
}
return -(low + 1);
}
protected static int branchyUnsignedBinarySearch(final ByteBuffer array, int position,
final int begin, final int end, final char k) {
// next line accelerates the possibly common case where the value would be inserted at the end
if ((end > 0) && ((array.getChar(position + (end - 1)*2)) < (int) (k))) {
return -end - 1;
}
int low = begin;
int high = end - 1;
while (low <= high) {
final int middleIndex = (low + high) >>> 1;
final int middleValue = (array.getChar(position + 2* middleIndex));
if (middleValue < (int) (k)) {
low = middleIndex + 1;
} else if (middleValue > (int) (k)) {
high = middleIndex - 1;
} else {
return middleIndex;
}
}
return -(low + 1);
}
protected static void fillArrayAND(char[] container, LongBuffer bitmap1, LongBuffer bitmap2) {
int pos = 0;
if (bitmap1.limit() != bitmap2.limit()) {
throw new IllegalArgumentException("not supported");
}
if (BufferUtil.isBackedBySimpleArray(bitmap1) && BufferUtil.isBackedBySimpleArray(bitmap2)) {
int len = bitmap1.limit();
long[] b1 = bitmap1.array();
long[] b2 = bitmap2.array();
for (int k = 0; k < len; ++k) {
long bitset = b1[k] & b2[k];
while (bitset != 0) {
container[pos++] = (char) (k * 64 + numberOfTrailingZeros(bitset));
bitset &= (bitset - 1);
}
}
} else {
int len = bitmap1.limit();
for (int k = 0; k < len; ++k) {
long bitset = bitmap1.get(k) & bitmap2.get(k);
while (bitset != 0) {
container[pos++] = (char) (k * 64 + numberOfTrailingZeros(bitset));
bitset &= (bitset - 1);
}
}
}
}
protected static void fillArrayANDNOT(char[] container, LongBuffer bitmap1, LongBuffer bitmap2) {
int pos = 0;
if (bitmap1.limit() != bitmap2.limit()) {
throw new IllegalArgumentException("not supported");
}
if (BufferUtil.isBackedBySimpleArray(bitmap1) && BufferUtil.isBackedBySimpleArray(bitmap2)) {
int len = bitmap1.limit();
long[] b1 = bitmap1.array();
long[] b2 = bitmap2.array();
for (int k = 0; k < len; ++k) {
long bitset = b1[k] & (~b2[k]);
while (bitset != 0) {
container[pos++] = (char) (k * 64 + numberOfTrailingZeros(bitset));
bitset &= (bitset - 1);
}
}
} else {
int len = bitmap1.limit();
for (int k = 0; k < len; ++k) {
long bitset = bitmap1.get(k) & (~bitmap2.get(k));
while (bitset != 0) {
container[pos++] = (char) (k * 64 + numberOfTrailingZeros(bitset));
bitset &= (bitset - 1);
}
}
}
}
protected static void fillArrayXOR(char[] container, LongBuffer bitmap1, LongBuffer bitmap2) {
int pos = 0;
if (bitmap1.limit() != bitmap2.limit()) {
throw new IllegalArgumentException("not supported");
}
if (BufferUtil.isBackedBySimpleArray(bitmap1) && BufferUtil.isBackedBySimpleArray(bitmap2)) {
org.roaringbitmap.Util.fillArrayXOR(container, bitmap1.array(), bitmap2.array());
} else {
int len = bitmap1.limit();
for (int k = 0; k < len; ++k) {
long bitset = bitmap1.get(k) ^ bitmap2.get(k);
while (bitset != 0) {
container[pos++] = (char) (k * 64 + numberOfTrailingZeros(bitset));
bitset &= (bitset - 1);
}
}
}
}
/**
* flip bits at start, start+1,..., end-1
*
* @param bitmap array of words to be modified
* @param start first index to be modified (inclusive)
* @param end last index to be modified (exclusive)
*/
public static void flipBitmapRange(LongBuffer bitmap, int start, int end) {
if (isBackedBySimpleArray(bitmap)) {
Util.flipBitmapRange(bitmap.array(), start, end);
return;
}
if (start == end) {
return;
}
int firstword = start / 64;
int endword = (end - 1) / 64;
bitmap.put(firstword, bitmap.get(firstword) ^ ~(~0L << start));
for (int i = firstword; i < endword; i++) {
bitmap.put(i, ~bitmap.get(i));
}
bitmap.put(endword, bitmap.get(endword) ^ (~0L >>> -end));
}
/**
* Hamming weight of the 64-bit words involved in the range start, start+1,..., end-1
* that is, it will compute the cardinality of the bitset from index
* (floor(start/64) to floor((end-1)/64)) inclusively.
*
* @param bitmap array of words representing a bitset
* @param start first index (inclusive)
* @param end last index (exclusive)
* @return the hamming weight of the corresponding words
*/
@Deprecated
private static int cardinalityInBitmapWordRange(LongBuffer bitmap, int start, int end) {
if (isBackedBySimpleArray(bitmap)) {
return Util.cardinalityInBitmapWordRange(bitmap.array(), start, end);
}
if (start >= end) {
return 0;
}
int firstword = start / 64;
int endword = (end - 1) / 64;
int answer = 0;
for (int i = firstword; i <= endword; i++) {
answer += Long.bitCount(bitmap.get(i));
}
return answer;
}
/**
* Hamming weight of the bitset in the range
* start, start+1,..., end-1
*
* @param bitmap array of words representing a bitset
* @param start first index (inclusive)
* @param end last index (exclusive)
* @return the hamming weight of the corresponding range
*/
public static int cardinalityInBitmapRange(LongBuffer bitmap, int start, int end) {
if (isBackedBySimpleArray(bitmap)) {
return Util.cardinalityInBitmapRange(bitmap.array(), start, end);
}
if (start >= end) {
return 0;
}
int firstword = start / 64;
int endword = (end - 1) / 64;
if (firstword == endword) {
return Long.bitCount(bitmap.get(firstword) & ((~0L << start) & (~0L >>> -end)));
}
int answer = Long.bitCount(bitmap.get(firstword) & (~0L << start));
for (int i = firstword + 1; i < endword; i++) {
answer += Long.bitCount(bitmap.get(i));
}
answer += Long.bitCount(bitmap.get(endword) & (~0L >>> -end));
return answer;
}
/**
* set bits at start, start+1,..., end-1 and report the cardinality change
*
* @param bitmap array of words to be modified
* @param start first index to be modified (inclusive)
* @param end last index to be modified (exclusive)
* @return cardinality change
*/
@Deprecated
public static int setBitmapRangeAndCardinalityChange(LongBuffer bitmap, int start, int end) {
if (BufferUtil.isBackedBySimpleArray(bitmap)) {
return Util.setBitmapRangeAndCardinalityChange(bitmap.array(), start, end);
}
int cardbefore = cardinalityInBitmapWordRange(bitmap, start, end);
setBitmapRange(bitmap, start, end);
int cardafter = cardinalityInBitmapWordRange(bitmap, start, end);
return cardafter - cardbefore;
}
/**
* flip bits at start, start+1,..., end-1 and report the cardinality change
*
* @param bitmap array of words to be modified
* @param start first index to be modified (inclusive)
* @param end last index to be modified (exclusive)
* @return cardinality change
*/
@Deprecated
public static int flipBitmapRangeAndCardinalityChange(LongBuffer bitmap, int start, int end) {
if (BufferUtil.isBackedBySimpleArray(bitmap)) {
return Util.flipBitmapRangeAndCardinalityChange(bitmap.array(), start, end);
}
int cardbefore = cardinalityInBitmapWordRange(bitmap, start, end);
flipBitmapRange(bitmap, start, end);
int cardafter = cardinalityInBitmapWordRange(bitmap, start, end);
return cardafter - cardbefore;
}
/**
* reset bits at start, start+1,..., end-1 and report the cardinality change
*
* @param bitmap array of words to be modified
* @param start first index to be modified (inclusive)
* @param end last index to be modified (exclusive)
* @return cardinality change
*/
@Deprecated
public static int resetBitmapRangeAndCardinalityChange(LongBuffer bitmap, int start, int end) {
if (BufferUtil.isBackedBySimpleArray(bitmap)) {
return Util.resetBitmapRangeAndCardinalityChange(bitmap.array(), start, end);
}
int cardbefore = cardinalityInBitmapWordRange(bitmap, start, end);
resetBitmapRange(bitmap, start, end);
int cardafter = cardinalityInBitmapWordRange(bitmap, start, end);
return cardafter - cardbefore;
}
/**
* From the cardinality of a container, compute the corresponding size in bytes of the container.
* Additional information is required if the container is run encoded.
*
* @param card the cardinality if this is not run encoded, otherwise ignored
* @param numRuns number of runs if run encoded, othewise ignored
* @param isRunEncoded boolean
*
* @return the size in bytes
*/
protected static int getSizeInBytesFromCardinalityEtc(int card, int numRuns,
boolean isRunEncoded) {
if (isRunEncoded) {
return 2 + numRuns * 2 * 2; // each run uses 2 chars, plus the initial char giving num runs
}
boolean isBitmap = card > MappeableArrayContainer.DEFAULT_MAX_SIZE;
if (isBitmap) {
return MappeableBitmapContainer.MAX_CAPACITY / 8;
} else {
return card * 2;
}
}
protected static char highbits(int x) {
return (char) (x >>> 16);
}
protected static char highbits(long x) {
return (char) (x >>> 16);
}
/**
* Checks whether the Buffer is backed by a simple array. In java, a Buffer is an abstraction that
* can represent various data, from data on disk all the way to native Java arrays. Like all
* abstractions, a Buffer might carry a performance penalty. Thus, we sometimes check whether the
* Buffer is simply a wrapper around a Java array. In these instances, it might be best, from a
* performance point of view, to access the underlying array (using the array()) method.
* @param b the provided Buffer
* @return whether the Buffer is backed by a simple array
*/
protected static boolean isBackedBySimpleArray(Buffer b) {
return b.hasArray() && (b.arrayOffset() == 0);
}
protected static char lowbits(int x) {
return (char) x;
}
protected static char lowbits(long x) {
return (char) x;
}
protected static int lowbitsAsInteger(long x) {
return (int)(x & 0xFFFF);
}
protected static char maxLowBit() {
return (char) 0xFFFF;
}
protected static int maxLowBitAsInteger() {
return 0xFFFF;
}
/**
* clear bits at start, start+1,..., end-1
*
* @param bitmap array of words to be modified
* @param start first index to be modified (inclusive)
* @param end last index to be modified (exclusive)
*/
public static void resetBitmapRange(LongBuffer bitmap, int start, int end) {
if (isBackedBySimpleArray(bitmap)) {
Util.resetBitmapRange(bitmap.array(), start, end);
return;
}
if (start == end) {
return;
}
int firstword = start / 64;
int endword = (end - 1) / 64;
if (firstword == endword) {
bitmap.put(firstword, bitmap.get(firstword) & ~((~0L << start) & (~0L >>> -end)));
return;
}
bitmap.put(firstword, bitmap.get(firstword) & (~(~0L << start)));
for (int i = firstword + 1; i < endword; i++) {
bitmap.put(i, 0L);
}
bitmap.put(endword, bitmap.get(endword) & (~(~0L >>> -end)));
}
/**
* set bits at start, start+1,..., end-1
*
* @param bitmap array of words to be modified
* @param start first index to be modified (inclusive)
* @param end last index to be modified (exclusive)
*/
public static void setBitmapRange(LongBuffer bitmap, int start, int end) {
if (isBackedBySimpleArray(bitmap)) {
Util.setBitmapRange(bitmap.array(), start, end);
return;
}
if (start == end) {
return;
}
int firstword = start / 64;
int endword = (end - 1) / 64;
if (firstword == endword) {
bitmap.put(firstword, bitmap.get(firstword) | ((~0L << start) & (~0L >>> -end)));
return;
}
bitmap.put(firstword, bitmap.get(firstword) | (~0L << start));
for (int i = firstword + 1; i < endword; i++) {
bitmap.put(i, ~0L);
}
bitmap.put(endword, bitmap.get(endword) | (~0L >>> -end));
}
/**
* Look for value k in buffer in the range [begin,end). If the value is found, return its index.
* If not, return -(i+1) where i is the index where the value would be inserted. The buffer is
* assumed to contain sorted values where chars are interpreted as unsigned integers.
*
* @param array buffer where we search
* @param begin first index (inclusive)
* @param end last index (exclusive)
* @param k value we search for
* @return count
*/
public static int unsignedBinarySearch(final CharBuffer array, final int begin, final int end,
final char k) {
return branchyUnsignedBinarySearch(array, begin, end, k);
}
/**
* Look for value k in buffer in the range [begin,end). If the value is found, return its index.
* If not, return -(i+1) where i is the index where the value would be inserted. The buffer is
* assumed to contain sorted values where chars are interpreted as unsigned integers.
*
* @param array buffer where we search
* @param position starting position of the container in the ByteBuffer
* @param begin first index (inclusive)
* @param end last index (exclusive)
* @param k value we search for
* @return count
*/
public static int unsignedBinarySearch(final ByteBuffer array, int position,
final int begin, final int end, final char k) {
return branchyUnsignedBinarySearch(array, position, begin, end, k);
}
protected static int unsignedDifference(final CharBuffer set1, final int length1,
final CharBuffer set2, final int length2, final char[] buffer) {
int pos = 0;
int k1 = 0, k2 = 0;
if (0 == length2) {
set1.get(buffer, 0, length1);
return length1;
}
if (0 == length1) {
return 0;
}
char s1 = set1.get(k1);
char s2 = set2.get(k2);
while (true) {
if (s1 < s2) {
buffer[pos++] = s1;
++k1;
if (k1 >= length1) {
break;
}
s1 = set1.get(k1);
} else if (s1 == s2) {
++k1;
++k2;
if (k1 >= length1) {
break;
}
if (k2 >= length2) {
set1.position(k1);
set1.get(buffer, pos, length1 - k1);
return pos + length1 - k1;
}
s1 = set1.get(k1);
s2 = set2.get(k2);
} else {// if (val1>val2)
++k2;
if (k2 >= length2) {
set1.position(k1);
set1.get(buffer, pos, length1 - k1);
return pos + length1 - k1;
}
s2 = set2.get(k2);
}
}
return pos;
}
/**
* Intersects the bitmap with the array, returning the cardinality of the result
* @param bitmap the bitmap, modified
* @param array the array, not modified
* @param length how much of the array to consume
* @return the size of the intersection, i.e. how many bits still set in the bitmap
*/
public static int intersectArrayIntoBitmap(long[] bitmap, CharBuffer array, int length) {
int lastWordIndex = 0;
int wordIndex = 0;
long word = 0L;
int cardinality = 0;
for (int i = 0; i < length; ++i) {
wordIndex = array.get(i) >>> 6;
if (wordIndex != lastWordIndex) {
bitmap[lastWordIndex] &= word;
cardinality += Long.bitCount(bitmap[lastWordIndex]);
word = 0L;
Arrays.fill(bitmap, lastWordIndex + 1, wordIndex, 0L);
lastWordIndex = wordIndex;
}
word |= 1L << array.get(i);
}
if (word != 0L) {
bitmap[wordIndex] &= word;
cardinality += Long.bitCount(bitmap[lastWordIndex]);
}
if (wordIndex < bitmap.length) {
Arrays.fill(bitmap, wordIndex + 1, bitmap.length, 0L);
}
return cardinality;
}
/**
* Intersects the bitmap with the array, returning the cardinality of the result
* @param bitmap the bitmap, modified
* @param array the array, not modified
* @param length how much of the array to consume
* @return the size of the intersection, i.e. how many bits still set in the bitmap
*/
public static int intersectArrayIntoBitmap(LongBuffer bitmap, CharBuffer array, int length) {
if (isBackedBySimpleArray(bitmap)) {
return intersectArrayIntoBitmap(bitmap.array(), array, length);
}
int lastWordIndex = 0;
int wordIndex = 0;
long word = 0L;
int cardinality = 0;
for (int i = 0; i < length; ++i) {
wordIndex = array.get(i) >>> 6;
if (wordIndex != lastWordIndex) {
long lastWord = bitmap.get(lastWordIndex);
lastWord &= word;
bitmap.put(lastWordIndex, lastWord);
cardinality += Long.bitCount(lastWord);
word = 0L;
for (int j = lastWordIndex + 1; j < wordIndex; ++j) {
bitmap.put(j, 0L);
}
lastWordIndex = wordIndex;
}
word |= 1L << array.get(i);
}
if (word != 0L) {
long currentWord = bitmap.get(wordIndex);
currentWord &= word;
bitmap.put(wordIndex, currentWord);
cardinality += Long.bitCount(currentWord);
}
if (wordIndex < bitmap.limit()) {
for (int j = wordIndex + 1; j < bitmap.limit(); ++j) {
bitmap.put(j, 0L);
}
}
return cardinality;
}
protected static int unsignedExclusiveUnion2by2(final CharBuffer set1, final int length1,
final CharBuffer set2, final int length2, final char[] buffer) {
int pos = 0;
int k1 = 0, k2 = 0;
if (0 == length2) {
set1.get(buffer, 0, length1);
return length1;
}
if (0 == length1) {
set2.get(buffer, 0, length2);
return length2;
}
char s1 = set1.get(k1);
char s2 = set2.get(k2);
while (true) {
if (s1 < s2) {
buffer[pos++] = s1;
++k1;
if (k1 >= length1) {
set2.position(k2);
set2.get(buffer, pos, length2 - k2);
return pos + length2 - k2;
}
s1 = set1.get(k1);
} else if (s1 == s2) {
++k1;
++k2;
if (k1 >= length1) {
set2.position(k2);
set2.get(buffer, pos, length2 - k2);
return pos + length2 - k2;
}
if (k2 >= length2) {
set1.position(k1);
set1.get(buffer, pos, length1 - k1);
return pos + length1 - k1;
}
s1 = set1.get(k1);
s2 = set2.get(k2);
} else {// if (val1>val2)
buffer[pos++] = s2;
++k2;
if (k2 >= length2) {
set1.position(k1);
set1.get(buffer, pos, length1 - k1);
return pos + length1 - k1;
}
s2 = set2.get(k2);
}
}
// return pos;
}
protected static int unsignedIntersect2by2(final CharBuffer set1, final int length1,
final CharBuffer set2, final int length2, final char[] buffer) {
final int THRESHOLD = 34;
if (length1 * THRESHOLD < length2) {
return unsignedOneSidedGallopingIntersect2by2(set1, length1, set2, length2, buffer);
} else if (length2 * THRESHOLD < length1) {
return unsignedOneSidedGallopingIntersect2by2(set2, length2, set1, length1, buffer);
} else {
return unsignedLocalIntersect2by2(set1, length1, set2, length2, buffer);
}
}
/**
* Checks if two arrays intersect
*
* @param set1 first array
* @param length1 length of first array
* @param set2 second array
* @param length2 length of second array
* @return true if they intersect
*/
public static boolean unsignedIntersects(CharBuffer set1, int length1, CharBuffer set2,
int length2) {
if ((0 == length1) || (0 == length2)) {
return false;
}
int k1 = 0;
int k2 = 0;
// could be more efficient with galloping
char s1 = set1.get(k1);
char s2 = set2.get(k2);
mainwhile: while (true) {
if (s2 < s1) {
do {
++k2;
if (k2 == length2) {
break mainwhile;
}
s2 = set2.get(k2);
} while (s2 < s1);
}
if (s1 < s2) {
do {
++k1;
if (k1 == length1) {
break mainwhile;
}
s1 = set1.get(k1);
} while (s1 < s2);
} else {
return true;
}
}
return false;
}
protected static int unsignedLocalIntersect2by2(final CharBuffer set1, final int length1,
final CharBuffer set2, final int length2, final char[] buffer) {
if ((0 == length1) || (0 == length2)) {
return 0;
}
int k1 = 0;
int k2 = 0;
int pos = 0;
char s1 = set1.get(k1);
char s2 = set2.get(k2);
mainwhile: while (true) {
if (s2 < s1) {
do {
++k2;
if (k2 == length2) {
break mainwhile;
}
s2 = set2.get(k2);
} while (s2 < s1);
}
if (s1 < s2) {
do {
++k1;
if (k1 == length1) {
break mainwhile;
}
s1 = set1.get(k1);
} while (s1 < s2);
} else {
// (set2.get(k2) == set1.get(k1))
buffer[pos++] = s1;
++k1;
if (k1 == length1) {
break;
}
s1 = set1.get(k1);
++k2;
if (k2 == length2) {
break;
}
s2 = set2.get(k2);
}
}
return pos;
}
protected static int unsignedLocalIntersect2by2Cardinality(final CharBuffer set1,
final int length1, final CharBuffer set2, final int length2) {
if ((0 == length1) || (0 == length2)) {
return 0;
}
int k1 = 0;
int k2 = 0;
int pos = 0;
char s1 = set1.get(k1);
char s2 = set2.get(k2);
mainwhile: while (true) {
if (s2 < s1) {
do {
++k2;
if (k2 == length2) {
break mainwhile;
}
s2 = set2.get(k2);
} while (s2 < s1);
}
if (s1 < s2) {
do {
++k1;
if (k1 == length1) {
break mainwhile;
}
s1 = set1.get(k1);
} while (s1 < s2);
} else {
++pos;
++k1;
if (k1 == length1) {
break;
}
s1 = set1.get(k1);
++k2;
if (k2 == length2) {
break;
}
s2 = set2.get(k2);
}
}
return pos;
}
protected static int unsignedOneSidedGallopingIntersect2by2(final CharBuffer smallSet,
final int smallLength, final CharBuffer largeSet, final int largeLength,
final char[] buffer) {
if (0 == smallLength) {
return 0;
}
int k1 = 0;
int k2 = 0;
int pos = 0;
char s1 = largeSet.get(k1);
char s2 = smallSet.get(k2);
while (true) {
if (s1 < s2) {
k1 = advanceUntil(largeSet, k1, largeLength, s2);
if (k1 == largeLength) {
break;
}
s1 = largeSet.get(k1);
}
if (s2 < s1) {
++k2;
if (k2 == smallLength) {
break;
}
s2 = smallSet.get(k2);
} else {
// (set2.get(k2) == set1.get(k1))
buffer[pos++] = s2;
++k2;
if (k2 == smallLength) {
break;
}
s2 = smallSet.get(k2);
k1 = advanceUntil(largeSet, k1, largeLength, s2);
if (k1 == largeLength) {
break;
}
s1 = largeSet.get(k1);
}
}
return pos;
}
protected static int unsignedUnion2by2(
final CharBuffer set1, final int offset1, final int length1,
final CharBuffer set2, final int offset2, final int length2,
final char[] buffer) {
if (0 == length2) {
set1.position(offset1);
set1.get(buffer, 0, length1);
return length1;
}
if (0 == length1) {
set2.position(offset2);
set2.get(buffer, 0, length2);
return length2;
}
int pos = 0;
int k1 = offset1, k2 = offset2;
char s1 = set1.get(k1);
char s2 = set2.get(k2);
while (true) {
int v1 = s1;
int v2 = s2;
if (v1 < v2) {
buffer[pos++] = s1;
++k1;
if (k1 >= length1 + offset1) {
set2.position(k2);
set2.get(buffer, pos, length2 - k2 + offset2);
return pos + length2 - k2 + offset2;
}
s1 = set1.get(k1);
} else if (v1 == v2) {
buffer[pos++] = s1;
++k1;
++k2;
if (k1 >= length1 + offset1) {
set2.position(k2);
set2.get(buffer, pos, length2 - k2 + offset2);
return pos + length2 - k2 + offset2;
}
if (k2 >= length2 + offset2) {
set1.position(k1);
set1.get(buffer, pos, length1 - k1 + offset1);
return pos + length1 - k1 + offset1;
}
s1 = set1.get(k1);
s2 = set2.get(k2);
} else {// if (set1.get(k1)>set2.get(k2))
buffer[pos++] = s2;
++k2;
if (k2 >= length2 + offset2) {
set1.position(k1);
set1.get(buffer, pos, length1 - k1 + offset1);
return pos + length1 - k1 + offset1;
}
s2 = set2.get(k2);
}
}
// return pos;
}
/**
* Private constructor to prevent instantiation of utility class
*/
private BufferUtil() {
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy