Coverage Report

Created: 2026-09-01 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/croaring/cpp/roaring/roaring.hh
Line
Count
Source
1
/*
2
A C++ header for Roaring Bitmaps.
3
*/
4
#ifndef INCLUDE_ROARING_HH_
5
#define INCLUDE_ROARING_HH_
6
7
#include <algorithm>
8
#include <cstdarg>
9
#include <initializer_list>
10
#include <limits>
11
#include <new>
12
#include <stdexcept>
13
#include <string>
14
15
#if !defined(ROARING_EXCEPTIONS)
16
// We assume that if __cpp_exceptions is given a positive integer
17
// value, then exceptions are enabled.
18
#if __cpp_exceptions
19
#define ROARING_EXCEPTIONS 1
20
#else
21
#define ROARING_EXCEPTIONS 0
22
#endif
23
#endif
24
25
#ifndef ROARING_TERMINATE
26
#if ROARING_EXCEPTIONS
27
6.23k
#define ROARING_TERMINATE(_s) throw std::runtime_error(_s)
28
#else
29
#define ROARING_TERMINATE(_s) std::terminate()
30
#endif
31
#endif
32
33
#define ROARING_API_NOT_IN_GLOBAL_NAMESPACE  // see remarks in roaring.h
34
#include <roaring/roaring.h>
35
#undef ROARING_API_NOT_IN_GLOBAL_NAMESPACE
36
37
#include <roaring/roaring_array.h>  // roaring::internal array functions used
38
39
namespace roaring {
40
41
class RoaringSetBitBiDirectionalIterator;
42
43
/** DEPRECATED, use `RoaringSetBitBiDirectionalIterator`. */
44
using RoaringSetBitForwardIterator = RoaringSetBitBiDirectionalIterator;
45
46
/**
47
 * A bit of context usable with `*Bulk()` functions.
48
 *
49
 * A context may only be used with a single bitmap, and any modification to a
50
 * bitmap (other than modifications performed with `Bulk()` functions with the
51
 * context passed) will invalidate any contexts associated with that bitmap.
52
 */
53
class BulkContext {
54
   public:
55
    friend class Roaring;
56
    using roaring_bitmap_bulk_context_t = api::roaring_bulk_context_t;
57
0
    BulkContext() : context_{nullptr, 0, 0, 0} {}
58
59
    BulkContext(const BulkContext &) = delete;
60
    BulkContext &operator=(const BulkContext &) = delete;
61
    BulkContext(BulkContext &&) noexcept = default;
62
    BulkContext &operator=(BulkContext &&) noexcept = default;
63
64
   private:
65
    roaring_bitmap_bulk_context_t context_;
66
};
67
68
class Roaring {
69
    typedef api::roaring_bitmap_t roaring_bitmap_t;  // class-local name alias
70
71
   public:
72
    /**
73
     * Create an empty bitmap in the existing memory for the class.
74
     * The bitmap will be in the "clear" state with no auxiliary allocations.
75
     */
76
18.7k
    Roaring() : roaring{} {
77
        // The empty constructor roaring{} silences warnings from pedantic
78
        // static analyzers.
79
18.7k
        api::roaring_bitmap_init_cleared(&roaring);
80
18.7k
    }
81
82
    /**
83
     * Construct a bitmap from a list of 32-bit integer values.
84
     */
85
12.4k
    Roaring(size_t n, const uint32_t *data) : Roaring() {
86
12.4k
        api::roaring_bitmap_add_many(&roaring, n, data);
87
12.4k
    }
88
89
    /**
90
     * Construct a bitmap from an initializer list.
91
     */
92
0
    Roaring(std::initializer_list<uint32_t> l) : Roaring() {
93
0
        addMany(l.size(), l.begin());
94
0
    }
95
96
    /**
97
     * Construct a roaring object by taking control of a malloc()'d C struct.
98
     *
99
     * Passing a NULL pointer is unsafe.
100
     * The pointer to the C struct will be invalid after the call.
101
     */
102
31.2k
    explicit Roaring(roaring_bitmap_t *s) noexcept : roaring(*s) {
103
31.2k
        roaring_free(s);  // deallocate the passed-in pointer
104
31.2k
    }
105
106
    /**
107
     * Copy constructor.
108
     * It may throw std::runtime_error if there is insufficient memory.
109
     */
110
6.24k
    Roaring(const Roaring &r) : Roaring() {
111
6.24k
        if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
112
0
            ROARING_TERMINATE("failed roaring_bitmap_overwrite in constructor");
113
0
        }
114
6.24k
        api::roaring_bitmap_set_copy_on_write(
115
6.24k
            &roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
116
6.24k
    }
117
118
    /**
119
     * Move constructor. The moved-from object remains valid but empty, i.e.
120
     * it behaves as though it was just freshly constructed.
121
     */
122
6.24k
    Roaring(Roaring &&r) noexcept : roaring(r.roaring) {
123
        //
124
        // !!! This clones the bits of the roaring structure to a new location
125
        // and then overwrites the old bits...assuming that this will still
126
        // work.  There are scenarios where this could break; e.g. if some of
127
        // those bits were pointers into the structure memory itself.  If such
128
        // things were possible, a roaring_bitmap_move() API would be needed.
129
        //
130
6.24k
        api::roaring_bitmap_init_cleared(&r.roaring);
131
6.24k
    }
132
133
    /**
134
     * Construct a bitmap from a list of uint32_t values.
135
     */
136
0
    static Roaring bitmapOf(size_t n, ...) {
137
0
        Roaring ans;
138
0
        va_list vl;
139
0
        va_start(vl, n);
140
0
        for (size_t i = 0; i < n; i++) {
141
0
            ans.add(va_arg(vl, uint32_t));
142
0
        }
143
0
        va_end(vl);
144
0
        return ans;
145
0
    }
146
147
    /**
148
     * Copies the content of the provided bitmap, and
149
     * discard the current content.
150
     * It may throw std::runtime_error if there is insufficient memory.
151
     */
152
6.24k
    Roaring &operator=(const Roaring &r) {
153
6.24k
        if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
154
0
            ROARING_TERMINATE("failed memory alloc in assignment");
155
0
        }
156
6.24k
        api::roaring_bitmap_set_copy_on_write(
157
6.24k
            &roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
158
6.24k
        return *this;
159
6.24k
    }
160
161
    /**
162
     * Moves the content of the provided bitmap, and
163
     * discard the current content.
164
     */
165
6.24k
    Roaring &operator=(Roaring &&r) noexcept {
166
6.24k
        api::roaring_bitmap_clear(&roaring);  // free this class's allocations
167
168
        // !!! See notes in the Move Constructor regarding roaring_bitmap_move()
169
        //
170
6.24k
        roaring = r.roaring;
171
6.24k
        api::roaring_bitmap_init_cleared(&r.roaring);
172
173
6.24k
        return *this;
174
6.24k
    }
175
176
    /**
177
     * Assignment from an initializer list.
178
     */
179
0
    Roaring &operator=(std::initializer_list<uint32_t> l) {
180
0
        // Delegate to move assignment operator
181
0
        *this = Roaring(l);
182
0
        return *this;
183
0
    }
184
185
    /**
186
     * Construct a bitmap from a list of uint32_t values.
187
     * E.g., bitmapOfList({1,2,3}).
188
     */
189
0
    static Roaring bitmapOfList(std::initializer_list<uint32_t> l) {
190
0
        Roaring ans;
191
0
        ans.addMany(l.size(), l.begin());
192
0
        return ans;
193
0
    }
194
195
    /**
196
     * Add value x
197
     */
198
6.24k
    void add(uint32_t x) noexcept { api::roaring_bitmap_add(&roaring, x); }
199
200
    /**
201
     * Add value x
202
     * Returns true if a new value was added, false if the value was already
203
     * existing.
204
     */
205
6.24k
    bool addChecked(uint32_t x) noexcept {
206
6.24k
        return api::roaring_bitmap_add_checked(&roaring, x);
207
6.24k
    }
208
209
    /**
210
     * Add all values in range [min, max)
211
     */
212
6.24k
    void addRange(const uint64_t min, const uint64_t max) noexcept {
213
6.24k
        return api::roaring_bitmap_add_range(&roaring, min, max);
214
6.24k
    }
215
216
    /**
217
     * Add all values in range [min, max]
218
     */
219
0
    void addRangeClosed(const uint32_t min, const uint32_t max) noexcept {
220
0
        return api::roaring_bitmap_add_range_closed(&roaring, min, max);
221
0
    }
222
223
    /**
224
     * Add value n_args from pointer vals
225
     */
226
6.24k
    void addMany(size_t n_args, const uint32_t *vals) noexcept {
227
6.24k
        api::roaring_bitmap_add_many(&roaring, n_args, vals);
228
6.24k
    }
229
230
    /**
231
     * Add value val, using context from a previous insert for speed
232
     * optimization.
233
     *
234
     * `context` will be used to store information between calls to make bulk
235
     * operations faster. `context` should be default-initialized before the
236
     * first call to this function.
237
     */
238
0
    void addBulk(BulkContext &context, uint32_t x) noexcept {
239
0
        api::roaring_bitmap_add_bulk(&roaring, &context.context_, x);
240
0
    }
241
242
    /**
243
     * Check if item x is present, using context from a previous insert or
244
     * search for speed optimization.
245
     *
246
     * `context` will be used to store information between calls to make bulk
247
     * operations faster. `context` should be default-initialized before the
248
     * first call to this function.
249
     */
250
0
    bool containsBulk(BulkContext &context, uint32_t x) const noexcept {
251
0
        return api::roaring_bitmap_contains_bulk(&roaring, &context.context_,
252
0
                                                 x);
253
0
    }
254
255
    /**
256
     * Remove value x
257
     */
258
6.24k
    void remove(uint32_t x) noexcept {
259
6.24k
        api::roaring_bitmap_remove(&roaring, x);
260
6.24k
    }
261
262
    /**
263
     * Remove value x
264
     * Returns true if a new value was removed, false if the value was not
265
     * existing.
266
     */
267
6.24k
    bool removeChecked(uint32_t x) noexcept {
268
6.24k
        return api::roaring_bitmap_remove_checked(&roaring, x);
269
6.24k
    }
270
271
    /**
272
     * Remove all values in range [min, max)
273
     */
274
6.24k
    void removeRange(uint64_t min, uint64_t max) noexcept {
275
6.24k
        return api::roaring_bitmap_remove_range(&roaring, min, max);
276
6.24k
    }
277
278
    /**
279
     * Remove all values in range [min, max]
280
     */
281
6.24k
    void removeRangeClosed(uint32_t min, uint32_t max) noexcept {
282
6.24k
        return api::roaring_bitmap_remove_range_closed(&roaring, min, max);
283
6.24k
    }
284
285
    /**
286
     * Keep only values in the half-open interval [min, max).
287
     * Equivalent to two consecutive removeRange calls.
288
     */
289
0
    void mask(uint64_t min, uint64_t max) noexcept {
290
0
        removeRange(0, min);
291
0
        if (!isEmpty()) {
292
0
            removeRange(max, (uint64_t)maximum() + 1);
293
0
        }
294
0
    }
295
296
    /**
297
     * Keep only values in the closed interval [min, max].
298
     * Equivalent to two consecutive removeRangeClosed calls.
299
     */
300
0
    void maskClosed(uint32_t min, uint32_t max) noexcept {
301
0
        if (min > 0) removeRangeClosed(0, min - 1);
302
0
        if (!isEmpty() && max < maximum()) {
303
0
            removeRangeClosed(max + 1, maximum());
304
0
        }
305
0
    }
306
307
    /**
308
     * Clears the bitmap.
309
     */
310
0
    void clear() { api::roaring_bitmap_clear(&roaring); }
311
312
    /**
313
     * Returns the greatest value in the set, or 0 if the set is empty.
314
     */
315
6.24k
    uint32_t maximum() const noexcept {
316
6.24k
        return api::roaring_bitmap_maximum(&roaring);
317
6.24k
    }
318
319
    /**
320
     * Returns the smallest value in the set, or UINT32_MAX if the set is empty.
321
     */
322
6.24k
    uint32_t minimum() const noexcept {
323
6.24k
        return api::roaring_bitmap_minimum(&roaring);
324
6.24k
    }
325
326
    /**
327
     * Check if value x is present
328
     */
329
6.24k
    bool contains(uint32_t x) const noexcept {
330
6.24k
        return api::roaring_bitmap_contains(&roaring, x);
331
6.24k
    }
332
333
    /**
334
     * Check if all values from x (included) to y (excluded) are present
335
     */
336
6.24k
    bool containsRange(const uint64_t x, const uint64_t y) const noexcept {
337
6.24k
        return api::roaring_bitmap_contains_range(&roaring, x, y);
338
6.24k
    }
339
340
    /**
341
     * Check if all values from x (included) to y (included) are present.
342
     */
343
    bool containsRangeClosed(const uint32_t x,
344
0
                             const uint32_t y) const noexcept {
345
0
        return api::roaring_bitmap_contains_range_closed(&roaring, x, y);
346
0
    }
347
348
    /**
349
     * Compute the intersection between the current bitmap and the provided
350
     * bitmap, writing the result in the current bitmap. The provided bitmap
351
     * is not modified.
352
     *
353
     * Performance hint: if you are computing the intersection between several
354
     * bitmaps, two-by-two, it is best to start with the smallest bitmap.
355
     */
356
6.24k
    Roaring &operator&=(const Roaring &r) noexcept {
357
6.24k
        api::roaring_bitmap_and_inplace(&roaring, &r.roaring);
358
6.24k
        return *this;
359
6.24k
    }
360
361
    /**
362
     * Compute the difference between the current bitmap and the provided
363
     * bitmap, writing the result in the current bitmap. The provided bitmap
364
     * is not modified.
365
     */
366
6.24k
    Roaring &operator-=(const Roaring &r) noexcept {
367
6.24k
        api::roaring_bitmap_andnot_inplace(&roaring, &r.roaring);
368
6.24k
        return *this;
369
6.24k
    }
370
371
    /**
372
     * Compute the union between the current bitmap and the provided bitmap,
373
     * writing the result in the current bitmap. The provided bitmap is not
374
     * modified.
375
     *
376
     * See also the fastunion function to aggregate many bitmaps more quickly.
377
     */
378
6.24k
    Roaring &operator|=(const Roaring &r) noexcept {
379
6.24k
        api::roaring_bitmap_or_inplace(&roaring, &r.roaring);
380
6.24k
        return *this;
381
6.24k
    }
382
383
    /**
384
     * Compute the symmetric union between the current bitmap and the provided
385
     * bitmap, writing the result in the current bitmap. The provided bitmap
386
     * is not modified.
387
     */
388
6.24k
    Roaring &operator^=(const Roaring &r) noexcept {
389
6.24k
        api::roaring_bitmap_xor_inplace(&roaring, &r.roaring);
390
6.24k
        return *this;
391
6.24k
    }
392
393
    /**
394
     * Exchange the content of this bitmap with another.
395
     */
396
0
    void swap(Roaring &r) noexcept { std::swap(r.roaring, roaring); }
397
398
    /**
399
     * Get the cardinality of the bitmap (number of elements).
400
     */
401
6.24k
    uint64_t cardinality() const noexcept {
402
6.24k
        return api::roaring_bitmap_get_cardinality(&roaring);
403
6.24k
    }
404
405
    /**
406
     * Returns true if the bitmap is empty (cardinality is zero).
407
     */
408
12.4k
    bool isEmpty() const noexcept {
409
12.4k
        return api::roaring_bitmap_is_empty(&roaring);
410
12.4k
    }
411
412
    /**
413
     * Returns true if the bitmap is full (cardinality is uint32_t max + 1).
414
     * we put std::numeric_limits<>::max/min in parentheses
415
     * to avoid a clash with the Windows.h header under Windows.
416
     */
417
0
    bool isFull() const noexcept {
418
0
        return api::roaring_bitmap_get_cardinality(&roaring) ==
419
0
               ((uint64_t)(std::numeric_limits<uint32_t>::max)()) + 1;
420
0
    }
421
422
    /**
423
     * Returns true if the bitmap is subset of the other.
424
     */
425
6.24k
    bool isSubset(const Roaring &r) const noexcept {
426
6.24k
        return api::roaring_bitmap_is_subset(&roaring, &r.roaring);
427
6.24k
    }
428
429
    /**
430
     * Returns true if the bitmap is strict subset of the other.
431
     */
432
6.24k
    bool isStrictSubset(const Roaring &r) const noexcept {
433
6.24k
        return api::roaring_bitmap_is_strict_subset(&roaring, &r.roaring);
434
6.24k
    }
435
436
    /**
437
     * Convert the bitmap to an array. Write the output to "ans", caller is
438
     * responsible to ensure that there is enough memory allocated
439
     * (e.g., ans = new uint32[mybitmap.cardinality()];)
440
     */
441
6.24k
    void toUint32Array(uint32_t *ans) const noexcept {
442
6.24k
        api::roaring_bitmap_to_uint32_array(&roaring, ans);
443
6.24k
    }
444
    /**
445
     * Write to "ans" a sorted slice of the bitmap's values: skip the first
446
     * "offset" values and copy up to "limit" of the values that follow. This
447
     * is the paginated form of toUint32Array(). The caller must ensure that
448
     * "ans" has room for at least "limit" values.
449
     */
450
    void rangeUint32Array(uint32_t *ans, size_t offset,
451
0
                          size_t limit) const noexcept {
452
0
        api::roaring_bitmap_range_uint32_array(&roaring, offset, limit, ans);
453
0
    }
454
455
    /**
456
     * Return true if the two bitmaps contain the same elements.
457
     */
458
12.4k
    bool operator==(const Roaring &r) const noexcept {
459
12.4k
        return api::roaring_bitmap_equals(&roaring, &r.roaring);
460
12.4k
    }
461
462
    /**
463
     * Compute the negation of the roaring bitmap within the half-open interval
464
     * [range_start, range_end). Areas outside the interval are unchanged.
465
     */
466
6.24k
    void flip(uint64_t range_start, uint64_t range_end) noexcept {
467
6.24k
        api::roaring_bitmap_flip_inplace(&roaring, range_start, range_end);
468
6.24k
    }
469
470
    /**
471
     * Compute the negation of the roaring bitmap within the closed interval
472
     * [range_start, range_end]. Areas outside the interval are unchanged.
473
     */
474
6.24k
    void flipClosed(uint32_t range_start, uint32_t range_end) noexcept {
475
6.24k
        api::roaring_bitmap_flip_inplace_closed(&roaring, range_start,
476
6.24k
                                                range_end);
477
6.24k
    }
478
479
    /**
480
     * Remove run-length encoding even when it is more space efficient.
481
     * Return whether a change was applied.
482
     */
483
6.24k
    bool removeRunCompression() noexcept {
484
6.24k
        return api::roaring_bitmap_remove_run_compression(&roaring);
485
6.24k
    }
486
487
    /**
488
     * Convert array and bitmap containers to run containers when it is more
489
     * efficient; also convert from run containers when more space efficient.
490
     * Returns true if the result has at least one run container.  Additional
491
     * savings might be possible by calling shrinkToFit().
492
     */
493
12.4k
    bool runOptimize() noexcept {
494
12.4k
        return api::roaring_bitmap_run_optimize(&roaring);
495
12.4k
    }
496
497
    /**
498
     * If needed, reallocate memory to shrink the memory usage. Returns
499
     * the number of bytes saved.
500
     */
501
6.24k
    size_t shrinkToFit() noexcept {
502
6.24k
        return api::roaring_bitmap_shrink_to_fit(&roaring);
503
6.24k
    }
504
505
    /**
506
     * Iterate over the bitmap elements. The function iterator is called once
507
     * for all the values with ptr (can be NULL) as the second parameter of
508
     * each call.
509
     *
510
     * roaring_iterator is simply a pointer to a function that returns bool
511
     * (true means that the iteration should continue while false means that it
512
     * should stop), and takes (uint32_t,void*) as inputs.
513
     */
514
6.23k
    void iterate(api::roaring_iterator iterator, void *ptr) const {
515
6.23k
        api::roaring_iterate(&roaring, iterator, ptr);
516
6.23k
    }
517
518
    /**
519
     * Selects the value at index rnk in the bitmap, where the smallest value
520
     * is at index 0.
521
     *
522
     * If the size of the roaring bitmap is strictly greater than rank, then
523
     * this function returns true and sets element to the element of given rank.
524
     * Otherwise, it returns false.
525
     */
526
6.24k
    bool select(uint32_t rnk, uint32_t *element) const noexcept {
527
6.24k
        return api::roaring_bitmap_select(&roaring, rnk, element);
528
6.24k
    }
529
530
    /**
531
     * Computes the size of the intersection between two bitmaps.
532
     */
533
0
    uint64_t and_cardinality(const Roaring &r) const noexcept {
534
0
        return api::roaring_bitmap_and_cardinality(&roaring, &r.roaring);
535
0
    }
536
537
    /**
538
     * Check whether the two bitmaps intersect.
539
     */
540
6.24k
    bool intersect(const Roaring &r) const noexcept {
541
6.24k
        return api::roaring_bitmap_intersect(&roaring, &r.roaring);
542
6.24k
    }
543
544
    /**
545
     * Computes the Jaccard index between two bitmaps. (Also known as the
546
     * Tanimoto distance,
547
     * or the Jaccard similarity coefficient)
548
     *
549
     * The Jaccard index is undefined if both bitmaps are empty.
550
     */
551
6.24k
    double jaccard_index(const Roaring &r) const noexcept {
552
6.24k
        return api::roaring_bitmap_jaccard_index(&roaring, &r.roaring);
553
6.24k
    }
554
555
    /**
556
     * Computes the size of the union between two bitmaps.
557
     */
558
6.24k
    uint64_t or_cardinality(const Roaring &r) const noexcept {
559
6.24k
        return api::roaring_bitmap_or_cardinality(&roaring, &r.roaring);
560
6.24k
    }
561
562
    /**
563
     * Computes the size of the difference (andnot) between two bitmaps.
564
     */
565
6.24k
    uint64_t andnot_cardinality(const Roaring &r) const noexcept {
566
6.24k
        return api::roaring_bitmap_andnot_cardinality(&roaring, &r.roaring);
567
6.24k
    }
568
569
    /**
570
     * Computes the size of the symmetric difference (andnot) between two
571
     * bitmaps.
572
     */
573
6.24k
    uint64_t xor_cardinality(const Roaring &r) const noexcept {
574
6.24k
        return api::roaring_bitmap_xor_cardinality(&roaring, &r.roaring);
575
6.24k
    }
576
577
    /**
578
     * Returns the number of integers that are smaller or equal to x.
579
     * Thus the rank of the smallest element is one.  If
580
     * x is smaller than the smallest element, this function will return 0.
581
     * The rank and select functions differ in convention: this function returns
582
     * 1 when ranking the smallest value, but the select function returns the
583
     * smallest value when using index 0.
584
     */
585
6.24k
    uint64_t rank(uint32_t x) const noexcept {
586
6.24k
        return api::roaring_bitmap_rank(&roaring, x);
587
6.24k
    }
588
589
    /**
590
     * Get `rank()` values in bulk. The values in `[begin .. end)` must be in
591
     * Ascending order. possible implementation: for(auto* iter = begin; iter !=
592
     * end; ++iter) *(ans++) = rank(*iter);
593
     */
594
    void rank_many(const uint32_t *begin, const uint32_t *end,
595
0
                   uint64_t *ans) const noexcept {
596
0
        return api::roaring_bitmap_rank_many(&roaring, begin, end, ans);
597
0
    }
598
599
    /**
600
     * Returns the index of x in the set, index start from 0.
601
     * If the set doesn't contain x , this function will return -1.
602
     * The difference with rank function is that this function will return -1
603
     * when x isn't in the set, but the rank function will return a
604
     * non-negative number.
605
     */
606
0
    int64_t getIndex(uint32_t x) const noexcept {
607
0
        return api::roaring_bitmap_get_index(&roaring, x);
608
0
    }
609
610
    /**
611
     * Write a bitmap to a char buffer. This is meant to be compatible with
612
     * the Java and Go versions. Returns how many bytes were written which
613
     * should be getSizeInBytes().
614
     *
615
     * Setting the portable flag to false enable a custom format that
616
     * can save space compared to the portable format (e.g., for very
617
     * sparse bitmaps).
618
     *
619
     * Boost users can serialize bitmaps in this manner:
620
     *
621
     *       BOOST_SERIALIZATION_SPLIT_FREE(Roaring)
622
     *       namespace boost {
623
     *       namespace serialization {
624
     *
625
     *       template <class Archive>
626
     *       void save(Archive& ar, const Roaring& bitmask,
627
     *          const unsigned int version) {
628
     *         std::size_t expected_size_in_bytes = bitmask.getSizeInBytes();
629
     *         std::vector<char> buffer(expected_size_in_bytes);
630
     *         std::size_t       size_in_bytes = bitmask.write(buffer.data());
631
     *
632
     *         ar& size_in_bytes;
633
     *         ar& boost::serialization::make_binary_object(buffer.data(),
634
     *             size_in_bytes);
635
     *      }
636
     *      template <class Archive>
637
     *      void load(Archive& ar, Roaring& bitmask,
638
     *          const unsigned int version) {
639
     *         std::size_t size_in_bytes = 0;
640
     *         ar& size_in_bytes;
641
     *         std::vector<char> buffer(size_in_bytes);
642
     *         ar&  boost::serialization::make_binary_object(buffer.data(),
643
     *            size_in_bytes);
644
     *         bitmask = Roaring::readSafe(buffer.data(), size_in_bytes);
645
     *      }
646
     *      }  // namespace serialization
647
     *      }  // namespace boost
648
     */
649
6.24k
    size_t write(char *buf, bool portable = true) const noexcept {
650
6.24k
        if (portable) {
651
6.24k
            return api::roaring_bitmap_portable_serialize(&roaring, buf);
652
6.24k
        } else {
653
0
            return api::roaring_bitmap_serialize(&roaring, buf);
654
0
        }
655
6.24k
    }
656
657
    /**
658
     * Read a bitmap from a serialized version. This is meant to be compatible
659
     * with the Java and Go versions.
660
     *
661
     * Setting the portable flag to false enable a custom format that
662
     * can save space compared to the portable format (e.g., for very
663
     * sparse bitmaps).
664
     *
665
     * This function is unsafe in the sense that if you provide bad data,
666
     * many, many bytes could be read. See also readSafe.
667
     *
668
     * The function may throw std::runtime_error if a bitmap could not be read.
669
     * Note that even if it does not throw, the bitmap could still be unusable
670
     * if the loaded data does not match the portable Roaring specification: you
671
     * should ensure that the data you load come from a serialized bitmap.
672
     */
673
0
    static Roaring read(const char *buf, bool portable = true) {
674
0
        roaring_bitmap_t *r =
675
0
            portable ? api::roaring_bitmap_portable_deserialize(buf)
676
0
                     : api::roaring_bitmap_deserialize(buf);
677
0
        if (r == NULL) {
678
0
            ROARING_TERMINATE("failed alloc while reading");
679
0
        }
680
0
        return Roaring(r);
681
0
    }
682
683
    /**
684
     * Read a bitmap from a serialized version, reading no more than maxbytes
685
     * bytes.  This is meant to be compatible with the Java and Go versions.
686
     * The function itself is safe in the sense that it will not cause buffer
687
     * overflows. However, for correct operations, it is assumed that the bitmap
688
     * read was once serialized from a valid bitmap. If you provided an
689
     * incorrect input (garbage), then the bitmap read may not be in a valid
690
     * state and following operations may not lead to sensible results. It is
691
     * your responsability to ensure that the input bytes follow the format
692
     * specification if you want a usable bitmap:
693
     * https://github.com/RoaringBitmap/RoaringFormatSpec
694
     * In particular, the serialized array containers need to be in sorted
695
     * order, and the run containers should be in sorted non-overlapping order.
696
     * This is is guaranteed to happen when serializing an existing bitmap, but
697
     * not for random inputs. Note that this function assumes that your bitmap
698
     * was serialized in *portable* mode (which is the default with the 'write'
699
     * method).
700
     *
701
     * The function may throw std::runtime_error if a bitmap could not be read.
702
     * Note that even if it does not throw, the bitmap could still be unusable
703
     * if the loaded data does not match the portable Roaring specification: you
704
     * should ensure that the data you load come from a serialized bitmap.
705
     */
706
12.4k
    static Roaring readSafe(const char *buf, size_t maxbytes) {
707
12.4k
        roaring_bitmap_t *r =
708
12.4k
            api::roaring_bitmap_portable_deserialize_safe(buf, maxbytes);
709
12.4k
        if (r == NULL) {
710
6.23k
            ROARING_TERMINATE("failed alloc while reading");
711
6.23k
        }
712
6.25k
        return Roaring(r);
713
12.4k
    }
714
715
    /**
716
     * Compute how many bytes would be read by readSafe.  Returns 0 if the
717
     * serialized data is invalid.
718
     * This is meant to be compatible with the Java and Go versions.
719
     */
720
0
    static size_t serializedSizeInBytesSafe(const char *buf, size_t maxbytes) {
721
0
        return api::roaring_bitmap_portable_deserialize_size(buf, maxbytes);
722
0
    }
723
724
    /**
725
     * How many bytes are required to serialize this bitmap (meant to be
726
     * compatible with Java and Go versions)
727
     *
728
     * Setting the portable flag to false enable a custom format that
729
     * can save space compared to the portable format (e.g., for very
730
     * sparse bitmaps).
731
     */
732
12.4k
    size_t getSizeInBytes(bool portable = true) const noexcept {
733
12.4k
        if (portable) {
734
12.4k
            return api::roaring_bitmap_portable_size_in_bytes(&roaring);
735
12.4k
        } else {
736
0
            return api::roaring_bitmap_size_in_bytes(&roaring);
737
0
        }
738
12.4k
    }
739
740
    /**
741
     * For advanced users.
742
     * This function may throw std::runtime_error.
743
     */
744
0
    static Roaring frozenView(const char *buf, size_t length) {
745
0
        const roaring_bitmap_t *s =
746
0
            api::roaring_bitmap_frozen_view(buf, length);
747
0
        if (s == NULL) {
748
0
            ROARING_TERMINATE("failed to read frozen bitmap");
749
0
        }
750
0
        Roaring r;
751
0
        r.roaring = *s;
752
0
        return r;
753
0
    }
754
755
    /**
756
     * For advanced users; see roaring_bitmap_portable_deserialize_frozen.
757
     * This function may throw std::runtime_error.
758
     */
759
0
    static Roaring portableDeserializeFrozen(const char *buf) {
760
0
        const roaring_bitmap_t *s =
761
0
            api::roaring_bitmap_portable_deserialize_frozen(buf);
762
0
        if (s == NULL) {
763
0
            ROARING_TERMINATE("failed to read portable frozen bitmap");
764
0
        }
765
0
        Roaring r;
766
0
        r.roaring = *s;
767
0
        return r;
768
0
    }
769
770
    /**
771
     * For advanced users.
772
     */
773
0
    void writeFrozen(char *buf) const noexcept {
774
0
        roaring_bitmap_frozen_serialize(&roaring, buf);
775
0
    }
776
777
    /**
778
     * For advanced users.
779
     */
780
0
    size_t getFrozenSizeInBytes() const noexcept {
781
0
        return roaring_bitmap_frozen_size_in_bytes(&roaring);
782
0
    }
783
784
    /**
785
     * Computes the intersection between two bitmaps and returns new bitmap.
786
     * The current bitmap and the provided bitmap are unchanged.
787
     *
788
     * Performance hint: if you are computing the intersection between several
789
     * bitmaps, two-by-two, it is best to start with the smallest bitmap.
790
     * Consider also using the operator &= to avoid needlessly creating
791
     * many temporary bitmaps.
792
     * This function may throw std::runtime_error.
793
     */
794
6.24k
    Roaring operator&(const Roaring &o) const {
795
6.24k
        roaring_bitmap_t *r = api::roaring_bitmap_and(&roaring, &o.roaring);
796
6.24k
        if (r == NULL) {
797
0
            ROARING_TERMINATE("failed materialization in and");
798
0
        }
799
6.24k
        return Roaring(r);
800
6.24k
    }
801
802
    /**
803
     * Computes the difference between two bitmaps and returns new bitmap.
804
     * The current bitmap and the provided bitmap are unchanged.
805
     * This function may throw std::runtime_error.
806
     */
807
6.24k
    Roaring operator-(const Roaring &o) const {
808
6.24k
        roaring_bitmap_t *r = api::roaring_bitmap_andnot(&roaring, &o.roaring);
809
6.24k
        if (r == NULL) {
810
0
            ROARING_TERMINATE("failed materialization in andnot");
811
0
        }
812
6.24k
        return Roaring(r);
813
6.24k
    }
814
815
    /**
816
     * Computes the union between two bitmaps and returns new bitmap.
817
     * The current bitmap and the provided bitmap are unchanged.
818
     * This function may throw std::runtime_error.
819
     */
820
6.24k
    Roaring operator|(const Roaring &o) const {
821
6.24k
        roaring_bitmap_t *r = api::roaring_bitmap_or(&roaring, &o.roaring);
822
6.24k
        if (r == NULL) {
823
0
            ROARING_TERMINATE("failed materialization in or");
824
0
        }
825
6.24k
        return Roaring(r);
826
6.24k
    }
827
828
    /**
829
     * Computes the symmetric union between two bitmaps and returns new bitmap.
830
     * The current bitmap and the provided bitmap are unchanged.
831
     * This function may throw std::runtime_error.
832
     */
833
6.24k
    Roaring operator^(const Roaring &o) const {
834
6.24k
        roaring_bitmap_t *r = api::roaring_bitmap_xor(&roaring, &o.roaring);
835
6.24k
        if (r == NULL) {
836
0
            ROARING_TERMINATE("failed materialization in xor");
837
0
        }
838
6.24k
        return Roaring(r);
839
6.24k
    }
840
841
    /**
842
     * Whether or not we apply copy and write.
843
     */
844
0
    void setCopyOnWrite(bool val) noexcept {
845
0
        api::roaring_bitmap_set_copy_on_write(&roaring, val);
846
0
    }
847
848
    /**
849
     * Print the content of the bitmap
850
     */
851
0
    void printf() const noexcept { api::roaring_bitmap_printf(&roaring); }
852
853
    /**
854
     * Print the content of the bitmap into a string
855
     */
856
6.24k
    std::string toString() const noexcept {
857
6.24k
        struct iter_data {
858
6.24k
            std::string str{};  // The empty constructor silences warnings from
859
                                // pedantic static analyzers.
860
6.24k
            char first_char = '{';
861
6.24k
        } outer_iter_data;
862
6.24k
        if (!isEmpty()) {
863
6.23k
            iterate(
864
3.62G
                [](uint32_t value, void *inner_iter_data) -> bool {
865
3.62G
                    ((iter_data *)inner_iter_data)->str +=
866
3.62G
                        ((iter_data *)inner_iter_data)->first_char;
867
3.62G
                    ((iter_data *)inner_iter_data)->str +=
868
3.62G
                        std::to_string(value);
869
3.62G
                    ((iter_data *)inner_iter_data)->first_char = ',';
870
3.62G
                    return true;
871
3.62G
                },
872
6.23k
                (void *)&outer_iter_data);
873
6.23k
        } else
874
14
            outer_iter_data.str = '{';
875
6.24k
        outer_iter_data.str += '}';
876
6.24k
        return outer_iter_data.str;
877
6.24k
    }
878
879
    /**
880
     * Whether or not copy and write is active.
881
     */
882
0
    bool getCopyOnWrite() const noexcept {
883
0
        return api::roaring_bitmap_get_copy_on_write(&roaring);
884
0
    }
885
886
    /**
887
     * Computes the logical or (union) between "n" bitmaps (referenced by a
888
     * pointer).
889
     * This function may throw std::runtime_error.
890
     */
891
0
    static Roaring fastunion(size_t n, const Roaring **inputs) {
892
0
        const roaring_bitmap_t **x = (const roaring_bitmap_t **)roaring_malloc(
893
0
            n * sizeof(roaring_bitmap_t *));
894
0
        if (x == NULL) {
895
0
            ROARING_TERMINATE("failed memory alloc in fastunion");
896
0
        }
897
0
        for (size_t k = 0; k < n; ++k) x[k] = &inputs[k]->roaring;
898
0
899
0
        roaring_bitmap_t *c_ans = api::roaring_bitmap_or_many(n, x);
900
0
        if (c_ans == NULL) {
901
0
            roaring_free(x);
902
0
            ROARING_TERMINATE("failed memory alloc in fastunion");
903
0
        }
904
0
        Roaring ans(c_ans);
905
0
        roaring_free(x);
906
0
        return ans;
907
0
    }
908
909
    /**
910
     * Destructor.  By contract, calling roaring_bitmap_clear() is enough to
911
     * release all auxiliary memory used by the structure.
912
     */
913
56.2k
    ~Roaring() {
914
56.2k
        if (!(roaring.high_low_container.flags & ROARING_FLAG_FROZEN)) {
915
56.2k
            api::roaring_bitmap_clear(&roaring);
916
56.2k
        } else {
917
            // The roaring member variable copies the `roaring_bitmap_t` and
918
            // nested `roaring_array_t` structures by value and is freed in the
919
            // constructor, however the underlying memory arena used for the
920
            // container data is not freed with it. Here we derive the arena
921
            // pointer from the second arena allocation in
922
            // `roaring_bitmap_frozen_view` and free it as well.
923
0
            roaring_bitmap_free(
924
0
                (roaring_bitmap_t *)((char *)
925
0
                                         roaring.high_low_container.containers -
926
0
                                     sizeof(roaring_bitmap_t)));
927
0
        }
928
56.2k
    }
929
930
    friend class RoaringSetBitBiDirectionalIterator;
931
    typedef RoaringSetBitBiDirectionalIterator const_iterator;
932
    typedef RoaringSetBitBiDirectionalIterator const_bidirectional_iterator;
933
934
    /**
935
     * Returns an iterator that can be used to access the position of the set
936
     * bits. The running time complexity of a full scan is proportional to the
937
     * number of set bits: be aware that if you have long strings of 1s, this
938
     * can be very inefficient.
939
     *
940
     * It can be much faster to use the toArray method if you want to retrieve
941
     * the set bits.
942
     */
943
    const_iterator begin() const;
944
945
    /**
946
     * A bogus iterator that can be used together with begin()
947
     * for constructions such as for (auto i = b.begin(); * i!=b.end(); ++i) {}
948
     */
949
    const_iterator &end() const;
950
951
    roaring_bitmap_t roaring;
952
};
953
954
/**
955
 * Used to go through the set bits. Not optimally fast, but convenient.
956
 */
957
class RoaringSetBitBiDirectionalIterator final {
958
   public:
959
    typedef std::bidirectional_iterator_tag iterator_category;
960
    typedef uint32_t *pointer;
961
    typedef uint32_t &reference_type;
962
    typedef uint32_t value_type;
963
    typedef int32_t difference_type;
964
    typedef RoaringSetBitBiDirectionalIterator type_of_iterator;
965
966
    explicit RoaringSetBitBiDirectionalIterator(const Roaring &parent,
967
12.4k
                                                bool exhausted = false) {
968
12.4k
        if (exhausted) {
969
1
            i.parent = &parent.roaring;
970
1
            i.container_index = INT32_MAX;
971
1
            i.has_value = false;
972
1
            i.current_value = UINT32_MAX;
973
12.4k
        } else {
974
12.4k
            api::roaring_iterator_init(&parent.roaring, &i);
975
12.4k
        }
976
12.4k
    }
977
978
    /**
979
     * Provides the location of the set bit.
980
     */
981
335k
    value_type operator*() const { return i.current_value; }
982
983
0
    bool operator<(const type_of_iterator &o) const {
984
0
        if (!i.has_value) return false;
985
0
        if (!o.i.has_value) return true;
986
0
        return i.current_value < *o;
987
0
    }
988
989
0
    bool operator<=(const type_of_iterator &o) const {
990
0
        if (!o.i.has_value) return true;
991
0
        if (!i.has_value) return false;
992
0
        return i.current_value <= *o;
993
0
    }
994
995
0
    bool operator>(const type_of_iterator &o) const {
996
0
        if (!o.i.has_value) return false;
997
0
        if (!i.has_value) return true;
998
0
        return i.current_value > *o;
999
0
    }
1000
1001
0
    bool operator>=(const type_of_iterator &o) const {
1002
0
        if (!i.has_value) return true;
1003
0
        if (!o.i.has_value) return false;
1004
0
        return i.current_value >= *o;
1005
0
    }
1006
1007
0
    type_of_iterator &operator++() {  // ++i, must returned inc. value
1008
0
        api::roaring_uint32_iterator_advance(&i);
1009
0
        return *this;
1010
0
    }
1011
1012
329k
    type_of_iterator operator++(int) {  // i++, must return orig. value
1013
329k
        RoaringSetBitBiDirectionalIterator orig(*this);
1014
329k
        api::roaring_uint32_iterator_advance(&i);
1015
329k
        return orig;
1016
329k
    }
1017
1018
    /**
1019
     * Move the iterator to the first value >= val.
1020
     * Return true if there is such a value.
1021
     */
1022
0
    bool move_equalorlarger(value_type val) {
1023
0
        return api::roaring_uint32_iterator_move_equalorlarger(&i, val);
1024
0
    }
1025
1026
    /** DEPRECATED, use `move_equalorlarger`.*/
1027
6.24k
    CROARING_DEPRECATED void equalorlarger(uint32_t val) {
1028
6.24k
        api::roaring_uint32_iterator_move_equalorlarger(&i, val);
1029
6.24k
    }
1030
1031
    /**
1032
     * Reads up to ${count} ranges into ${buf}. Returns the number of ranges
1033
     * read. See roaring_uint32_iterator_read_ranges for full semantics.
1034
     */
1035
0
    size_t read_ranges(api::roaring_uint32_range_closed_t *buf, size_t count) {
1036
0
        return api::roaring_uint32_iterator_read_ranges(&i, buf, count);
1037
0
    }
1038
1039
    /**
1040
     * Reads up to ${count} ranges in reverse into ${buf}. Returns the number
1041
     * of ranges read. See roaring_uint32_iterator_read_prev_ranges for full
1042
     * semantics.
1043
     */
1044
    size_t read_prev_ranges(api::roaring_uint32_range_closed_t *buf,
1045
0
                            size_t count) {
1046
0
        return api::roaring_uint32_iterator_read_prev_ranges(&i, buf, count);
1047
0
    }
1048
1049
0
    type_of_iterator &operator--() {  // prefix --
1050
0
        api::roaring_uint32_iterator_previous(&i);
1051
0
        return *this;
1052
0
    }
1053
1054
0
    type_of_iterator operator--(int) {  // postfix --
1055
0
        RoaringSetBitBiDirectionalIterator orig(*this);
1056
0
        api::roaring_uint32_iterator_previous(&i);
1057
0
        return orig;
1058
0
    }
1059
1060
0
    bool operator==(const RoaringSetBitBiDirectionalIterator &o) const {
1061
0
        return i.current_value == *o && i.has_value == o.i.has_value;
1062
0
    }
1063
1064
335k
    bool operator!=(const RoaringSetBitBiDirectionalIterator &o) const {
1065
335k
        return i.current_value != *o || i.has_value != o.i.has_value;
1066
335k
    }
1067
1068
    api::roaring_uint32_iterator_t
1069
        i{};  // The empty constructor silences warnings from pedantic static
1070
              // analyzers.
1071
};
1072
1073
12.4k
inline RoaringSetBitBiDirectionalIterator Roaring::begin() const {
1074
12.4k
    return RoaringSetBitBiDirectionalIterator(*this);
1075
12.4k
}
1076
1077
335k
inline RoaringSetBitBiDirectionalIterator &Roaring::end() const {
1078
335k
    static RoaringSetBitBiDirectionalIterator e(*this, true);
1079
335k
    return e;
1080
335k
}
1081
1082
}  // namespace roaring
1083
1084
#endif /* INCLUDE_ROARING_HH_ */