Skip to content

Commit 5f15802

Browse files
authored
Improve consistency in the C++ interface (#653)
* Improve consistency in the C++ interface These changes aim to improve the consistency of the C++ API between the 32-bit version and the 64-bit version. Details: - Rename `RoaringSetBitForwardIterator` to `RoaringSetBitBiDirectionalIterator` (the old one is now deprecated). - Add methods: `Roaring::clear` `Roaring::isFull` `Roaring::containsRangeClosed`. - Revise `move_equalorlarger` methods in iterators. - Add `api::roaring_bitmap_flip_inplace_closed` method. - Add `api::roaring_bitmap_contains_range_closed` method. - Add `api::roaring_bitmap_flip_closed` method. - Other minor changes. * Further optimization of C++ API consistency Main changes: - Add the `api::roaring_bitmap_range_cardinality_closed` method. - Add boundary checks for methods: `api::roaring_bitmap_add_range` `api::roaring_bitmap_remove_range`. * Remove `explicit` constraint on the iterator ctor * Code style fixes
1 parent c26049e commit 5f15802

File tree

8 files changed

+259
-148
lines changed

8 files changed

+259
-148
lines changed

benchmarks/containsmulti_benchmark.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "benchmark.h"
1010
#include "numbersfromtextfiles.h"
11+
#include "portability.h"
1112
#include "random.h"
1213

1314
void contains_multi_via_contains(roaring_bitmap_t* bm, const uint32_t* values,
@@ -19,7 +20,7 @@ void contains_multi_via_contains(roaring_bitmap_t* bm, const uint32_t* values,
1920

2021
void contains_multi_bulk(roaring_bitmap_t* bm, const uint32_t* values,
2122
bool* results, const size_t count) {
22-
roaring_bulk_context_t context = {0, 0};
23+
roaring_bulk_context_t context = CROARING_ZERO_INITIALIZER;
2324
for (size_t i = 0; i < count; ++i) {
2425
results[i] = roaring_bitmap_contains_bulk(bm, &context, values[i]);
2526
}

cpp/roaring.hh

Lines changed: 133 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ A C++ header for Roaring Bitmaps.
77
#include <algorithm>
88
#include <cstdarg>
99
#include <initializer_list>
10+
#include <limits>
1011
#include <new>
1112
#include <stdexcept>
1213
#include <string>
@@ -39,7 +40,10 @@ A C++ header for Roaring Bitmaps.
3940

4041
namespace roaring {
4142

42-
class RoaringSetBitForwardIterator;
43+
class RoaringSetBitBiDirectionalIterator;
44+
45+
/** DEPRECATED, use `RoaringSetBitBiDirectionalIterator`. */
46+
using RoaringSetBitForwardIterator = RoaringSetBitBiDirectionalIterator;
4347

4448
/**
4549
* A bit of context usable with `*Bulk()` functions.
@@ -91,6 +95,16 @@ class Roaring {
9195
addMany(l.size(), l.begin());
9296
}
9397

98+
/**
99+
* Construct a roaring object by taking control of a malloc()'d C struct.
100+
*
101+
* Passing a NULL pointer is unsafe.
102+
* The pointer to the C struct will be invalid after the call.
103+
*/
104+
explicit Roaring(roaring_bitmap_t *s) noexcept : roaring(*s) {
105+
roaring_free(s); // deallocate the passed-in pointer
106+
}
107+
94108
/**
95109
* Copy constructor.
96110
* It may throw std::runtime_error if there is insufficient memory.
@@ -118,16 +132,6 @@ class Roaring {
118132
api::roaring_bitmap_init_cleared(&r.roaring);
119133
}
120134

121-
/**
122-
* Construct a roaring object by taking control of a malloc()'d C struct.
123-
*
124-
* Passing a NULL pointer is unsafe.
125-
* The pointer to the C struct will be invalid after the call.
126-
*/
127-
explicit Roaring(roaring_bitmap_t *s) noexcept : roaring(*s) {
128-
roaring_free(s); // deallocate the passed-in pointer
129-
}
130-
131135
/**
132136
* Construct a bitmap from a list of uint32_t values.
133137
*/
@@ -142,6 +146,44 @@ class Roaring {
142146
return ans;
143147
}
144148

149+
/**
150+
* Copies the content of the provided bitmap, and
151+
* discard the current content.
152+
* It may throw std::runtime_error if there is insufficient memory.
153+
*/
154+
Roaring &operator=(const Roaring &r) {
155+
if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
156+
ROARING_TERMINATE("failed memory alloc in assignment");
157+
}
158+
api::roaring_bitmap_set_copy_on_write(
159+
&roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
160+
return *this;
161+
}
162+
163+
/**
164+
* Moves the content of the provided bitmap, and
165+
* discard the current content.
166+
*/
167+
Roaring &operator=(Roaring &&r) noexcept {
168+
api::roaring_bitmap_clear(&roaring); // free this class's allocations
169+
170+
// !!! See notes in the Move Constructor regarding roaring_bitmap_move()
171+
//
172+
roaring = r.roaring;
173+
api::roaring_bitmap_init_cleared(&r.roaring);
174+
175+
return *this;
176+
}
177+
178+
/**
179+
* Assignment from an initializer list.
180+
*/
181+
Roaring &operator=(std::initializer_list<uint32_t> l) {
182+
// Delegate to move assignment operator
183+
*this = Roaring(l);
184+
return *this;
185+
}
186+
145187
/**
146188
* Construct a bitmap from a list of uint32_t values.
147189
* E.g., bitmapOfList({1,2,3}).
@@ -242,6 +284,11 @@ class Roaring {
242284
return api::roaring_bitmap_remove_range_closed(&roaring, min, max);
243285
}
244286

287+
/**
288+
* Clears the bitmap.
289+
*/
290+
void clear() { api::roaring_bitmap_clear(&roaring); }
291+
245292
/**
246293
* Return the largest value (if not empty)
247294
*/
@@ -270,63 +317,9 @@ class Roaring {
270317
return api::roaring_bitmap_contains_range(&roaring, x, y);
271318
}
272319

273-
/**
274-
* Destructor. By contract, calling roaring_bitmap_clear() is enough to
275-
* release all auxiliary memory used by the structure.
276-
*/
277-
~Roaring() {
278-
if (!(roaring.high_low_container.flags & ROARING_FLAG_FROZEN)) {
279-
api::roaring_bitmap_clear(&roaring);
280-
} else {
281-
// The roaring member variable copies the `roaring_bitmap_t` and
282-
// nested `roaring_array_t` structures by value and is freed in the
283-
// constructor, however the underlying memory arena used for the
284-
// container data is not freed with it. Here we derive the arena
285-
// pointer from the second arena allocation in
286-
// `roaring_bitmap_frozen_view` and free it as well.
287-
roaring_bitmap_free(
288-
(roaring_bitmap_t *)((char *)
289-
roaring.high_low_container.containers -
290-
sizeof(roaring_bitmap_t)));
291-
}
292-
}
293-
294-
/**
295-
* Copies the content of the provided bitmap, and
296-
* discard the current content.
297-
* It may throw std::runtime_error if there is insufficient memory.
298-
*/
299-
Roaring &operator=(const Roaring &r) {
300-
if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
301-
ROARING_TERMINATE("failed memory alloc in assignment");
302-
}
303-
api::roaring_bitmap_set_copy_on_write(
304-
&roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
305-
return *this;
306-
}
307-
308-
/**
309-
* Moves the content of the provided bitmap, and
310-
* discard the current content.
311-
*/
312-
Roaring &operator=(Roaring &&r) noexcept {
313-
api::roaring_bitmap_clear(&roaring); // free this class's allocations
314-
315-
// !!! See notes in the Move Constructor regarding roaring_bitmap_move()
316-
//
317-
roaring = r.roaring;
318-
api::roaring_bitmap_init_cleared(&r.roaring);
319-
320-
return *this;
321-
}
322-
323-
/**
324-
* Assignment from an initializer list.
325-
*/
326-
Roaring &operator=(std::initializer_list<uint32_t> l) {
327-
// Delegate to move assignment operator
328-
*this = Roaring(l);
329-
return *this;
320+
bool containsRangeClosed(const uint32_t x,
321+
const uint32_t y) const noexcept {
322+
return api::roaring_bitmap_contains_range_closed(&roaring, x, y);
330323
}
331324

332325
/**
@@ -393,6 +386,16 @@ class Roaring {
393386
return api::roaring_bitmap_is_empty(&roaring);
394387
}
395388

389+
/**
390+
* Returns true if the bitmap is full (cardinality is uint32_t max + 1).
391+
* we put std::numeric_limits<>::max/min in parentheses
392+
* to avoid a clash with the Windows.h header under Windows.
393+
*/
394+
bool isFull() const noexcept {
395+
return api::roaring_bitmap_get_cardinality(&roaring) ==
396+
((uint64_t)(std::numeric_limits<uint32_t>::max)()) + 1;
397+
}
398+
396399
/**
397400
* Returns true if the bitmap is subset of the other.
398401
*/
@@ -443,8 +446,8 @@ class Roaring {
443446
* [range_start, range_end]. Areas outside the interval are unchanged.
444447
*/
445448
void flipClosed(uint32_t range_start, uint32_t range_end) noexcept {
446-
api::roaring_bitmap_flip_inplace(&roaring, range_start,
447-
uint64_t(range_end) + 1);
449+
api::roaring_bitmap_flip_inplace_closed(&roaring, range_start,
450+
range_end);
448451
}
449452

450453
/**
@@ -868,7 +871,30 @@ class Roaring {
868871
return ans;
869872
}
870873

871-
typedef RoaringSetBitForwardIterator const_iterator;
874+
/**
875+
* Destructor. By contract, calling roaring_bitmap_clear() is enough to
876+
* release all auxiliary memory used by the structure.
877+
*/
878+
~Roaring() {
879+
if (!(roaring.high_low_container.flags & ROARING_FLAG_FROZEN)) {
880+
api::roaring_bitmap_clear(&roaring);
881+
} else {
882+
// The roaring member variable copies the `roaring_bitmap_t` and
883+
// nested `roaring_array_t` structures by value and is freed in the
884+
// constructor, however the underlying memory arena used for the
885+
// container data is not freed with it. Here we derive the arena
886+
// pointer from the second arena allocation in
887+
// `roaring_bitmap_frozen_view` and free it as well.
888+
roaring_bitmap_free(
889+
(roaring_bitmap_t *)((char *)
890+
roaring.high_low_container.containers -
891+
sizeof(roaring_bitmap_t)));
892+
}
893+
}
894+
895+
friend class RoaringSetBitBiDirectionalIterator;
896+
typedef RoaringSetBitBiDirectionalIterator const_iterator;
897+
typedef RoaringSetBitBiDirectionalIterator const_bidirectional_iterator;
872898

873899
/**
874900
* Returns an iterator that can be used to access the position of the set
@@ -893,14 +919,26 @@ class Roaring {
893919
/**
894920
* Used to go through the set bits. Not optimally fast, but convenient.
895921
*/
896-
class RoaringSetBitForwardIterator final {
922+
class RoaringSetBitBiDirectionalIterator final {
897923
public:
898-
typedef std::forward_iterator_tag iterator_category;
924+
typedef std::bidirectional_iterator_tag iterator_category;
899925
typedef uint32_t *pointer;
900926
typedef uint32_t &reference_type;
901927
typedef uint32_t value_type;
902928
typedef int32_t difference_type;
903-
typedef RoaringSetBitForwardIterator type_of_iterator;
929+
typedef RoaringSetBitBiDirectionalIterator type_of_iterator;
930+
931+
explicit RoaringSetBitBiDirectionalIterator(const Roaring &parent,
932+
bool exhausted = false) {
933+
if (exhausted) {
934+
i.parent = &parent.roaring;
935+
i.container_index = INT32_MAX;
936+
i.has_value = false;
937+
i.current_value = UINT32_MAX;
938+
} else {
939+
api::roaring_iterator_init(&parent.roaring, &i);
940+
}
941+
}
904942

905943
/**
906944
* Provides the location of the set bit.
@@ -931,66 +969,60 @@ class RoaringSetBitForwardIterator final {
931969
return i.current_value >= *o;
932970
}
933971

934-
/**
935-
* Move the iterator to the first value >= val.
936-
*/
937-
void equalorlarger(uint32_t val) {
938-
api::roaring_uint32_iterator_move_equalorlarger(&i, val);
939-
}
940-
941972
type_of_iterator &operator++() { // ++i, must returned inc. value
942973
api::roaring_uint32_iterator_advance(&i);
943974
return *this;
944975
}
945976

946977
type_of_iterator operator++(int) { // i++, must return orig. value
947-
RoaringSetBitForwardIterator orig(*this);
978+
RoaringSetBitBiDirectionalIterator orig(*this);
948979
api::roaring_uint32_iterator_advance(&i);
949980
return orig;
950981
}
951982

983+
/**
984+
* Move the iterator to the first value >= val.
985+
* Return true if there is such a value.
986+
*/
987+
bool move_equalorlarger(value_type val) {
988+
return api::roaring_uint32_iterator_move_equalorlarger(&i, val);
989+
}
990+
991+
/** DEPRECATED, use `move_equalorlarger`.*/
992+
CROARING_DEPRECATED void equalorlarger(uint32_t val) {
993+
api::roaring_uint32_iterator_move_equalorlarger(&i, val);
994+
}
995+
952996
type_of_iterator &operator--() { // prefix --
953997
api::roaring_uint32_iterator_previous(&i);
954998
return *this;
955999
}
9561000

9571001
type_of_iterator operator--(int) { // postfix --
958-
RoaringSetBitForwardIterator orig(*this);
1002+
RoaringSetBitBiDirectionalIterator orig(*this);
9591003
api::roaring_uint32_iterator_previous(&i);
9601004
return orig;
9611005
}
9621006

963-
bool operator==(const RoaringSetBitForwardIterator &o) const {
1007+
bool operator==(const RoaringSetBitBiDirectionalIterator &o) const {
9641008
return i.current_value == *o && i.has_value == o.i.has_value;
9651009
}
9661010

967-
bool operator!=(const RoaringSetBitForwardIterator &o) const {
1011+
bool operator!=(const RoaringSetBitBiDirectionalIterator &o) const {
9681012
return i.current_value != *o || i.has_value != o.i.has_value;
9691013
}
9701014

971-
explicit RoaringSetBitForwardIterator(const Roaring &parent,
972-
bool exhausted = false) {
973-
if (exhausted) {
974-
i.parent = &parent.roaring;
975-
i.container_index = INT32_MAX;
976-
i.has_value = false;
977-
i.current_value = UINT32_MAX;
978-
} else {
979-
api::roaring_iterator_init(&parent.roaring, &i);
980-
}
981-
}
982-
9831015
api::roaring_uint32_iterator_t
9841016
i{}; // The empty constructor silences warnings from pedantic static
9851017
// analyzers.
9861018
};
9871019

988-
inline RoaringSetBitForwardIterator Roaring::begin() const {
989-
return RoaringSetBitForwardIterator(*this);
1020+
inline RoaringSetBitBiDirectionalIterator Roaring::begin() const {
1021+
return RoaringSetBitBiDirectionalIterator(*this);
9901022
}
9911023

992-
inline RoaringSetBitForwardIterator &Roaring::end() const {
993-
static RoaringSetBitForwardIterator e(*this, true);
1024+
inline RoaringSetBitBiDirectionalIterator &Roaring::end() const {
1025+
static RoaringSetBitBiDirectionalIterator e(*this, true);
9941026
return e;
9951027
}
9961028

0 commit comments

Comments
 (0)