Packages
rocksdb
3.1.1
3.1.2
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Current section
Files
Jump to
Current section
Files
deps/CRoaring/src/containers/convert.c
#include <stdio.h>
#include <roaring/bitset_util.h>
#include <roaring/containers/containers.h>
#include <roaring/containers/convert.h>
#include <roaring/containers/perfparameters.h>
#if CROARING_IS_X64
#ifndef CROARING_COMPILER_SUPPORTS_AVX512
#error "CROARING_COMPILER_SUPPORTS_AVX512 needs to be defined."
#endif // CROARING_COMPILER_SUPPORTS_AVX512
#endif
#ifdef __cplusplus
extern "C" {
namespace roaring {
namespace internal {
#endif
// file contains grubby stuff that must know impl. details of all container
// types.
bitset_container_t *bitset_container_from_array(const array_container_t *ac) {
bitset_container_t *ans = bitset_container_create();
int limit = array_container_cardinality(ac);
for (int i = 0; i < limit; ++i) bitset_container_set(ans, ac->array[i]);
return ans;
}
bitset_container_t *bitset_container_from_run(const run_container_t *arr) {
int card = run_container_cardinality(arr);
bitset_container_t *answer = bitset_container_create();
for (int rlepos = 0; rlepos < arr->n_runs; ++rlepos) {
rle16_t vl = arr->runs[rlepos];
bitset_set_lenrange(answer->words, vl.value, vl.length);
}
answer->cardinality = card;
return answer;
}
array_container_t *array_container_from_run(const run_container_t *arr) {
array_container_t *answer =
array_container_create_given_capacity(run_container_cardinality(arr));
answer->cardinality = 0;
for (int rlepos = 0; rlepos < arr->n_runs; ++rlepos) {
int run_start = arr->runs[rlepos].value;
int run_end = run_start + arr->runs[rlepos].length;
for (int run_value = run_start; run_value <= run_end; ++run_value) {
answer->array[answer->cardinality++] = (uint16_t)run_value;
}
}
return answer;
}
array_container_t *array_container_from_bitset(const bitset_container_t *bits) {
array_container_t *result =
array_container_create_given_capacity(bits->cardinality);
result->cardinality = bits->cardinality;
#if CROARING_IS_X64
#if CROARING_COMPILER_SUPPORTS_AVX512
if (croaring_hardware_support() & ROARING_SUPPORTS_AVX512) {
bitset_extract_setbits_avx512_uint16(
bits->words, BITSET_CONTAINER_SIZE_IN_WORDS, result->array,
bits->cardinality, 0);
} else
#endif
{
// sse version ends up being slower here
// (bitset_extract_setbits_sse_uint16)
// because of the sparsity of the data
bitset_extract_setbits_uint16(
bits->words, BITSET_CONTAINER_SIZE_IN_WORDS, result->array, 0);
}
#else
// If the system is not x64, then we have no accelerated function.
bitset_extract_setbits_uint16(bits->words, BITSET_CONTAINER_SIZE_IN_WORDS,
result->array, 0);
#endif
return result;
}
/* assumes that container has adequate space. Run from [s,e] (inclusive) */
static void add_run(run_container_t *rc, int s, int e) {
rc->runs[rc->n_runs].value = s;
rc->runs[rc->n_runs].length = e - s;
rc->n_runs++;
}
run_container_t *run_container_from_array(const array_container_t *c) {
int32_t n_runs = array_container_number_of_runs(c);
run_container_t *answer = run_container_create_given_capacity(n_runs);
int prev = -2;
int run_start = -1;
int32_t card = c->cardinality;
if (card == 0) return answer;
for (int i = 0; i < card; ++i) {
const uint16_t cur_val = c->array[i];
if (cur_val != prev + 1) {
// new run starts; flush old one, if any
if (run_start != -1) add_run(answer, run_start, prev);
run_start = cur_val;
}
prev = c->array[i];
}
// now prev is the last seen value
add_run(answer, run_start, prev);
// assert(run_container_cardinality(answer) == c->cardinality);
return answer;
}
/**
* Convert the runcontainer to either a Bitmap or an Array Container, depending
* on the cardinality. Frees the container.
* Allocates and returns new container, which caller is responsible for freeing.
* It does not free the run container.
*/
container_t *convert_to_bitset_or_array_container(run_container_t *rc,
int32_t card,
uint8_t *resulttype) {
if (card <= DEFAULT_MAX_SIZE) {
array_container_t *answer = array_container_create_given_capacity(card);
answer->cardinality = 0;
for (int rlepos = 0; rlepos < rc->n_runs; ++rlepos) {
uint16_t run_start = rc->runs[rlepos].value;
uint16_t run_end = run_start + rc->runs[rlepos].length;
for (uint16_t run_value = run_start; run_value < run_end;
++run_value) {
answer->array[answer->cardinality++] = run_value;
}
answer->array[answer->cardinality++] = run_end;
}
assert(card == answer->cardinality);
*resulttype = ARRAY_CONTAINER_TYPE;
// run_container_free(r);
return answer;
}
bitset_container_t *answer = bitset_container_create();
for (int rlepos = 0; rlepos < rc->n_runs; ++rlepos) {
uint16_t run_start = rc->runs[rlepos].value;
bitset_set_lenrange(answer->words, run_start, rc->runs[rlepos].length);
}
answer->cardinality = card;
*resulttype = BITSET_CONTAINER_TYPE;
// run_container_free(r);
return answer;
}
/* Converts a run container to either an array or a bitset, IF it saves space.
*/
/* If a conversion occurs, the caller is responsible to free the original
* container and
* he becomes responsible to free the new one. */
container_t *convert_run_to_efficient_container(run_container_t *c,
uint8_t *typecode_after) {
int32_t size_as_run_container =
run_container_serialized_size_in_bytes(c->n_runs);
int32_t size_as_bitset_container =
bitset_container_serialized_size_in_bytes();
int32_t card = run_container_cardinality(c);
int32_t size_as_array_container =
array_container_serialized_size_in_bytes(card);
int32_t min_size_non_run =
size_as_bitset_container < size_as_array_container
? size_as_bitset_container
: size_as_array_container;
if (size_as_run_container <= min_size_non_run) { // no conversion
*typecode_after = RUN_CONTAINER_TYPE;
return c;
}
if (card <= DEFAULT_MAX_SIZE) {
// to array
array_container_t *answer = array_container_create_given_capacity(card);
answer->cardinality = 0;
for (int rlepos = 0; rlepos < c->n_runs; ++rlepos) {
int run_start = c->runs[rlepos].value;
int run_end = run_start + c->runs[rlepos].length;
for (int run_value = run_start; run_value <= run_end; ++run_value) {
answer->array[answer->cardinality++] = (uint16_t)run_value;
}
}
*typecode_after = ARRAY_CONTAINER_TYPE;
return answer;
}
// else to bitset
bitset_container_t *answer = bitset_container_create();
for (int rlepos = 0; rlepos < c->n_runs; ++rlepos) {
int start = c->runs[rlepos].value;
int end = start + c->runs[rlepos].length;
bitset_set_range(answer->words, start, end + 1);
}
answer->cardinality = card;
*typecode_after = BITSET_CONTAINER_TYPE;
return answer;
}
// like convert_run_to_efficient_container but frees the old result if needed
container_t *convert_run_to_efficient_container_and_free(
run_container_t *c, uint8_t *typecode_after) {
container_t *answer = convert_run_to_efficient_container(c, typecode_after);
if (answer != c) run_container_free(c);
return answer;
}
/* once converted, the original container is disposed here, rather than
in roaring_array
*/
// TODO: split into run- array- and bitset- subfunctions for sanity;
// a few function calls won't really matter.
container_t *convert_run_optimize(container_t *c, uint8_t typecode_original,
uint8_t *typecode_after) {
if (typecode_original == RUN_CONTAINER_TYPE) {
container_t *newc =
convert_run_to_efficient_container(CAST_run(c), typecode_after);
if (newc != c) {
container_free(c, typecode_original);
}
return newc;
} else if (typecode_original == ARRAY_CONTAINER_TYPE) {
// it might need to be converted to a run container.
array_container_t *c_qua_array = CAST_array(c);
int32_t n_runs = array_container_number_of_runs(c_qua_array);
int32_t size_as_run_container =
run_container_serialized_size_in_bytes(n_runs);
int32_t card = array_container_cardinality(c_qua_array);
int32_t size_as_array_container =
array_container_serialized_size_in_bytes(card);
if (size_as_run_container >= size_as_array_container) {
*typecode_after = ARRAY_CONTAINER_TYPE;
return c;
}
// else convert array to run container
run_container_t *answer = run_container_create_given_capacity(n_runs);
int prev = -2;
int run_start = -1;
assert(card > 0);
for (int i = 0; i < card; ++i) {
uint16_t cur_val = c_qua_array->array[i];
if (cur_val != prev + 1) {
// new run starts; flush old one, if any
if (run_start != -1) add_run(answer, run_start, prev);
run_start = cur_val;
}
prev = c_qua_array->array[i];
}
assert(run_start >= 0);
// now prev is the last seen value
add_run(answer, run_start, prev);
*typecode_after = RUN_CONTAINER_TYPE;
array_container_free(c_qua_array);
return answer;
} else if (typecode_original ==
BITSET_CONTAINER_TYPE) { // run conversions on bitset
// does bitset need conversion to run?
bitset_container_t *c_qua_bitset = CAST_bitset(c);
int32_t n_runs = bitset_container_number_of_runs(c_qua_bitset);
int32_t size_as_run_container =
run_container_serialized_size_in_bytes(n_runs);
int32_t size_as_bitset_container =
bitset_container_serialized_size_in_bytes();
if (size_as_bitset_container <= size_as_run_container) {
// no conversion needed.
*typecode_after = BITSET_CONTAINER_TYPE;
return c;
}
// bitset to runcontainer (ported from Java RunContainer(
// BitmapContainer bc, int nbrRuns))
assert(n_runs > 0); // no empty bitmaps
run_container_t *answer = run_container_create_given_capacity(n_runs);
int long_ctr = 0;
uint64_t cur_word = c_qua_bitset->words[0];
while (true) {
while (cur_word == UINT64_C(0) &&
long_ctr < BITSET_CONTAINER_SIZE_IN_WORDS - 1)
cur_word = c_qua_bitset->words[++long_ctr];
if (cur_word == UINT64_C(0)) {
bitset_container_free(c_qua_bitset);
*typecode_after = RUN_CONTAINER_TYPE;
return answer;
}
int local_run_start = roaring_trailing_zeroes(cur_word);
int run_start = local_run_start + 64 * long_ctr;
uint64_t cur_word_with_1s = cur_word | (cur_word - 1);
int run_end = 0;
while (cur_word_with_1s == UINT64_C(0xFFFFFFFFFFFFFFFF) &&
long_ctr < BITSET_CONTAINER_SIZE_IN_WORDS - 1)
cur_word_with_1s = c_qua_bitset->words[++long_ctr];
if (cur_word_with_1s == UINT64_C(0xFFFFFFFFFFFFFFFF)) {
run_end = 64 + long_ctr * 64; // exclusive, I guess
add_run(answer, run_start, run_end - 1);
bitset_container_free(c_qua_bitset);
*typecode_after = RUN_CONTAINER_TYPE;
return answer;
}
int local_run_end = roaring_trailing_zeroes(~cur_word_with_1s);
run_end = local_run_end + long_ctr * 64;
add_run(answer, run_start, run_end - 1);
cur_word = cur_word_with_1s & (cur_word_with_1s + 1);
}
return answer;
} else {
assert(false);
roaring_unreachable;
return NULL;
}
}
container_t *container_from_run_range(const run_container_t *run, uint32_t min,
uint32_t max, uint8_t *typecode_after) {
// We expect most of the time to end up with a bitset container
bitset_container_t *bitset = bitset_container_create();
*typecode_after = BITSET_CONTAINER_TYPE;
int32_t union_cardinality = 0;
for (int32_t i = 0; i < run->n_runs; ++i) {
uint32_t rle_min = run->runs[i].value;
uint32_t rle_max = rle_min + run->runs[i].length;
bitset_set_lenrange(bitset->words, rle_min, rle_max - rle_min);
union_cardinality += run->runs[i].length + 1;
}
union_cardinality += max - min + 1;
union_cardinality -=
bitset_lenrange_cardinality(bitset->words, min, max - min);
bitset_set_lenrange(bitset->words, min, max - min);
bitset->cardinality = union_cardinality;
if (bitset->cardinality <= DEFAULT_MAX_SIZE) {
// we need to convert to an array container
array_container_t *array = array_container_from_bitset(bitset);
*typecode_after = ARRAY_CONTAINER_TYPE;
bitset_container_free(bitset);
return array;
}
return bitset;
}
#ifdef __cplusplus
}
}
} // extern "C" { namespace roaring { namespace internal {
#endif