Coverage Report

Created: 2026-01-17 06:10

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