Skip to content

feat: native pure-Rust u64 FastPFOR codec#85

Open
CommanderStorm wants to merge 26 commits into
fast-pack:mainfrom
CommanderStorm:feat/native-u64-fastpfor
Open

feat: native pure-Rust u64 FastPFOR codec#85
CommanderStorm wants to merge 26 commits into
fast-pack:mainfrom
CommanderStorm:feat/native-u64-fastpfor

Conversation

@CommanderStorm

@CommanderStorm CommanderStorm commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Adds a native 64-bit (u64) FastPFOR codec to the pure-Rust side

CommanderStorm and others added 2 commits July 17, 2026 12:43
Adds a 64-bit (`u64`) FastPFOR codec to the pure-Rust side, which was
previously 32-bit only. `FastPForWide128`/`FastPForWide256` compress `u64`
values via the (now un-gated) `BlockCodec64` trait: FastPFOR-packed aligned
blocks plus a variable-byte tail for the sub-block remainder.

The wire format is byte-identical to the C++ `CppFastPFor128`/`CppFastPFor256`
`encode64`/`decode64` paths, verified by parity unit tests and a 30-minute
differential fuzz run (13.8M executions, no crashes).

- bitpacking_wide: generic scalar packer for `u64` at widths 0..=64, whose
  bit-ordering is cross-checked against the proven u32 kernels.
- fastpfor64: `FastPForWide<N>` with 65-entry exception tables, a 2-word
  exception bitmap, and u64 exception values.
- Un-gate `BlockCodec64` so pure-Rust builds get 64-bit support.
- Add the `fastpfor_u64` differential fuzz target and a README example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.35350% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/rust/integer_compression/fastpfor32.rs 95.94% 6 Missing ⚠️
src/rust/integer_compression/variable_byte.rs 93.65% 4 Missing ⚠️
src/test_utils.rs 76.47% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

CommanderStorm and others added 3 commits July 17, 2026 12:52
Explain the Rust code on its own terms rather than by reference to the C++
implementation, drop a redundant test comment, and write comments as short
single-sentence lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Consolidate the separate FastPForWide128/256 types into the existing
FastPFor128/FastPFor256: each now implements AnyLenCodec (u32) and
BlockCodec64 (u64), mirroring the C++ codecs that expose both widths from
one type. The u64 engine is retained as a private field, so buffer reuse is
preserved and the public API drops the extra FastPForWide* names.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread fuzz/fuzz_targets/fastpfor_u64.rs Outdated
CommanderStorm and others added 3 commits July 17, 2026 13:50
The u32 and u64 codecs had near-identical encode_page/decode_page/best_bit
implementations differing only in element width. Extract a single generic
FastPForEngine<N, T> parameterized by a FastPForInt trait that abstracts the
width-specific pieces (bit width, exception bitmap word count, pack/unpack,
shifts). u32 keeps its hand-unrolled bit-packing kernels via trait dispatch,
so there is no performance regression; u64 uses the generic wide packer.

fastpfor.rs and fastpfor64.rs become thin wrappers over the engine. Net
-296 lines with the page algorithm now written once.

Verified byte-identical: u32 encode_compare fuzz (Rust==C++, 808K runs) and
u64 differential fuzz (619K runs) both clean, plus the full test suite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@CommanderStorm
CommanderStorm marked this pull request as ready for review July 17, 2026 12:30
Copilot AI review requested due to automatic review settings July 17, 2026 12:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

- Use Vec::clear() instead of truncate(0) in the encode_compare fuzz target
  (newer clippy flags truncate-to-zero).
- Apply rustfmt to the generic-engine allow-attribute and the u64 fuzz target.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@CommanderStorm
CommanderStorm requested a review from nyurik July 17, 2026 12:48
@nyurik

nyurik commented Jul 17, 2026

Copy link
Copy Markdown
Member

why not flatten FastPForEngine into FastPFor ?

pub struct FastPFor<const N: usize, T: FastPForInt = u32> {...}

@nyurik

nyurik commented Jul 18, 2026

Copy link
Copy Markdown
Member

i did a number of refactorings, and did a bit of a deep dive into benchmarks - making sure the new impl has the same speed (inlining always seems to be the key sadly). I think a bit more cleanup might be needed

CommanderStorm and others added 2 commits July 18, 2026 13:07
The pedantic `clippy::inline_always` lint was failing CI on the thin
forwarders in the `FastPForInt` impls. The `#[inline(always)]` is
intentional (documented above each fn); add an explicit `#[allow]` with
reason so clippy stops flagging it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI's `just docs` denies rustdoc warnings. Fix the four broken links on
the `FastPFor` doc comment:
- `BlockCodec`, `FastPForBlock128`, `FastPForBlock256` now use explicit
  `crate::` paths (they're re-exported at the crate root, not in scope
  in this module).
- `FastPForInt` is a private sealed trait, so drop the intra-doc link
  and leave it as plain code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread src/rust/fastpfor_codec.rs Outdated
Comment on lines +18 to +21
pub struct $name {
narrow: CompositeCodec<$block, VariableByte>,
wide: FastPFor<$n, u64>,
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not entirely happy with this.

So now that we have smushed u32 and u64 together, we have the worst of both worlds imo.
Your version means that

  • the code uses a bit harder to read macros (likely fine)
  • allocates both narrow AND wide

I would still prefer the engine abstraction because at least there, we are not allocating wide+narrow.

We can OnceCell it, but that also has costs for perf..

CommanderStorm and others added 2 commits July 18, 2026 15:12
Collapse the two-field FastPFor codec into a single generic
`FastPForCodec<N, T>` with one `inner: CompositeCodec<FastPFor<N,T>,
VariableByte<T>>`.

- Give `BlockCodec`/`AnyLenCodec` an associated `Elem` so the block
  engine and composite are one width-generic implementation instead of
  duplicated u32/u64 paths.
- Unify `VariableByte` into a generic `VariableByte<T>` with u32 and u64
  tail impls; drop the free `vbyte_encode64`/`vbyte_decode64` functions
  and `VariableByteWide`.
- Split the public codec by width: `FastPFor128`/`FastPFor256` are u32;
  add `FastPForWide128`/`FastPForWide256` for u64. Each type serves one
  width, so it holds one codec.
- Delete the redundant `BlockCodec64 for FastPFor<N,u64>`; the u64 type
  keeps a delegating `BlockCodec64` impl for C++ parity comparison.

Wire format unchanged: C++ u64 parity tests pass. All tests, clippy,
rustfmt, and rustdoc clean under both default and `cpp` features.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqJPh46kx6YzhwUjX6EPDn
Replace the hand-written operator bounds, ZERO/ONE constants, and per-type
significant_bits impls on FastPForInt with a PrimInt supertrait bound. Only
the width-specific members (scratch buffers, packing/bitmap kernels) remain.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EqJPh46kx6YzhwUjX6EPDn
Comment thread src/rust/integer_compression/fastpfor_int.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants