Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

std.sketch.xor

A static approximate-membership filter over u64 keys. build(keys, max_keys: NonNegative[i64], seed=0) accepts duplicates, sorts/deduplicates a fallible copy, and returns an XorFilter. The input is not mutated. max_keys bounds input entries, not just distinct keys; a max_keys above 16,777,216 traps.

from std.sketch import SketchError
import std.sketch.xor as xor

def main() -> Result[(), SketchError | AllocError | IoError]:
    keys = [10u64, 20u64, 30u64, 20u64]?
    filter = xor.build(&keys, 1000)?
    print(filter.len(), filter.contains(20u64), filter.contains(25u64))?
    Ok(())
3 True False

contains(key) allocates nothing and reads three fingerprint positions. Inserted keys have no false negatives for an intact filter. Absent keys may return true: approximately 1/256 with well-distributed hashes. This is not an exact set, security boundary, or an adversarial-key guarantee. len() counts distinct input keys; the empty filter always returns false.

Construction uses three disjoint blocks, graph peeling, and reverse XOR8 fingerprint assignment. The persistent filter has 3 * (1 + unique_count // 2) one-byte slots, plus metadata. At the maximum key count, each block has 8,388,609 slots. Position reduction multiplies a 32-bit hash fragment by this bounded block size without overflow; only the SplitMix64 mixer and attempt-seed schedule use explicit modular arithmetic. Scratch memory is O(input entries + slots), considerably larger than the final filter. Sorting is O(n log n), followed by up to 32 O(n) peeling attempts. Failure to peel returns SketchError.ConstructionFailed; allocation failures return SketchError.Allocation(cause). See Graf and Lemire’s xor-filter paper.

This first implementation deliberately uses more construction slack than a tuned xor/fuse filter. It is immutable after construction. For changing data, see cuckoo filters.

to_bytes() returns Result[Bytes, AllocError]. from_bytes(data, max_keys: NonNegative[i64]) reads a &[u8] view and returns SketchError. The PSX1 format stores seed, unique count, block size (little-endian u64), then fingerprint bytes. Readers validate the count/shape and exact length before allocation, and reject values beyond the caller’s limit. It is a Plenty-specific versioned checkpoint, not the xorf crate’s representation. It has no integrity checksum: valid-looking corruption can introduce false negatives.

Acknowledgements

  • Uses the xor filter by Thomas Mueller Graf and Daniel Lemire (2020).