Update to CRoaring 5.1.0 and complete the 32-bit and 64-bit API - #30
Conversation
Replace the bundled amalgamation with the v5.1.0 release, then fill in the
Go wrapper so that it covers both C APIs rather than a subset of the 32-bit
one.
Bitmap64 is new: it wraps roaring64_bitmap_t and offers the same operations
as Bitmap, with the free functions carrying a 64 suffix (Or64, Read64...).
The 32-bit side gains the entry points it was missing: checked add/remove,
closed ranges, bulk contexts, RankMany, GetIndex, subset tests, the lazy
operations and RepairAfterLazy, FastOrHeap and FastXor, AddOffset,
copy-on-write control, the native and portable-frozen serialization formats,
PortableDeserializeSize, RangeToArray, ToDenseBitset, InternalValidate, and
seekable iterators.
Memory is now released through runtime.AddCleanup instead of
runtime.SetFinalizer, following the approach taken by ada-url/goada. A
bitmap is reclaimed in a single garbage collection cycle rather than two,
and Free stops the cleanup so that explicit and automatic release cannot
double free. Creating and discarding a bitmap goes from 348ns to 272ns.
This requires Go 1.24, so go.mod and the CI matrix move up.
Two more changes cut the cost of crossing the Go/C boundary:
- Iterators read values in blocks of 512 rather than one per cgo call.
Walking a bitmap of a million values takes 1.4ms instead of 32ms
(1.4ms instead of 93ms for the 64-bit iterator).
- ReadValidated deserializes and validates in a single crossing, through
a small static inline trampoline.
The CRoaring entry points are declared #cgo nocallback, and #cgo noescape
wherever the function does not keep the buffer it is handed. The four
frozen-view functions do retain their buffer and are deliberately left out
of the noescape list.
Two behaviours worth noting. The frozen views now report a misaligned
buffer as such, where CRoaring merely returned NULL, and AlignedBuffer and
AlignedBuffer64 hand back a buffer with the alignment each format needs.
Bitmap64.WriteFrozen returns ErrNotShrunken unless ShrinkToFit has been
called, which the C API requires but does not signal.
Claude-Session: https://claude.ai/code/session_01NzKGBVi8pbqkwocqktcjLU
|
Pushed a follow-up commit after an audit of the wrapper against the C sources. Two real bugs, both pre-existing in the branch, plus two doc gaps. In-place operations aborted the process on self-application. With
Docs: Regression tests cover every aliased combination on both widths and the empty-range cases. Full suite passes, including under For the record, the audit found nothing in these areas: all 189 |
Updates the bundled amalgamation to the v5.1.0 release (we were on 4.5.0) and completes the Go wrapper so that it covers both C APIs rather than a subset of the 32-bit one.
64-bit bitmaps
Bitmap64wrapsroaring64_bitmap_tand offers the same operations asBitmap, with the free functions carrying a64suffix (Or64,And64,Read64...).32-bit gaps filled
Checked add/remove, closed ranges, bulk contexts,
RankMany,GetIndex, subset tests, the lazy operations andRepairAfterLazy,FastOrHeapandFastXor,AddOffset, copy-on-write control, the native and portable-frozen serialization formats,PortableDeserializeSize,RangeToArray,ToDenseBitset,InternalValidate, and seekable iterators.The exported surface goes from about 50 functions to 202. Nothing that was exported before was removed or had its signature changed;
StatisticsgainsMinValueandMaxValue.Memory management
Memory is now released through
runtime.AddCleanupinstead ofruntime.SetFinalizer, following the approach taken by ada-url/goada. A bitmap is reclaimed in a single garbage collection cycle rather than two, the cleanup closure never captures the object, andFreestops the cleanup so explicit and automatic release cannot double free.This requires Go 1.24, so
go.modand the CI matrix move up (1.24.x, 1.25.x).Fewer, cheaper boundary crossings
Iterators read values in blocks of 512 rather than one per cgo call:
ReadValidateddeserializes and validates in a single crossing, through a small static inline trampoline, the way goada combines parse and validity check.The CRoaring entry points are declared
#cgo nocallback, and#cgo noescapewherever the function does not keep the buffer it is handed. The four frozen-view functions do retain their buffer and are deliberately left out of thenoescapelist.Behaviour worth reviewing
ErrMisaligned, where CRoaring merely returned NULL and we surfaced a generic read failure.AlignedBufferandAlignedBuffer64hand back a buffer with the alignment each format needs (32 and 64 bytes).Bitmap64.WriteFrozenreturnsErrNotShrunkenunlessShrinkToFithas been called, whichroaring64_bitmap_frozen_size_in_bytesrequires but signals only by returning zero.Testing
New tests cover the added 32-bit surface and the whole 64-bit one. The full suite passes, including under
-race(which enablescheckptr), andmake qais clean.https://claude.ai/code/session_01NzKGBVi8pbqkwocqktcjLU