From ae16917c1defd0db6334a4424727157fe12169ab Mon Sep 17 00:00:00 2001 From: Adrien Grand Date: Sat, 5 Mar 2022 18:38:57 +0100 Subject: [PATCH] LUCENE-10311: Remove pop_XXX helpers from `BitUtil`. (#724) As @rmuir noted, it would be as simple and create less cognitive overhead to use `Long#bitCount` directly. --- .../java/org/apache/lucene/util/BitUtil.java | 52 ------------------- .../org/apache/lucene/util/FixedBitSet.java | 42 +++++++++++---- .../org/apache/lucene/util/LongBitSet.java | 6 ++- 3 files changed, 36 insertions(+), 64 deletions(-) diff --git a/lucene/core/src/java/org/apache/lucene/util/BitUtil.java b/lucene/core/src/java/org/apache/lucene/util/BitUtil.java index 9848117bc49..60f0914f5bf 100644 --- a/lucene/core/src/java/org/apache/lucene/util/BitUtil.java +++ b/lucene/core/src/java/org/apache/lucene/util/BitUtil.java @@ -115,58 +115,6 @@ public final class BitUtil { public static final VarHandle VH_BE_DOUBLE = MethodHandles.byteArrayViewVarHandle(double[].class, ByteOrder.BIG_ENDIAN); - // The pop methods used to rely on bit-manipulation tricks for speed but it - // turns out that it is faster to use the Long.bitCount method (which is an - // intrinsic since Java 6u18) in a naive loop, see LUCENE-2221 - - /** Returns the number of set bits in an array of longs. */ - public static long pop_array(long[] arr, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr[i]); - } - return popCount; - } - - /** - * Returns the popcount or cardinality of the two sets after an intersection. Neither array is - * modified. - */ - public static long pop_intersect(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] & arr2[i]); - } - return popCount; - } - - /** Returns the popcount or cardinality of the union of two sets. Neither array is modified. */ - public static long pop_union(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] | arr2[i]); - } - return popCount; - } - - /** Returns the popcount or cardinality of {@code A & ~B}. Neither array is modified. */ - public static long pop_andnot(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] & ~arr2[i]); - } - return popCount; - } - - /** Returns the popcount or cardinality of A ^ B Neither array is modified. */ - public static long pop_xor(long[] arr1, long[] arr2, int wordOffset, int numWords) { - long popCount = 0; - for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) { - popCount += Long.bitCount(arr1[i] ^ arr2[i]); - } - return popCount; - } - /** * returns the next highest power of two, or the current value if it's already a power of two or * zero diff --git a/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java b/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java index 5b5b5fc1348..ec1b676dc89 100644 --- a/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java +++ b/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java @@ -73,17 +73,27 @@ public final class FixedBitSet extends BitSet { */ public static long intersectionCount(FixedBitSet a, FixedBitSet b) { // Depends on the ghost bits being clear! - return BitUtil.pop_intersect(a.bits, b.bits, 0, Math.min(a.numWords, b.numWords)); + long tot = 0; + final int numCommonWords = Math.min(a.numWords, b.numWords); + for (int i = 0; i < numCommonWords; ++i) { + tot += Long.bitCount(a.bits[i] & b.bits[i]); + } + return tot; } /** Returns the popcount or cardinality of the union of the two sets. Neither set is modified. */ public static long unionCount(FixedBitSet a, FixedBitSet b) { // Depends on the ghost bits being clear! - long tot = BitUtil.pop_union(a.bits, b.bits, 0, Math.min(a.numWords, b.numWords)); - if (a.numWords < b.numWords) { - tot += BitUtil.pop_array(b.bits, a.numWords, b.numWords - a.numWords); - } else if (a.numWords > b.numWords) { - tot += BitUtil.pop_array(a.bits, b.numWords, a.numWords - b.numWords); + long tot = 0; + final int numCommonWords = Math.min(a.numWords, b.numWords); + for (int i = 0; i < numCommonWords; ++i) { + tot += Long.bitCount(a.bits[i] | b.bits[i]); + } + for (int i = numCommonWords; i < a.numWords; ++i) { + tot += Long.bitCount(a.bits[i]); + } + for (int i = numCommonWords; i < b.numWords; ++i) { + tot += Long.bitCount(b.bits[i]); } return tot; } @@ -94,9 +104,13 @@ public final class FixedBitSet extends BitSet { */ public static long andNotCount(FixedBitSet a, FixedBitSet b) { // Depends on the ghost bits being clear! - long tot = BitUtil.pop_andnot(a.bits, b.bits, 0, Math.min(a.numWords, b.numWords)); - if (a.numWords > b.numWords) { - tot += BitUtil.pop_array(a.bits, b.numWords, a.numWords - b.numWords); + long tot = 0; + final int numCommonWords = Math.min(a.numWords, b.numWords); + for (int i = 0; i < numCommonWords; ++i) { + tot += Long.bitCount(a.bits[i] & ~b.bits[i]); + } + for (int i = numCommonWords; i < a.numWords; ++i) { + tot += Long.bitCount(a.bits[i]); } return tot; } @@ -173,7 +187,11 @@ public final class FixedBitSet extends BitSet { @Override public int cardinality() { // Depends on the ghost bits being clear! - return (int) BitUtil.pop_array(bits, 0, numWords); + long tot = 0; + for (int i = 0; i < numWords; ++i) { + tot += Long.bitCount(bits[i]); + } + return Math.toIntExact(tot); } @Override @@ -193,7 +211,9 @@ public final class FixedBitSet extends BitSet { long popCount = 0; int maxWord; for (maxWord = 0; maxWord + interval < numWords; maxWord += interval) { - popCount += BitUtil.pop_array(bits, maxWord, rangeLength); + for (int i = 0; i < rangeLength; ++i) { + popCount += Long.bitCount(bits[maxWord + i]); + } } popCount *= (interval / rangeLength) * numWords / maxWord; diff --git a/lucene/core/src/java/org/apache/lucene/util/LongBitSet.java b/lucene/core/src/java/org/apache/lucene/util/LongBitSet.java index 150fb3a95e3..8d2b0e592e0 100644 --- a/lucene/core/src/java/org/apache/lucene/util/LongBitSet.java +++ b/lucene/core/src/java/org/apache/lucene/util/LongBitSet.java @@ -136,7 +136,11 @@ public final class LongBitSet implements Accountable { */ public long cardinality() { // Depends on the ghost bits being clear! - return BitUtil.pop_array(bits, 0, numWords); + long tot = 0; + for (int i = 0; i < numWords; ++i) { + tot += Long.bitCount(bits[i]); + } + return tot; } public boolean get(long index) {