Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ tests/config.h
# CMake
build

# clangd
.cache/clangd/


#############BEGIN VISUAL STUDIO############
Expand Down
14 changes: 14 additions & 0 deletions include/roaring/containers/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,20 @@ inline int array_container_index_equalorlarger(const array_container_t *arr,
}
}

/**
* Reads values from the array container into a boolean buffer.
*
* @param ac The array container to read from
* @param it Iterator state (index into the array)
* @param buf Boolean buffer to write to
* @param max_value Stop reading when it->current_value > this value.
* @param value_out Output parameter for the next value
* @return true if there are more values to read, false otherwise
*/
bool array_container_iterator_read_into_bool(
const array_container_t *ac, struct roaring_container_iterator_s *it,
bool *buf, uint16_t max_value, uint16_t *value_out);

/*
* Adds all values in range [min,max] using hint:
* nvals_less is the number of array values less than $min
Expand Down
14 changes: 14 additions & 0 deletions include/roaring/containers/bitset.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,20 @@ int bitset_container_get_index(const bitset_container_t *container, uint16_t x);
int bitset_container_index_equalorlarger(const bitset_container_t *container,
uint16_t x);

/**
* Reads values from the bitset container into a boolean buffer.
*
* @param bc The bitset container to read from
* @param it Iterator state (index into the bitset)
* @param buf Boolean buffer to write to
* @param max_value Stop reading when it->current_value > this value.
* @param value_out Output parameter for the next value
* @return true if there are more values to read, false otherwise
*/
bool bitset_container_iterator_read_into_bool(
const bitset_container_t *bc, struct roaring_container_iterator_s *it,
bool *buf, uint16_t max_value, uint16_t *value_out);

#ifdef __cplusplus
}
}
Expand Down
18 changes: 18 additions & 0 deletions include/roaring/containers/containers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2477,6 +2477,24 @@ bool container_iterator_read_into_uint64(const container_t *c, uint8_t typecode,
uint32_t count, uint32_t *consumed,
uint16_t *value_out);

/**
* Iterate all entries within [it->current_value, max_value], and sets
* corresponding positions in `buf` to true.
*
* The `buf` array is filled starting from index 0, which corresponds to the
* initial iterator position `it`. For subsequent iterator positions `it_new`,
* set `buf[it_new->current_value - it->current_value]` to true.
*
* Returns true and sets `value_out` if a value is present after reading the
* entries.
*
* The initial `it` should have a value.
*/
bool container_iterator_read_into_bool(const container_t *c, uint8_t typecode,
roaring_container_iterator_t *it,
bool *buf, uint16_t max_value,
uint16_t *value_out);

/**
* Skips the next `skip_count` entries in the container iterator. Returns true
* and sets `value_out` if a value is present after skipping. Returns false if
Expand Down
14 changes: 14 additions & 0 deletions include/roaring/containers/run.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,20 @@ static inline void run_container_remove_range(run_container_t *run,
}
}

/**
* Reads values from the run container into a boolean buffer.
*
* @param rc The run container to read from
* @param it Iterator state (index into the runs array)
* @param buf Boolean buffer to write to
* @param max_value Stop reading when it->current_value > this value.
* @param value_out Output parameter for the current/next value
* @return true if there are more values to read, false otherwise
*/
bool run_container_iterator_read_into_bool(
const run_container_t *rc, struct roaring_container_iterator_s *it,
bool *buf, uint16_t max_value, uint16_t *value_out);

#ifdef __cplusplus
}
}
Expand Down
56 changes: 56 additions & 0 deletions include/roaring/roaring.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,33 @@ void roaring_bitmap_to_uint32_array(const roaring_bitmap_t *r, uint32_t *ans);
*/
bool roaring_bitmap_to_bitset(const roaring_bitmap_t *r, bitset_t *bitset);

/**
* Convert the bitmap within the range [range_start, range_end] to a dense bool
* array and output in `ans`.
*
* For each value at position `i` (where i ranges from 0 to
* range_end-range_start) in the output array, `ans[i]` is set to true if the
* value range_start + i is present in the bitmap.
*
* Caller is responsible to ensure that there is enough memory allocated, and
* that the memory is initialized to zero, e.g.
*
* ans = calloc((range_end - range_start + 1) * sizeof(bool));
*
* For more control, see `roaring_uint32_iterator_move_equalorlarger` and
* `roaring_uint32_iterator_read_into_bool`.
*/
void roaring_bitmap_to_bool_array_range_closed(const roaring_bitmap_t *r,
uint32_t range_start,
uint32_t range_end, bool *ans);

/**
* Same as `roaring_bitmap_to_bool_array_range_closed`, but the range is
* [range_start, range_end).
*/
void roaring_bitmap_to_bool_array_range(const roaring_bitmap_t *r,
uint64_t range_start,
uint64_t range_end, bool *ans);
/**
* Convert the bitmap to a sorted array from `offset` by `limit`, output in
* `ans`.
Expand Down Expand Up @@ -1238,6 +1265,35 @@ uint32_t roaring_uint32_iterator_skip(roaring_uint32_iterator_t *it,
uint32_t roaring_uint32_iterator_skip_backward(roaring_uint32_iterator_t *it,
uint32_t count);

/**
* Iterate over `it` in range [it->current_value, max_value] and fill bool array
* `buf` from its beginning.
*
* This function satisfies semantics of iteration and can be used together with
* other iterator functions.
*
* Let `init_it` be the initial iterator and it has value, then for every
* iterated `it`, buf[init_it.current_value - it.current_value] will be set to
* true; other positions will remain to be false. The final `it` will be invalid
* or point to the first value > max_value.
*
* User should ensure that `buf` has enough space for holding the bool values.
*
* Here is an example:
* max_value(8)
* init_it(4) │ final_it(9)
* │ │ │
* ▼ ▼ ▼
* Values: 1 2 3 4 5 6 7 8 9
* Roaring: x x x x x
* The result bool array: [1 0 0 1 1]
* Size of the bool array: 5 ▲
* │
* Beginning of the bool array
*/
void roaring_uint32_iterator_read_into_bool(roaring_uint32_iterator_t *it,
bool *buf, uint32_t max_value);

#ifdef __cplusplus
}
}
Expand Down
15 changes: 15 additions & 0 deletions microbenchmarks/bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,21 @@ struct to_array64 {
auto ToArray64 = BasicBench<to_array64>;
BENCHMARK(ToArray64);

struct to_array_bool {
static uint64_t run() {
uint64_t marker = 0;
for (size_t i = 0; i < count; ++i) {
uint64_t card = roaring_bitmap_get_cardinality(bitmaps[i]);
roaring_bitmap_to_bool_array_range(bitmaps[i], 0, card,
array_buffer_bool);
marker += array_buffer_bool[0];
}
return marker;
}
};
auto ToArrayBool = BasicBench<to_array_bool>;
BENCHMARK(ToArrayBool);

struct iterate_all {
static uint64_t run() {
uint64_t marker = 0;
Expand Down
2 changes: 2 additions & 0 deletions microbenchmarks/bench.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ roaring64_bitmap_t **bitmaps64 = NULL;
Roaring64Map **bitmaps64cpp = NULL;
uint32_t *array_buffer;
uint64_t *array_buffer64;
bool *array_buffer_bool;
uint32_t maxvalue = 0;
uint32_t maxcard = 0;

Expand Down Expand Up @@ -200,6 +201,7 @@ static roaring_bitmap_t **create_all_bitmaps(size_t *howmany,
}
array_buffer = (uint32_t *)malloc(maxcard * sizeof(uint32_t));
array_buffer64 = (uint64_t *)malloc(maxcard * sizeof(uint64_t));
array_buffer_bool = (bool *)calloc(maxvalue + 1, sizeof(bool));
return answer;
}

Expand Down
27 changes: 27 additions & 0 deletions src/containers/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,33 @@ bool array_container_iterate64(const array_container_t *cont, uint32_t base,
return true;
}

CROARING_ALLOW_UNALIGNED
bool array_container_iterator_read_into_bool(const array_container_t *ac,
roaring_container_iterator_t *it,
bool *buf, uint16_t max_value,
uint16_t *value_out) {
int32_t initial_index = it->index;

if (max_value == UINT16_MAX) {
// TODO: SIMD optimization
while (it->index < ac->cardinality) {
buf[ac->array[it->index] - ac->array[initial_index]] = true;
it->index++;
}
return false;
}

while (it->index < ac->cardinality && ac->array[it->index] <= max_value) {
buf[ac->array[it->index] - ac->array[initial_index]] = true;
it->index++;
}
if (it->index < ac->cardinality) {
*value_out = ac->array[it->index];
return true;
}
return false;
}

#ifdef __cplusplus
}
}
Expand Down
48 changes: 48 additions & 0 deletions src/containers/bitset.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,54 @@ bool bitset_container_intersect(const bitset_container_t *src_1,
return false;
}

CROARING_ALLOW_UNALIGNED
bool bitset_container_iterator_read_into_bool(const bitset_container_t *bc,
roaring_container_iterator_t *it,
bool *buf, uint16_t max_value,
uint16_t *value_out) {
uint16_t max_wordindex = max_value / 64;
uint16_t wordindex = it->index / 64;
uint64_t word = bc->words[wordindex] & (UINT64_MAX << (it->index % 64));
uint16_t initial_value = it->index;
// Remain the last word to process out of loop for reducing `if` branches
while (wordindex < max_wordindex) {
// TODO: SIMD optimization
while (word != 0) {
it->index = wordindex * 64 + roaring_trailing_zeroes(word);
buf[it->index - initial_value] = true;
word = word & (word - 1);
}
wordindex++;
if (wordindex < BITSET_CONTAINER_SIZE_IN_WORDS) {
word = bc->words[wordindex];
}
}
// Process the last word (which is at max_wordindex)
while (word != 0) {
it->index = wordindex * 64 + roaring_trailing_zeroes(word);
if ((uint16_t)it->index > max_value) {
*value_out = it->index;
return true;
}
buf[it->index - initial_value] = true;
word = word & (word - 1);
}
wordindex++;
/// If the bitset is not drained, iterate to the next set bit.
while (wordindex < BITSET_CONTAINER_SIZE_IN_WORDS &&
bc->words[wordindex] == 0) {
wordindex++;
}
if (wordindex >= BITSET_CONTAINER_SIZE_IN_WORDS) return false;
word = bc->words[wordindex];
if (word != 0) {
it->index = wordindex * 64 + roaring_trailing_zeroes(word);
*value_out = it->index;
return true;
}
return false;
}

#if CROARING_IS_X64
#ifndef CROARING_WORDS_IN_AVX2_REG
#define CROARING_WORDS_IN_AVX2_REG sizeof(__m256i) / sizeof(uint64_t)
Expand Down
22 changes: 22 additions & 0 deletions src/containers/containers.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,28 @@ bool container_iterator_read_into_uint64(const container_t *c, uint8_t typecode,
}
}

bool container_iterator_read_into_bool(const container_t *c, uint8_t typecode,
roaring_container_iterator_t *it,
bool *buf, uint16_t max_value,
uint16_t *value_out) {
c = container_unwrap_shared(c, &typecode);
switch (typecode) {
case BITSET_CONTAINER_TYPE:
return bitset_container_iterator_read_into_bool(
const_CAST_bitset(c), it, buf, max_value, value_out);
case ARRAY_CONTAINER_TYPE:
return array_container_iterator_read_into_bool(
const_CAST_array(c), it, buf, max_value, value_out);
case RUN_CONTAINER_TYPE:
return run_container_iterator_read_into_bool(
const_CAST_run(c), it, buf, max_value, value_out);
default:
assert(false);
roaring_unreachable;
return false;
}
}

bool container_iterator_skip(const container_t *c, uint8_t typecode,
roaring_container_iterator_t *it,
uint32_t skip_count, uint32_t *consumed_count,
Expand Down
46 changes: 46 additions & 0 deletions src/containers/run.c
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,52 @@ int run_container_to_uint32_array(void *vout, const run_container_t *cont,

#endif

CROARING_ALLOW_UNALIGNED
bool run_container_iterator_read_into_bool(const run_container_t *rc,
roaring_container_iterator_t *it,
bool *buf, uint16_t max_value,
uint16_t *value_out) {
uint16_t initial_value = *value_out;

// TODO: SIMD optimization
if (max_value == UINT16_MAX) {
while (it->index < rc->n_runs) {
uint16_t run_start = rc->runs[it->index].value;
uint16_t run_end = run_start + rc->runs[it->index].length;
// Start from current value if we're in the middle of a run
run_start = (*value_out >= run_start) ? *value_out : run_start;
memset(buf + run_start - initial_value, true,
run_end - run_start + 1);
it->index++;
}
return false;
}

while (it->index < rc->n_runs) {
uint16_t run_start = rc->runs[it->index].value;
uint16_t run_end = run_start + rc->runs[it->index].length;

// Start from current value if we're in the middle of a run
uint16_t start = (*value_out >= run_start) ? *value_out : run_start;
// max_value .. [start .. run_end]
if (max_value < start) {
*value_out = start;
return true;
}
// [start .. max_value .. run_end]
if (max_value < run_end) {
memset(buf + start - initial_value, true, max_value - start + 1);
*value_out = max_value + 1;
return true;
}
// [start .. run_end] .. max_value
memset(buf + start - initial_value, true, run_end - start + 1);
*value_out = run_end;
it->index++;
}
return false;
}

#ifdef __cplusplus
}
}
Expand Down
Loading