int contains_test(run_container_t* B) { int card = 0; int x; for (x = 0; x < (1 << 16); x++) { card += run_container_contains(B, (uint16_t)x); } return card; }
void add_contains_test() { run_container_t* B = run_container_create(); assert_non_null(B); int expected_card = 0; for (size_t x = 0; x < 1 << 16; x += 3) { assert_true(run_container_add(B, x)); assert_true(run_container_contains(B, x)); assert_int_equal(run_container_cardinality(B), ++expected_card); assert_true(run_container_cardinality(B) <= B->capacity); } for (size_t x = 0; x < 1 << 16; x++) { assert_int_equal(run_container_contains(B, x), (x / 3 * 3 == x)); } assert_int_equal(run_container_cardinality(B), (1 << 16) / 3 + 1); for (size_t x = 0; x < 1 << 16; x += 3) { assert_true(run_container_contains(B, x)); assert_true(run_container_remove(B, x)); assert_int_equal(run_container_cardinality(B), --expected_card); assert_false(run_container_contains(B, x)); } assert_int_equal(run_container_cardinality(B), 0); for (int x = 65535; x >= 0; x -= 3) { assert_true(run_container_add(B, x)); assert_true(run_container_contains(B, x)); assert_int_equal(run_container_cardinality(B), ++expected_card); assert_true(run_container_cardinality(B) <= B->capacity); } assert_int_equal(run_container_cardinality(B), (1 << 16) / 3 + 1); for (size_t x = 0; x < 1 << 16; x++) { assert_int_equal(run_container_contains(B, x), (x / 3 * 3 == x)); } for (size_t x = 0; x < 1 << 16; x += 3) { assert_true(run_container_contains(B, x)); assert_true(run_container_remove(B, x)); assert_int_equal(run_container_cardinality(B), --expected_card); assert_false(run_container_contains(B, x)); } run_container_free(B); }
/* * Same as run_container_negation except that if the output is to * be a * run_container_t, and has the capacity to hold the result, * then src is modified and no allocation is made. * In all cases, the result is in *dst. */ int run_container_negation_range_inplace(run_container_t *src, const int range_start, const int range_end, void **dst) { uint8_t return_typecode; if (range_end <= range_start) { *dst = src; return RUN_CONTAINER_TYPE_CODE; } // TODO: efficient special case when range is 0 to 65535 inclusive if (src->capacity == src->n_runs) { // no excess room. More checking to see if result can fit bool last_val_before_range = false; bool first_val_in_range = false; bool last_val_in_range = false; bool first_val_past_range = false; if (range_start > 0) last_val_before_range = run_container_contains(src, (uint16_t)(range_start - 1)); first_val_in_range = run_container_contains(src, (uint16_t)range_start); if (last_val_before_range == first_val_in_range) { last_val_in_range = run_container_contains(src, (uint16_t)(range_end - 1)); if (range_end != 0x10000) first_val_past_range = run_container_contains(src, (uint16_t)range_end); if (last_val_in_range == first_val_past_range) { // no space for inplace int ans = run_container_negation_range(src, range_start, range_end, dst); run_container_free(src); return ans; } } } // all other cases: result will fit run_container_t *ans = src; int my_nbr_runs = src->n_runs; ans->n_runs = 0; int k = 0; for (; (k < my_nbr_runs) && (src->runs[k].value < range_start); ++k) { // ans->runs[k] = src->runs[k]; (would be self-copy) ans->n_runs++; } // as with Java implementation, use locals to give self a buffer of depth 1 rle16_t buffered = (rle16_t){.value = (uint16_t)0, .length = (uint16_t)0}; rle16_t next = buffered; if (k < my_nbr_runs) buffered = src->runs[k]; run_container_smart_append_exclusive( ans, (uint16_t)range_start, (uint16_t)(range_end - range_start - 1)); for (; k < my_nbr_runs; ++k) { if (k + 1 < my_nbr_runs) next = src->runs[k + 1]; run_container_smart_append_exclusive(ans, buffered.value, buffered.length); buffered = next; } *dst = convert_run_to_efficient_container(ans, &return_typecode); if (return_typecode != RUN_CONTAINER_TYPE_CODE) run_container_free(ans); return return_typecode; }