fix(core):使用位运算解决极端情况下Math.abs()失败导致的BitSet报错

This commit is contained in:
LettuceLeaves 2025-11-21 01:37:52 +08:00
parent a31e3ff096
commit 6ad6a8022e
3 changed files with 24 additions and 9 deletions

View File

@ -50,12 +50,12 @@ public abstract class AbstractFilter implements BloomFilter {
@Override @Override
public boolean contains(final String str) { public boolean contains(final String str) {
return bitSet.get(Math.abs(hash(str))); return bitSet.get(hash(str));
} }
@Override @Override
public boolean add(final String str) { public boolean add(final String str) {
final int hash = Math.abs(hash(str)); final int hash = hash(str);
if (bitSet.get(hash)) { if (bitSet.get(hash)) {
return false; return false;
} }

View File

@ -51,28 +51,40 @@ public class FuncFilter extends AbstractFilter {
/** /**
* @param size 最大值 * @param size 最大值
* @param hashFunc Hash函数 * @param hashFuncs Hash函数
*/ */
@SafeVarargs @SafeVarargs
public FuncFilter(final int size, final Function<String, Number>... hashFunc) { public FuncFilter(final int size, final Function<String, Number>... hashFuncs) {
super(size); super(size);
Assert.notEmpty(hashFunc, "Hash functions must not be empty"); Assert.notEmpty(hashFuncs, "Hash functions must not be empty");
this.hashFuncs = Collections.unmodifiableList(Arrays.asList(hashFunc)); this.hashFuncs = Collections.unmodifiableList(Arrays.asList(hashFuncs));
} }
/**
*兼容父类如果存在多个哈希函数就使用第一个
*
* @param str 字符串
*/
@Override @Override
public int hash(final String str) { public int hash(final String str) {
return hash(str, hashFuncs.get(0)); return hash(str, hashFuncs.get(0));
} }
/**
*
* @param str 字符串
* @param hashFunc 哈希函数
* @return HashCode 指定哈希函数的计算结果
*/
public int hash(final String str, final Function<String, Number> hashFunc) { public int hash(final String str, final Function<String, Number> hashFunc) {
return hashFunc.apply(str).intValue() % size; // 通过位运算获取正数
return (hashFunc.apply(str).intValue() & 0x7FFFFFFF) % size;
} }
@Override @Override
public boolean contains(final String str) { public boolean contains(final String str) {
for (final Function<String, Number> hashFunc : hashFuncs) { for (final Function<String, Number> hashFunc : hashFuncs) {
if (!bitSet.get(Math.abs(hash(str, hashFunc)))) { if (!bitSet.get(hash(str, hashFunc))) {
return false; return false;
} }
} }
@ -83,7 +95,7 @@ public class FuncFilter extends AbstractFilter {
public boolean add(final String str) { public boolean add(final String str) {
boolean add = false; boolean add = false;
for (final Function<String, Number> hashFunc : hashFuncs) { for (final Function<String, Number> hashFunc : hashFuncs) {
int hash = Math.abs(hash(str, hashFunc)); int hash = hash(str, hashFunc);
if (!bitSet.get(hash)) { if (!bitSet.get(hash)) {
bitSet.set(hash); bitSet.set(hash);
add = true; add = true;

View File

@ -20,6 +20,8 @@ import cn.hutool.v7.core.codec.hash.HashUtil;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.BitSet;
public class BitMapBloomFilterTest { public class BitMapBloomFilterTest {
@Test @Test
@ -35,4 +37,5 @@ public class BitMapBloomFilterTest {
Assertions.assertTrue(filter.contains("ddd")); Assertions.assertTrue(filter.contains("ddd"));
Assertions.assertTrue(filter.contains("123")); Assertions.assertTrue(filter.contains("123"));
} }
} }