Coverage Report

Created: 2026-10-17 07:19

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.28k
#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.9k
    Roaring() : roaring{} {
77
        // The empty constructor roaring{} silences warnings from pedantic
78
        // static analyzers.
79
18.9k
        api::roaring_bitmap_init_cleared(&roaring);
80
18.9k
    }
81
82
    /**
83
     * Construct a bitmap from a list of 32-bit integer values.
84
     */
85
12.6k
    Roaring(size_t n, const uint32_t *data) : Roaring() {
86
12.6k
        api::roaring_bitmap_add_many(&roaring, n, data);
87
12.6k
    }
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.5k
    explicit Roaring(roaring_bitmap_t *s) noexcept : roaring(*s) {
103
31.5k
        roaring_free(s);  // deallocate the passed-in pointer
104
31.5k
    }
105
106
    /**
107
     * Copy constructor.
108
     * It may throw std::runtime_error if there is insufficient memory.
109
     */
110
6.30k
    Roaring(const Roaring &r) : Roaring() {
111
6.30k
        if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
112
0
            ROARING_TERMINATE("failed roaring_bitmap_overwrite in constructor");
113
0
        }
114
6.30k
        api::roaring_bitmap_set_copy_on_write(
115
6.30k
            &roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
116
6.30k
    }
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.30k
    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.30k
        api::roaring_bitmap_init_cleared(&r.roaring);
131
6.30k
    }
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.30k
    Roaring &operator=(const Roaring &r) {
153
6.30k
        if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
154
0
            ROARING_TERMINATE("failed memory alloc in assignment");
155
0
        }
156
6.30k
        api::roaring_bitmap_set_copy_on_write(
157
6.30k
            &roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
158
6.30k
        return *this;
159
6.30k
    }
160
161
    /**
162
     * Moves the content of the provided bitmap, and
163
     * discard the current content.
164
     */
165
6.30k
    Roaring &operator=(Roaring &&r) noexcept {
166
6.30k
        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.30k
        roaring = r.roaring;
171
6.30k
        api::roaring_bitmap_init_cleared(&r.roaring);
172
173
6.30k
        return *this;
174
6.30k
    }
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.30k
    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.30k
    bool addChecked(uint32_t x) noexcept {
206
6.30k
        return api::roaring_bitmap_add_checked(&roaring, x);
207
6.30k
    }
208
209
    /**
210
     * Add all values in range [min, max)
211
     */
212
6.30k
    void addRange(const uint64_t min, const uint64_t max) noexcept {
213
6.30k
        return api::roaring_bitmap_add_range(&roaring, min, max);
214
6.30k
    }
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.30k
    void addMany(size_t n_args, const uint32_t *vals) noexcept {
227
6.30k
        api::roaring_bitmap_add_many(&roaring, n_args, vals);
228
6.30k
    }
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.30k
    void remove(uint32_t x) noexcept {
259
6.30k
        api::roaring_bitmap_remove(&roaring, x);
260
6.30k
    }
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.30k
    bool removeChecked(uint32_t x) noexcept {
268
6.30k
        return api::roaring_bitmap_remove_checked(&roaring, x);
269
6.30k
    }
270
271
    /**
272
     * Remove all values in range [min, max)
273
     */
274
6.30k
    void removeRange(uint64_t min, uint64_t max) noexcept {
275
6.30k
        return api::roaring_bitmap_remove_range(&roaring, min, max);
276
6.30k
    }
277
278
    /**
279
     * Remove all values in range [min, max]
280
     */
281
6.30k
    void removeRangeClosed(uint32_t min, uint32_t max) noexcept {
282
6.30k
        return api::roaring_bitmap_remove_range_closed(&roaring, min, max);
283
6.30k
    }
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.30k
    uint32_t maximum() const noexcept {
316
6.30k
        return api::roaring_bitmap_maximum(&roaring);
317
6.30k
    }
318
319
    /**
320
     * Returns the smallest value in the set, or UINT32_MAX if the set is empty.
321
     */
322
6.30k
    uint32_t minimum() const noexcept {
323
6.30k
        return api::roaring_bitmap_minimum(&roaring);
324
6.30k
    }
325
326
    /**
327
     * Check if value x is present
328
     */
329
6.30k
    bool contains(uint32_t x) const noexcept {
330
6.30k
        return api::roaring_bitmap_contains(&roaring, x);
331
6.30k
    }
332
333
    /**
334
     * Check if all values from x (included) to y (excluded) are present
335
     */
336
6.30k
    bool containsRange(const uint64_t x, const uint64_t y) const noexcept {
337
6.30k
        return api::roaring_bitmap_contains_range(&roaring, x, y);
338
6.30k
    }
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.30k
    Roaring &operator&=(const Roaring &r) noexcept {
357
6.30k
        api::roaring_bitmap_and_inplace(&roaring, &r.roaring);
358
6.30k
        return *this;
359
6.30k
    }
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.30k
    Roaring &operator-=(const Roaring &r) noexcept {
367
6.30k
        api::roaring_bitmap_andnot_inplace(&roaring, &r.roaring);
368
6.30k
        return *this;
369
6.30k
    }
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.30k
    Roaring &operator|=(const Roaring &r) noexcept {
379
6.30k
        api::roaring_bitmap_or_inplace(&roaring, &r.roaring);
380
6.30k
        return *this;
381
6.30k
    }
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.30k
    Roaring &operator^=(const Roaring &r) noexcept {
389
6.30k
        api::roaring_bitmap_xor_inplace(&roaring, &r.roaring);
390
6.30k
        return *this;
391
6.30k
    }
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.30k
    uint64_t cardinality() const noexcept {
402
6.30k
        return api::roaring_bitmap_get_cardinality(&roaring);
403
6.30k
    }
404
405
    /**
406
     * Returns true if the bitmap is empty (cardinality is zero).
407
     */
408
12.6k
    bool isEmpty() const noexcept {
409
12.6k
        return api::roaring_bitmap_is_empty(&roaring);
410
12.6k
    }
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.30k
    bool isSubset(const Roaring &r) const noexcept {
426
6.30k
        return api::roaring_bitmap_is_subset(&roaring, &r.roaring);
427
6.30k
    }
428
429
    /**
430
     * Returns true if the bitmap is strict subset of the other.
431
     */
432
6.30k
    bool isStrictSubset(const Roaring &r) const noexcept {
433
6.30k
        return api::roaring_bitmap_is_strict_subset(&roaring, &r.roaring);
434
6.30k
    }
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.30k
    void toUint32Array(uint32_t *ans) const noexcept {
442
6.30k
        api::roaring_bitmap_to_uint32_array(&roaring, ans);
443
6.30k
    }
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.6k
    bool operator==(const Roaring &r) const noexcept {
459
12.6k
        return api::roaring_bitmap_equals(&roaring, &r.roaring);
460
12.6k
    }
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.30k
    void flip(uint64_t range_start, uint64_t range_end) noexcept {
467
6.30k
        api::roaring_bitmap_flip_inplace(&roaring, range_start, range_end);
468
6.30k
    }
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.30k
    void flipClosed(uint32_t range_start, uint32_t range_end) noexcept {
475
6.30k
        api::roaring_bitmap_flip_inplace_closed(&roaring, range_start,
476
6.30k
                                                range_end);
477
6.30k
    }
478
479
    /**
480
     * Remove run-length encoding even when it is more space efficient.
481
     * Return whether a change was applied.
482
     */
483
6.30k
    bool removeRunCompression() noexcept {
484
6.30k
        return api::roaring_bitmap_remove_run_compression(&roaring);
485
6.30k
    }
486
487
    /**
488
     * Validate the structure of a bitmap read from an untrusted source.
489
     * Returns false and sets *reason (when not null) if it is invalid.
490
     */
491
0
    bool internal_validate(const char **reason = nullptr) const noexcept {
492
0
        return api::roaring_bitmap_internal_validate(&roaring, reason);
493
0
    }
494
495
    /**
496
     * Convert array and bitmap containers to run containers when it is more
497
     * efficient; also convert from run containers when more space efficient.
498
     * Returns true if the result has at least one run container.  Additional
499
     * savings might be possible by calling shrinkToFit().
500
     */
501
12.6k
    bool runOptimize() noexcept {
502
12.6k
        return api::roaring_bitmap_run_optimize(&roaring);
503
12.6k
    }
504
505
    /**
506
     * If needed, reallocate memory to shrink the memory usage. Returns
507
     * the number of bytes saved.
508
     */
509
6.30k
    size_t shrinkToFit() noexcept {
510
6.30k
        return api::roaring_bitmap_shrink_to_fit(&roaring);
511
6.30k
    }
512
513
    /**
514
     * Iterate over the bitmap elements. The function iterator is called once
515
     * for all the values with ptr (can be NULL) as the second parameter of
516
     * each call.
517
     *
518
     * roaring_iterator is simply a pointer to a function that returns bool
519
     * (true means that the iteration should continue while false means that it
520
     * should stop), and takes (uint32_t,void*) as inputs.
521
     */
522
6.28k
    void iterate(api::roaring_iterator iterator, void *ptr) const {
523
6.28k
        api::roaring_iterate(&roaring, iterator, ptr);
524
6.28k
    }
525
526
    /**
527
     * Selects the value at index rnk in the bitmap, where the smallest value
528
     * is at index 0.
529
     *
530
     * If the size of the roaring bitmap is strictly greater than rank, then
531
     * this function returns true and sets element to the element of given rank.
532
     * Otherwise, it returns false.
533
     */
534
6.30k
    bool select(uint32_t rnk, uint32_t *element) const noexcept {
535
6.30k
        return api::roaring_bitmap_select(&roaring, rnk, element);
536
6.30k
    }
537
538
    /**
539
     * Computes the size of the intersection between two bitmaps.
540
     */
541
0
    uint64_t and_cardinality(const Roaring &r) const noexcept {
542
0
        return api::roaring_bitmap_and_cardinality(&roaring, &r.roaring);
543
0
    }
544
545
    /**
546
     * Check whether the two bitmaps intersect.
547
     */
548
6.30k
    bool intersect(const Roaring &r) const noexcept {
549
6.30k
        return api::roaring_bitmap_intersect(&roaring, &r.roaring);
550
6.30k
    }
551
552
    /**
553
     * Computes the Jaccard index between two bitmaps. (Also known as the
554
     * Tanimoto distance,
555
     * or the Jaccard similarity coefficient)
556
     *
557
     * The Jaccard index is undefined if both bitmaps are empty.
558
     */
559
6.30k
    double jaccard_index(const Roaring &r) const noexcept {
560
6.30k
        return api::roaring_bitmap_jaccard_index(&roaring, &r.roaring);
561
6.30k
    }
562
563
    /**
564
     * Computes the size of the union between two bitmaps.
565
     */
566
6.30k
    uint64_t or_cardinality(const Roaring &r) const noexcept {
567
6.30k
        return api::roaring_bitmap_or_cardinality(&roaring, &r.roaring);
568
6.30k
    }
569
570
    /**
571
     * Computes the size of the difference (andnot) between two bitmaps.
572
     */
573
6.30k
    uint64_t andnot_cardinality(const Roaring &r) const noexcept {
574
6.30k
        return api::roaring_bitmap_andnot_cardinality(&roaring, &r.roaring);
575
6.30k
    }
576
577
    /**
578
     * Computes the size of the symmetric difference (andnot) between two
579
     * bitmaps.
580
     */
581
6.30k
    uint64_t xor_cardinality(const Roaring &r) const noexcept {
582
6.30k
        return api::roaring_bitmap_xor_cardinality(&roaring, &r.roaring);
583
6.30k
    }
584
585
    /**
586
     * Returns the number of integers that are smaller or equal to x.
587
     * Thus the rank of the smallest element is one.  If
588
     * x is smaller than the smallest element, this function will return 0.
589
     * The rank and select functions differ in convention: this function returns
590
     * 1 when ranking the smallest value, but the select function returns the
591
     * smallest value when using index 0.
592
     */
593
6.30k
    uint64_t rank(uint32_t x) const noexcept {
594
6.30k
        return api::roaring_bitmap_rank(&roaring, x);
595
6.30k
    }
596
597
    /**
598
     * Get `rank()` values in bulk. The values in `[begin .. end)` must be in
599
     * Ascending order. possible implementation: for(auto* iter = begin; iter !=
600
     * end; ++iter) *(ans++) = rank(*iter);
601
     */
602
    void rank_many(const uint32_t *begin, const uint32_t *end,
603
0
                   uint64_t *ans) const noexcept {
604
0
        return api::roaring_bitmap_rank_many(&roaring, begin, end, ans);
605
0
    }
606
607
    /**
608
     * Returns the index of x in the set, index start from 0.
609
     * If the set doesn't contain x , this function will return -1.
610
     * The difference with rank function is that this function will return -1
611
     * when x isn't in the set, but the rank function will return a
612
     * non-negative number.
613
     */
614
0
    int64_t getIndex(uint32_t x) const noexcept {
615
0
        return api::roaring_bitmap_get_index(&roaring, x);
616
0
    }
617
618
    /**
619
     * Write a bitmap to a char buffer. This is meant to be compatible with
620
     * the Java and Go versions. Returns how many bytes were written which
621
     * should be getSizeInBytes().
622
     *
623
     * Setting the portable flag to false enable a custom format that
624
     * can save space compared to the portable format (e.g., for very
625
     * sparse bitmaps).
626
     *
627
     * Boost users can serialize bitmaps in this manner:
628
     *
629
     *       BOOST_SERIALIZATION_SPLIT_FREE(Roaring)
630
     *       namespace boost {
631
     *       namespace serialization {
632
     *
633
     *       template <class Archive>
634
     *       void save(Archive& ar, const Roaring& bitmask,
635
     *          const unsigned int version) {
636
     *         std::size_t expected_size_in_bytes = bitmask.getSizeInBytes();
637
     *         std::vector<char> buffer(expected_size_in_bytes);
638
     *         std::size_t       size_in_bytes = bitmask.write(buffer.data());
639
     *
640
     *         ar& size_in_bytes;
641
     *         ar& boost::serialization::make_binary_object(buffer.data(),
642
     *             size_in_bytes);
643
     *      }
644
     *      template <class Archive>
645
     *      void load(Archive& ar, Roaring& bitmask,
646
     *          const unsigned int version) {
647
     *         std::size_t size_in_bytes = 0;
648
     *         ar& size_in_bytes;
649
     *         std::vector<char> buffer(size_in_bytes);
650
     *         ar&  boost::serialization::make_binary_object(buffer.data(),
651
     *            size_in_bytes);
652
     *         bitmask = Roaring::readSafe(buffer.data(), size_in_bytes);
653
     *      }
654
     *      }  // namespace serialization
655
     *      }  // namespace boost
656
     */
657
6.30k
    size_t write(char *buf, bool portable = true) const noexcept {
658
6.30k
        if (portable) {
659
6.30k
            return api::roaring_bitmap_portable_serialize(&roaring, buf);
660
6.30k
        } else {
661
0
            return api::roaring_bitmap_serialize(&roaring, buf);
662
0
        }
663
6.30k
    }
664
665
    /**
666
     * Read a bitmap from a serialized version. This is meant to be compatible
667
     * with the Java and Go versions.
668
     *
669
     * Setting the portable flag to false enable a custom format that
670
     * can save space compared to the portable format (e.g., for very
671
     * sparse bitmaps).
672
     *
673
     * This function is unsafe in the sense that if you provide bad data,
674
     * many, many bytes could be read. See also readSafe.
675
     *
676
     * The function may throw std::runtime_error if a bitmap could not be read.
677
     * Note that even if it does not throw, the bitmap could still be unusable
678
     * if the loaded data does not match the portable Roaring specification: you
679
     * should ensure that the data you load come from a serialized bitmap.
680
     */
681
0
    static Roaring read(const char *buf, bool portable = true) {
682
0
        roaring_bitmap_t *r =
683
0
            portable ? api::roaring_bitmap_portable_deserialize(buf)
684
0
                     : api::roaring_bitmap_deserialize(buf);
685
0
        if (r == NULL) {
686
0
            ROARING_TERMINATE("failed alloc while reading");
687
0
        }
688
0
        return Roaring(r);
689
0
    }
690
691
    /**
692
     * Read a bitmap from a serialized version, reading no more than maxbytes
693
     * bytes.  This is meant to be compatible with the Java and Go versions.
694
     * The function itself is safe in the sense that it will not cause buffer
695
     * overflows. However, for correct operations, it is assumed that the bitmap
696
     * read was once serialized from a valid bitmap. If you provided an
697
     * incorrect input (garbage), then the bitmap read may not be in a valid
698
     * state and following operations may not lead to sensible results. It is
699
     * your responsability to ensure that the input bytes follow the format
700
     * specification if you want a usable bitmap:
701
     * https://github.com/RoaringBitmap/RoaringFormatSpec
702
     * In particular, the serialized array containers need to be in sorted
703
     * order, and the run containers should be in sorted non-overlapping order.
704
     * This is is guaranteed to happen when serializing an existing bitmap, but
705
     * not for random inputs. Note that this function assumes that your bitmap
706
     * was serialized in *portable* mode (which is the default with the 'write'
707
     * method).
708
     *
709
     * The function may throw std::runtime_error if a bitmap could not be read.
710
     * Note that even if it does not throw, the bitmap could still be unusable
711
     * if the loaded data does not match the portable Roaring specification: you
712
     * should ensure that the data you load come from a serialized bitmap.
713
     */
714
12.6k
    static Roaring readSafe(const char *buf, size_t maxbytes) {
715
12.6k
        roaring_bitmap_t *r =
716
12.6k
            api::roaring_bitmap_portable_deserialize_safe(buf, maxbytes);
717
12.6k
        if (r == NULL) {
718
6.28k
            ROARING_TERMINATE("failed alloc while reading");
719
6.28k
        }
720
6.31k
        return Roaring(r);
721
12.6k
    }
722
723
    /**
724
     * Compute how many bytes would be read by readSafe.  Returns 0 if the
725
     * serialized data is invalid.
726
     * This is meant to be compatible with the Java and Go versions.
727
     */
728
0
    static size_t serializedSizeInBytesSafe(const char *buf, size_t maxbytes) {
729
0
        return api::roaring_bitmap_portable_deserialize_size(buf, maxbytes);
730
0
    }
731
732
    /**
733
     * How many bytes are required to serialize this bitmap (meant to be
734
     * compatible with Java and Go versions)
735
     *
736
     * Setting the portable flag to false enable a custom format that
737
     * can save space compared to the portable format (e.g., for very
738
     * sparse bitmaps).
739
     */
740
12.6k
    size_t getSizeInBytes(bool portable = true) const noexcept {
741
12.6k
        if (portable) {
742
12.6k
            return api::roaring_bitmap_portable_size_in_bytes(&roaring);
743
12.6k
        } else {
744
0
            return api::roaring_bitmap_size_in_bytes(&roaring);
745
0
        }
746
12.6k
    }
747
748
    /**
749
     * For advanced users.
750
     * This function may throw std::runtime_error.
751
     */
752
0
    static Roaring frozenView(const char *buf, size_t length) {
753
0
        const roaring_bitmap_t *s =
754
0
            api::roaring_bitmap_frozen_view(buf, length);
755
0
        if (s == NULL) {
756
0
            ROARING_TERMINATE("failed to read frozen bitmap");
757
0
        }
758
0
        Roaring r;
759
0
        r.roaring = *s;
760
0
        return r;
761
0
    }
762
763
    /**
764
     * For advanced users; see roaring_bitmap_portable_deserialize_frozen.
765
     * This function may throw std::runtime_error.
766
     */
767
0
    static Roaring portableDeserializeFrozen(const char *buf) {
768
0
        const roaring_bitmap_t *s =
769
0
            api::roaring_bitmap_portable_deserialize_frozen(buf);
770
0
        if (s == NULL) {
771
0
            ROARING_TERMINATE("failed to read portable frozen bitmap");
772
0
        }
773
0
        Roaring r;
774
0
        r.roaring = *s;
775
0
        return r;
776
0
    }
777
778
    /**
779
     * For advanced users.
780
     */
781
0
    void writeFrozen(char *buf) const noexcept {
782
0
        roaring_bitmap_frozen_serialize(&roaring, buf);
783
0
    }
784
785
    /**
786
     * For advanced users.
787
     */
788
0
    size_t getFrozenSizeInBytes() const noexcept {
789
0
        return roaring_bitmap_frozen_size_in_bytes(&roaring);
790
0
    }
791
792
    /**
793
     * Computes the intersection between two bitmaps and returns new bitmap.
794
     * The current bitmap and the provided bitmap are unchanged.
795
     *
796
     * Performance hint: if you are computing the intersection between several
797
     * bitmaps, two-by-two, it is best to start with the smallest bitmap.
798
     * Consider also using the operator &= to avoid needlessly creating
799
     * many temporary bitmaps.
800
     * This function may throw std::runtime_error.
801
     */
802
6.30k
    Roaring operator&(const Roaring &o) const {
803
6.30k
        roaring_bitmap_t *r = api::roaring_bitmap_and(&roaring, &o.roaring);
804
6.30k
        if (r == NULL) {
805
0
            ROARING_TERMINATE("failed materialization in and");
806
0
        }
807
6.30k
        return Roaring(r);
808
6.30k
    }
809
810
    /**
811
     * Computes the difference between two bitmaps and returns new bitmap.
812
     * The current bitmap and the provided bitmap are unchanged.
813
     * This function may throw std::runtime_error.
814
     */
815
6.30k
    Roaring operator-(const Roaring &o) const {
816
6.30k
        roaring_bitmap_t *r = api::roaring_bitmap_andnot(&roaring, &o.roaring);
817
6.30k
        if (r == NULL) {
818
0
            ROARING_TERMINATE("failed materialization in andnot");
819
0
        }
820
6.30k
        return Roaring(r);
821
6.30k
    }
822
823
    /**
824
     * Computes the union between two bitmaps and returns new bitmap.
825
     * The current bitmap and the provided bitmap are unchanged.
826
     * This function may throw std::runtime_error.
827
     */
828
6.30k
    Roaring operator|(const Roaring &o) const {
829
6.30k
        roaring_bitmap_t *r = api::roaring_bitmap_or(&roaring, &o.roaring);
830
6.30k
        if (r == NULL) {
831
0
            ROARING_TERMINATE("failed materialization in or");
832
0
        }
833
6.30k
        return Roaring(r);
834
6.30k
    }
835
836
    /**
837
     * Computes the symmetric union between two bitmaps and returns new bitmap.
838
     * The current bitmap and the provided bitmap are unchanged.
839
     * This function may throw std::runtime_error.
840
     */
841
6.30k
    Roaring operator^(const Roaring &o) const {
842
6.30k
        roaring_bitmap_t *r = api::roaring_bitmap_xor(&roaring, &o.roaring);
843
6.30k
        if (r == NULL) {
844
0
            ROARING_TERMINATE("failed materialization in xor");
845
0
        }
846
6.30k
        return Roaring(r);
847
6.30k
    }
848
849
    /**
850
     * Whether or not we apply copy and write.
851
     */
852
0
    void setCopyOnWrite(bool val) noexcept {
853
0
        api::roaring_bitmap_set_copy_on_write(&roaring, val);
854
0
    }
855
856
    /**
857
     * Print the content of the bitmap
858
     */
859
0
    void printf() const noexcept { api::roaring_bitmap_printf(&roaring); }
860
861
    /**
862
     * Print the content of the bitmap into a string
863
     */
864
6.30k
    std::string toString() const noexcept {
865
6.30k
        struct iter_data {
866
6.30k
            std::string str{};  // The empty constructor silences warnings from
867
                                // pedantic static analyzers.
868
6.30k
            char first_char = '{';
869
6.30k
        } outer_iter_data;
870
6.30k
        if (!isEmpty()) {
871
6.28k
            iterate(
872
3.66G
                [](uint32_t value, void *inner_iter_data) -> bool {
873
3.66G
                    ((iter_data *)inner_iter_data)->str +=
874
3.66G
                        ((iter_data *)inner_iter_data)->first_char;
875
3.66G
                    ((iter_data *)inner_iter_data)->str +=
876
3.66G
                        std::to_string(value);
877
3.66G
                    ((iter_data *)inner_iter_data)->first_char = ',';
878
3.66G
                    return true;
879
3.66G
                },
880
6.28k
                (void *)&outer_iter_data);
881
6.28k
        } else
882
11
            outer_iter_data.str = '{';
883
6.30k
        outer_iter_data.str += '}';
884
6.30k
        return outer_iter_data.str;
885
6.30k
    }
886
887
    /**
888
     * Whether or not copy and write is active.
889
     */
890
0
    bool getCopyOnWrite() const noexcept {
891
0
        return api::roaring_bitmap_get_copy_on_write(&roaring);
892
0
    }
893
894
    /**
895
     * Computes the logical or (union) between "n" bitmaps (referenced by a
896
     * pointer).
897
     * This function may throw std::runtime_error.
898
     */
899
0
    static Roaring fastunion(size_t n, const Roaring **inputs) {
900
0
        const roaring_bitmap_t **x = (const roaring_bitmap_t **)roaring_malloc(
901
0
            n * sizeof(roaring_bitmap_t *));
902
0
        if (x == NULL) {
903
0
            ROARING_TERMINATE("failed memory alloc in fastunion");
904
0
        }
905
0
        for (size_t k = 0; k < n; ++k) x[k] = &inputs[k]->roaring;
906
0
907
0
        roaring_bitmap_t *c_ans = api::roaring_bitmap_or_many(n, x);
908
0
        if (c_ans == NULL) {
909
0
            roaring_free(x);
910
0
            ROARING_TERMINATE("failed memory alloc in fastunion");
911
0
        }
912
0
        Roaring ans(c_ans);
913
0
        roaring_free(x);
914
0
        return ans;
915
0
    }
916
917
    /**
918
     * Destructor.  By contract, calling roaring_bitmap_clear() is enough to
919
     * release all auxiliary memory used by the structure.
920
     */
921
56.7k
    ~Roaring() {
922
56.7k
        if (!(roaring.high_low_container.flags & ROARING_FLAG_FROZEN)) {
923
56.7k
            api::roaring_bitmap_clear(&roaring);
924
56.7k
        } else {
925
            // The roaring member variable copies the `roaring_bitmap_t` and
926
            // nested `roaring_array_t` structures by value and is freed in the
927
            // constructor, however the underlying memory arena used for the
928
            // container data is not freed with it. Here we derive the arena
929
            // pointer from the second arena allocation in
930
            // `roaring_bitmap_frozen_view` and free it as well.
931
0
            roaring_bitmap_free(
932
0
                (roaring_bitmap_t *)((char *)
933
0
                                         roaring.high_low_container.containers -
934
0
                                     sizeof(roaring_bitmap_t)));
935
0
        }
936
56.7k
    }
937
938
    friend class RoaringSetBitBiDirectionalIterator;
939
    typedef RoaringSetBitBiDirectionalIterator const_iterator;
940
    typedef RoaringSetBitBiDirectionalIterator const_bidirectional_iterator;
941
942
    /**
943
     * Returns an iterator that can be used to access the position of the set
944
     * bits. The running time complexity of a full scan is proportional to the
945
     * number of set bits: be aware that if you have long strings of 1s, this
946
     * can be very inefficient.
947
     *
948
     * It can be much faster to use the toArray method if you want to retrieve
949
     * the set bits.
950
     */
951
    const_iterator begin() const;
952
953
    /**
954
     * A bogus iterator that can be used together with begin()
955
     * for constructions such as for (auto i = b.begin(); * i!=b.end(); ++i) {}
956
     */
957
    const_iterator &end() const;
958
959
    roaring_bitmap_t roaring;
960
};
961
962
/**
963
 * Used to go through the set bits. Not optimally fast, but convenient.
964
 */
965
class RoaringSetBitBiDirectionalIterator final {
966
   public:
967
    typedef std::bidirectional_iterator_tag iterator_category;
968
    typedef uint32_t *pointer;
969
    typedef uint32_t &reference_type;
970
    typedef uint32_t value_type;
971
    typedef int32_t difference_type;
972
    typedef RoaringSetBitBiDirectionalIterator type_of_iterator;
973
974
    explicit RoaringSetBitBiDirectionalIterator(const Roaring &parent,
975
12.6k
                                                bool exhausted = false) {
976
12.6k
        if (exhausted) {
977
1
            i.parent = &parent.roaring;
978
1
            i.container_index = INT32_MAX;
979
1
            i.has_value = false;
980
1
            i.current_value = UINT32_MAX;
981
12.6k
        } else {
982
12.6k
            api::roaring_iterator_init(&parent.roaring, &i);
983
12.6k
        }
984
12.6k
    }
985
986
    /**
987
     * Provides the location of the set bit.
988
     */
989
318k
    value_type operator*() const { return i.current_value; }
990
991
0
    bool operator<(const type_of_iterator &o) const {
992
0
        if (!i.has_value) return false;
993
0
        if (!o.i.has_value) return true;
994
0
        return i.current_value < *o;
995
0
    }
996
997
0
    bool operator<=(const type_of_iterator &o) const {
998
0
        if (!o.i.has_value) return true;
999
0
        if (!i.has_value) return false;
1000
0
        return i.current_value <= *o;
1001
0
    }
1002
1003
0
    bool operator>(const type_of_iterator &o) const {
1004
0
        if (!o.i.has_value) return false;
1005
0
        if (!i.has_value) return true;
1006
0
        return i.current_value > *o;
1007
0
    }
1008
1009
0
    bool operator>=(const type_of_iterator &o) const {
1010
0
        if (!i.has_value) return true;
1011
0
        if (!o.i.has_value) return false;
1012
0
        return i.current_value >= *o;
1013
0
    }
1014
1015
0
    type_of_iterator &operator++() {  // ++i, must returned inc. value
1016
0
        api::roaring_uint32_iterator_advance(&i);
1017
0
        return *this;
1018
0
    }
1019
1020
312k
    type_of_iterator operator++(int) {  // i++, must return orig. value
1021
312k
        RoaringSetBitBiDirectionalIterator orig(*this);
1022
312k
        api::roaring_uint32_iterator_advance(&i);
1023
312k
        return orig;
1024
312k
    }
1025
1026
    /**
1027
     * Move the iterator to the first value >= val.
1028
     * Return true if there is such a value.
1029
     */
1030
0
    bool move_equalorlarger(value_type val) {
1031
0
        return api::roaring_uint32_iterator_move_equalorlarger(&i, val);
1032
0
    }
1033
1034
    /** DEPRECATED, use `move_equalorlarger`.*/
1035
6.30k
    CROARING_DEPRECATED void equalorlarger(uint32_t val) {
1036
6.30k
        api::roaring_uint32_iterator_move_equalorlarger(&i, val);
1037
6.30k
    }
1038
1039
    /**
1040
     * Reads up to ${count} ranges into ${buf}. Returns the number of ranges
1041
     * read. See roaring_uint32_iterator_read_ranges for full semantics.
1042
     */
1043
0
    size_t read_ranges(api::roaring_uint32_range_closed_t *buf, size_t count) {
1044
0
        return api::roaring_uint32_iterator_read_ranges(&i, buf, count);
1045
0
    }
1046
1047
    /**
1048
     * Reads up to ${count} ranges in reverse into ${buf}. Returns the number
1049
     * of ranges read. See roaring_uint32_iterator_read_prev_ranges for full
1050
     * semantics.
1051
     */
1052
    size_t read_prev_ranges(api::roaring_uint32_range_closed_t *buf,
1053
0
                            size_t count) {
1054
0
        return api::roaring_uint32_iterator_read_prev_ranges(&i, buf, count);
1055
0
    }
1056
1057
0
    type_of_iterator &operator--() {  // prefix --
1058
0
        api::roaring_uint32_iterator_previous(&i);
1059
0
        return *this;
1060
0
    }
1061
1062
0
    type_of_iterator operator--(int) {  // postfix --
1063
0
        RoaringSetBitBiDirectionalIterator orig(*this);
1064
0
        api::roaring_uint32_iterator_previous(&i);
1065
0
        return orig;
1066
0
    }
1067
1068
0
    bool operator==(const RoaringSetBitBiDirectionalIterator &o) const {
1069
0
        return i.current_value == *o && i.has_value == o.i.has_value;
1070
0
    }
1071
1072
318k
    bool operator!=(const RoaringSetBitBiDirectionalIterator &o) const {
1073
318k
        return i.current_value != *o || i.has_value != o.i.has_value;
1074
318k
    }
1075
1076
    api::roaring_uint32_iterator_t
1077
        i{};  // The empty constructor silences warnings from pedantic static
1078
              // analyzers.
1079
};
1080
1081
12.6k
inline RoaringSetBitBiDirectionalIterator Roaring::begin() const {
1082
12.6k
    return RoaringSetBitBiDirectionalIterator(*this);
1083
12.6k
}
1084
1085
318k
inline RoaringSetBitBiDirectionalIterator &Roaring::end() const {
1086
318k
    static RoaringSetBitBiDirectionalIterator e(*this, true);
1087
318k
    return e;
1088
318k
}
1089
1090
}  // namespace roaring
1091
1092
#endif /* INCLUDE_ROARING_HH_ */