org.roaringbitmap.buffer.BufferUtil Maven / Gradle / Ivy
/*
* (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 - 2025 Weber Informatics LLC | Privacy Policy