CRoaring  4.0.0
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 
505  if (this == &other) {
506  // ANDing *this with itself is a no-op.
507  return *this;
508  }
509 
510  // Logic table summarizing what to do when a given outer key is
511  // present vs. absent from self and other.
512  //
513  // self other (self & other) work to do
514  // --------------------------------------------
515  // absent absent empty None
516  // absent present empty None
517  // present absent empty Erase self
518  // present present empty or not Intersect self with other, but
519  // erase self if result is empty.
520  //
521  // Because there is only work to do when a key is present in 'self', the
522  // main for loop iterates over entries in 'self'.
523 
524  decltype(roarings.begin()) self_next;
525  for (auto self_iter = roarings.begin(); self_iter != roarings.end();
526  self_iter = self_next) {
527  // Do the 'next' operation now, so we don't have to worry about
528  // invalidation of self_iter down below with the 'erase' operation.
529  self_next = std::next(self_iter);
530 
531  auto self_key = self_iter->first;
532  auto &self_bitmap = self_iter->second;
533 
534  auto other_iter = other.roarings.find(self_key);
535  if (other_iter == other.roarings.end()) {
536  // 'other' doesn't have self_key. In the logic table above,
537  // this reflects the case (self.present & other.absent).
538  // So, erase self.
539  roarings.erase(self_iter);
540  continue;
541  }
542 
543  // Both sides have self_key. In the logic table above, this reflects
544  // the case (self.present & other.present). So, intersect self with
545  // other.
546  const auto &other_bitmap = other_iter->second;
547  self_bitmap &= other_bitmap;
548  if (self_bitmap.isEmpty()) {
549  // ...but if intersection is empty, remove it altogether.
550  roarings.erase(self_iter);
551  }
552  }
553  return *this;
554  }
555 
562  if (this == &other) {
563  // Subtracting *this from itself results in the empty map.
564  roarings.clear();
565  return *this;
566  }
567 
568  // Logic table summarizing what to do when a given outer key is
569  // present vs. absent from self and other.
570  //
571  // self other (self - other) work to do
572  // --------------------------------------------
573  // absent absent empty None
574  // absent present empty None
575  // present absent unchanged None
576  // present present empty or not Subtract other from self, but
577  // erase self if result is empty
578  //
579  // Because there is only work to do when a key is present in both 'self'
580  // and 'other', the main while loop ping-pongs back and forth until it
581  // finds the next key that is the same on both sides.
582 
583  auto self_iter = roarings.begin();
584  auto other_iter = other.roarings.cbegin();
585 
586  while (self_iter != roarings.end() &&
587  other_iter != other.roarings.cend()) {
588  auto self_key = self_iter->first;
589  auto other_key = other_iter->first;
590  if (self_key < other_key) {
591  // Because self_key is < other_key, advance self_iter to the
592  // first point where self_key >= other_key (or end).
593  self_iter = roarings.lower_bound(other_key);
594  continue;
595  }
596 
597  if (self_key > other_key) {
598  // Because self_key is > other_key, advance other_iter to the
599  // first point where other_key >= self_key (or end).
600  other_iter = other.roarings.lower_bound(self_key);
601  continue;
602  }
603 
604  // Both sides have self_key. In the logic table above, this reflects
605  // the case (self.present & other.present). So subtract other from
606  // self.
607  auto &self_bitmap = self_iter->second;
608  const auto &other_bitmap = other_iter->second;
609  self_bitmap -= other_bitmap;
610 
611  if (self_bitmap.isEmpty()) {
612  // ...but if subtraction is empty, remove it altogether.
613  self_iter = roarings.erase(self_iter);
614  } else {
615  ++self_iter;
616  }
617  ++other_iter;
618  }
619  return *this;
620  }
621 
630  if (this == &other) {
631  // ORing *this with itself is a no-op.
632  return *this;
633  }
634 
635  // Logic table summarizing what to do when a given outer key is
636  // present vs. absent from self and other.
637  //
638  // self other (self | other) work to do
639  // --------------------------------------------
640  // absent absent empty None
641  // absent present not empty Copy other to self and set flags
642  // present absent unchanged None
643  // present present not empty self |= other
644  //
645  // Because there is only work to do when a key is present in 'other',
646  // the main for loop iterates over entries in 'other'.
647 
648  for (const auto &other_entry : other.roarings) {
649  const auto &other_bitmap = other_entry.second;
650 
651  // Try to insert other_bitmap into self at other_key. We take
652  // advantage of the fact that std::map::insert will not overwrite an
653  // existing entry.
654  auto insert_result = roarings.insert(other_entry);
655  auto self_iter = insert_result.first;
656  auto insert_happened = insert_result.second;
657  auto &self_bitmap = self_iter->second;
658 
659  if (insert_happened) {
660  // Key was not present in self, so insert was performed above.
661  // In the logic table above, this reflects the case
662  // (self.absent | other.present). Because the copy has already
663  // happened, thanks to the 'insert' operation above, we just
664  // need to set the copyOnWrite flag.
665  self_bitmap.setCopyOnWrite(copyOnWrite);
666  continue;
667  }
668 
669  // Both sides have self_key, and the insert was not performed. In
670  // the logic table above, this reflects the case
671  // (self.present & other.present). So OR other into self.
672  self_bitmap |= other_bitmap;
673  }
674  return *this;
675  }
676 
682  if (this == &other) {
683  // XORing *this with itself results in the empty map.
684  roarings.clear();
685  return *this;
686  }
687 
688  // Logic table summarizing what to do when a given outer key is
689  // present vs. absent from self and other.
690  //
691  // self other (self ^ other) work to do
692  // --------------------------------------------
693  // absent absent empty None
694  // absent present non-empty Copy other to self and set flags
695  // present absent unchanged None
696  // present present empty or not XOR other into self, but erase self
697  // if result is empty.
698  //
699  // Because there is only work to do when a key is present in 'other',
700  // the main for loop iterates over entries in 'other'.
701 
702  for (const auto &other_entry : other.roarings) {
703  const auto &other_bitmap = other_entry.second;
704 
705  // Try to insert other_bitmap into self at other_key. We take
706  // advantage of the fact that std::map::insert will not overwrite an
707  // existing entry.
708  auto insert_result = roarings.insert(other_entry);
709  auto self_iter = insert_result.first;
710  auto insert_happened = insert_result.second;
711  auto &self_bitmap = self_iter->second;
712 
713  if (insert_happened) {
714  // Key was not present in self, so insert was performed above.
715  // In the logic table above, this reflects the case
716  // (self.absent ^ other.present). Because the copy has already
717  // happened, thanks to the 'insert' operation above, we just
718  // need to set the copyOnWrite flag.
719  self_bitmap.setCopyOnWrite(copyOnWrite);
720  continue;
721  }
722 
723  // Both sides have self_key, and the insert was not performed. In
724  // the logic table above, this reflects the case
725  // (self.present ^ other.present). So XOR other into self.
726  self_bitmap ^= other_bitmap;
727 
728  if (self_bitmap.isEmpty()) {
729  // ...but if intersection is empty, remove it altogether.
730  roarings.erase(self_iter);
731  }
732  }
733  return *this;
734  }
735 
739  void swap(Roaring64Map &r) { roarings.swap(r.roarings); }
740 
747  uint64_t cardinality() const {
748  if (isFull()) {
749 #if ROARING_EXCEPTIONS
750  throw std::length_error(
751  "bitmap is full, cardinality is 2^64, "
752  "unable to represent in a 64-bit integer");
753 #else
755  "bitmap is full, cardinality is 2^64, "
756  "unable to represent in a 64-bit integer");
757 #endif
758  }
759  return std::accumulate(
760  roarings.cbegin(), roarings.cend(), (uint64_t)0,
761  [](uint64_t previous,
762  const std::pair<const uint32_t, Roaring> &map_entry) {
763  return previous + map_entry.second.cardinality();
764  });
765  }
766 
770  bool isEmpty() const {
771  return std::all_of(
772  roarings.cbegin(), roarings.cend(),
773  [](const std::pair<const uint32_t, Roaring> &map_entry) {
774  return map_entry.second.isEmpty();
775  });
776  }
777 
781  bool isFull() const {
782  // only bother to check if map is fully saturated
783  //
784  // we put std::numeric_limits<>::max/min in parentheses
785  // to avoid a clash with the Windows.h header under Windows
786  return roarings.size() ==
787  ((uint64_t)(std::numeric_limits<uint32_t>::max)()) + 1
788  ? std::all_of(
789  roarings.cbegin(), roarings.cend(),
790  [](const std::pair<const uint32_t, Roaring>
791  &roaring_map_entry) {
792  // roarings within map are saturated if cardinality
793  // is uint32_t max + 1
794  return roaring_map_entry.second.cardinality() ==
795  ((uint64_t)(std::numeric_limits<
796  uint32_t>::max)()) +
797  1;
798  })
799  : false;
800  }
801 
805  bool isSubset(const Roaring64Map &r) const {
806  for (const auto &map_entry : roarings) {
807  if (map_entry.second.isEmpty()) {
808  continue;
809  }
810  auto roaring_iter = r.roarings.find(map_entry.first);
811  if (roaring_iter == r.roarings.cend())
812  return false;
813  else if (!map_entry.second.isSubset(roaring_iter->second))
814  return false;
815  }
816  return true;
817  }
818 
825  bool isStrictSubset(const Roaring64Map &r) const {
826  return isSubset(r) && cardinality() != r.cardinality();
827  }
828 
835  void toUint64Array(uint64_t *ans) const {
836  // Annoyingly, VS 2017 marks std::accumulate() as [[nodiscard]]
837  (void)std::accumulate(
838  roarings.cbegin(), roarings.cend(), ans,
839  [](uint64_t *previous,
840  const std::pair<const uint32_t, Roaring> &map_entry) {
841  for (uint32_t low_bits : map_entry.second)
842  *previous++ = uniteBytes(map_entry.first, low_bits);
843  return previous;
844  });
845  }
846 
850  bool operator==(const Roaring64Map &r) const {
851  // we cannot use operator == on the map because either side may contain
852  // empty Roaring Bitmaps
853  auto lhs_iter = roarings.cbegin();
854  auto lhs_cend = roarings.cend();
855  auto rhs_iter = r.roarings.cbegin();
856  auto rhs_cend = r.roarings.cend();
857  while (lhs_iter != lhs_cend && rhs_iter != rhs_cend) {
858  auto lhs_key = lhs_iter->first, rhs_key = rhs_iter->first;
859  const auto &lhs_map = lhs_iter->second, &rhs_map = rhs_iter->second;
860  if (lhs_map.isEmpty()) {
861  ++lhs_iter;
862  continue;
863  }
864  if (rhs_map.isEmpty()) {
865  ++rhs_iter;
866  continue;
867  }
868  if (!(lhs_key == rhs_key)) {
869  return false;
870  }
871  if (!(lhs_map == rhs_map)) {
872  return false;
873  }
874  ++lhs_iter;
875  ++rhs_iter;
876  }
877  while (lhs_iter != lhs_cend) {
878  if (!lhs_iter->second.isEmpty()) {
879  return false;
880  }
881  ++lhs_iter;
882  }
883  while (rhs_iter != rhs_cend) {
884  if (!rhs_iter->second.isEmpty()) {
885  return false;
886  }
887  ++rhs_iter;
888  }
889  return true;
890  }
891 
896  void flip(uint64_t min, uint64_t max) {
897  if (min >= max) {
898  return;
899  }
900  flipClosed(min, max - 1);
901  }
902 
907  void flipClosed(uint32_t min, uint32_t max) {
908  auto iter = roarings.begin();
909  // Since min and max are uint32_t, highbytes(min or max) == 0. The inner
910  // bitmap we are looking for, if it exists, will be at the first slot of
911  // 'roarings'. If it does not exist, we have to create it.
912  if (iter == roarings.end() || iter->first != 0) {
913  iter = roarings.emplace_hint(iter, std::piecewise_construct,
914  std::forward_as_tuple(0),
915  std::forward_as_tuple());
916  auto &bitmap = iter->second;
917  bitmap.setCopyOnWrite(copyOnWrite);
918  }
919  auto &bitmap = iter->second;
920  bitmap.flipClosed(min, max);
921  eraseIfEmpty(iter);
922  }
923 
928  void flipClosed(uint64_t min, uint64_t max) {
929  if (min > max) {
930  return;
931  }
932  uint32_t start_high = highBytes(min);
933  uint32_t start_low = lowBytes(min);
934  uint32_t end_high = highBytes(max);
935  uint32_t end_low = lowBytes(max);
936 
937  // We put std::numeric_limits<>::max in parentheses to avoid a
938  // clash with the Windows.h header under Windows.
939  const uint32_t uint32_max = (std::numeric_limits<uint32_t>::max)();
940 
941  // Fill in any nonexistent slots with empty Roarings. This simplifies
942  // the logic below, allowing it to simply iterate over the map between
943  // 'start_high' and 'end_high' in a linear fashion.
944  auto current_iter = ensureRangePopulated(start_high, end_high);
945 
946  // If start and end land on the same inner bitmap, then we can do the
947  // whole operation in one call.
948  if (start_high == end_high) {
949  auto &bitmap = current_iter->second;
950  bitmap.flipClosed(start_low, end_low);
951  eraseIfEmpty(current_iter);
952  return;
953  }
954 
955  // Because start and end don't land on the same inner bitmap,
956  // we need to do this in multiple steps:
957  // 1. Partially flip the first bitmap in the closed interval
958  // [start_low, uint32_max]
959  // 2. Flip intermediate bitmaps completely: [0, uint32_max]
960  // 3. Partially flip the last bitmap in the closed interval
961  // [0, end_low]
962 
963  auto num_intermediate_bitmaps = end_high - start_high - 1;
964 
965  // 1. Partially flip the first bitmap.
966  {
967  auto &bitmap = current_iter->second;
968  bitmap.flipClosed(start_low, uint32_max);
969  auto temp = current_iter++;
970  eraseIfEmpty(temp);
971  }
972 
973  // 2. Flip intermediate bitmaps completely.
974  for (uint32_t i = 0; i != num_intermediate_bitmaps; ++i) {
975  auto &bitmap = current_iter->second;
976  bitmap.flipClosed(0, uint32_max);
977  auto temp = current_iter++;
978  eraseIfEmpty(temp);
979  }
980 
981  // 3. Partially flip the last bitmap.
982  auto &bitmap = current_iter->second;
983  bitmap.flipClosed(0, end_low);
984  eraseIfEmpty(current_iter);
985  }
986 
992  return std::accumulate(
993  roarings.begin(), roarings.end(), true,
994  [](bool previous, std::pair<const uint32_t, Roaring> &map_entry) {
995  return map_entry.second.removeRunCompression() && previous;
996  });
997  }
998 
1005  bool runOptimize() {
1006  return std::accumulate(
1007  roarings.begin(), roarings.end(), true,
1008  [](bool previous, std::pair<const uint32_t, Roaring> &map_entry) {
1009  return map_entry.second.runOptimize() && previous;
1010  });
1011  }
1012 
1017  size_t shrinkToFit() {
1018  size_t savedBytes = 0;
1019  auto iter = roarings.begin();
1020  while (iter != roarings.cend()) {
1021  if (iter->second.isEmpty()) {
1022  // empty Roarings are 84 bytes
1023  savedBytes += 88;
1024  roarings.erase(iter++);
1025  } else {
1026  savedBytes += iter->second.shrinkToFit();
1027  iter++;
1028  }
1029  }
1030  return savedBytes;
1031  }
1032 
1044  void iterate(api::roaring_iterator64 iterator, void *ptr) const {
1045  for (const auto &map_entry : roarings) {
1046  bool should_continue =
1047  roaring_iterate64(&map_entry.second.roaring, iterator,
1048  uint64_t(map_entry.first) << 32, ptr);
1049  if (!should_continue) {
1050  break;
1051  }
1052  }
1053  }
1054 
1061  bool select(uint64_t rank, uint64_t *element) const {
1062  for (const auto &map_entry : roarings) {
1063  auto key = map_entry.first;
1064  const auto &bitmap = map_entry.second;
1065 
1066  uint64_t sub_cardinality = bitmap.cardinality();
1067  if (rank < sub_cardinality) {
1068  uint32_t low_bytes;
1069  // Casting rank to uint32_t is safe because
1070  // rank < sub_cardinality and sub_cardinality <= 2^32.
1071  if (!bitmap.select((uint32_t)rank, &low_bytes)) {
1073  "Logic error: bitmap.select() "
1074  "returned false despite rank < cardinality()");
1075  }
1076  *element = uniteBytes(key, low_bytes);
1077  return true;
1078  }
1079  rank -= sub_cardinality;
1080  }
1081  return false;
1082  }
1083 
1087  uint64_t rank(uint64_t x) const {
1088  uint64_t result = 0;
1089  // Find the first bitmap >= x's bucket. If that is the bucket x would be
1090  // in, find it's rank in that bucket. Either way, we're left with a
1091  // range of all buckets strictly smaller than x's bucket, add all their
1092  // cardinalities together.
1093  auto end = roarings.lower_bound(highBytes(x));
1094  if (end != roarings.cend() && end->first == highBytes(x)) {
1095  result += end->second.rank(lowBytes(x));
1096  }
1097  for (auto iter = roarings.cbegin(); iter != end; ++iter) {
1098  result += iter->second.cardinality();
1099  }
1100  return result;
1101  }
1102 
1110  int64_t getIndex(uint64_t x) const {
1111  int64_t index = 0;
1112  auto roaring_destination = roarings.find(highBytes(x));
1113  if (roaring_destination != roarings.cend()) {
1114  for (auto roaring_iter = roarings.cbegin();
1115  roaring_iter != roaring_destination; ++roaring_iter) {
1116  index += roaring_iter->second.cardinality();
1117  }
1118  auto low_idx = roaring_destination->second.getIndex(lowBytes(x));
1119  if (low_idx < 0) return -1;
1120  index += low_idx;
1121  return index;
1122  }
1123  return -1;
1124  }
1125 
1135  size_t write(char *buf, bool portable = true) const {
1136  const char *orig = buf;
1137  // push map size
1138  uint64_t map_size = roarings.size();
1139  std::memcpy(buf, &map_size, sizeof(uint64_t));
1140  buf += sizeof(uint64_t);
1141  std::for_each(roarings.cbegin(), roarings.cend(),
1142  [&buf, portable](
1143  const std::pair<const uint32_t, Roaring> &map_entry) {
1144  // push map key
1145  std::memcpy(buf, &map_entry.first, sizeof(uint32_t));
1146  // ^-- Note: `*((uint32_t*)buf) = map_entry.first;` is
1147  // undefined
1148 
1149  buf += sizeof(uint32_t);
1150  // push map value Roaring
1151  buf += map_entry.second.write(buf, portable);
1152  });
1153  return buf - orig;
1154  }
1155 
1168  static Roaring64Map read(const char *buf, bool portable = true) {
1169  Roaring64Map result;
1170  // get map size
1171  uint64_t map_size;
1172  std::memcpy(&map_size, buf, sizeof(uint64_t));
1173  buf += sizeof(uint64_t);
1174  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1175  // get map key
1176  uint32_t key;
1177  std::memcpy(&key, buf, sizeof(uint32_t));
1178  // ^-- Note: `uint32_t key = *((uint32_t*)buf);` is undefined
1179 
1180  buf += sizeof(uint32_t);
1181  // read map value Roaring
1182  Roaring read_var = Roaring::read(buf, portable);
1183  // forward buffer past the last Roaring Bitmap
1184  buf += read_var.getSizeInBytes(portable);
1185  result.emplaceOrInsert(key, std::move(read_var));
1186  }
1187  return result;
1188  }
1189 
1197  static Roaring64Map readSafe(const char *buf, size_t maxbytes) {
1198  if (maxbytes < sizeof(uint64_t)) {
1199  ROARING_TERMINATE("ran out of bytes");
1200  }
1201  Roaring64Map result;
1202  uint64_t map_size;
1203  std::memcpy(&map_size, buf, sizeof(uint64_t));
1204  buf += sizeof(uint64_t);
1205  maxbytes -= sizeof(uint64_t);
1206  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1207  if (maxbytes < sizeof(uint32_t)) {
1208  ROARING_TERMINATE("ran out of bytes");
1209  }
1210  uint32_t key;
1211  std::memcpy(&key, buf, sizeof(uint32_t));
1212  // ^-- Note: `uint32_t key = *((uint32_t*)buf);` is undefined
1213 
1214  buf += sizeof(uint32_t);
1215  maxbytes -= sizeof(uint32_t);
1216  // read map value Roaring
1217  Roaring read_var = Roaring::readSafe(buf, maxbytes);
1218  // forward buffer past the last Roaring Bitmap
1219  size_t tz = read_var.getSizeInBytes(true);
1220  buf += tz;
1221  maxbytes -= tz;
1222  result.emplaceOrInsert(key, std::move(read_var));
1223  }
1224  return result;
1225  }
1226 
1234  size_t getSizeInBytes(bool portable = true) const {
1235  // start with, respectively, map size and size of keys for each map
1236  // entry
1237  return std::accumulate(
1238  roarings.cbegin(), roarings.cend(),
1239  sizeof(uint64_t) + roarings.size() * sizeof(uint32_t),
1240  [=](size_t previous,
1241  const std::pair<const uint32_t, Roaring> &map_entry) {
1242  // add in bytes used by each Roaring
1243  return previous + map_entry.second.getSizeInBytes(portable);
1244  });
1245  }
1246 
1247  static const Roaring64Map frozenView(const char *buf) {
1248  // size of bitmap buffer and key
1249  const size_t metadata_size = sizeof(size_t) + sizeof(uint32_t);
1250 
1251  Roaring64Map result;
1252 
1253  // get map size
1254  uint64_t map_size;
1255  memcpy(&map_size, buf, sizeof(uint64_t));
1256  buf += sizeof(uint64_t);
1257 
1258  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1259  // pad to 32 bytes minus the metadata size
1260  while (((uintptr_t)buf + metadata_size) % 32 != 0) buf++;
1261 
1262  // get bitmap size
1263  size_t len;
1264  memcpy(&len, buf, sizeof(size_t));
1265  buf += sizeof(size_t);
1266 
1267  // get map key
1268  uint32_t key;
1269  memcpy(&key, buf, sizeof(uint32_t));
1270  buf += sizeof(uint32_t);
1271 
1272  // read map value Roaring
1273  const Roaring read = Roaring::frozenView(buf, len);
1274  result.emplaceOrInsert(key, read);
1275 
1276  // forward buffer past the last Roaring Bitmap
1277  buf += len;
1278  }
1279  return result;
1280  }
1281 
1282  static const Roaring64Map portableDeserializeFrozen(const char *buf) {
1283  Roaring64Map result;
1284  // get map size
1285  uint64_t map_size;
1286  std::memcpy(&map_size, buf, sizeof(uint64_t));
1287  buf += sizeof(uint64_t);
1288  for (uint64_t lcv = 0; lcv < map_size; lcv++) {
1289  // get map key
1290  uint32_t key;
1291  std::memcpy(&key, buf, sizeof(uint32_t));
1292  buf += sizeof(uint32_t);
1293  // read map value Roaring
1295  // forward buffer past the last Roaring bitmap
1296  buf += read_var.getSizeInBytes(true);
1297  result.emplaceOrInsert(key, std::move(read_var));
1298  }
1299  return result;
1300  }
1301 
1302  // As with serialized 64-bit bitmaps, 64-bit frozen bitmaps are serialized
1303  // by concatenating one or more Roaring::write output buffers with the
1304  // preceeding map key. Unlike standard bitmap serialization, frozen bitmaps
1305  // must be 32-byte aligned and requires a buffer length to parse. As a
1306  // result, each concatenated output of Roaring::writeFrozen is preceeded by
1307  // padding, the buffer size (size_t), and the map key (uint32_t). The
1308  // padding is used to ensure 32-byte alignment, but since it is followed by
1309  // the buffer size and map key, it actually pads to `(x - sizeof(size_t) +
1310  // sizeof(uint32_t)) mod 32` to leave room for the metadata.
1311  void writeFrozen(char *buf) const {
1312  // size of bitmap buffer and key
1313  const size_t metadata_size = sizeof(size_t) + sizeof(uint32_t);
1314 
1315  // push map size
1316  uint64_t map_size = roarings.size();
1317  memcpy(buf, &map_size, sizeof(uint64_t));
1318  buf += sizeof(uint64_t);
1319 
1320  for (auto &map_entry : roarings) {
1321  size_t frozenSizeInBytes = map_entry.second.getFrozenSizeInBytes();
1322 
1323  // pad to 32 bytes minus the metadata size
1324  while (((uintptr_t)buf + metadata_size) % 32 != 0) buf++;
1325 
1326  // push bitmap size
1327  memcpy(buf, &frozenSizeInBytes, sizeof(size_t));
1328  buf += sizeof(size_t);
1329 
1330  // push map key
1331  memcpy(buf, &map_entry.first, sizeof(uint32_t));
1332  buf += sizeof(uint32_t);
1333 
1334  // push map value Roaring
1335  map_entry.second.writeFrozen(buf);
1336  buf += map_entry.second.getFrozenSizeInBytes();
1337  }
1338  }
1339 
1340  size_t getFrozenSizeInBytes() const {
1341  // size of bitmap size and map key
1342  const size_t metadata_size = sizeof(size_t) + sizeof(uint32_t);
1343  size_t ret = 0;
1344 
1345  // map size
1346  ret += sizeof(uint64_t);
1347 
1348  for (auto &map_entry : roarings) {
1349  // pad to 32 bytes minus the metadata size
1350  while ((ret + metadata_size) % 32 != 0) ret++;
1351  ret += metadata_size;
1352 
1353  // frozen bitmaps must be 32-byte aligned
1354  ret += map_entry.second.getFrozenSizeInBytes();
1355  }
1356  return ret;
1357  }
1358 
1369  return Roaring64Map(*this) &= o;
1370  }
1371 
1377  return Roaring64Map(*this) -= o;
1378  }
1379 
1385  return Roaring64Map(*this) |= o;
1386  }
1387 
1393  return Roaring64Map(*this) ^= o;
1394  }
1395 
1399  void setCopyOnWrite(bool val) {
1400  if (copyOnWrite == val) return;
1401  copyOnWrite = val;
1402  std::for_each(roarings.begin(), roarings.end(),
1403  [=](std::pair<const uint32_t, Roaring> &map_entry) {
1404  map_entry.second.setCopyOnWrite(val);
1405  });
1406  }
1407 
1412  void printf() const {
1413  auto sink = [](const std::string &s) { fputs(s.c_str(), stdout); };
1414  printToSink(sink);
1415  sink("\n");
1416  }
1417 
1421  std::string toString() const {
1422  std::string result;
1423  auto sink = [&result](const std::string &s) { result += s; };
1424  printToSink(sink);
1425  return result;
1426  }
1427 
1431  bool getCopyOnWrite() const { return copyOnWrite; }
1432 
1437  static Roaring64Map fastunion(size_t n, const Roaring64Map **inputs) {
1438  // The strategy here is to basically do a "group by" operation.
1439  // We group the input roarings by key, do a 32-bit
1440  // roaring_bitmap_or_many on each group, and collect the results.
1441  // We accomplish the "group by" operation using a priority queue, which
1442  // tracks the next key for each of our input maps. At each step, our
1443  // algorithm takes the next subset of maps that share the same next key,
1444  // runs roaring_bitmap_or_many on those bitmaps, and then advances the
1445  // current_iter on all the affected entries and then repeats.
1446 
1447  // There is an entry in our priority queue for each of the 'n' inputs.
1448  // For a given Roaring64Map, we look at its underlying 'roarings'
1449  // std::map, and take its begin() and end(). This forms our half-open
1450  // interval [current_iter, end_iter), which we keep in the priority
1451  // queue as a pq_entry. These entries are updated (removed and then
1452  // reinserted with the pq_entry.iterator field advanced by one step) as
1453  // our algorithm progresses. But when a given interval becomes empty
1454  // (i.e. pq_entry.iterator == pq_entry.end) it is not returned to the
1455  // priority queue.
1456  struct pq_entry {
1457  roarings_t::const_iterator iterator;
1458  roarings_t::const_iterator end;
1459  };
1460 
1461  // Custom comparator for the priority queue.
1462  auto pq_comp = [](const pq_entry &lhs, const pq_entry &rhs) {
1463  auto left_key = lhs.iterator->first;
1464  auto right_key = rhs.iterator->first;
1465 
1466  // We compare in the opposite direction than normal because priority
1467  // queues normally order from largest to smallest, but we want
1468  // smallest to largest.
1469  return left_key > right_key;
1470  };
1471 
1472  // Create and populate the priority queue.
1473  std::priority_queue<pq_entry, std::vector<pq_entry>, decltype(pq_comp)>
1474  pq(pq_comp);
1475  for (size_t i = 0; i < n; ++i) {
1476  const auto &roarings = inputs[i]->roarings;
1477  if (roarings.begin() != roarings.end()) {
1478  pq.push({roarings.begin(), roarings.end()});
1479  }
1480  }
1481 
1482  // A reusable vector that holds the pointers to the inner bitmaps that
1483  // we pass to the underlying 32-bit fastunion operation.
1484  std::vector<const roaring_bitmap_t *> group_bitmaps;
1485 
1486  // Summary of the algorithm:
1487  // 1. While the priority queue is not empty:
1488  // A. Get its lowest key. Call this group_key
1489  // B. While the lowest entry in the priority queue has a key equal to
1490  // group_key:
1491  // 1. Remove this entry (the pair {current_iter, end_iter}) from
1492  // the priority queue.
1493  // 2. Add the bitmap pointed to by current_iter to a list of
1494  // 32-bit bitmaps to process.
1495  // 3. Advance current_iter. Now it will point to a bitmap entry
1496  // with some key greater than group_key (or it will point to
1497  // end()).
1498  // 4. If current_iter != end_iter, reinsert the pair into the
1499  // priority queue.
1500  // C. Invoke the 32-bit roaring_bitmap_or_many() and add to result
1501  Roaring64Map result;
1502  while (!pq.empty()) {
1503  // Find the next key (the lowest key) in the priority queue.
1504  auto group_key = pq.top().iterator->first;
1505 
1506  // The purpose of the inner loop is to gather all the inner bitmaps
1507  // that share "group_key" into "group_bitmaps" so that they can be
1508  // fed to roaring_bitmap_or_many(). While we are doing this, we
1509  // advance those iterators to their next value and reinsert them
1510  // into the priority queue (unless they reach their end).
1511  group_bitmaps.clear();
1512  while (!pq.empty()) {
1513  auto candidate_current_iter = pq.top().iterator;
1514  auto candidate_end_iter = pq.top().end;
1515 
1516  auto candidate_key = candidate_current_iter->first;
1517  const auto &candidate_bitmap = candidate_current_iter->second;
1518 
1519  // This element will either be in the group (having
1520  // key == group_key) or it will not be in the group (having
1521  // key > group_key). (Note it cannot have key < group_key
1522  // because of the ordered nature of the priority queue itself
1523  // and the ordered nature of all the underlying roaring maps).
1524  if (candidate_key != group_key) {
1525  // This entry, and (thanks to the nature of the priority
1526  // queue) all other entries as well, are all greater than
1527  // group_key, so we're done collecting elements for the
1528  // current group. Because of the way this loop was written,
1529  // the group will will always contain at least one element.
1530  break;
1531  }
1532 
1533  group_bitmaps.push_back(&candidate_bitmap.roaring);
1534  // Remove this entry from the priority queue. Note this
1535  // invalidates pq.top() so make sure you don't have any dangling
1536  // references to it.
1537  pq.pop();
1538 
1539  // Advance 'candidate_current_iter' and insert a new entry
1540  // {candidate_current_iter, candidate_end_iter} into the
1541  // priority queue (unless it has reached its end).
1542  ++candidate_current_iter;
1543  if (candidate_current_iter != candidate_end_iter) {
1544  pq.push({candidate_current_iter, candidate_end_iter});
1545  }
1546  }
1547 
1548  // Use the fast inner union to combine these.
1549  auto *inner_result = roaring_bitmap_or_many(group_bitmaps.size(),
1550  group_bitmaps.data());
1551  // Insert the 32-bit result at end of the 'roarings' map of the
1552  // result we are building.
1553  result.roarings.insert(
1554  result.roarings.end(),
1555  std::make_pair(group_key, Roaring(inner_result)));
1556  }
1557  return result;
1558  }
1559 
1564 
1574  const_iterator begin() const;
1575 
1580  const_iterator end() const;
1581 
1582  private:
1583  typedef std::map<uint32_t, Roaring> roarings_t;
1584  roarings_t roarings{}; // The empty constructor silences warnings from
1585  // pedantic static analyzers.
1586  bool copyOnWrite{false};
1587  static constexpr uint32_t highBytes(const uint64_t in) {
1588  return uint32_t(in >> 32);
1589  }
1590  static constexpr uint32_t lowBytes(const uint64_t in) {
1591  return uint32_t(in);
1592  }
1593  static constexpr uint64_t uniteBytes(const uint32_t highBytes,
1594  const uint32_t lowBytes) {
1595  return (uint64_t(highBytes) << 32) | uint64_t(lowBytes);
1596  }
1597  // this is needed to tolerate gcc's C++11 libstdc++ lacking emplace
1598  // prior to version 4.8
1599  void emplaceOrInsert(const uint32_t key, const Roaring &value) {
1600 #if defined(__GLIBCXX__) && __GLIBCXX__ < 20130322
1601  roarings.insert(std::make_pair(key, value));
1602 #else
1603  roarings.emplace(std::make_pair(key, value));
1604 #endif
1605  }
1606 
1607  void emplaceOrInsert(const uint32_t key, Roaring &&value) {
1608 #if defined(__GLIBCXX__) && __GLIBCXX__ < 20130322
1609  roarings.insert(std::make_pair(key, std::move(value)));
1610 #else
1611  roarings.emplace(key, std::move(value));
1612 #endif
1613  }
1614 
1615  /*
1616  * Look up 'key' in the 'roarings' map. If it does not exist, create it.
1617  * Also, set its copyOnWrite flag to 'copyOnWrite'. Then return a reference
1618  * to the (already existing or newly created) inner bitmap.
1619  */
1620  Roaring &lookupOrCreateInner(uint32_t key) {
1621  auto &bitmap = roarings[key];
1622  bitmap.setCopyOnWrite(copyOnWrite);
1623  return bitmap;
1624  }
1625 
1629  void printToSink(
1630  const std::function<void(const std::string &)> &sink) const {
1631  sink("{");
1632 
1633  // Storage for snprintf. Big enough to store the decimal representation
1634  // of the largest uint64_t value and trailing \0.
1635  char buffer[32];
1636  const char *separator = "";
1637  // Reusable, and therefore avoids many repeated heap allocations.
1638  std::string callback_string;
1639  for (const auto &entry : roarings) {
1640  auto high_bits = entry.first;
1641  const auto &bitmap = entry.second;
1642  for (const auto low_bits : bitmap) {
1643  auto value = uniteBytes(high_bits, low_bits);
1644  snprintf(buffer, sizeof(buffer), "%" PRIu64, value);
1645  callback_string = separator;
1646  callback_string.append(buffer);
1647  sink(callback_string);
1648  separator = ",";
1649  }
1650  }
1651  sink("}");
1652  }
1653 
1660  roarings_t::iterator ensureRangePopulated(uint32_t start_high,
1661  uint32_t end_high) {
1662  if (start_high > end_high) {
1663  ROARING_TERMINATE("Logic error: start_high > end_high");
1664  }
1665  // next_populated_iter points to the first entry in the outer map with
1666  // key >= start_high, or end().
1667  auto next_populated_iter = roarings.lower_bound(start_high);
1668 
1669  // Use uint64_t to avoid an infinite loop when end_high == uint32_max.
1670  roarings_t::iterator start_iter{}; // Definitely assigned in loop.
1671  for (uint64_t slot = start_high; slot <= end_high; ++slot) {
1672  roarings_t::iterator slot_iter;
1673  if (next_populated_iter != roarings.end() &&
1674  next_populated_iter->first == slot) {
1675  // 'slot' index has caught up to next_populated_iter.
1676  // Note it here and advance next_populated_iter.
1677  slot_iter = next_populated_iter++;
1678  } else {
1679  // 'slot' index has not yet caught up to next_populated_iter.
1680  // Make a fresh entry {key = 'slot', value = Roaring()}, insert
1681  // it just prior to next_populated_iter, and set its copy
1682  // on write flag. We take pains to use emplace_hint and
1683  // piecewise_construct to minimize effort.
1684  slot_iter = roarings.emplace_hint(
1685  next_populated_iter, std::piecewise_construct,
1686  std::forward_as_tuple(uint32_t(slot)),
1687  std::forward_as_tuple());
1688  auto &bitmap = slot_iter->second;
1689  bitmap.setCopyOnWrite(copyOnWrite);
1690  }
1691 
1692  // Make a note of the iterator of the starting slot. It will be
1693  // needed for the return value.
1694  if (slot == start_high) {
1695  start_iter = slot_iter;
1696  }
1697  }
1698  return start_iter;
1699  }
1700 
1705  void eraseIfEmpty(roarings_t::iterator iter) {
1706  const auto &bitmap = iter->second;
1707  if (bitmap.isEmpty()) {
1708  roarings.erase(iter);
1709  }
1710  }
1711 };
1712 
1717  public:
1718  typedef std::bidirectional_iterator_tag iterator_category;
1719  typedef uint64_t *pointer;
1720  typedef uint64_t &reference;
1721  typedef uint64_t value_type;
1722  typedef int64_t difference_type;
1724 
1726  bool exhausted = false)
1727  : p(&parent.roarings) {
1728  if (exhausted || parent.roarings.empty()) {
1729  map_iter = p->cend();
1730  } else {
1731  map_iter = parent.roarings.cbegin();
1732  roaring_iterator_init(&map_iter->second.roaring, &i);
1733  while (!i.has_value) {
1734  map_iter++;
1735  if (map_iter == p->cend()) return;
1736  roaring_iterator_init(&map_iter->second.roaring, &i);
1737  }
1738  }
1739  }
1740 
1745  return Roaring64Map::uniteBytes(map_iter->first, i.current_value);
1746  }
1747 
1748  bool operator<(const type_of_iterator &o) const {
1749  if (map_iter == p->cend()) return false;
1750  if (o.map_iter == o.p->cend()) return true;
1751  return **this < *o;
1752  }
1753 
1754  bool operator<=(const type_of_iterator &o) const {
1755  if (o.map_iter == o.p->cend()) return true;
1756  if (map_iter == p->cend()) return false;
1757  return **this <= *o;
1758  }
1759 
1760  bool operator>(const type_of_iterator &o) const {
1761  if (o.map_iter == o.p->cend()) return false;
1762  if (map_iter == p->cend()) return true;
1763  return **this > *o;
1764  }
1765 
1766  bool operator>=(const type_of_iterator &o) const {
1767  if (map_iter == p->cend()) return true;
1768  if (o.map_iter == o.p->cend()) return false;
1769  return **this >= *o;
1770  }
1771 
1772  type_of_iterator &operator++() { // ++i, must returned inc. value
1773  if (i.has_value == true) roaring_uint32_iterator_advance(&i);
1774  while (!i.has_value) {
1775  ++map_iter;
1776  if (map_iter == p->cend()) return *this;
1777  roaring_iterator_init(&map_iter->second.roaring, &i);
1778  }
1779  return *this;
1780  }
1781 
1782  type_of_iterator operator++(int) { // i++, must return orig. value
1785  while (!i.has_value) {
1786  ++map_iter;
1787  if (map_iter == p->cend()) return orig;
1788  roaring_iterator_init(&map_iter->second.roaring, &i);
1789  }
1790  return orig;
1791  }
1792 
1793  bool move(const value_type &x) {
1794  map_iter = p->lower_bound(Roaring64Map::highBytes(x));
1795  if (map_iter != p->cend()) {
1796  roaring_iterator_init(&map_iter->second.roaring, &i);
1797  if (map_iter->first == Roaring64Map::highBytes(x)) {
1799  &i, Roaring64Map::lowBytes(x)))
1800  return true;
1801  ++map_iter;
1802  if (map_iter == p->cend()) return false;
1803  roaring_iterator_init(&map_iter->second.roaring, &i);
1804  }
1805  return true;
1806  }
1807  return false;
1808  }
1809 
1810  type_of_iterator &operator--() { // --i, must return dec.value
1811  if (map_iter == p->cend()) {
1812  --map_iter;
1813  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1814  if (i.has_value) return *this;
1815  }
1816 
1818  while (!i.has_value) {
1819  if (map_iter == p->cbegin()) return *this;
1820  map_iter--;
1821  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1822  }
1823  return *this;
1824  }
1825 
1826  type_of_iterator operator--(int) { // i--, must return orig. value
1828  if (map_iter == p->cend()) {
1829  --map_iter;
1830  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1831  return orig;
1832  }
1833 
1835  while (!i.has_value) {
1836  if (map_iter == p->cbegin()) return orig;
1837  map_iter--;
1838  roaring_iterator_init_last(&map_iter->second.roaring, &i);
1839  }
1840  return orig;
1841  }
1842 
1844  if (map_iter == p->cend() && o.map_iter == o.p->cend()) return true;
1845  if (o.map_iter == o.p->cend()) return false;
1846  return **this == *o;
1847  }
1848 
1850  if (map_iter == p->cend() && o.map_iter == o.p->cend()) return false;
1851  if (o.map_iter == o.p->cend()) return true;
1852  return **this != *o;
1853  }
1854 
1855  private:
1856  const std::map<uint32_t, Roaring> *p{nullptr};
1857  std::map<uint32_t, Roaring>::const_iterator
1858  map_iter{}; // The empty constructor silences warnings from pedantic
1859  // static analyzers.
1861  i{}; // The empty constructor silences warnings from pedantic static
1862  // analyzers.
1863 };
1864 
1867 }
1868 
1870  return Roaring64MapSetBitBiDirectionalIterator(*this, true);
1871 }
1872 
1873 } // namespace roaring
1874 
1875 #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
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:677
bool addChecked(uint32_t x) noexcept
Definition: roaring.hh:165
void addRangeClosed(const uint32_t min, const uint32_t max) noexcept
Definition: roaring.hh:179
static Roaring read(const char *buf, bool portable=true)
Definition: roaring.hh:644
void add(uint32_t x) noexcept
Definition: roaring.hh:158
void addBulk(BulkContext &context, uint32_t x) noexcept
Definition: roaring.hh:198
void addMany(size_t n_args, const uint32_t *vals) noexcept
Definition: roaring.hh:186
static const Roaring frozenView(const char *buf, size_t length)
Definition: roaring.hh:706
static const Roaring portableDeserializeFrozen(const char *buf)
Definition: roaring.hh:721
size_t getSizeInBytes(bool portable=true) const noexcept
Definition: roaring.hh:694
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:30