Skip to content

Commit

Permalink
Replace roaring{,64}_bitmap_of with roaring{,64}_bitmap_from macro (
Browse files Browse the repository at this point in the history
#570)

Using a macro allows us to count the number of items passed, and avoid having
to explicitly pass the count as the first parameter.
  • Loading branch information
Dr-Emann authored Jan 24, 2024
1 parent d127f19 commit 413230b
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 36 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ int main() {
expectedsizebasic, expectedsizerun);

// create a new bitmap containing the values {1,2,3,5,6}
roaring_bitmap_t *r2 = roaring_bitmap_of(5, 1, 2, 3, 5, 6);
roaring_bitmap_t *r2 = roaring_bitmap_from(1, 2, 3, 5, 6);
roaring_bitmap_printf(r2); // print it

// we can also create a bitmap from a pointer to 32-bit integers
Expand Down
50 changes: 47 additions & 3 deletions include/roaring/roaring.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <stdint.h>
#include <stddef.h> // for `size_t`

#include <roaring/portability.h>
#include <roaring/memory.h>
#include <roaring/roaring_types.h>
#include <roaring/roaring_version.h>
Expand Down Expand Up @@ -94,8 +95,51 @@ void roaring_bitmap_printf_describe(const roaring_bitmap_t *r);

/**
* Creates a new bitmap from a list of uint32_t integers
*
* This function is deprecated, use `roaring_bitmap_from` instead, which
* doesn't require the number of elements to be passed in.
*
* @see roaring_bitmap_from
*/
roaring_bitmap_t *roaring_bitmap_of(size_t n, ...);
CROARING_DEPRECATED roaring_bitmap_t *roaring_bitmap_of(size_t n, ...);

#ifdef __cplusplus
/**
* Creates a new bitmap which contains all values passed in as arguments.
*
* To create a bitmap from a variable number of arguments, use the
* `roaring_bitmap_of_ptr` function instead.
*/
// Use an immediately invoked closure, capturing by reference
// (in case __VA_ARGS__ refers to context outside the closure)
// Include a 0 at the beginning of the array to make the array length > 0
// (zero sized arrays are not valid in standard c/c++)
#define roaring_bitmap_from(...) \
[&]() { \
const uint32_t roaring_bitmap_from_array[] = {0, __VA_ARGS__}; \
return roaring_bitmap_of_ptr((sizeof(roaring_bitmap_from_array) / \
sizeof(roaring_bitmap_from_array[0])) - \
1, \
&roaring_bitmap_from_array[1]); \
}()
#else
/**
* Creates a new bitmap which contains all values passed in as arguments.
*
* To create a bitmap from a variable number of arguments, use the
* `roaring_bitmap_of_ptr` function instead.
*/
// While __VA_ARGS__ occurs twice in expansion, one of the times is in a sizeof
// expression, which is an unevaluated context, so it's even safe in the case
// where expressions passed have side effects (roaring64_bitmap_from(my_func(),
// ++i))
// Include a 0 at the beginning of the array to make the array length > 0
// (zero sized arrays are not valid in standard c/c++)
#define roaring_bitmap_from(...) \
roaring_bitmap_of_ptr( \
(sizeof((const uint32_t[]){0, __VA_ARGS__}) / sizeof(uint32_t)) - 1, \
&((const uint32_t[]){0, __VA_ARGS__})[1])
#endif

/**
* Copies a bitmap (this does memory allocation).
Expand Down Expand Up @@ -446,7 +490,7 @@ void roaring_bitmap_to_uint32_array(const roaring_bitmap_t *r, uint32_t *ans);
*
* bitset_t * out = bitset_create();
* // if the bitset has content in it, call "bitset_clear(out)"
* bool success = roaring_bitmap_to_bitset(mybitmap, out);
* bool success = roaring_bitmap_to_bitset(mybitmap, out);
* // on failure, success will be false.
* // You can then query the bitset:
* bool is_present = bitset_get(out, 10011 );
Expand Down Expand Up @@ -524,7 +568,7 @@ roaring_bitmap_t *roaring_bitmap_deserialize(const void *buf);
*
* This function is endian-sensitive. If you have a big-endian system (e.g., a mainframe IBM s390x),
* the data format is going to be big-endian and not compatible with little-endian systems.
*
*
* The difference with `roaring_bitmap_deserialize()` is that this function checks that the input buffer
* is a valid bitmap. If the buffer is too small, NULL is returned.
*/
Expand Down
42 changes: 38 additions & 4 deletions include/roaring/roaring64.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define ROARING64_H

#include <roaring/memory.h>
#include <roaring/portability.h>
#include <roaring/roaring_types.h>
#include <stdbool.h>
#include <stddef.h>
Expand Down Expand Up @@ -51,10 +52,44 @@ roaring64_bitmap_t *roaring64_bitmap_copy(const roaring64_bitmap_t *r);
roaring64_bitmap_t *roaring64_bitmap_of_ptr(size_t n_args,
const uint64_t *vals);

#ifdef __cplusplus
/**
* Creates a new bitmap of a pointer to N 64-bit integers.
*/
roaring64_bitmap_t *roaring64_bitmap_of(size_t n_args, ...);
* Creates a new bitmap which contains all values passed in as arguments.
*
* To create a bitmap from a variable number of arguments, use the
* `roaring64_bitmap_of_ptr` function instead.
*/
// Use an immediately invoked closure, capturing by reference
// (in case __VA_ARGS__ refers to context outside the closure)
// Include a 0 at the beginning of the array to make the array length > 0
// (zero sized arrays are not valid in standard c/c++)
#define roaring64_bitmap_from(...) \
[&]() { \
const uint64_t roaring64_bitmap_from_array[] = {0, __VA_ARGS__}; \
return roaring64_bitmap_of_ptr( \
(sizeof(roaring64_bitmap_from_array) / \
sizeof(roaring64_bitmap_from_array[0])) - \
1, \
&roaring64_bitmap_from_array[1]); \
}()
#else
/**
* Creates a new bitmap which contains all values passed in as arguments.
*
* To create a bitmap from a variable number of arguments, use the
* `roaring64_bitmap_of_ptr` function instead.
*/
// While __VA_ARGS__ occurs twice in expansion, one of the times is in a sizeof
// expression, which is an unevaluated context, so it's even safe in the case
// where expressions passed have side effects (roaring64_bitmap_from(my_func(),
// ++i))
// Include a 0 at the beginning of the array to make the array length > 0
// (zero sized arrays are not valid in standard c/c++)
#define roaring64_bitmap_from(...) \
roaring64_bitmap_of_ptr( \
(sizeof((const uint64_t[]){0, __VA_ARGS__}) / sizeof(uint64_t)) - 1, \
&((const uint64_t[]){0, __VA_ARGS__})[1])
#endif

/**
* Create a new bitmap containing all the values in [min, max) that are at a
Expand Down Expand Up @@ -543,4 +578,3 @@ uint64_t roaring64_iterator_read(roaring64_iterator_t *it, uint64_t *buf,
#endif

#endif /* ROARING64_H */

2 changes: 1 addition & 1 deletion tests/c_example1.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ int main() {
printf("size before run optimize %d bytes, and after %d bytes\n",
expectedsizebasic, expectedsizerun);
// create a new bitmap containing the values {1,2,3,5,6}
roaring_bitmap_t *r2 = roaring_bitmap_of(5, 1, 2, 3, 5, 6);
roaring_bitmap_t *r2 = roaring_bitmap_from(1, 2, 3, 5, 6);
roaring_bitmap_printf(r2); // print it

// we can also create a bitmap from a pointer to 32-bit integers
Expand Down
2 changes: 1 addition & 1 deletion tests/cpp_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void test_example(bool copy_on_write) {
printf("size before run optimize %zu bytes, and after %zu bytes\n", size,
compact_size);
// create a new bitmap with varargs
roaring_bitmap_t *r2 = roaring_bitmap_of(5, 1, 2, 3, 5, 6);
roaring_bitmap_t *r2 = roaring_bitmap_from(1, 2, 3, 5, 6);
assert_ptr_not_equal(r2, NULL);
roaring_bitmap_printf(r2);
printf("\n");
Expand Down
24 changes: 12 additions & 12 deletions tests/roaring64_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ DEFINE_TEST(test_of_ptr) {
}

DEFINE_TEST(test_of) {
roaring64_bitmap_t* r = roaring64_bitmap_of(3, 1ULL, 20000ULL, 500000ULL);
roaring64_bitmap_t* r = roaring64_bitmap_from(1, 20000, 500000);
assert_true(roaring64_bitmap_contains(r, 1));
assert_true(roaring64_bitmap_contains(r, 20000));
assert_true(roaring64_bitmap_contains(r, 500000));
Expand Down Expand Up @@ -1038,9 +1038,9 @@ DEFINE_TEST(test_flip) {
}
{
// Only the specified range should be flipped.
roaring64_bitmap_t* r1 = roaring64_bitmap_of(3, 1ULL, 3ULL, 6ULL);
roaring64_bitmap_t* r1 = roaring64_bitmap_from(1, 3, 6);
roaring64_bitmap_t* r2 = roaring64_bitmap_flip(r1, 2, 5);
roaring64_bitmap_t* r3 = roaring64_bitmap_of(4, 1ULL, 2ULL, 4ULL, 6ULL);
roaring64_bitmap_t* r3 = roaring64_bitmap_from(1, 2, 4, 6);
assert_true(roaring64_bitmap_equals(r2, r3));

roaring64_bitmap_free(r1);
Expand All @@ -1049,7 +1049,7 @@ DEFINE_TEST(test_flip) {
}
{
// An empty range does nothing.
roaring64_bitmap_t* r1 = roaring64_bitmap_of(3, 1ULL, 3ULL, 6);
roaring64_bitmap_t* r1 = roaring64_bitmap_from(1, 3, 6);
roaring64_bitmap_t* r2 = roaring64_bitmap_flip(r1, 3, 3);
assert_true(roaring64_bitmap_equals(r2, r1));

Expand All @@ -1058,8 +1058,8 @@ DEFINE_TEST(test_flip) {
}
{
// A bitmap with values in all affected containers.
roaring64_bitmap_t* r1 = roaring64_bitmap_of(
3, (2ULL << 16), (3ULL << 16) + 1, (4ULL << 16) + 3);
roaring64_bitmap_t* r1 = roaring64_bitmap_from(
(2 << 16), (3 << 16) + 1, (4 << 16) + 3);
roaring64_bitmap_t* r2 =
roaring64_bitmap_flip(r1, (2 << 16), (4 << 16) + 4);
roaring64_bitmap_t* r3 =
Expand All @@ -1084,28 +1084,28 @@ DEFINE_TEST(test_flip_inplace) {
}
{
// Only the specified range should be flipped.
roaring64_bitmap_t* r1 = roaring64_bitmap_of(3, 1ULL, 3ULL, 6ULL);
roaring64_bitmap_t* r1 = roaring64_bitmap_from(1, 3, 6);
roaring64_bitmap_flip_inplace(r1, 2, 5);
roaring64_bitmap_t* r2 = roaring64_bitmap_of(4, 1ULL, 2ULL, 4ULL, 6ULL);
roaring64_bitmap_t* r2 = roaring64_bitmap_from(1, 2, 4, 6);
assert_true(roaring64_bitmap_equals(r1, r2));

roaring64_bitmap_free(r1);
roaring64_bitmap_free(r2);
}
{
// An empty range does nothing.
roaring64_bitmap_t* r1 = roaring64_bitmap_of(3, 1ULL, 3ULL, 6ULL);
roaring64_bitmap_t* r1 = roaring64_bitmap_from(1, 3, 6);
roaring64_bitmap_flip_inplace(r1, 3, 3);
roaring64_bitmap_t* r2 = roaring64_bitmap_of(3, 1ULL, 3ULL, 6ULL);
roaring64_bitmap_t* r2 = roaring64_bitmap_from(1, 3, 6);
assert_true(roaring64_bitmap_equals(r1, r2));

roaring64_bitmap_free(r1);
roaring64_bitmap_free(r2);
}
{
// A bitmap with values in all affected containers.
roaring64_bitmap_t* r1 = roaring64_bitmap_of(
3, (2ULL << 16), (3ULL << 16) + 1, (4ULL << 16) + 3);
roaring64_bitmap_t* r1 = roaring64_bitmap_from(
(2 << 16), (3 << 16) + 1, (4 << 16) + 3);
roaring64_bitmap_flip_inplace(r1, (2 << 16), (4 << 16) + 4);
roaring64_bitmap_t* r2 =
roaring64_bitmap_from_range((2 << 16) + 1, (4 << 16) + 3, 1);
Expand Down
2 changes: 1 addition & 1 deletion tests/threads_unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ bool run_threads_unit_tests() {

roaring_bitmap_set_copy_on_write(r1, true);
roaring_bitmap_run_optimize(r1);
roaring_bitmap_t *r2 = roaring_bitmap_of(5, 10010,10020,10030,10040,10050);
roaring_bitmap_t *r2 = roaring_bitmap_from(10010,10020,10030,10040,10050);
roaring_bitmap_set_copy_on_write(r2, true);
roaring_bitmap_t *r3 = roaring_bitmap_copy(r1);
roaring_bitmap_set_copy_on_write(r3, true);
Expand Down
26 changes: 13 additions & 13 deletions tests/toplevel_unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ DEFINE_TEST(leaks_with_empty_false) { leaks_with_empty(false); }

DEFINE_TEST(check_interval) {
// create a new bitmap with varargs
roaring_bitmap_t *r = roaring_bitmap_of(4, 1, 2, 3, 1000);
roaring_bitmap_t *r = roaring_bitmap_from(1, 2, 3, 1000);
assert_non_null(r);

roaring_bitmap_printf(r);
Expand Down Expand Up @@ -728,7 +728,7 @@ void test_example(bool copy_on_write) {
compact_size);

// create a new bitmap with varargs
roaring_bitmap_t *r2 = roaring_bitmap_of(5, 1, 2, 3, 5, 6);
roaring_bitmap_t *r2 = roaring_bitmap_from(1, 2, 3, 5, 6);
assert_bitmap_validate(r2);
assert_non_null(r2);

Expand Down Expand Up @@ -1186,7 +1186,7 @@ DEFINE_TEST(test_bitmap_from_range) {

DEFINE_TEST(test_printf) {
roaring_bitmap_t *r1 =
roaring_bitmap_of(8, 1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
roaring_bitmap_from(1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
assert_bitmap_validate(r1);
assert_non_null(r1);
roaring_bitmap_printf(r1);
Expand Down Expand Up @@ -1230,7 +1230,7 @@ bool dummy_iterator(uint32_t value, void *param) {

DEFINE_TEST(test_iterate) {
roaring_bitmap_t *r1 =
roaring_bitmap_of(8, 1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
roaring_bitmap_from(1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
assert_non_null(r1);

uint32_t num = 0;
Expand Down Expand Up @@ -1302,7 +1302,7 @@ DEFINE_TEST(test_remove_withrun) {

DEFINE_TEST(test_portable_serialize) {
roaring_bitmap_t *r1 =
roaring_bitmap_of(8, 1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
roaring_bitmap_from(1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
assert_non_null(r1);

uint32_t serialize_len;
Expand Down Expand Up @@ -1335,8 +1335,8 @@ DEFINE_TEST(test_portable_serialize) {
roaring_bitmap_free(r1);
roaring_bitmap_free(r2);

r1 = roaring_bitmap_of(6, 2946000, 2997491, 10478289, 10490227, 10502444,
19866827);
r1 = roaring_bitmap_from(2946000, 2997491, 10478289, 10490227, 10502444,
19866827);
expectedsize = roaring_bitmap_portable_size_in_bytes(r1);
serialized = (char *)malloc(expectedsize);
serialize_len = roaring_bitmap_portable_serialize(r1, serialized);
Expand Down Expand Up @@ -1397,7 +1397,7 @@ DEFINE_TEST(test_portable_serialize) {

DEFINE_TEST(test_serialize) {
roaring_bitmap_t *r1 =
roaring_bitmap_of(8, 1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
roaring_bitmap_from(1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
assert_non_null(r1);

uint32_t serialize_len;
Expand Down Expand Up @@ -1466,8 +1466,8 @@ DEFINE_TEST(test_serialize) {
roaring_bitmap_free(r1);
roaring_bitmap_free(r2);

r1 = roaring_bitmap_of(6, 2946000, 2997491, 10478289, 10490227, 10502444,
19866827);
r1 = roaring_bitmap_from(2946000, 2997491, 10478289, 10490227, 10502444,
19866827);

serialized = (char *)malloc(roaring_bitmap_size_in_bytes(r1));
serialize_len = roaring_bitmap_serialize(r1, serialized);
Expand Down Expand Up @@ -4531,7 +4531,7 @@ DEFINE_TEST(test_frozen_serialization_max_containers) {

DEFINE_TEST(test_portable_deserialize_frozen) {
roaring_bitmap_t *r1 =
roaring_bitmap_of(8, 1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
roaring_bitmap_from(1, 2, 3, 100, 1000, 10000, 1000000, 20000000);
assert_non_null(r1);

uint32_t serialize_len;
Expand Down Expand Up @@ -4563,8 +4563,8 @@ DEFINE_TEST(test_portable_deserialize_frozen) {
roaring_bitmap_free(r1);
roaring_bitmap_free(r2);

r1 = roaring_bitmap_of(6, 2946000, 2997491, 10478289, 10490227, 10502444,
19866827);
r1 = roaring_bitmap_from(2946000, 2997491, 10478289, 10490227, 10502444,
19866827);
expectedsize = roaring_bitmap_portable_size_in_bytes(r1);
serialized = (char *)malloc(expectedsize);
serialize_len = roaring_bitmap_portable_serialize(r1, serialized);
Expand Down

0 comments on commit 413230b

Please sign in to comment.