CRoaring  4.2.1
Roaring bitmaps in C (and C++)
roaring64map.hh
Go to the documentation of this file.
1 
9 #ifndef INCLUDE_ROARING_64_MAP_HH_
10 #define INCLUDE_ROARING_64_MAP_HH_
11 
12 #include <algorithm>
13 #include <cinttypes> // PRIu64 macro
14 #include <cstdarg> // for va_list handling in bitmapOf()
15 #include <cstdio> // for std::printf() in the printf() method
16 #include <cstring> // for std::memcpy()
17 #include <functional>
18 #include <initializer_list>
19 #include <limits>
20 #include <map>
21 #include <new>
22 #include <numeric>
23 #include <queue>
24 #include <stdexcept>
25 #include <string>
26 #include <utility>
27 
28 #include "roaring.hh"
29 
30 namespace roaring {
31 
32 using roaring::Roaring;
33 
34 class Roaring64MapSetBitBiDirectionalIterator;
35 
36 // For backwards compatibility; there used to be two kinds of iterators
37 // (forward and bidirectional) and now there's only one.
38 typedef Roaring64MapSetBitBiDirectionalIterator
40 
41 class Roaring64Map {
42  typedef api::roaring_bitmap_t roaring_bitmap_t;
43 
44  public:
48  Roaring64Map() = default;
49 
53  Roaring64Map(size_t n, const uint32_t *data) { addMany(n, data); }
54 
58  Roaring64Map(size_t n, const uint64_t *data) { addMany(n, data); }
59 
63  Roaring64Map(std::initializer_list<uint64_t> l) {
64  addMany(l.size(), l.begin());
65  }
66 
70  explicit Roaring64Map(const Roaring &r) { emplaceOrInsert(0, r); }
71 
75  explicit Roaring64Map(Roaring &&r) { emplaceOrInsert(0, std::move(r)); }
76 
82  explicit Roaring64Map(roaring_bitmap_t *s) {
83  emplaceOrInsert(0, Roaring(s));
84  }
85 
86  Roaring64Map(const Roaring64Map &r) = default;
87 
88  Roaring64Map(Roaring64Map &&r) noexcept = default;
89 
93  Roaring64Map &operator=(const Roaring64Map &r) = default;
94 
98  Roaring64Map &operator=(Roaring64Map &&r) noexcept = default;
99 
103  Roaring64Map &operator=(std::initializer_list<uint64_t> l) {
104  // Delegate to move assignment operator
105  *this = Roaring64Map(l);
106  return *this;
107  }
108 
112  static Roaring64Map bitmapOf(size_t n...) {
113  Roaring64Map ans;
114  va_list vl;
115  va_start(vl, n);
116  for (size_t i = 0; i < n; i++) {
117  ans.add(va_arg(vl, uint64_t));
118  }
119  va_end(vl);
120  return ans;
121  }
122 
127  static Roaring64Map bitmapOfList(std::initializer_list<uint64_t> l) {
128  Roaring64Map ans;
129  ans.addMany(l.size(), l.begin());
130  return ans;
131  }
132 
136  void add(uint32_t x) { lookupOrCreateInner(0).add(x); }
137 
141  void add(uint64_t x) { lookupOrCreateInner(highBytes(x)).add(lowBytes(x)); }
142 
148  bool addChecked(uint32_t x) { return lookupOrCreateInner(0).addChecked(x); }
149 
155  bool addChecked(uint64_t x) {
156  return lookupOrCreateInner(highBytes(x)).addChecked(lowBytes(x));
157  }
158 
162  void addRange(uint64_t min, uint64_t max) {
163  if (min >= max) {
164  return;
165  }
166  addRangeClosed(min, max - 1);
167  }
168 
172  void addRangeClosed(uint32_t min, uint32_t max) {
173  lookupOrCreateInner(0).addRangeClosed(min, max);
174  }
175 
179  void addRangeClosed(uint64_t min, uint64_t max) {
180  if (min > max) {
181  return;
182  }
183  uint32_t start_high = highBytes(min);
184  uint32_t start_low = lowBytes(min);
185  uint32_t end_high = highBytes(max);
186  uint32_t end_low = lowBytes(max);
187 
188  // We put std::numeric_limits<>::max in parentheses to avoid a
189  // clash with the Windows.h header under Windows.
190  const uint32_t uint32_max = (std::numeric_limits<uint32_t>::max)();
191 
192  // Fill in any nonexistent slots with empty Roarings. This simplifies
193  // the logic below, allowing it to simply iterate over the map between
194  // 'start_high' and 'end_high' in a linear fashion.
195  auto current_iter = ensureRangePopulated(start_high, end_high);
196 
197  // If start and end land on the same inner bitmap, then we can do the
198  // whole operation in one call.
199  if (start_high == end_high) {
200  auto &bitmap = current_iter->second;
201  bitmap.addRangeClosed(start_low, end_low);
202  return;
203  }
204 
205  // Because start and end don't land on the same inner bitmap,
206  // we need to do this in multiple steps:
207  // 1. Partially fill the first bitmap with values from the closed
208  // interval [start_low, uint32_max]
209  // 2. Fill intermediate bitmaps completely: [0, uint32_max]
210  // 3. Partially fill the last bitmap with values from the closed
211  // interval [0, end_low]
212  auto num_intermediate_bitmaps = end_high - start_high - 1;
213 
214  // Step 1: Partially fill the first bitmap.
215  {
216  auto &bitmap = current_iter->second;
217  bitmap.addRangeClosed(start_low, uint32_max);
218  ++current_iter;
219  }
220 
221  // Step 2. Fill intermediate bitmaps completely.
222  if (num_intermediate_bitmaps != 0) {
223  auto &first_intermediate = current_iter->second;
224  first_intermediate.addRangeClosed(0, uint32_max);
225  ++current_iter;
226 
227  // Now make (num_intermediate_bitmaps - 1) copies of this.
228  for (uint32_t i = 1; i != num_intermediate_bitmaps; ++i) {
229  auto &next_intermediate = current_iter->second;
230  next_intermediate = first_intermediate;
231  ++current_iter;
232  }
233  }
234 
235  // Step 3: Partially fill the last bitmap.
236  auto &bitmap = current_iter->second;
237  bitmap.addRangeClosed(0, end_low);
238  }
239 
243  void addMany(size_t n_args, const uint32_t *vals) {
244  lookupOrCreateInner(0).addMany(n_args, vals);
245  }
246 
250  void addMany(size_t n_args, const uint64_t *vals) {
251  // Potentially reduce outer map lookups by optimistically
252  // assuming that adjacent values will belong to the same inner bitmap.
253  Roaring *last_inner_bitmap = nullptr;
254  uint32_t last_value_high = 0;
255  BulkContext last_bulk_context;
256  for (size_t lcv = 0; lcv < n_args; lcv++) {
257  auto value = vals[lcv];
258  auto value_high = highBytes(value);
259  auto value_low = lowBytes(value);
260  if (last_inner_bitmap == nullptr || value_high != last_value_high) {
261  last_inner_bitmap = &lookupOrCreateInner(value_high);
262  last_value_high = value_high;
263  last_bulk_context = BulkContext{};
264  }
265  last_inner_bitmap->addBulk(last_bulk_context, value_low);
266  }
267  }
268 
272  void remove(uint32_t x) {
273  auto iter = roarings.begin();
274  // Since x is a uint32_t, highbytes(x) == 0. The inner bitmap we are
275  // looking for, if it exists, will be at the first slot of 'roarings'.
276  if (iter == roarings.end() || iter->first != 0) {
277  return;
278  }
279  auto &bitmap = iter->second;
280  bitmap.remove(x);
281  eraseIfEmpty(iter);
282  }
283 
287  void remove(uint64_t x) {
288  auto iter = roarings.find(highBytes(x));
289  if (iter == roarings.end()) {
290  return;
291  }
292  auto &bitmap = iter->second;
293  bitmap.remove(lowBytes(x));
294  eraseIfEmpty(iter);
295  }
296 
302  bool removeChecked(uint32_t x) {
303  auto iter = roarings.begin();
304  // Since x is a uint32_t, highbytes(x) == 0. The inner bitmap we are
305  // looking for, if it exists, will be at the first slot of 'roarings'.
306  if (iter == roarings.end() || iter->first != 0) {
307  return false;
308  }
309  auto &bitmap = iter->second;
310  if (!bitmap.removeChecked(x)) {
311  return false;
312  }
313  eraseIfEmpty(iter);
314  return true;
315  }
316 
322  bool removeChecked(uint64_t x) {
323  auto iter = roarings.find(highBytes(x));
324  if (iter == roarings.end()) {
325  return false;
326  }
327  auto &bitmap = iter->second;
328  if (!bitmap.removeChecked(lowBytes(x))) {
329  return false;
330  }
331  eraseIfEmpty(iter);
332  return true;
333  }
334 
338  void removeRange(uint64_t min, uint64_t max) {
339  if (min >= max) {
340  return;
341  }
342  return removeRangeClosed(min, max - 1);
343  }
344 
348  void removeRangeClosed(uint32_t min, uint32_t max) {
349  auto iter = roarings.begin();
350  // Since min and max are uint32_t, highbytes(min or max) == 0. The inner
351  // bitmap we are looking for, if it exists, will be at the first slot of
352  // 'roarings'.
353  if (iter == roarings.end() || iter->first != 0) {
354  return;
355  }
356  auto &bitmap = iter->second;
357  bitmap.removeRangeClosed(min, max);
358  eraseIfEmpty(iter);
359  }
360 
364  void removeRangeClosed(uint64_t min, uint64_t max) {
365  if (min > max) {
366  return;
367  }
368  uint32_t start_high = highBytes(min);
369  uint32_t start_low = lowBytes(min);
370  uint32_t end_high = highBytes(max);
371  uint32_t end_low = lowBytes(max);
372 
373  // We put std::numeric_limits<>::max in parentheses to avoid a
374  // clash with the Windows.h header under Windows.
375  const uint32_t uint32_max = (std::numeric_limits<uint32_t>::max)();
376 
377  // If the outer map is empty, end_high is less than the first key,
378  // or start_high is greater than the last key, then exit now because
379  // there is no work to do.
380  if (roarings.empty() || end_high < roarings.cbegin()->first ||
381  start_high > (roarings.crbegin())->first) {
382  return;
383  }
384 
385  // If we get here, start_iter points to the first entry in the outer map
386  // with key >= start_high. Such an entry is known to exist (i.e. the
387  // iterator will not be equal to end()) because start_high <= the last
388  // key in the map (thanks to the above if statement).
389  auto start_iter = roarings.lower_bound(start_high);
390  // end_iter points to the first entry in the outer map with
391  // key >= end_high, if such a key exists. Otherwise, it equals end().
392  auto end_iter = roarings.lower_bound(end_high);
393 
394  // Note that the 'lower_bound' method will find the start and end slots,
395  // if they exist; otherwise it will find the next-higher slots.
396  // In the case where 'start' landed on an existing slot, we need to do a
397  // partial erase of that slot, and likewise for 'end'. But all the slots
398  // in between can be fully erased. More precisely:
399  //
400  // 1. If the start point falls on an existing entry, there are two
401  // subcases:
402  // a. if the end point falls on that same entry, remove the closed
403  // interval [start_low, end_low] from that entry and we are done.
404  // b. Otherwise, remove the closed interval [start_low, uint32_max]
405  // from that entry, advance start_iter, and fall through to
406  // step 2.
407  // 2. Completely erase all slots in the half-open interval
408  // [start_iter, end_iter)
409  // 3. If the end point falls on an existing entry, remove the closed
410  // interval [0, end_high] from it.
411 
412  // Step 1. If the start point falls on an existing entry...
413  if (start_iter->first == start_high) {
414  auto &start_inner = start_iter->second;
415  // 1a. if the end point falls on that same entry...
416  if (start_iter == end_iter) {
417  start_inner.removeRangeClosed(start_low, end_low);
418  eraseIfEmpty(start_iter);
419  return;
420  }
421 
422  // 1b. Otherwise, remove the closed range [start_low, uint32_max]...
423  start_inner.removeRangeClosed(start_low, uint32_max);
424  // Advance start_iter, but keep the old value so we can check the
425  // bitmap we just modified for emptiness and erase if it necessary.
426  auto temp = start_iter++;
427  eraseIfEmpty(temp);
428  }
429 
430  // 2. Completely erase all slots in the half-open interval...
431  roarings.erase(start_iter, end_iter);
432 
433  // 3. If the end point falls on an existing entry...
434  if (end_iter != roarings.end() && end_iter->first == end_high) {
435  auto &end_inner = end_iter->second;
436  end_inner.removeRangeClosed(0, end_low);
437  eraseIfEmpty(end_iter);
438  }
439  }
440 
444  void clear() { roarings.clear(); }
445 
449  uint64_t maximum() const {
450  for (auto roaring_iter = roarings.crbegin();
451  roaring_iter != roarings.crend(); ++roaring_iter) {
452  if (!roaring_iter->second.isEmpty()) {
453  return uniteBytes(roaring_iter->first,
454  roaring_iter->second.maximum());
455  }
456  }
457  // we put std::numeric_limits<>::max/min in parentheses
458  // to avoid a clash with the Windows.h header under Windows
459  return (std::numeric_limits<uint64_t>::min)();
460  }
461 
465  uint64_t minimum() const {
466  for (auto roaring_iter = roarings.cbegin();
467  roaring_iter != roarings.cend(); ++roaring_iter) {
468  if (!roaring_iter->second.isEmpty()) {
469  return uniteBytes(roaring_iter->first,
470  roaring_iter->second.minimum());
471  }
472  }
473  // we put std::numeric_limits<>::max/min in parentheses
474  // to avoid a clash with the Windows.h header under Windows
475  return (std::numeric_limits<uint64_t>::max)();
476  }
477 
481  bool contains(uint32_t x) const {
482  auto iter = roarings.find(0);
483  if (iter == roarings.end()) {
484  return false;
485  }
486  return iter->second.contains(x);
487  }
488  bool contains(uint64_t x) const {
489  auto iter = roarings.find(highBytes(x));
490  if (iter == roarings.end()) {
491  return false;
492  }
493  return iter->second.contains(lowBytes(x));
494  }
495 
496  // TODO: implement `containsRange`
497 
507  if (this == &other) {
508  // ANDing *this with itself is a no-op.
509  return *this;
510  }
511 
512  // Logic table summarizing what to do when a given outer key is
513  // present vs. absent from self and other.
514  //
515  // self other (self & other) work to do
516  // --------------------------------------------
517  // absent absent empty None
518  // absent present empty None
519  // present absent empty Erase self
520  // present present empty or not Intersect self with other, but
521  // erase self if result is empty.
522  //
523  // Because there is only work to do when a key is present in 'self', the
524  // main for loop iterates over entries in 'self'.
525 
526  decltype(roarings.begin()) self_next;
527  for (auto self_iter = roarings.begin(); self_iter != roarings.end();
528  self_iter = self_next) {
529  // Do the 'next' operation now, so we don't have to worry about
530  // invalidation of self_iter down below with the 'erase' operation.
531  self_next = std::next(self_iter);
532 
533  auto self_key = self_iter->first;
534  auto &self_bitmap = self_iter->second;
535 
536  auto other_iter = other.roarings.find(self_key);
537  if (other_iter == other.roarings.end()) {
538  // 'other' doesn't have self_key. In the logic table above,
539  // this reflects the case (self.present & other.absent).
540  // So, erase self.
541  roarings.erase(self_iter);
542  continue;
543  }
544 
545  // Both sides have self_key. In the logic table above, this reflects
546  // the case (self.present & other.present). So, intersect self with
547  // other.
548  const auto &other_bitmap = other_iter->second;
549  self_bitmap &= other_bitmap;
550  if (self_bitmap.isEmpty()) {
551  // ...but if intersection is empty, remove it altogether.
552  roarings.erase(self_iter);
553  }
554  }
555  return *this;
556  }
557 
564  if (this == &other) {
565  // Subtracting *this from itself results in the empty map.
566  roarings.clear();
567  return *this;
568  }
569 
570  // Logic table summarizing what to do when a given outer key is
571  // present vs. absent from self and other.
572  //
573  // self other (self - other) work to do
574  // --------------------------------------------
575  // absent absent empty None
576  // absent present empty None
577  // present absent unchanged None
578  // present present empty or not Subtract other from self, but
579  // erase self if result is empty
580  //
581  // Because there is only work to do when a key is present in both 'self'
582  // and 'other', the main while loop ping-pongs back and forth until it
583  // finds the next key that is the same on both sides.
584 
585  auto self_iter = roarings.begin();
586  auto other_iter = other.roarings.cbegin();
587 
588  while (self_iter != roarings.end() &&
589  other_iter != other.roarings.cend()) {
590  auto self_key = self_iter->first;
591  auto other_key = other_iter->first;
592  if (self_key < other_key) {
593  // Because self_key is < other_key, advance self_iter to the
594  // first point where self_key >= other_key (or end).
595  self_iter = roarings.lower_bound(other_key);
596  continue;
597  }
598 
599  if (self_key > other_key) {
600  // Because self_key is > other_key, advance other_iter to the
601  // first point where other_key >= self_key (or end).
602  other_iter = other.roarings.lower_bound(self_key);
603  continue;
604  }
605 
606  // Both sides have self_key. In the logic table above, this reflects
607  // the case (self.present & other.present). So subtract other from
608  // self.
609  auto &self_bitmap = self_iter->second;
610  const auto &other_bitmap = other_iter->second;
611  self_bitmap -= other_bitmap;
612 
613  if (self_bitmap.isEmpty()) {
614  // ...but if subtraction is empty, remove it altogether.
615  self_iter = roarings.erase(self_iter);
616  } else {
617  ++self_iter;
618  }
619  ++other_iter;
620  }
621  return *this;
622  }
623 
632  if (this == &other) {
633  // ORing *this with itself is a no-op.
634  return *this;
635  }
636 
637  // Logic table summarizing what to do when a given outer key is
638  // present vs. absent from self and other.
639  //
640  // self other (self | other) work to do
641  // --------------------------------------------
642  // absent absent empty None
643  // absent present not empty Copy other to self and set flags
644  // present absent unchanged None
645  // present present not empty self |= other
646  //
647  // Because there is only work to do when a key is present in 'other',
648  // the main for loop iterates over entries in 'other'.
649 
650  for (const auto &other_entry : other.roarings) {
651  const auto &other_bitmap = other_entry.second;
652 
653  // Try to insert other_bitmap into self at other_key. We take
654  // advantage of the fact that std::map::insert will not overwrite an
655  // existing entry.
656  auto insert_result = roarings.insert(other_entry);
657  auto self_iter = insert_result.first;
658  auto insert_happened = insert_result.second;
659  auto &self_bitmap = self_iter->second;
660 
661  if (insert_happened) {
662  // Key was not present in self, so insert was performed above.
663  // In the logic table above, this reflects the case
664  // (self.absent | other.present). Because the copy has already
665  // happened, thanks to the 'insert' operation above, we just
666  // need to set the copyOnWrite flag.
667  self_bitmap.setCopyOnWrite(copyOnWrite);
668  continue;
669  }
670 
671  // Both sides have self_key, and the insert was not performed. In
672  // the logic table above, this reflects the case
673  // (self.present & other.present). So OR other into self.
674  self_bitmap |= other_bitmap;
675  }
676  return *this;
677  }
678 
684  if (this == &other) {
685  // XORing *this with itself results in the empty map.
686  roarings.clear();
687  return *this;
688  }
689 
690  // Logic table summarizing what to do when a given outer key is
691  // present vs. absent from self and other.
692  //
693  // self other (self ^ other) work to do
694  // --------------------------------------------
695  // absent absent empty None
696  // absent present non-empty Copy other to self and set flags
697  // present absent unchanged None
698  // present present empty or not XOR other into self, but erase self
699  // if result is empty.
700  //
701  // Because there is only work to do when a key is present in 'other',
702  // the main for loop iterates over entries in 'other'.
703 
704  for (const auto &other_entry : other.roarings) {
705  const auto &other_bitmap = other_entry.second;
706 
707  // Try to insert other_bitmap into self at other_key. We take
708  // advantage of the fact that std::map::insert will not overwrite an
709  // existing entry.
710  auto insert_result = roarings.insert(other_entry);
711  auto self_iter = insert_result.first;
712  auto insert_happened = insert_result.second;
713  auto &self_bitmap = self_iter->second;
714 
715  if (insert_happened) {
716  // Key was not present in self, so insert was performed above.
717  // In the logic table above, this reflects the case
718  // (self.absent ^ other.present). Because the copy has already
719  // happened, thanks to the 'insert' operation above, we just
720  // need to set the copyOnWrite flag.
721  self_bitmap.setCopyOnWrite(copyOnWrite);
722  continue;
723  }
724 
725  // Both sides have self_key, and the insert was not performed. In
726  // the logic table above, this reflects the case
727  // (self.present ^ other.present). So XOR other into self.
728  self_bitmap ^= other_bitmap;
729 
730  if (self_bitmap.isEmpty()) {
731  // ...but if intersection is empty, remove it altogether.
732  roarings.erase(self_iter);
733  }
734  }
735  return *this;
736  }
737 
741  void swap(Roaring64Map &r) { roarings.swap(r.roarings); }
742 
749  uint64_t cardinality() const {
750  if (isFull()) {
751 #if ROARING_EXCEPTIONS
752  throw std::length_error(
753  "bitmap is full, cardinality is 2^64, "
754  "unable to represent in a 64-bit integer");
755 #else
757  "bitmap is full, cardinality is 2^64, "
758  "unable to represent in a 64-bit integer");
759 #endif
760  }
761  return std::accumulate(
762  roarings.cbegin(), roarings.cend(), (uint64_t)0,
763  [](uint64_t previous,
764  const std::pair<const uint32_t, Roaring> &map_entry) {
765  return previous + map_entry.second.cardinality();
766  });
767  }
768 
772  bool isEmpty() const {
773  return std::all_of(
774  roarings.cbegin(), roarings.cend(),
775  [](const std::pair<const uint32_t, Roaring> &map_entry) {
776  return map_entry.second.isEmpty();
777  });
778  }
779 
783  bool isFull() const {
784  // only bother to check if map is fully saturated
785  //
786  // we put std::numeric_limits<>::max/min in parentheses
787  // to avoid a clash with the Windows.h header under Windows
788  return roarings.size() ==
789  ((uint64_t)(std::numeric_limits<uint32_t>::max)()) + 1
790  ? std::all_of(roarings.cbegin(), roarings.cend(),
791  [](const std::pair<const uint32_t, Roaring>
792  &roaring_map_entry) {
793  return roaring_map_entry.second.isFull();
794  })
795  : false;
796  }
797 
801  bool isSubset(const Roaring64Map &r) const {
802  for (const auto &map_entry : roarings) {
803  if (map_entry.second.isEmpty()) {
804  continue;
805  }
806  auto roaring_iter = r.roarings.find(map_entry.first);
807  if (roaring_iter == r.roarings.cend())
808  return false;
809  else if (!map_entry.second.isSubset(roaring_iter->second))
810  return false;
811  }
812  return true;
813  }
814 
821  bool isStrictSubset(const Roaring64Map &r) const {
822  return isSubset(r) && cardinality() != r.cardinality();
823  }
824 
831  void toUint64Array(uint64_t *ans) const {
832  // Annoyingly, VS 2017 marks std::accumulate() as [[nodiscard]]
833  (void)std::accumulate(
834  roarings.cbegin(), roarings.cend(), ans,
835  [](uint64_t *previous,
836  const std::pair<const uint32_t, Roaring> &map_entry) {
837  for (uint32_t low_bits : map_entry.second)
838  *previous++ = uniteBytes(map_entry.first, low_bits);
839  return previous;
840  });
841  }
842 
846  bool operator==(const Roaring64Map &r) const {
847  // we cannot use operator == on the map because either side may contain
848  // empty Roaring Bitmaps
849  auto lhs_iter = roarings.cbegin();
850  auto lhs_cend = roarings.cend();
851  auto rhs_iter = r.roarings.cbegin();
852  auto rhs_cend = r.roarings.cend();
853  while (lhs_iter != lhs_cend && rhs_iter != rhs_cend) {
854  auto lhs_key = lhs_iter->first, rhs_key = rhs_iter->first;
855  const auto &lhs_map = lhs_iter->second, &rhs_map = rhs_iter->second;
856  if (lhs_map.isEmpty()) {
857  ++lhs_iter;
858  continue;
859  }
860  if (rhs_map.isEmpty()) {
861  ++rhs_iter;
862  continue;
863  }
864  if (!(lhs_key == rhs_key)) {
865  return false;
866  }
867  if (!(lhs_map == rhs_map)) {
868  return false;
869  }
870  ++lhs_iter;
871  ++rhs_iter;
872  }
873  while (lhs_iter != lhs_cend) {
874  if (!lhs_iter->second.isEmpty()) {
875  return false;
876  }
877  ++lhs_iter;
878  }
879  while (rhs_iter != rhs_cend) {
880  if (!rhs_iter->second.isEmpty()) {
881  return false;
882  }
883  ++rhs_iter;
884  }
885  return true;
886  }
887 
892  void flip(uint64_t min, uint64_t max) {
893  if (min >= max) {
894  return;
895  }
896  flipClosed(min, max - 1);
897  }
898 
903  void flipClosed(uint32_t min, uint32_t max) {
904  auto iter = roarings.begin();
905  // Since min and max are uint32_t, highbytes(min or max) == 0. The inner
906  // bitmap we are looking for, if it exists, will be at the first slot of
907  // 'roarings'. If it does not exist, we have to create it.
908  if (iter == roarings.end() || iter->first != 0) {
909  iter = roarings.emplace_hint(iter, std::piecewise_construct,
910  std::forward_as_tuple(0),
911  std::forward_as_tuple());
912  auto &bitmap = iter->second;
913  bitmap.setCopyOnWrite(copyOnWrite);
914  }
915  auto &bitmap = iter->second;
916  bitmap.flipClosed(min, max);
917  eraseIfEmpty(iter);
918  }
919 
924  void flipClosed(uint64_t min, uint64_t max) {
925  if (min > max) {
926  return;
927  }
928  uint32_t start_high = highBytes(min);
929  uint32_t start_low = lowBytes(min);
930  uint32_t end_high = highBytes(max);
931  uint32_t end_low = lowBytes(max);
932 
933  // We put std::numeric_limits<>::max in parentheses to avoid a
934  // clash with the Windows.h header under Windows.
935  const uint32_t uint32_max = (std::numeric_limits<uint32_t>::max)();
936 
937  // Fill in any nonexistent slots with empty Roarings. This simplifies
938  // the logic below, allowing it to simply iterate over the map between
939  // 'start_high' and 'end_high' in a linear fashion.
940  auto current_iter = ensureRangePopulated(start_high, end_high);
941 
942  // If start and end land on the same inner bitmap, then we can do the
943  // whole operation in one call.
944  if (start_high == end_high) {
945  auto &bitmap = current_iter->second;
946  bitmap.flipClosed(start_low, end_low);
947  eraseIfEmpty(current_iter);
948  return;
949  }
950 
951  // Because start and end don't land on the same inner bitmap,
952  // we need to do this in multiple steps:
953  // 1. Partially flip the first bitmap in the closed interval
954  // [start_low, uint32_max]
955  // 2. Flip intermediate bitmaps completely: [0, uint32_max]
956  // 3. Partially flip the last bitmap in the closed interval
957  // [0, end_low]
958 
959  auto num_intermediate_bitmaps = end_high - start_high - 1;
960 
961  // 1. Partially flip the first bitmap.
962  {
963  auto &bitmap = current_iter->second;
964  bitmap.flipClosed(start_low, uint32_max);
965  auto temp = current_iter++;
966  eraseIfEmpty(temp);
967  }
968 
969  // 2. Flip intermediate bitmaps completely.
970  for (uint32_t i = 0; i != num_intermediate_bitmaps; ++i) {
971  auto &bitmap = current_iter->second;
972  bitmap.flipClosed(0, uint32_max);
973  auto temp = current_iter++;
974  eraseIfEmpty(temp);
975  }
976 
977  // 3. Partially flip the last bitmap.
978  auto &bitmap = current_iter->second;
979  bitmap.flipClosed(0, end_low);
980  eraseIfEmpty(current_iter);
981  }
982 
988  return std::accumulate(
989  roarings.begin(), roarings.end(), true,
990  [](bool previous, std::pair<const uint32_t, Roaring> &map_entry) {
991  return map_entry.second.removeRunCompression() && previous;
992  });
993  }
994 
1001  bool runOptimize() {
1002  return std::accumulate(
1003  roarings.begin(), roarings.end(), true,
1004  [](bool previous, std::pair<const uint32_t, Roaring> &map_entry) {
1005  return map_entry.second.runOptimize() && previous;
1006  });
1007  }
1008 
1013  size_t shrinkToFit() {
1014  size_t savedBytes = 0;
1015  auto iter = roarings.begin();
1016  while (iter != roarings.cend()) {
1017  if (iter->second.isEmpty()) {
1018  // empty Roarings are 84 bytes
1019  savedBytes += 88;
1020  roarings.erase(iter++);
1021  } else {
1022  savedBytes += iter->second.shrinkToFit();
1023  iter++;
1024  }
1025  }
1026  return savedBytes;
1027  }
1028 
1040  void iterate(api::roaring_iterator64 iterator, void *ptr) const {
1041  for (const auto &map_entry : roarings) {
1042  bool should_continue =
1043  roaring_iterate64(&map_entry.second.roaring, iterator,
1044  uint64_t(map_entry.first) << 32, ptr);
1045  if (!should_continue) {
1046  break;
1047  }
1048  }
1049  }
1050 
1057  bool select(uint64_t rank, uint64_t *element) const {
1058  for (const auto &map_entry : roarings) {
1059  auto key = map_entry.first;
1060  const auto &bitmap = map_entry.second;
1061 
1062  uint64_t sub_cardinality = bitmap.cardinality();
1063  if (rank < sub_cardinality) {
1064  uint32_t low_bytes;
1065  // Casting rank to uint32_t is safe because
1066  // rank < sub_cardinality and sub_cardinality <= 2^32.
1067  if (!bitmap.select((uint32_t)rank, &low_bytes)) {
1069  "Logic error: bitmap.select() "
1070  "returned false despite rank < cardinality()");
1071  }
1072  *element = uniteBytes(key, low_bytes);
1073  return true;
1074  }
1075  rank -= sub_cardinality;
1076  }
1077  return false;
1078  }
1079 
1083  uint64_t rank(uint64_t x) const {
1084  uint64_t result = 0;
1085  // Find the first bitmap >= x's bucket. If that is the bucket x would be
1086  // in, find it's rank in that bucket. Either way, we're left with a
1087  // range of all buckets strictly smaller than x's bucket, add all their
1088  // cardinalities together.
1089  auto end = roarings.lower_bound(highBytes(x));
1090  if (end != roarings.cend() && end->first == highBytes(x)) {
1091  result += end->second.rank(lowBytes(x));
1092  }
1093  for (auto iter = roarings.cbegin(); iter != end; ++iter) {
1094  result += iter->second.cardinality();
1095  }
1096  return result;
1097  }
1098 
1106  int64_t getIndex(uint64_t x) const {
1107  int64_t index = 0;
1108  auto roaring_destination = roarings.find(highBytes(x));
1109  if (roaring_destination != roarings.cend()) {
1110  for (auto roaring_iter = roarings.cbegin();
1111  roaring_iter != roaring_destination; ++roaring_iter) {
1112  index += roaring_iter->second.cardinality();
1113  }
1114  auto low_idx = roaring_destination->second.getIndex(lowBytes(x));
1115  if (low_idx < 0) return -1;
1116  index += low_idx;
1117  return index;
1118  }
1119  return -1;
1120  }
1121 
1131  size_t write(char *buf, bool portable = true) const {
1132  const char *orig = buf;
1133  // push map size
1134  uint64_t map_size = roarings.size();
1135  std::memcpy(buf, &map_size, sizeof(uint64_t));
1136  buf += sizeof(uint64_t);
1137  std::for_each(roarings.cbegin(), roarings.cend(),
1138  [&buf, portable](
1139  const std::pair<const uint32_t, Roaring> &map_entry) {
1140  // push map key
1141  std::memcpy(buf, &map_entry.first, sizeof(uint32_t));
1142  // ^-- Note: `*((uint32_t*)buf) = map_entry.first;` is
1143  // undefined
1144 
1145  buf += sizeof(uint32_t);
1146  // push map value Roaring
1147  buf += map_entry.second.write(buf, portable);
1148  });
1149  return buf - orig;
1150  }
1151 
1164  static Roaring64Map read(const char *buf, bool portable = true) {
1165  Roaring64Map result;
1166  // get map size
1167  uint64_t map_size;
1168  std::memcpy(&map_size, buf, sizeof(uint64_t));
1169  buf += sizeof(uint64_t);
1170  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1171  // get map key
1172  uint32_t key;
1173  std::memcpy(&key, buf, sizeof(uint32_t));
1174  // ^-- Note: `uint32_t key = *((uint32_t*)buf);` is undefined
1175 
1176  buf += sizeof(uint32_t);
1177  // read map value Roaring
1178  Roaring read_var = Roaring::read(buf, portable);
1179  // forward buffer past the last Roaring Bitmap
1180  buf += read_var.getSizeInBytes(portable);
1181  result.emplaceOrInsert(key, std::move(read_var));
1182  }
1183  return result;
1184  }
1185 
1193  static Roaring64Map readSafe(const char *buf, size_t maxbytes) {
1194  if (maxbytes < sizeof(uint64_t)) {
1195  ROARING_TERMINATE("ran out of bytes");
1196  }
1197  Roaring64Map result;
1198  uint64_t map_size;
1199  std::memcpy(&map_size, buf, sizeof(uint64_t));
1200  buf += sizeof(uint64_t);
1201  maxbytes -= sizeof(uint64_t);
1202  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1203  if (maxbytes < sizeof(uint32_t)) {
1204  ROARING_TERMINATE("ran out of bytes");
1205  }
1206  uint32_t key;
1207  std::memcpy(&key, buf, sizeof(uint32_t));
1208  // ^-- Note: `uint32_t key = *((uint32_t*)buf);` is undefined
1209 
1210  buf += sizeof(uint32_t);
1211  maxbytes -= sizeof(uint32_t);
1212  // read map value Roaring
1213  Roaring read_var = Roaring::readSafe(buf, maxbytes);
1214  // forward buffer past the last Roaring Bitmap
1215  size_t tz = read_var.getSizeInBytes(true);
1216  buf += tz;
1217  maxbytes -= tz;
1218  result.emplaceOrInsert(key, std::move(read_var));
1219  }
1220  return result;
1221  }
1222 
1230  size_t getSizeInBytes(bool portable = true) const {
1231  // start with, respectively, map size and size of keys for each map
1232  // entry
1233  return std::accumulate(
1234  roarings.cbegin(), roarings.cend(),
1235  sizeof(uint64_t) + roarings.size() * sizeof(uint32_t),
1236  [=](size_t previous,
1237  const std::pair<const uint32_t, Roaring> &map_entry) {
1238  // add in bytes used by each Roaring
1239  return previous + map_entry.second.getSizeInBytes(portable);
1240  });
1241  }
1242 
1243  static const Roaring64Map frozenView(const char *buf) {
1244  // size of bitmap buffer and key
1245  const size_t metadata_size = sizeof(size_t) + sizeof(uint32_t);
1246 
1247  Roaring64Map result;
1248 
1249  // get map size
1250  uint64_t map_size;
1251  memcpy(&map_size, buf, sizeof(uint64_t));
1252  buf += sizeof(uint64_t);
1253 
1254  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1255  // pad to 32 bytes minus the metadata size
1256  while (((uintptr_t)buf + metadata_size) % 32 != 0) buf++;
1257 
1258  // get bitmap size
1259  size_t len;
1260  memcpy(&len, buf, sizeof(size_t));
1261  buf += sizeof(size_t);
1262 
1263  // get map key
1264  uint32_t key;
1265  memcpy(&key, buf, sizeof(uint32_t));
1266  buf += sizeof(uint32_t);
1267 
1268  // read map value Roaring
1269  const Roaring read = Roaring::frozenView(buf, len);
1270  result.emplaceOrInsert(key, read);
1271 
1272  // forward buffer past the last Roaring Bitmap
1273  buf += len;
1274  }
1275  return result;
1276  }
1277 
1278  static const Roaring64Map portableDeserializeFrozen(const char *buf) {
1279  Roaring64Map result;
1280  // get map size
1281  uint64_t map_size;
1282  std::memcpy(&map_size, buf, sizeof(uint64_t));
1283  buf += sizeof(uint64_t);
1284  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1285  // get map key
1286  uint32_t key;
1287  std::memcpy(&key, buf, sizeof(uint32_t));
1288  buf += sizeof(uint32_t);
1289  // read map value Roaring
1291  // forward buffer past the last Roaring bitmap
1292  buf += read_var.getSizeInBytes(true);
1293  result.emplaceOrInsert(key, std::move(read_var));
1294  }
1295  return result;
1296  }
1297 
1298  // As with serialized 64-bit bitmaps, 64-bit frozen bitmaps are serialized
1299  // by concatenating one or more Roaring::write output buffers with the
1300  // preceeding map key. Unlike standard bitmap serialization, frozen bitmaps
1301  // must be 32-byte aligned and requires a buffer length to parse. As a
1302  // result, each concatenated output of Roaring::writeFrozen is preceeded by
1303  // padding, the buffer size (size_t), and the map key (uint32_t). The
1304  // padding is used to ensure 32-byte alignment, but since it is followed by
1305  // the buffer size and map key, it actually pads to `(x - sizeof(size_t) +
1306  // sizeof(uint32_t)) mod 32` to leave room for the metadata.
1307  void writeFrozen(char *buf) const {
1308  // size of bitmap buffer and key
1309  const size_t metadata_size = sizeof(size_t) + sizeof(uint32_t);
1310 
1311  // push map size
1312  uint64_t map_size = roarings.size();
1313  memcpy(buf, &map_size, sizeof(uint64_t));
1314  buf += sizeof(uint64_t);
1315 
1316  for (auto &map_entry : roarings) {
1317  size_t frozenSizeInBytes = map_entry.second.getFrozenSizeInBytes();
1318 
1319  // pad to 32 bytes minus the metadata size
1320  while (((uintptr_t)buf + metadata_size) % 32 != 0) buf++;
1321 
1322  // push bitmap size
1323  memcpy(buf, &frozenSizeInBytes, sizeof(size_t));
1324  buf += sizeof(size_t);
1325 
1326  // push map key
1327  memcpy(buf, &map_entry.first, sizeof(uint32_t));
1328  buf += sizeof(uint32_t);
1329 
1330  // push map value Roaring
1331  map_entry.second.writeFrozen(buf);
1332  buf += map_entry.second.getFrozenSizeInBytes();
1333  }
1334  }
1335 
1336  size_t getFrozenSizeInBytes() const {
1337  // size of bitmap size and map key
1338  const size_t metadata_size = sizeof(size_t) + sizeof(uint32_t);
1339  size_t ret = 0;
1340 
1341  // map size
1342  ret += sizeof(uint64_t);
1343 
1344  for (auto &map_entry : roarings) {
1345  // pad to 32 bytes minus the metadata size
1346  while ((ret + metadata_size) % 32 != 0) ret++;
1347  ret += metadata_size;
1348 
1349  // frozen bitmaps must be 32-byte aligned
1350  ret += map_entry.second.getFrozenSizeInBytes();
1351  }
1352  return ret;
1353  }
1354 
1365  return Roaring64Map(*this) &= o;
1366  }
1367 
1373  return Roaring64Map(*this) -= o;
1374  }
1375 
1381  return Roaring64Map(*this) |= o;
1382  }
1383 
1389  return Roaring64Map(*this) ^= o;
1390  }
1391 
1395  void setCopyOnWrite(bool val) {
1396  if (copyOnWrite == val) return;
1397  copyOnWrite = val;
1398  std::for_each(roarings.begin(), roarings.end(),
1399  [=](std::pair<const uint32_t, Roaring> &map_entry) {
1400  map_entry.second.setCopyOnWrite(val);
1401  });
1402  }
1403 
1408  void printf() const {
1409  auto sink = [](const std::string &s) { fputs(s.c_str(), stdout); };
1410  printToSink(sink);
1411  sink("\n");
1412  }
1413 
1417  std::string toString() const {
1418  std::string result;
1419  auto sink = [&result](const std::string &s) { result += s; };
1420  printToSink(sink);
1421  return result;
1422  }
1423 
1427  bool getCopyOnWrite() const { return copyOnWrite; }
1428 
1433  static Roaring64Map fastunion(size_t n, const Roaring64Map **inputs) {
1434  // The strategy here is to basically do a "group by" operation.
1435  // We group the input roarings by key, do a 32-bit
1436  // roaring_bitmap_or_many on each group, and collect the results.
1437  // We accomplish the "group by" operation using a priority queue, which
1438  // tracks the next key for each of our input maps. At each step, our
1439  // algorithm takes the next subset of maps that share the same next key,
1440  // runs roaring_bitmap_or_many on those bitmaps, and then advances the
1441  // current_iter on all the affected entries and then repeats.
1442 
1443  // There is an entry in our priority queue for each of the 'n' inputs.
1444  // For a given Roaring64Map, we look at its underlying 'roarings'
1445  // std::map, and take its begin() and end(). This forms our half-open
1446  // interval [current_iter, end_iter), which we keep in the priority
1447  // queue as a pq_entry. These entries are updated (removed and then
1448  // reinserted with the pq_entry.iterator field advanced by one step) as
1449  // our algorithm progresses. But when a given interval becomes empty
1450  // (i.e. pq_entry.iterator == pq_entry.end) it is not returned to the
1451  // priority queue.
1452  struct pq_entry {
1453  roarings_t::const_iterator iterator;
1454  roarings_t::const_iterator end;
1455  };
1456 
1457  // Custom comparator for the priority queue.
1458  auto pq_comp = [](const pq_entry &lhs, const pq_entry &rhs) {
1459  auto left_key = lhs.iterator->first;
1460  auto right_key = rhs.iterator->first;
1461 
1462  // We compare in the opposite direction than normal because priority
1463  // queues normally order from largest to smallest, but we want
1464  // smallest to largest.
1465  return left_key > right_key;
1466  };
1467 
1468  // Create and populate the priority queue.
1469  std::priority_queue<pq_entry, std::vector<pq_entry>, decltype(pq_comp)>
1470  pq(pq_comp);
1471  for (size_t i = 0; i < n; ++i) {
1472  const auto &roarings = inputs[i]->roarings;
1473  if (roarings.begin() != roarings.end()) {
1474  pq.push({roarings.begin(), roarings.end()});
1475  }
1476  }
1477 
1478  // A reusable vector that holds the pointers to the inner bitmaps that
1479  // we pass to the underlying 32-bit fastunion operation.
1480  std::vector<const roaring_bitmap_t *> group_bitmaps;
1481 
1482  // Summary of the algorithm:
1483  // 1. While the priority queue is not empty:
1484  // A. Get its lowest key. Call this group_key
1485  // B. While the lowest entry in the priority queue has a key equal to
1486  // group_key:
1487  // 1. Remove this entry (the pair {current_iter, end_iter}) from
1488  // the priority queue.
1489  // 2. Add the bitmap pointed to by current_iter to a list of
1490  // 32-bit bitmaps to process.
1491  // 3. Advance current_iter. Now it will point to a bitmap entry
1492  // with some key greater than group_key (or it will point to
1493  // end()).
1494  // 4. If current_iter != end_iter, reinsert the pair into the
1495  // priority queue.
1496  // C. Invoke the 32-bit roaring_bitmap_or_many() and add to result
1497  Roaring64Map result;
1498  while (!pq.empty()) {
1499  // Find the next key (the lowest key) in the priority queue.
1500  auto group_key = pq.top().iterator->first;
1501 
1502  // The purpose of the inner loop is to gather all the inner bitmaps
1503  // that share "group_key" into "group_bitmaps" so that they can be
1504  // fed to roaring_bitmap_or_many(). While we are doing this, we
1505  // advance those iterators to their next value and reinsert them
1506  // into the priority queue (unless they reach their end).
1507  group_bitmaps.clear();
1508  while (!pq.empty()) {
1509  auto candidate_current_iter = pq.top().iterator;
1510  auto candidate_end_iter = pq.top().end;
1511 
1512  auto candidate_key = candidate_current_iter->first;
1513  const auto &candidate_bitmap = candidate_current_iter->second;
1514 
1515  // This element will either be in the group (having
1516  // key == group_key) or it will not be in the group (having
1517  // key > group_key). (Note it cannot have key < group_key
1518  // because of the ordered nature of the priority queue itself
1519  // and the ordered nature of all the underlying roaring maps).
1520  if (candidate_key != group_key) {
1521  // This entry, and (thanks to the nature of the priority
1522  // queue) all other entries as well, are all greater than
1523  // group_key, so we're done collecting elements for the
1524  // current group. Because of the way this loop was written,
1525  // the group will will always contain at least one element.
1526  break;
1527  }
1528 
1529  group_bitmaps.push_back(&candidate_bitmap.roaring);
1530  // Remove this entry from the priority queue. Note this
1531  // invalidates pq.top() so make sure you don't have any dangling
1532  // references to it.
1533  pq.pop();
1534 
1535  // Advance 'candidate_current_iter' and insert a new entry
1536  // {candidate_current_iter, candidate_end_iter} into the
1537  // priority queue (unless it has reached its end).
1538  ++candidate_current_iter;
1539  if (candidate_current_iter != candidate_end_iter) {
1540  pq.push({candidate_current_iter, candidate_end_iter});
1541  }
1542  }
1543 
1544  // Use the fast inner union to combine these.
1545  auto *inner_result = roaring_bitmap_or_many(group_bitmaps.size(),
1546  group_bitmaps.data());
1547  // Insert the 32-bit result at end of the 'roarings' map of the
1548  // result we are building.
1549  result.roarings.insert(
1550  result.roarings.end(),
1551  std::make_pair(group_key, Roaring(inner_result)));
1552  }
1553  return result;
1554  }
1555 
1560 
1570  const_iterator begin() const;
1571 
1576  const_iterator end() const;
1577 
1578  private:
1579  typedef std::map<uint32_t, Roaring> roarings_t;
1580  roarings_t roarings{}; // The empty constructor silences warnings from
1581  // pedantic static analyzers.
1582  bool copyOnWrite{false};
1583  static constexpr uint32_t highBytes(const uint64_t in) {
1584  return uint32_t(in >> 32);
1585  }
1586  static constexpr uint32_t lowBytes(const uint64_t in) {
1587  return uint32_t(in);
1588  }
1589  static constexpr uint64_t uniteBytes(const uint32_t highBytes,
1590  const uint32_t lowBytes) {
1591  return (uint64_t(highBytes) << 32) | uint64_t(lowBytes);
1592  }
1593  // this is needed to tolerate gcc's C++11 libstdc++ lacking emplace
1594  // prior to version 4.8
1595  void emplaceOrInsert(const uint32_t key, const Roaring &value) {
1596 #if defined(__GLIBCXX__) && __GLIBCXX__ < 20130322
1597  roarings.insert(std::make_pair(key, value));
1598 #else
1599  roarings.emplace(std::make_pair(key, value));
1600 #endif
1601  }
1602 
1603  void emplaceOrInsert(const uint32_t key, Roaring &&value) {
1604 #if defined(__GLIBCXX__) && __GLIBCXX__ < 20130322
1605  roarings.insert(std::make_pair(key, std::move(value)));
1606 #else
1607  roarings.emplace(key, std::move(value));
1608 #endif
1609  }
1610 
1611  /*
1612  * Look up 'key' in the 'roarings' map. If it does not exist, create it.
1613  * Also, set its copyOnWrite flag to 'copyOnWrite'. Then return a reference
1614  * to the (already existing or newly created) inner bitmap.
1615  */
1616  Roaring &lookupOrCreateInner(uint32_t key) {
1617  auto &bitmap = roarings[key];
1618  bitmap.setCopyOnWrite(copyOnWrite);
1619  return bitmap;
1620  }
1621 
1625  void printToSink(
1626  const std::function<void(const std::string &)> &sink) const {
1627  sink("{");
1628 
1629  // Storage for snprintf. Big enough to store the decimal representation
1630  // of the largest uint64_t value and trailing \0.
1631  char buffer[32];
1632  const char *separator = "";
1633  // Reusable, and therefore avoids many repeated heap allocations.
1634  std::string callback_string;
1635  for (const auto &entry : roarings) {
1636  auto high_bits = entry.first;
1637  const auto &bitmap = entry.second;
1638  for (const auto low_bits : bitmap) {
1639  auto value = uniteBytes(high_bits, low_bits);
1640  snprintf(buffer, sizeof(buffer), "%" PRIu64, value);
1641  callback_string = separator;
1642  callback_string.append(buffer);
1643  sink(callback_string);
1644  separator = ",";
1645  }
1646  }
1647  sink("}");
1648  }
1649 
1656  roarings_t::iterator ensureRangePopulated(uint32_t start_high,
1657  uint32_t end_high) {
1658  if (start_high > end_high) {
1659  ROARING_TERMINATE("Logic error: start_high > end_high");
1660  }
1661  // next_populated_iter points to the first entry in the outer map with
1662  // key >= start_high, or end().
1663  auto next_populated_iter = roarings.lower_bound(start_high);
1664 
1665  // Use uint64_t to avoid an infinite loop when end_high == uint32_max.
1666  roarings_t::iterator start_iter{}; // Definitely assigned in loop.
1667  for (uint64_t slot = start_high; slot <= end_high; ++slot) {
1668  roarings_t::iterator slot_iter;
1669  if (next_populated_iter != roarings.end() &&
1670  next_populated_iter->first == slot) {
1671  // 'slot' index has caught up to next_populated_iter.
1672  // Note it here and advance next_populated_iter.
1673  slot_iter = next_populated_iter++;
1674  } else {
1675  // 'slot' index has not yet caught up to next_populated_iter.
1676  // Make a fresh entry {key = 'slot', value = Roaring()}, insert
1677  // it just prior to next_populated_iter, and set its copy
1678  // on write flag. We take pains to use emplace_hint and
1679  // piecewise_construct to minimize effort.
1680  slot_iter = roarings.emplace_hint(
1681  next_populated_iter, std::piecewise_construct,
1682  std::forward_as_tuple(uint32_t(slot)),
1683  std::forward_as_tuple());
1684  auto &bitmap = slot_iter->second;
1685  bitmap.setCopyOnWrite(copyOnWrite);
1686  }
1687 
1688  // Make a note of the iterator of the starting slot. It will be
1689  // needed for the return value.
1690  if (slot == start_high) {
1691  start_iter = slot_iter;
1692  }
1693  }
1694  return start_iter;
1695  }
1696 
1701  void eraseIfEmpty(roarings_t::iterator iter) {
1702  const auto &bitmap = iter->second;
1703  if (bitmap.isEmpty()) {
1704  roarings.erase(iter);
1705  }
1706  }
1707 };
1708 
1715  public:
1716  typedef std::bidirectional_iterator_tag iterator_category;
1717  typedef uint64_t *pointer;
1718  typedef uint64_t &reference;
1719  typedef uint64_t value_type;
1720  typedef int64_t difference_type;
1722 
1724  bool exhausted = false)
1725  : p(&parent.roarings) {
1726  if (exhausted || parent.roarings.empty()) {
1727  map_iter = p->cend();
1728  } else {
1729  map_iter = parent.roarings.cbegin();
1730  roaring_iterator_init(&map_iter->second.roaring, &i);
1731  while (!i.has_value) {
1732  map_iter++;
1733  if (map_iter == p->cend()) return;
1734  roaring_iterator_init(&map_iter->second.roaring, &i);
1735  }
1736  }
1737  }
1738 
1743  return Roaring64Map::uniteBytes(map_iter->first, i.current_value);
1744  }
1745 
1746  bool operator<(const type_of_iterator &o) const {
1747  if (map_iter == p->cend()) return false;
1748  if (o.map_iter == o.p->cend()) return true;
1749  return **this < *o;
1750  }
1751 
1752  bool operator<=(const type_of_iterator &o) const {
1753  if (o.map_iter == o.p->cend()) return true;
1754  if (map_iter == p->cend()) return false;
1755  return **this <= *o;
1756  }
1757 
1758  bool operator>(const type_of_iterator &o) const {
1759  if (o.map_iter == o.p->cend()) return false;
1760  if (map_iter == p->cend()) return true;
1761  return **this > *o;
1762  }
1763 
1764  bool operator>=(const type_of_iterator &o) const {
1765  if (map_iter == p->cend()) return true;
1766  if (o.map_iter == o.p->cend()) return false;
1767  return **this >= *o;
1768  }
1769 
1770  type_of_iterator &operator++() { // ++i, must returned inc. value
1771  if (i.has_value == true) roaring_uint32_iterator_advance(&i);
1772  while (!i.has_value) {
1773  ++map_iter;
1774  if (map_iter == p->cend()) return *this;
1775  roaring_iterator_init(&map_iter->second.roaring, &i);
1776  }
1777  return *this;
1778  }
1779 
1780  type_of_iterator operator++(int) { // i++, must return orig. value
1783  while (!i.has_value) {
1784  ++map_iter;
1785  if (map_iter == p->cend()) return orig;
1786  roaring_iterator_init(&map_iter->second.roaring, &i);
1787  }
1788  return orig;
1789  }
1790 
1796  map_iter = p->lower_bound(Roaring64Map::highBytes(x));
1797  if (map_iter != p->cend()) {
1798  roaring_iterator_init(&map_iter->second.roaring, &i);
1799  if (map_iter->first == Roaring64Map::highBytes(x)) {
1801  &i, Roaring64Map::lowBytes(x)))
1802  return true;
1803  ++map_iter;
1804  if (map_iter == p->cend()) return false;
1805  roaring_iterator_init(&map_iter->second.roaring, &i);
1806  }
1807  return true;
1808  }
1809  return false;
1810  }
1811 
1813  CROARING_DEPRECATED bool move(const value_type &x) {
1814  return move_equalorlarger(x);
1815  }
1816 
1817  type_of_iterator &operator--() { // --i, must return dec.value
1818  if (map_iter == p->cend()) {
1819  --map_iter;
1820  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1821  if (i.has_value) return *this;
1822  }
1823 
1825  while (!i.has_value) {
1826  if (map_iter == p->cbegin()) return *this;
1827  map_iter--;
1828  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1829  }
1830  return *this;
1831  }
1832 
1833  type_of_iterator operator--(int) { // i--, must return orig. value
1835  if (map_iter == p->cend()) {
1836  --map_iter;
1837  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1838  return orig;
1839  }
1840 
1842  while (!i.has_value) {
1843  if (map_iter == p->cbegin()) return orig;
1844  map_iter--;
1845  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1846  }
1847  return orig;
1848  }
1849 
1851  if (map_iter == p->cend() && o.map_iter == o.p->cend()) return true;
1852  if (o.map_iter == o.p->cend()) return false;
1853  return **this == *o;
1854  }
1855 
1857  if (map_iter == p->cend() && o.map_iter == o.p->cend()) return false;
1858  if (o.map_iter == o.p->cend()) return true;
1859  return **this != *o;
1860  }
1861 
1862  private:
1863  const std::map<uint32_t, Roaring> *p{nullptr};
1864  std::map<uint32_t, Roaring>::const_iterator
1865  map_iter{}; // The empty constructor silences warnings from pedantic
1866  // static analyzers.
1868  i{}; // The empty constructor silences warnings from pedantic static
1869  // analyzers.
1870 };
1871 
1874 }
1875 
1877  return Roaring64MapSetBitBiDirectionalIterator(*this, true);
1878 }
1879 
1880 } // namespace roaring
1881 
1882 #endif /* INCLUDE_ROARING_64_MAP_HH_ */
bool operator<(const type_of_iterator &o) const
bool operator<=(const type_of_iterator &o) const
bool operator!=(const Roaring64MapSetBitBiDirectionalIterator &o) const
Roaring64MapSetBitBiDirectionalIterator(const Roaring64Map &parent, bool exhausted=false)
bool operator>(const type_of_iterator &o) const
CROARING_DEPRECATED bool move(const value_type &x)
std::bidirectional_iterator_tag iterator_category
bool operator==(const Roaring64MapSetBitBiDirectionalIterator &o) const
Roaring64MapSetBitBiDirectionalIterator type_of_iterator
bool operator>=(const type_of_iterator &o) const
void addMany(size_t n_args, const uint32_t *vals)
void flip(uint64_t min, uint64_t max)
friend class Roaring64MapSetBitBiDirectionalIterator
Roaring64Map(size_t n, const uint64_t *data)
Definition: roaring64map.hh:58
uint64_t rank(uint64_t x) const
size_t getFrozenSizeInBytes() const
Roaring64Map operator-(const Roaring64Map &o) const
void flipClosed(uint32_t min, uint32_t max)
bool contains(uint32_t x) const
uint64_t cardinality() const
const_iterator end() const
void remove(uint64_t x)
bool contains(uint64_t x) const
Roaring64Map(size_t n, const uint32_t *data)
Definition: roaring64map.hh:53
Roaring64Map & operator|=(const Roaring64Map &other)
Roaring64Map & operator=(std::initializer_list< uint64_t > l)
Roaring64Map & operator&=(const Roaring64Map &other)
std::string toString() const
Roaring64Map(const Roaring &r)
Definition: roaring64map.hh:70
Roaring64Map & operator=(const Roaring64Map &r)=default
Roaring64MapSetBitBiDirectionalIterator const_iterator
bool operator==(const Roaring64Map &r) const
uint64_t maximum() const
bool isSubset(const Roaring64Map &r) const
const_iterator begin() const
size_t write(char *buf, bool portable=true) const
void removeRangeClosed(uint64_t min, uint64_t max)
bool removeChecked(uint32_t x)
Roaring64Map operator|(const Roaring64Map &o) const
bool addChecked(uint64_t x)
void addRangeClosed(uint64_t min, uint64_t max)
bool getCopyOnWrite() const
Roaring64Map(Roaring &&r)
Definition: roaring64map.hh:75
static Roaring64Map readSafe(const char *buf, size_t maxbytes)
void add(uint32_t x)
static Roaring64Map fastunion(size_t n, const Roaring64Map **inputs)
Roaring64Map & operator^=(const Roaring64Map &other)
Roaring64Map(const Roaring64Map &r)=default
Roaring64Map operator^(const Roaring64Map &o) const
static const Roaring64Map frozenView(const char *buf)
static Roaring64Map read(const char *buf, bool portable=true)
void addMany(size_t n_args, const uint64_t *vals)
static Roaring64Map bitmapOfList(std::initializer_list< uint64_t > l)
void addRange(uint64_t min, uint64_t max)
Roaring64Map operator&(const Roaring64Map &o) const
static Roaring64Map bitmapOf(size_t n...)
bool removeChecked(uint64_t x)
Roaring64Map(roaring_bitmap_t *s)
Definition: roaring64map.hh:82
uint64_t minimum() const
Roaring64Map & operator-=(const Roaring64Map &other)
Roaring64MapSetBitBiDirectionalIterator const_bidirectional_iterator
void setCopyOnWrite(bool val)
Roaring64Map(Roaring64Map &&r) noexcept=default
void flipClosed(uint64_t min, uint64_t max)
void toUint64Array(uint64_t *ans) const
static const Roaring64Map portableDeserializeFrozen(const char *buf)
size_t getSizeInBytes(bool portable=true) const
void remove(uint32_t x)
void removeRange(uint64_t min, uint64_t max)
void iterate(api::roaring_iterator64 iterator, void *ptr) const
Roaring64Map & operator=(Roaring64Map &&r) noexcept=default
void removeRangeClosed(uint32_t min, uint32_t max)
void swap(Roaring64Map &r)
void addRangeClosed(uint32_t min, uint32_t max)
void add(uint64_t x)
bool select(uint64_t rank, uint64_t *element) const
void writeFrozen(char *buf) const
Roaring64Map(std::initializer_list< uint64_t > l)
Definition: roaring64map.hh:63
bool isStrictSubset(const Roaring64Map &r) const
bool addChecked(uint32_t x)
int64_t getIndex(uint64_t x) const
static Roaring readSafe(const char *buf, size_t maxbytes)
Definition: roaring.hh:680
bool addChecked(uint32_t x) noexcept
Definition: roaring.hh:207
void addRangeClosed(const uint32_t min, const uint32_t max) noexcept
Definition: roaring.hh:221
static Roaring read(const char *buf, bool portable=true)
Definition: roaring.hh:647
void add(uint32_t x) noexcept
Definition: roaring.hh:200
void addBulk(BulkContext &context, uint32_t x) noexcept
Definition: roaring.hh:240
void addMany(size_t n_args, const uint32_t *vals) noexcept
Definition: roaring.hh:228
static const Roaring frozenView(const char *buf, size_t length)
Definition: roaring.hh:709
static const Roaring portableDeserializeFrozen(const char *buf)
Definition: roaring.hh:724
size_t getSizeInBytes(bool portable=true) const noexcept
Definition: roaring.hh:697
Roaring64MapSetBitBiDirectionalIterator Roaring64MapSetBitForwardIterator
Definition: roaring64map.hh:34
void roaring_iterator_init_last(const roaring_bitmap_t *r, roaring_uint32_iterator_t *newit)
roaring_bitmap_t * roaring_bitmap_or_many(size_t number, const roaring_bitmap_t **rs)
bool roaring_iterate64(const roaring_bitmap_t *r, roaring_iterator64 iterator, uint64_t high_bits, void *ptr)
void roaring_iterator_init(const roaring_bitmap_t *r, roaring_uint32_iterator_t *newit)
bool roaring_uint32_iterator_move_equalorlarger(roaring_uint32_iterator_t *it, uint32_t val)
bool roaring_uint32_iterator_previous(roaring_uint32_iterator_t *it)
struct roaring_bitmap_s roaring_bitmap_t
struct roaring_uint32_iterator_s roaring_uint32_iterator_t
bool roaring_uint32_iterator_advance(roaring_uint32_iterator_t *it)
#define ROARING_TERMINATE(_s)
Definition: roaring.hh:31