Skip to content

feat(tensor): byteConversionAppend — bit-offset packing for mixed-width streams#385

Merged
LeoBuron merged 2 commits into
developfrom
feat/byte-conversion-append
Jul 20, 2026
Merged

feat(tensor): byteConversionAppend — bit-offset packing for mixed-width streams#385
LeoBuron merged 2 commits into
developfrom
feat/byte-conversion-append

Conversation

@LeoBuron

@LeoBuron LeoBuron commented Jul 20, 2026

Copy link
Copy Markdown
Member

Context

A student is building delta compression (wide base values + narrow deltas, bit-dense) and hit two limits of the bit-packing layer: byteConversion can only start writing at bit 0 of a byte pointer, and its leading memset clobbers previously written bits in a shared byte. Appending mixed-width segments at non-byte-aligned boundaries is therefore impossible today. (In-tree chunked packing is unaffected: elemOffset % 8 == 0 keeps every chunk start byte-aligned for any qBits — see the _Static_assert in TensorConversion.c.)

Change

  • byteConversionAppend(dataIn, dataInBits, dataOut, dataOutBits, numValues, dstStartBit) (Tensor.h/Tensor.c): identical loop machinery, out cursor seeded from dstStartBit, no memset. Bits outside the written range are preserved; numValues == 0 is a safe no-op.
  • writeByte: OR → clear-then-set. The [startbit, endbit) range is now fully defined regardless of stale in-range bits, making appends robust on previously written buffers. Behavior-identical for all existing callers — every production write lands on memset-zeroed in-mask bits.
  • byteConversion delegates to byteConversionAppend(..., 0) after its memset — single source of truth for the loop.
  • Second commit — latent underflow fixed: byteConversion with numValues == 0 used to underflow its memset size (n*bits-1)/8+1 to ~SIZE_MAX (crash; one guard away via convertSymTensorToInt32Tensor + tensor: N=0 element allocation has implementation-defined behavior #160 N=0 tensors). Now: early return for numValues == 0 (no memset — N=0 tensor data may be NULL), and the size expression uses the canonical ceiling idiom (bits+7)/8, which is identical for bits > 0 and safely 0 for dataOutBits == 0.
  • One-line contract note in docs/conventions/tensor.md: zero-fill-on-widen / sign-extend caveat applies to the append entry point too.

Verification

  • TDD: all 9 new tests watched failing first (stub RED / SIGSEGV-RED for the underflow pair), gold fixtures derived via an independent LSB-first reference packer (not the implementation).
  • 7-round mutation check: every new test kills at least one wound (OR-writeByte, ignore dstStartBit%8, ignore dstStartBit/8, unconditional clobber, broken input reseed, skip-zero-fill, restored underflow formula). The skip-zero-fill mutation was surfaced by review and is covered by the widening-into-stale-buffer test.
  • Prototype of the same design passed 300k+ randomized differential fuzz trials (mixed widths 1–32, offsets to 5M bits, packed sub-byte input, ASan/UBSan clean) during the analysis phase.
  • ctest --preset unit_test_debug: 81/81; examples build 395/395; uv run pytest: 29/29.

Notes

🤖 Generated with Claude Code

LeoBuron and others added 2 commits July 20, 2026 18:33
…th streams

byteConversion can only start at bit 0 of a byte pointer and leads with a
memset, so mixed-width bit-dense streams (delta compression: wide base
values + narrow deltas) cannot be appended at non-byte-aligned boundaries.

- byteConversionAppend(..., dstStartBit): same loop machinery, out cursor
  seeded from dstStartBit, no memset; bits outside the written range are
  preserved, numValues==0 is a safe no-op.
- writeByte: OR -> clear-then-set, so the [startbit, endbit) range is fully
  defined regardless of stale in-range bits. Behavior-identical for all
  existing callers (every production write lands on memset-zeroed bits).
- byteConversion now delegates to byteConversionAppend(..., 0) after its
  memset (single source of truth for the loop).

Co-Authored-By: Claude Fable 5 <[email protected]>
(numValues * dataOutBits - 1) / 8 + 1 underflows to ~SIZE_MAX for an empty
stream (and for dataOutBits == 0), turning the leading memset into a crash.
Unreachable in-tree today, but one guard away: convertSymTensorToInt32Tensor
passes n straight through and N=0 tensors are constructible (#160).

- numValues == 0 returns early (no memset: N=0 tensor data may be NULL, #160)
- size expression switched to the canonical ceiling idiom (bits + 7) / 8
  (identical for bits > 0, safely 0 for dataOutBits == 0)

Co-Authored-By: Claude Fable 5 <[email protected]>
@LeoBuron
LeoBuron force-pushed the feat/byte-conversion-append branch from 4d7faa9 to 9de065f Compare July 20, 2026 16:34
@LeoBuron
LeoBuron merged commit 9de065f into develop Jul 20, 2026
12 checks passed
@LeoBuron
LeoBuron deleted the feat/byte-conversion-append branch July 20, 2026 18:55
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.

1 participant