/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_ */ |