Skip to content

v0.10.0 — PairedVerifiedConstMap, formats shared with Go and Rust

Latest

Choose a tag to compare

@lemire lemire released this 17 Sep 01:30

PairedVerifiedConstMap, a cache-friendlier layout for the verified map, and file formats shared with the Go and Rust implementations.

Nothing existing changes behaviour: every class, method and error is as before, and every file written by 0.9 or earlier still loads and answers correctly.

PairedVerifiedConstMap

VerifiedConstMap keeps values and check words in two arrays, so a lookup of a present key touches six cache lines. PairedVerifiedConstMap stores each value next to its check word: three cache lines, and each 16-byte slot is loaded and XORed as one 128-bit word on x86-64 (SSE2) and AArch64 (NEON).

pm = PairedVerifiedConstMap(d)
pm["apple"]      # 100
pm.get("grape")  # None

Same semantics, same ~18 bytes/key, same API as VerifiedConstMap, including batches, save/load, and zero-copy from_buffer. Faster when the keys you look up are usually present (batched lookups 21-34% faster cold at the C level), slower for absent keys, since the split layout stops after its half-size check array. The README has the numbers and the guidance.

Files shared with Go and Rust

A map saved by fastconstmap, constmap v1.2.0 (Go) or rsconstmap 0.3 (Rust) now loads in the other two, on a little-endian host. To get there, maps are built with XXH64, the key hash of the other two, instead of XXH3; VerifiedConstMap and PairedVerifiedConstMap write their formats as-is (VMAP0001, PMAP0001), and ConstMap writes CMAP0003, the Go/Rust CMAP0001 plus the key count that len() reports. A map loaded from a Go or Rust file reports len() == 0, since they do not record the count.

XXH64 is slower than XXH3 on short keys: about 1.3 ns per lookup on an Apple M4 Max and 2 ns on an Intel Xeon Gold 6548N at the C level, which through the Python API is 2-4% on a single m[k] and up to ~20% on get_many_into. If you do not need the shared format, ConstMap(d, hash="xxh3") (likewise the other classes) keeps the old hash and speed; such a map serializes with the legacy magic, readable by fastconstmap only. m.hash tells you which hash a map uses.

Files from 0.9 and earlier (CMAP0002, VCMP0002) keep working: the map keeps the XXH3 hash its file was built with, and re-saving it keeps the legacy magic (its table cannot be converted; rebuild from the keys to get a shared-format file). Files written by the Go package live under tests/interop and are checked by the test suite, as are files from 0.9.

Also

  • The key hash is force-inlined into every lookup; clang had been leaving it behind a call.
  • Deserialization of a paired map checks that its segment parameters describe its slot count (ValueError otherwise).