ZRoaring: flat roaring bitmaps

https://codeberg.org/archaistvolts/zroaring

a zig port of CRoaring

roaring bitmaps are a data structure for storing and operating on large sets of 32-bit integers. they’re used in major systems because of great compression and fast set operations.

Documentation

this project is quite early with lots to be done. its a little messy still but i think i’m ok with the current design except some regret that i’ve over engineered my WordBitset with comptime options.

just wanted to share incase others are interested in this. human contributions wanted!

4 Likes

i managed to create a workflow on github so that this project’s docs get auto built and deployed. first time i’ve done that with a zig project. was pretty easy to do really. mirroring from codeberg to github for hosting docs and ci doesn’t seem too bad so far.

1 Like

@awesomo4000

Thanks for your message. I saw your project was inspired by it to try myself. I’m following your validation strategy. Seems like you’ve covered a good bit of ground in your project. So far I’m somewhere between just porting the c code and trying for something simpler.

Some of my project’s c style memory management has been a bit difficult. I’m currently storing each container type as ptr and cardinality, capacity u32s with to/fromArrayList methods. and that works well.

Also like your project, I’m storing Conatiners as tagged pointers. Since each container has equal size, 128 bits, each is align 16 so the first 4 bits of every pointer will be clear. Though I’m only using 2 bits for 4 tags.

I want to add fuzzing and property based tests soon. I think roaring bitmaps are quite interesting and am enjoying learning about them.

Anyway, I’m curious to know how writing rawr went, what you learned and if you have any advice.

More passing validations today. I guess I’ll move on to frozen bitmaps. Hope to pass all validations soon.

Just added frozen_view() to complete an initial frozen de/serialization cycle :slight_smile:.

I think i’m happy now with a single shared allocation which gets cleaned up in deinit(). Better than my first pass with an out pointer the caller needed to free. Here’s how it looks now. And here is deinit.

I’ve struggled before with constructing a MultiArrayList from a buffer. Figured out something that works, seems ok along with MAL.capacityInBytes(). Curious to hear if anyone else has done similar. I’m hoping this will be fast - need start benchmarking soon.

2 Likes

I’ve started over with a more from scratch implementation after realizing previous memory management was a bit of a mess. I was struggling to get a testing.checkAllAllocationFailures() test passing. Now its passing :slight_smile:.

I deleted most of my old code. I think I’m happy with this new direction. I’ll still be trying to follow the CRoaring API, but I don’t think porting it was as correct, productive and fun as I’d hoped.

I’m going for more of a PWP style. Right now a Bitmap lives in just 2 allocations, one for a Header - with slices contained in the Header allocated right after the Header bytes. And all container data lives in a single ArrayList(Block).

Much happier with the current deinit(). No more pointer chasing and only 2 free()s. :light_bulb:

2 Likes

Still working on this. Ended up unhappy with the previous approach of storing everything in an array list. That also ended up too complex for me.

Now I’m using flexible-struct adapted from https://codeberg.org/ziglang/zig/pulls/30823 and everything lives in 1 allocation (instead of 2). Behold, another happy deinit() with no pointer chasing.

Currently I have most validations working again except for the ‘frozen’ ones. Maybe I’ll finally have some benchmarks vs CRoaring to share soon. :high_voltage: :factory_worker:

2 Likes

Quick progress update: we’ve reached 49.5% coverage of the C roaring_bitmap_ prefixed api :slight_smile:.

# 6/13/2026
$ zig build run -- api-coverage

parsed command:
  api-coverage --filter API-COVERAGE-FILTER-NONE

symbols coverage:
  prefix              : found / total / %   :
---------------------------------------------
  roaring_bitmap_     : 46    / 93    / 49.5%
  ra_                 : 14    / 40    / 35.0%
  container_          : 32    / 64    / 50.0%
  run_container_      : 31    / 60    / 51.7%
  bitset_container_   : 28    / 66    / 42.4%
  array_container_    : 28    / 58    / 48.3%
---------------------------------------------
  total               : 179   / 381   / 47.0%
---------------------------------------------
  filtered            : 0     / 0     / -nan%

Recent additions include add_bulk, and, or, xor, andnot, or_inplace, or_many, lazy_or, lazy_or_inplace

You can see a list of whats completed by running zig build run -- api-coverage --filter roaring_bitmap_.

Still hoping to post benchmarks soon :crossed_fingers:. I’ve been focusing on correctness, and fuzzing each commit extensively with the zig fuzzer and with AFL++.

1 Like

Very cool!

I’m using CRoaring for vind, but I’m looking forward to moving to ZRoaring, if you’re looking for a tangible active use-case. :slight_smile:

1 Like

Neat! Yes I’m definitely interested in exploring use-cases and seeing how it fares in other projects. I’d like to have good text search support. Let me know if you have any requests or find missing features. I’ll gladly work with you to make things fit.

Note that a lot of this progress is only local. Apologies if you went looking for it. Will push to codeberg soon.

Also note that docs/github repo is gone for the moment but should be back soon.

1 Like

I’ve pushed changes and the github repo is back up along with docs.

Over the weekend I’ve added Bitmap.<and/or/xor/andnot>_cardinality(), jaccard_index(), and iterator(). And roaring_bitmap_ api-coverage is now at 57% :factory_worker:

Not too much . It’s basically a rewrite of the c implementation in zig with the same tricks used for performance as the c version. The main thing I learned was that engineering the test harnesses was key to getting the library at parity with and compatible with Croaring. Also, choice of allocator was a make or break for performance. Im using this for another project so it has most of the core features of croaring that I needed. Things not available in rawr that are in croaring are rank/select and lazy n-way compares.

Reaching parity w/ croaring seems to be a lot of work :sweat_smile:. I’ve made a lot of changes since the message you repsonded to. I’ve gone with a flat, single allocation approach using resizable struct. And I have a couple (passing) testing.checkAllAllocationFailures tests, one which runs on all validations, which are similar to your project’s validations. And one which runs on all cases from fuzz-crash-corpus.zon where I’ve been accumulating crashing / failing inputs. I have a decent amount of FuzzOps which are checked against croaring (or std.ArrayHashMap with AFL) but not anywhere near 100% coverage. I ran into issues building an AFL fuzz exe with croaring included. So I resorted to fuzzing against a hash map there instead.

Still lots of ground to cover. But it feels like I’m making decent progress now after a couple early design reworks. I like the flat memory layout I’m using and hope it’ll result in competitive benchmarks. Although I’m skeptical. I think I’m doing too much copying when inserting. And haven’t settled on a plan for reusing container memory aside from telling users to shrink_to_fit often :person_shrugging:.

I’ll get there eventually. For now I’m enjoying working on this project and focusing on coverage and correctness.

Did you implement inplace and _cardinality variants of and/or/xor/andnot too? Thats been a decent amount of work. And by ‘n-way compares’ I guess you mean stuff like or_many?

Also, did you do any benchmarking with zig 0.16? I guess auto-vectorization has regressed for this release cycle so you might notice some slowdown vs 0.15.2.

Yes I’m definitely interested in exploring use-cases and seeing how it fares in other projects. I’d like to have good text search support. Let me know if you have any requests or find missing features. I’ll gladly work with you to make things fit.

Here’s what I’m using:

$ git grep -oP '\broaring[\w_]+' src/ | awk -F: '{print $2}' | sort -u
roaring_bitmap_add
roaring_bitmap_and_inplace
roaring_bitmap_contains
roaring_bitmap_create
roaring_bitmap_free
roaring_bitmap_get_cardinality
roaring_bitmap_or_inplace
roaring_bitmap_to_uint32_array
roaring_iterator_create
roaring_uint32_iterator_free
roaring_uint32_iterator_read

I haven’t checked if ZRoaring implements all of this, but if it does, I’m happy to start testing with it.

I need to write a benchmark so I could compare CRoaring to ZRoaring. Once I have it, I’ll share my results.

1 Like

ZRoaring includes everything except these two. There is and, but the inplace variant isn’t done yet. I think to_uint32_array might be straightforward to implement. I’ll try to get to these soon and let you when done.

I’m interested to see how it compares with with CRoaring. Know that I haven’t gotten to benchmarking yet. I’m planning do some benchmarking soon. Maybe within the fuzzer so as to bench individual operations (FuzzOps).

1 Like

I’ve added to_uint32_array and and_inplace if you want to try it out. The project is young so please feel free to suggest changes to API, docs or anything else you might notice needs polish. If you’re searching for examples, start in validate.zig or fuzz.zig.

As I mentioned, I haven’t started with benchmarking yet and I expect we’re slower than CRoaring in many cases. AVX512 is a TODO along with several AVX2 methods (including one used by and_inplace called intersect_vector16 i think).

1 Like

I’ve done some initial benchmarking. Looks like we’re going around 75% of CRoaring’s speed overall on this ReleaseFast benchmark with x86 / AVX2. We’re competitive on many of the individual ops. This benchmark uses ops from fuzz-crash-corpus.zon as input. There are a handful of :potato: ops which are between 50-70% of CRoaring’s speed. Hope to improve those soon.

I’ve generated some random values for minimum, maximum and contains* ops. They’re excluded from the corpus due to not usually being part of crash reproductions and I wanted to include them here.

One thing I should mention: users should consider calling shrink_to_fit() or run_optimize() before doing expensive operations, especially when many allocating operations have been performed. These may leave ‘holes’ of uninit (0xFF) blocks in the Bitmap and I haven’t yet decided on a strategy for efficiently reusing them. I imagine having all blocks closer together in memory might make up for shrink_to_fit’s cost of reallocating and copying memory in some scenarios. Not sure though. I recommend to benchmark and experiment.

Results with a Ryzen 7 5700X (+AVX2):
$ zig build bench -Doptimize=ReleaseFast
--------------------------------------------------------------------------------
totals:
--------------------------------------------------------------------------------
ops: 2461
CRoaring: 34.464ms     71.41kB ops/sec
ZRoaring: 45.618ms     53.95kB ops/sec                            ratio -- 0.76% 🥔

--------------------------------------------------------------------------------
individual ops (speed=ops/sec)
--------------------------------------------------------------------------------
  op                  count cr time   / zr time   : cr speed / zr speed -- ratio
--------------------------------------------------------------------------------
  add                 2200  1.344ms   / 1.346ms   : 1.64MB   / 1.63MB   -- 1.00% 👍🏻
  add_many            915   879.66us  / 818.2us   : 1.04MB   / 1.12MB   -- 1.08% ⚡
  add_range_closed    1545  1.497ms   / 1.596ms   : 1.03MB   / 0.97MB   -- 0.94% 🥔
  remove              630   384.56us  / 390.41us  : 1.64MB   / 1.61MB   -- 0.99% 👍🏻
  and                 420   1.485ms   / 1.205ms   : 0.28MB   / 0.35MB   -- 1.23% ⚡
  or                  305   1.782ms   / 2.767ms   : 171.07kB / 110.19kB -- 0.64% 🥔
  xor                 375   2.799ms   / 5.562ms   : 133.95kB / 67.42kB  -- 0.50% 🥔
  andnot              320   1.667ms   / 1.708ms   : 191.94kB / 187.34kB -- 0.98% 👍🏻
  lazy_or             250   1.695ms   / 1.354ms   : 147.49kB / 184.62kB -- 1.25% ⚡
  or_inplace          390   1.481ms   / 1.525ms   : 0.26MB   / 255.69kB -- 0.97% 👍🏻
  and_inplace         60    470.2us   / 712.47us  : 127.61kB / 84.21kB  -- 0.66% 🥔
  is_subset           180   1.463ms   / 1.355ms   : 122.95kB / 132.76kB -- 1.08% ⚡
  or_many             130   7.057ms   / 14.313ms  : 18.42kB  / 9.08kB   -- 0.49% 🥔
  clear               240   282.57us  / 186.71us  : 0.85MB   / 1.29MB   -- 1.51% ⚡
  run_optimize        365   749.321us / 1.361ms   : 0.49MB   / 0.27MB   -- 0.55% 🥔
  shrink_to_fit       330   256.8us   / 376.96us  : 1.29MB   / 0.88MB   -- 0.68% 🥔
  portable_serialize  105   212.59us  / 171.86us  : 0.49MB   / 0.61MB   -- 1.24% ⚡
  frozen_serialize    85    45.3us    / 45.83us   : 1.88MB   / 1.85MB   -- 0.99% 👍🏻
  equals              30    16.73us   / 17.12us   : 1.79MB   / 1.75MB   -- 0.98% 👍🏻
  minimum             790   437.54us  / 430.331us : 1.81MB   / 1.84MB   -- 1.02% 👍🏻
  maximum             810   478.36us  / 485.8us   : 1.69MB   / 1.67MB   -- 0.98% 👍🏻
  rank                25    15.72us   / 15.93us   : 1.59MB   / 1.57MB   -- 0.99% 👍🏻
  select              30    19.21us   / 19.38us   : 1.56MB   / 1.55MB   -- 0.99% 👍🏻
  contains            820   470.3us   / 464.51us  : 1.74MB   / 1.77MB   -- 1.01% 👍🏻
  contains_range      770   454.13us  / 447.7us   : 1.70MB   / 1.72MB   -- 1.01% 👍🏻
  and_cardinality     40    68.94us   / 58.33us   : 0.58MB   / 0.69MB   -- 1.18% ⚡
  or_cardinality      45    79.65us   / 72.08us   : 0.56MB   / 0.62MB   -- 1.11% ⚡
  xor_cardinality     35    59.53us   / 55.48us   : 0.59MB   / 0.63MB   -- 1.07% ⚡
  andnot_cardinality  20    32.99us   / 29.09us   : 0.61MB   / 0.69MB   -- 1.13% ⚡
  jaccard_index       40    67.08us   / 59.25us   : 0.60MB   / 0.68MB   -- 1.13% ⚡
  range_cardinality   5     3.43us    / 3.29us    : 1.46MB   / 1.52MB   -- 1.04% 👍🏻
With `-Dcpu=baseline`:
$ zig build bench -Doptimize=ReleaseFast -Dcpu=baseline
--------------------------------------------------------------------------------
totals:
--------------------------------------------------------------------------------
ops: 2461
CRoaring: 34.548ms     71.23kB ops/sec
ZRoaring: 52.118ms     47.22kB ops/sec                            ratio -- 0.66% 🥔

--------------------------------------------------------------------------------
individual ops (speed=ops/sec)
--------------------------------------------------------------------------------
  op                  count cr time   / zr time   : cr speed / zr speed -- ratio
--------------------------------------------------------------------------------
  add                 2200  1.329ms   / 1.352ms   : 1.65MB   / 1.63MB   -- 0.98% 👍🏻
  add_many            915   873.56us  / 822.73us  : 1.05MB   / 1.11MB   -- 1.06% ⚡
  add_range_closed    1545  1.533ms   / 1.65ms    : 1.01MB   / 0.94MB   -- 0.93% 🥔
  remove              630   382.09us  / 381.1us   : 1.65MB   / 1.65MB   -- 1.00% 👍🏻
  and                 420   1.459ms   / 1.815ms   : 0.29MB   / 231.38kB -- 0.80% 🥔
  or                  305   1.771ms   / 2.865ms   : 172.20kB / 106.43kB -- 0.62% 🥔
  xor                 375   2.759ms   / 5.014ms   : 135.88kB / 74.78kB  -- 0.55% 🥔
  andnot              320   1.675ms   / 2.215ms   : 191.01kB / 144.45kB -- 0.76% 🥔
  lazy_or             250   1.714ms   / 2.066ms   : 145.85kB / 120.95kB -- 0.83% 🥔
  or_inplace          390   1.491ms   / 2.5ms     : 261.43kB / 155.98kB -- 0.60% 🥔
  and_inplace         60    463.4us   / 1.378ms   : 129.48kB / 43.53kB  -- 0.34% 🥔
  is_subset           180   1.462ms   / 1.344ms   : 123.06kB / 133.89kB -- 1.09% ⚡
  or_many             130   7.152ms   / 17.203ms  : 18.18kB  / 7.56kB   -- 0.42% 🥔
  clear               240   274.68us  / 184.73us  : 0.87MB   / 1.30MB   -- 1.49% ⚡
  run_optimize        365   966.921us / 1.79ms    : 0.38MB   / 203.87kB -- 0.54% 🥔
  shrink_to_fit       330   255.29us  / 371.62us  : 1.29MB   / 0.89MB   -- 0.69% 🥔
  portable_serialize  105   211.99us  / 165.93us  : 0.50MB   / 0.63MB   -- 1.28% ⚡
  frozen_serialize    85    45.35us   / 44.72us   : 1.87MB   / 1.90MB   -- 1.01% 👍🏻
  equals              30    15.99us   / 20.34us   : 1.88MB   / 1.47MB   -- 0.79% 🥔
  minimum             790   422.531us / 418.61us  : 1.87MB   / 1.89MB   -- 1.01% 👍🏻
  maximum             810   463.12us  / 468.5us   : 1.75MB   / 1.73MB   -- 0.99% 👍🏻
  rank                25    15.34us   / 15.04us   : 1.63MB   / 1.66MB   -- 1.02% 👍🏻
  select              30    19.8us    / 18.6us    : 1.52MB   / 1.61MB   -- 1.06% ⚡
  contains            820   457.83us  / 449.161us : 1.79MB   / 1.83MB   -- 1.02% 👍🏻
  contains_range      770   437.39us  / 435.021us : 1.76MB   / 1.77MB   -- 1.01% 👍🏻
  and_cardinality     40    76.99us   / 87.66us   : 0.52MB   / 0.46MB   -- 0.88% 🥔
  or_cardinality      45    93.76us   / 128.79us  : 0.48MB   / 0.35MB   -- 0.73% 🥔
  xor_cardinality     35    57us      / 197.16us  : 0.61MB   / 177.52kB -- 0.29% 🥔
  andnot_cardinality  20    34.58us   / 37.99us   : 0.58MB   / 0.53MB   -- 0.91% 🥔
  jaccard_index       40    65.73us   / 112.25us  : 0.61MB   / 0.36MB   -- 0.59% 🥔
  range_cardinality   5     3.34us    / 3.24us    : 1.50MB   / 1.54MB   -- 1.03% 👍🏻

Updated benchmarks show a small improvement from last time. Notable benchmarking change: last time was only a single pass: croaring, zroaring. Now were doing 5 loops of croaring, zroaring. This seems to be a little more stable, maybe negating some variation from warmup. Also, the bench output is a little more concise and hopefully easier to read.

@xsawyerx I’m hoping we’re competitive with CRoaring in your benchmark as and_inplace has improved since last time along with some other general stuff. Curious to hear how it goes.

Of course, stills lots of room for improvement. Currently we’re seeing a big slowdown due to excessive copies needed with our flat layout. I’m leaning towards moving block storage into a separate allocation to avoid that or something.

$ zig build bench -Doptimize=ReleaseFast (+avx2)

--------------------------------------------------
overall:
--------------------------------------------------
CRoaring: 11430 ops 24.22ms    0.47MB ops/sec
ZRoaring: 11430 ops 30.484ms   0.37MB ops/sec

                                  ratio -- 0.79 🥔

--------------------------------------------------
individual ops: speed=ops/sec
--------------------------------------------------
op                 cr speed zr speed #    ratio
--------------------------------------------------
clear              1.45MB   29.70MB  240  20.43 ⚡
run_optimize       0.54MB   0.52MB   365  0.97  👍🏻
shrink_to_fit      3.39MB   0.59MB   330  0.17  💩
portable_serialize 0.57MB   0.83MB   105  1.46  ⚡
frozen_serialize   1.99MB   2.07MB   85   1.04  👍🏻
minimum            31.89MB  32.03MB  580  1.00  👍🏻
maximum            13.85MB  6.20MB   585  0.45  💩
add                10.59MB  9.65MB   2200 0.91  🥔
rank               8.33MB   9.06MB   25   1.09  ⚡
select             6.29MB   7.18MB   30   1.14  ⚡
contains           20.42MB  21.49MB  580  1.05  👍🏻
add_many           2.23MB   2.55MB   915  1.14  ⚡
add_range_closed   2.10MB   1.93MB   1545 0.92  🥔
contains_range     15.31MB  15.76MB  570  1.03  👍🏻
range_cardinality  5.95MB   5.62MB   5    0.94  👍🏻
remove             9.13MB   10.94MB  630  1.20  ⚡
and                0.31MB   0.30MB   420  0.97  👍🏻
or                 169.45kB 154.90kB 305  0.91  🥔
xor                132.78kB 85.77kB  375  0.65  💩
andnot             180.07kB 0.29MB   320  1.63  ⚡
lazy_or            135.95kB 217.75kB 250  1.60  ⚡
or_inplace         0.26MB   0.30MB   390  1.13  ⚡
and_inplace        123.48kB 137.54kB 60   1.11  ⚡
is_subset          114.96kB 135.10kB 180  1.18  ⚡
equals             23.44MB  5.81MB   30   0.25  💩
and_cardinality    0.65MB   0.95MB   40   1.47  ⚡
or_cardinality     0.67MB   0.89MB   45   1.32  ⚡
xor_cardinality    0.80MB   0.93MB   35   1.16  ⚡
andnot_cardinality 0.69MB   1.02MB   20   1.47  ⚡
jaccard_index      0.74MB   0.98MB   40   1.33  ⚡
or_many            16.76kB  9.39kB   130  0.56  💩
$ zig build bench -Doptimize=ReleaseFast -Dcpu=baseline
$ zig build bench -Doptimize=ReleaseFast -Dcpu=baseline
--------------------------------------------------
overall:
--------------------------------------------------
CRoaring: 11430 ops 22.374ms   0.51MB ops/sec
ZRoaring: 11430 ops 35.516ms   0.32MB ops/sec

                                  ratio -- 0.63 💩

--------------------------------------------------
individual ops: speed=ops/sec
--------------------------------------------------
op                 cr speed zr speed #    ratio
--------------------------------------------------
clear              1.63MB   34.99MB  240  21.48 ⚡
run_optimize       0.46MB   0.30MB   365  0.64  💩
shrink_to_fit      4.03MB   0.49MB   330  0.12  💩
portable_serialize 0.62MB   0.90MB   105  1.45  ⚡
frozen_serialize   2.16MB   2.11MB   85   0.97  👍🏻
minimum            34.81MB  26.13MB  580  0.75  🥔
maximum            15.42MB  12.23MB  585  0.79  🥔
add                11.70MB  10.20MB  2200 0.87  🥔
rank               10.08MB  3.90MB   25   0.39  💩
select             8.20MB   7.48MB   30   0.91  🥔
contains           19.84MB  22.88MB  580  1.15  ⚡
add_many           2.20MB   2.66MB   915  1.21  ⚡
add_range_closed   2.22MB   1.83MB   1545 0.82  🥔
contains_range     16.75MB  14.87MB  570  0.89  🥔
range_cardinality  5.49MB   5.26MB   5    0.96  👍🏻
remove             11.91MB  10.89MB  630  0.91  🥔
and                0.34MB   259.04kB 420  0.75  🥔
or                 189.05kB 149.53kB 305  0.79  🥔
xor                138.71kB 90.40kB  375  0.65  💩
andnot             211.24kB 210.12kB 320  0.99  👍🏻
lazy_or            155.90kB 145.39kB 250  0.93  👍🏻
or_inplace         0.31MB   174.97kB 390  0.57  💩
and_inplace        134.57kB 56.37kB  60   0.42  💩
is_subset          129.18kB 148.41kB 180  1.15  ⚡
equals             24.59MB  22.39MB  30   0.91  🥔
and_cardinality    0.38MB   0.58MB   40   1.54  ⚡
or_cardinality     0.57MB   0.45MB   45   0.78  🥔
xor_cardinality    0.88MB   192.50kB 35   0.22  💩
andnot_cardinality 0.81MB   0.76MB   20   0.93  👍🏻
jaccard_index      0.87MB   0.44MB   40   0.50  💩
or_many            17.79kB  8.38kB   130  0.47  💩
1 Like

I finally got around to writing the adapter to benchmark both,

Here’s what I got for you, using commit ID 5dd51c27b247a08e32a759d865788df7b6b6fb39:

It’s producing identical blob bytes (7,132,323), identical profile counters (postings, candidate sets after text/tag/date) on every query variant (CRoaring/ZRoaring). So hey, it’s a proper drop-in replacement in accuracy!

Working on 50K docs, 1K queries:

metric        | CRoaring | ZRoaring
------        | -------- | --------
build         | 588 ms   | 592 ms
deserialize   | 557 ms   | 586 ms
common text   | 266 ms   | 226 ms <- Yay
rare text     | 3.72 ms  | 3.73 ms
date only     | 203 ms   | 224 ms
text+tag+date | 205 ms   | 182 ms <- Yay

This is also just single run, so.. not the most accurate. For proper benchmarking comparison, I’ll need initial runs, multiple runs of the test, removing outliers, aiming for accuracy level, etc. Too lazy to do that right now, sorry.

Some issues with wasm32. I’ll try to provide a patch for that upstream. I was able to get it to build (but I want to clean it up before submitting it upstream), and CRoaring 91KB, ZRoaring 124KB. (Not sure how much it matters.)

Glad to hear a positive report about correctness. And the benchmark looks similar to what I’ve been seeing.

I’m not surprised wasm32 didn’t build. I haven’t tried any wasm builds yet. Patch would be appreciated! Is 124KB a release fast build? Maybe we can try to get the size down somehow.

No worries about less than ideal benchmarks. Glad to hear a report. I know the one i’ve been sharing has room for improvement too.

I’ve made more progress on benchmarks today. Around 90% of CRoaring’s overall speed now locally by keeping blocks in a separate allocation. So the longer you put off your benchmarking gives me more time to fix my code :slight_smile:.

1 Like