/* Negation across a range of the container. * Compute the negation of src and write the result * to *dst. Returns true if the result is a bitset container * and false for an array container. *dst is not preallocated. */ bool array_container_negation_range(const array_container_t *src, const int range_start, const int range_end, void **dst) { /* close port of the Java implementation */ if (range_start >= range_end) { *dst = array_container_clone(src); return false; } int32_t start_index = binarySearch(src->array, src->cardinality, (uint16_t)range_start); if (start_index < 0) start_index = -start_index - 1; int32_t last_index = binarySearch(src->array, src->cardinality, (uint16_t)(range_end - 1)); if (last_index < 0) last_index = -last_index - 2; const int32_t current_values_in_range = last_index - start_index + 1; const int32_t span_to_be_flipped = range_end - range_start; const int32_t new_values_in_range = span_to_be_flipped - current_values_in_range; const int32_t cardinality_change = new_values_in_range - current_values_in_range; const int32_t new_cardinality = src->cardinality + cardinality_change; if (new_cardinality > DEFAULT_MAX_SIZE) { bitset_container_t *temp = bitset_container_from_array(src); bitset_flip_range(temp->array, (uint32_t)range_start, (uint32_t)range_end); temp->cardinality = new_cardinality; *dst = temp; return true; } array_container_t *arr = array_container_create_given_capacity(new_cardinality); *dst = (void *)arr; // copy stuff before the active area memcpy(arr->array, src->array, start_index * sizeof(uint16_t)); // work on the range int32_t out_pos = start_index, in_pos = start_index; int32_t val_in_range = range_start; for (; val_in_range < range_end && in_pos <= last_index; ++val_in_range) { if ((uint16_t)val_in_range != src->array[in_pos]) { arr->array[out_pos++] = (uint16_t)val_in_range; } else { ++in_pos; } } for (; val_in_range < range_end; ++val_in_range) arr->array[out_pos++] = (uint16_t)val_in_range; // content after the active range memcpy(arr->array + out_pos, src->array + (last_index + 1), (src->cardinality - (last_index + 1)) * sizeof(uint16_t)); arr->cardinality = new_cardinality; return false; }
/* * Same as bitset_container_negation except that if the output is to * be a * bitset_container_t, then src is modified and no allocation is made. * If the output is to be an array_container_t, then caller is responsible * to free the container. * In all cases, the result is in *dst. */ bool bitset_container_negation_range_inplace(bitset_container_t *src, const int range_start, const int range_end, void **dst) { bitset_flip_range(src->array, (uint32_t)range_start, (uint32_t)range_end); src->cardinality = bitset_container_compute_cardinality(src); if (src->cardinality > DEFAULT_MAX_SIZE) { *dst = src; return true; } *dst = array_container_from_bitset(src); bitset_container_free(src); return false; }
bool run_bitset_container_andnot(const run_container_t *src_1, const bitset_container_t *src_2, void **dst) { // follows the Java implementation as of June 2016 int card = run_container_cardinality(src_1); if (card <= DEFAULT_MAX_SIZE) { // must be an array array_container_t *answer = array_container_create_given_capacity(card); answer->cardinality = 0; for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) { rle16_t rle = src_1->runs[rlepos]; for (int run_value = rle.value; run_value <= rle.value + rle.length; ++run_value) { if (!bitset_container_get(src_2, (uint16_t)run_value)) { answer->array[answer->cardinality++] = (uint16_t)run_value; } } } *dst = answer; return false; } else { // we guess it will be a bitset, though have to check guess when // done bitset_container_t *answer = bitset_container_clone(src_2); uint32_t last_pos = 0; for (int32_t rlepos = 0; rlepos < src_1->n_runs; ++rlepos) { rle16_t rle = src_1->runs[rlepos]; uint32_t start = rle.value; uint32_t end = start + rle.length + 1; bitset_reset_range(answer->array, last_pos, start); bitset_flip_range(answer->array, start, end); last_pos = end; } bitset_reset_range(answer->array, last_pos, (uint32_t)(1 << 16)); answer->cardinality = bitset_container_compute_cardinality(answer); if (answer->cardinality <= DEFAULT_MAX_SIZE) { *dst = array_container_from_bitset(answer); bitset_container_free(answer); return false; // not bitset } *dst = answer; return true; // bitset } }
/* Negation across a range of the container * Compute the negation of src and write the result * to *dst. A true return value indicates a bitset result, * otherwise the result is an array container. * We assume that dst is not pre-allocated. In * case of failure, *dst will be NULL. */ bool bitset_container_negation_range(const bitset_container_t *src, const int range_start, const int range_end, void **dst) { // TODO maybe consider density-based estimate // and sometimes build result directly as array, with // conversion back to bitset if wrong. Or determine // actual result cardinality, then go directly for the known final cont. // keep computation using bitsets as long as possible. bitset_container_t *t = bitset_container_clone(src); bitset_flip_range(t->array, (uint32_t)range_start, (uint32_t)range_end); t->cardinality = bitset_container_compute_cardinality(t); if (t->cardinality > DEFAULT_MAX_SIZE) { *dst = t; return true; } else { *dst = array_container_from_bitset(t); bitset_container_free(t); return false; } }