Skip to content

Commit fbfbebc

Browse files
committed
Merge branch 'fix-issue-77-small-segment-count'
2 parents c676938 + 327cd20 commit fbfbebc

7 files changed

Lines changed: 46 additions & 14 deletions

File tree

pyfusefilter/ffibuild.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
5555
typedef struct binary_fuse8_s {
5656
uint64_t Seed;
57+
uint32_t Size;
5758
uint32_t SegmentLength;
5859
uint32_t SegmentLengthMask;
5960
uint32_t SegmentCount;
@@ -64,6 +65,7 @@
6465
6566
typedef struct binary_fuse16_s {
6667
uint64_t Seed;
68+
uint32_t Size;
6769
uint32_t SegmentLength;
6870
uint32_t SegmentLengthMask;
6971
uint32_t SegmentCount;

pyfusefilter/pyfusefilter.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ def __init__(self, size_or_data):
3131
raise MemoryError("Unable to allocate memory for filter")
3232
else:
3333
data = list(map(lambda x: c_ulonglong((hash(x))).value, data))
34-
lib.xor8_buffered_populate(data, len(data), self.__filter)
34+
if not lib.xor8_buffered_populate(data, len(data), self.__filter):
35+
raise ValueError("Unable to populate the filter")
3536

3637
def __repr__(self):
3738
return "Xor8 object with size(in bytes):{}".format(self.size_in_bytes())
@@ -125,7 +126,8 @@ def __init__(self, size_or_data):
125126
raise MemoryError("Unable to allocate memory for filter")
126127
else:
127128
data = list(map(lambda x: c_ulonglong((hash(x))).value, data))
128-
lib.xor16_buffered_populate(data, len(data), self.__filter)
129+
if not lib.xor16_buffered_populate(data, len(data), self.__filter):
130+
raise ValueError("Unable to populate the filter")
129131

130132
def __repr__(self):
131133
"""
@@ -224,7 +226,8 @@ def __init__(self, size_or_data):
224226
raise MemoryError("Unable to allocate memory for filter")
225227
else:
226228
data = list(map(lambda x: c_ulonglong((hash(x))).value, data))
227-
lib.binary_fuse8_populate(data, len(data), self.__filter)
229+
if not lib.binary_fuse8_populate(data, len(data), self.__filter):
230+
raise ValueError("Unable to populate the filter")
228231

229232
def __repr__(self):
230233
"""
@@ -257,11 +260,15 @@ def __del__(self):
257260
def populate(self, data: list):
258261
"""
259262
Set the data of the filter. You may use this method to add data after
260-
allocating the filter with an integer size. The sizes should match.
261-
You can reuse a filter with new data (i.e., call populate several times)
262-
as long as the size remains a constant.
263+
allocating the filter with an integer size. If the number of items
264+
differs from the allocated size, the filter is reallocated.
265+
You can reuse a filter with new data (i.e., call populate several times).
263266
"""
264267
data = list(map(lambda x: c_ulonglong((hash(x))).value, data))
268+
if len(data) != self.__filter.Size:
269+
lib.binary_fuse8_free(self.__filter)
270+
if not lib.binary_fuse8_allocate(len(data), self.__filter):
271+
raise MemoryError("Unable to allocate memory for filter")
265272
return lib.binary_fuse8_populate(data, len(data), self.__filter)
266273

267274
def contains(self, item):
@@ -323,7 +330,8 @@ def __init__(self, size_or_data):
323330
raise MemoryError("Unable to allocate memory for filter")
324331
else:
325332
data = list(map(lambda x: c_ulonglong((hash(x))).value, data))
326-
lib.binary_fuse16_populate(data, len(data), self.__filter)
333+
if not lib.binary_fuse16_populate(data, len(data), self.__filter):
334+
raise ValueError("Unable to populate the filter")
327335

328336
def __repr__(self):
329337
"""
@@ -356,11 +364,15 @@ def __del__(self):
356364
def populate(self, data: list):
357365
"""
358366
Set the data of the filter. You may use this method to add data after
359-
allocating the filter with an integer size. The sizes should match.
360-
You can reuse a filter with new data (i.e., call populate several times)
361-
as long as the size remains a constant.
367+
allocating the filter with an integer size. If the number of items
368+
differs from the allocated size, the filter is reallocated.
369+
You can reuse a filter with new data (i.e., call populate several times).
362370
"""
363371
data = list(map(lambda x: c_ulonglong((hash(x))).value, data))
372+
if len(data) != self.__filter.Size:
373+
lib.binary_fuse16_free(self.__filter)
374+
if not lib.binary_fuse16_allocate(len(data), self.__filter):
375+
raise MemoryError("Unable to allocate memory for filter")
364376
return lib.binary_fuse16_populate(data, len(data), self.__filter)
365377

366378
def contains(self, item):

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ py-modules = []
33
# cffi-modules handled in setup.py
44
[project]
55
name = "pyfusefilter"
6-
version = "1.2.1"
6+
version = "1.3.0"
77
description = "Python bindings for C implementation of xor and fuse filters"
88
authors = [
99
{name = "Amey Narkhede", email = "ameynarkhede02@gmail.com"},
@@ -43,7 +43,7 @@ before-all = "apk add libffi-dev"
4343
# pdoc configuration
4444
name = "pyfusefilter"
4545
description = "Python bindings for C implementation of xor and fuse filters"
46-
version = "1.2.1"
46+
version = "1.3.0"
4747
author = "Amey Narkhede & Daniel Lemire"
4848
author_email = "daniel@lemire.me"
4949
url = "https://github.com/FastFilter/pyfusefilter"

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
setup(
55
name="pyfusefilter",
6-
version="1.2.1",
6+
version="1.3.0",
77
description="Python bindings for C implementation of xorfilter",
88
long_description=open("README.md", "r", encoding='utf-8').read(),
99
long_description_content_type="text/markdown",

tests/test_fuse16.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,12 @@ def test_fuse16_serialize():
6161
assert recover_xor_filter.contains(i)
6262

6363
os.remove(serialized_filter)
64+
65+
def test_fuse16_few_segments():
66+
# https://github.com/FastFilter/xor_singleheader/issues/77
67+
for size in (3551, 11504, 11521, 12372, 13224, 37454):
68+
for _ in range(5):
69+
keys = sample(range(1 << 62), size)
70+
filter = Fuse16(keys)
71+
for key in keys:
72+
assert key in filter

tests/test_fuse8.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,12 @@ def test_fuse8_serialize():
6060
assert recover_xor_filter.contains(i)
6161

6262
os.remove(serialized_filter)
63+
64+
def test_fuse8_few_segments():
65+
# https://github.com/FastFilter/xor_singleheader/issues/77
66+
for size in (3551, 11504, 11521, 12372, 13224, 37454):
67+
for _ in range(5):
68+
keys = sample(range(1 << 62), size)
69+
filter = Fuse8(keys)
70+
for key in keys:
71+
assert key in filter

0 commit comments

Comments
 (0)