From e68741c0ff9bc5ff9400786b560962f5b2ad682f Mon Sep 17 00:00:00 2001 From: Roman Tsisyk <roman@tsisyk.com> Date: Thu, 31 Jan 2013 18:59:33 +0400 Subject: [PATCH] libbitset: bitset_index (splited off from bitmap-index) --- .gitignore | 1 + include/lib/bitset/index.h | 218 +++++++++++++++++++++++ src/lib/bitset/CMakeLists.txt | 1 + src/lib/bitset/index.c | 323 ++++++++++++++++++++++++++++++++++ test/unit/CMakeLists.txt | 2 + test/unit/bitset_index.c | 287 ++++++++++++++++++++++++++++++ test/unit/bitset_index.result | 22 +++ test/unit/bitset_index.test | 1 + 8 files changed, 855 insertions(+) create mode 100644 include/lib/bitset/index.h create mode 100644 src/lib/bitset/index.c create mode 100644 test/unit/bitset_index.c create mode 100644 test/unit/bitset_index.result create mode 100644 test/unit/bitset_index.test diff --git a/.gitignore b/.gitignore index b532180bdc..c03c192d05 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ test/unit/rlist test/unit/bit_test test/unit/bitset_basic_test test/unit/bitset_iterator_test +test/unit/bitset_index_test Makefile CMakeFiles CMakeCache.txt diff --git a/include/lib/bitset/index.h b/include/lib/bitset/index.h new file mode 100644 index 0000000000..37c7bd13d5 --- /dev/null +++ b/include/lib/bitset/index.h @@ -0,0 +1,218 @@ +#ifndef TARANTOOL_LIB_BITSET_INDEX_H_INCLUDED +#define TARANTOOL_LIB_BITSET_INDEX_H_INCLUDED +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @file + * @brief BitsetIndex - a bit index based on @link bitset @endlink. + * @see bitset.h + */ + +#include <lib/bitset/bitset.h> +#include <lib/bitset/iterator.h> + +/** + * @brief BitsetIndex + */ +struct bitset_index { + /** @cond false **/ + struct bitset **bitsets; + size_t capacity; + void *(*realloc)(void *ptr, size_t size); + /** @endcond **/ +}; + +/** + * @brief Construct \a index + * @param index bitset index + * @param realloc memory allocator to use + * @retval 0 on success + * @retval -1 on memory error + */ +int +bitset_index_create(struct bitset_index *index, + void *(*realloc)(void *ptr, size_t size)); + +/** + * @brief Destruct \a index + * @param index bitset index + */ +void +bitset_index_destroy(struct bitset_index *index); + +/** + * @brief Insert (\a key, \a value) pair into \a index. + * Only one pair with same value can exist in the index. + * If pair with same \a value is exist, it will be updated quietly. + * @param index object + * @param key key + * @param key_size size of the key + * @param value value + * @retval 0 on success + * @retval -1 on memory error + */ +int +bitset_index_insert(struct bitset_index *index, const void *key, size_t key_size, + size_t value); + +/** + * @brief Remove a pair with \a value (*, \a value) from \a index. + * @param index bitset index + * @param value value + */ +void +bitset_index_remove_value(struct bitset_index *index, size_t value); + +/** + * @brief Initialize \a expr to iterate over a bitset index. + * The \a expr can be then passed to @link bitset_index_init_iterator @endlink. + * + * 'All' algorithm. Matches all pairs in a index. + * + * @param expr bitset expression + * @retval 0 on success + * @retval -1 on memory error + * @see @link bitset_index_init_iterator @endlink + * @see expr.h + */ +int +bitset_index_expr_all(struct bitset_expr *expr); + +/** + * @brief Initialize \a expr to iterate over a bitset index. + * The \a expr can be then passed to @link bitset_index_init_iterator @endlink. + * + * 'Equals' algorithm. Matches all pairs where \a key exactly equals to + * pair.key (\a key == pair.key). + * + * @param expr bitset expression + * @param key key + * @param key_size of \a key (in char, as sizeof returns) + * @retval 0 on success + * @retval -1 on memory error + * @see @link bitset_index_init_iterator @endlink + * @see expr.h + */ +int +bitset_index_expr_equals(struct bitset_expr *expr, const void *key, + size_t key_size); + +/** + * @brief Initialize \a expr to iterate over a bitset index. + * The \a expr can be then passed to @link bitset_index_init_iterator @endlink. + * + * 'All-Bits-Set' algorithm. Matches all pairs where all bits from \a key + * is set in pair.key ((\a key & pair.key) == \a key). + * + * @param expr bitset expression + * @retval 0 on success + * @retval -1 on memory error + * @see @link bitset_index_init_iterator @endlink + * @see expr.h + */ +int +bitset_index_expr_all_set(struct bitset_expr *expr, const void *key, + size_t key_size); + +/** + * @brief Initialize \a expr to iterate over a bitset index. + * The \a expr can be then passed to @link bitset_index_init_iterator @endlink. + * + * 'Any-Bits-Set' algorithm. Matches all pairs where at least one bit from + * \a key is set in pair.key ((\a key & pair.key) != 0). + * + * @param expr bitset expression + * @retval 0 on success + * @retval -1 on memory error + * @see @link bitset_index_init_iterator @endlink + * @see expr.h + */ +int +bitset_index_expr_any_set(struct bitset_expr *expr, const void *key, + size_t key_size); + +/** + * @brief Initialize \a expr to iterate over a bitset index. + * The \a expr can be then passed to @link bitset_index_init_iterator @endlink. + * + * 'All-Bits-Not-Set' algorithm. Matches all pairs in the \a index, where all + * bits from the \a key is not set in pair.key ((\a key & pair.key) == 0). + * + * @param expr bitset expression + * @retval 0 on success + * @retval -1 on memory error + * @see @link bitset_index_init_iterator @endlink + * @see expr.h + */ +int +bitset_index_expr_all_not_set(struct bitset_expr *expr, const void *key, + size_t key_size); + +/** + * @brief Initialize \a it using \a expr and bitsets used in \a index. + * + * @param index bitset index + * @param it bitset iterator + * @param expr bitset expression + * @retval 0 on success + * @retval 1 on memory error + */ +int +bitset_index_init_iterator(struct bitset_index *index, + struct bitset_iterator *it, + struct bitset_expr *expr); + +/** + * @brief Checks if a (*, \a value) pair exists in \a index + * @param index bitset index + * @param value + * @retval true if \a index contains pair with the \a value + * @retval false otherwise + */ +bool +bitset_index_contains_value(struct bitset_index *index, size_t value); + +/** + * @brief Return a number of pairs in \a index. + * @param index bitset index + * @return number of pairs in \a index + */ +inline size_t +bitset_index_size(struct bitset_index *index) +{ + return bitset_cardinality(index->bitsets[0]); +} + +#if defined(DEBUG) +void +bitset_index_dump(struct bitset_index *index, int verbose, FILE *stream); +#endif /* defined(DEBUG) */ + +#endif /* TARANTOOL_LIB_BITSET_INDEX_H_INCLUDED */ diff --git a/src/lib/bitset/CMakeLists.txt b/src/lib/bitset/CMakeLists.txt index 0b1316d002..1339a02efa 100644 --- a/src/lib/bitset/CMakeLists.txt +++ b/src/lib/bitset/CMakeLists.txt @@ -3,6 +3,7 @@ set(lib_sources page.c expr.c iterator.c + index.c ) set_source_files_compile_flags(${lib_sources}) diff --git a/src/lib/bitset/index.c b/src/lib/bitset/index.c new file mode 100644 index 0000000000..e8a408c4c6 --- /dev/null +++ b/src/lib/bitset/index.c @@ -0,0 +1,323 @@ +/* + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <lib/bitset/index.h> +#include <lib/bitset/expr.h> +#include <lib/bit/bit.h> + +#include <string.h> +#include <assert.h> + +const size_t INDEX_DEFAULT_CAPACITY = 32; + +static int +bitset_index_reserve(struct bitset_index *index, size_t size); + +int +bitset_index_create(struct bitset_index *index, + void *(*realloc)(void *ptr, size_t size)) +{ + assert (index != NULL); + memset(index, 0, sizeof(*index)); + index->realloc = realloc; + if (bitset_index_reserve(index, 1) != 0) + return -1; + + return 0; +} + +void +bitset_index_destroy(struct bitset_index *index) +{ + assert (index != NULL); + assert (index->capacity > 0); + + for (size_t b = 0; b < index->capacity; b++) { + if (index->bitsets[b] == NULL) + break; + + bitset_destroy(index->bitsets[b]); + index->realloc(index->bitsets[b], 0); + index->bitsets[b] = NULL; + } + if (index->capacity > 0) { + index->realloc(index->bitsets, 0); + } + + memset(index, 0, sizeof(*index)); +} + +static int +bitset_index_reserve(struct bitset_index *index, size_t size) +{ + if (size <= index->capacity) + return 0; + + size_t capacity = (index->capacity > 0) + ? index->capacity + : INDEX_DEFAULT_CAPACITY; + + while (capacity <= size) { + capacity *= 2; + } + + struct bitset **bitsets = index->realloc(index->bitsets, + capacity * sizeof(*index->bitsets)); + if (bitsets == NULL) + goto error_1; + + memset(bitsets + index->capacity, 0, + (capacity - index->capacity) * sizeof(*index->bitsets)); + + /* Save bitset ** but do not update index->capacity */ + index->bitsets = bitsets; + + for (size_t b = index->capacity; b < capacity; b++) { + index->bitsets[b] = index->realloc(NULL, + sizeof(*index->bitsets[b])); + if (index->bitsets[b] == NULL) + goto error_2; + + bitset_create(index->bitsets[b], index->realloc); + } + + index->capacity = capacity; + + return 0; + +error_2: + for (size_t b = index->capacity; b < capacity; b++) { + if (index->bitsets[b] == NULL) + break; + + bitset_destroy(index->bitsets[b]); + index->realloc(index->bitsets[b], 0); + index->bitsets[b] = NULL; + } +error_1: + return -1; +} + +int +bitset_index_insert(struct bitset_index *index, const void *key, + size_t key_size, size_t value) +{ + assert (index != NULL); + assert (key != NULL); + assert (index->capacity > 0); + + const size_t size = 1 + key_size * CHAR_BIT; + if (bitset_index_reserve(index, size) != 0) + return -1; + + struct bit_iterator bit_it; + bit_iterator_init(&bit_it, key, key_size, true); + size_t pos; + while ( (pos = bit_iterator_next(&bit_it)) != SIZE_MAX) { + size_t b = pos + 1; + if (bitset_set(index->bitsets[b], value) < 0) + goto rollback; + } + + if (bitset_set(index->bitsets[0], value) < 0) + goto rollback; + + return 0; + + /* TODO: partial rollback is not work properly here */ +rollback: + /* Rollback changes */ + bit_iterator_init(&bit_it, key, size, true); + while ( (pos = bit_iterator_next(&bit_it)) != SIZE_MAX) { + size_t b = pos + 1; + if (index->bitsets[b] == NULL) + continue; + + bitset_clear(index->bitsets[b], value); + } + + bitset_clear(index->bitsets[0], value); + + return -1; +} + +void +bitset_index_remove_value(struct bitset_index *index, size_t value) +{ + assert(index != NULL); + + if (index->capacity == 0) + return; + + for (size_t b = 1; b < index->capacity; b++) { + if (index->bitsets[b] == NULL) + continue; + + /* Ignore all errors here */ + bitset_clear(index->bitsets[b], value); + } + bitset_clear(index->bitsets[0], value); +} + +bool +bitset_index_contains_value(struct bitset_index *index, size_t value) +{ + assert(index != NULL); + + return bitset_test(index->bitsets[0], value); +} + +int +bitset_index_expr_all(struct bitset_expr *expr) +{ + (void) index; + + bitset_expr_clear(expr); + if (bitset_expr_add_conj(expr) != 0) + return -1; + + if (bitset_expr_add_param(expr, 0, false) != 0) + return -1; + + return 0; +} + +int +bitset_index_expr_equals(struct bitset_expr *expr, const void *key, + size_t key_size) +{ + bitset_expr_clear(expr); + + if (bitset_expr_add_conj(expr) != 0) + return -1; + + for (size_t pos = 0; pos < key_size * CHAR_BIT; pos++) { + size_t b = pos + 1; + bool bit_exist = bit_test(key, pos); + if (bitset_expr_add_param(expr, b, !bit_exist) != 0) + return -1; + } + + if (bitset_expr_add_param(expr, 0, false) != 0) { + return -1; + } + + return 0; +} + +int +bitset_index_expr_all_set(struct bitset_expr *expr, const void *key, + size_t key_size) +{ + bitset_expr_clear(expr); + + if (bitset_expr_add_conj(expr) != 0) + return -1; + + struct bit_iterator bit_it; + bit_iterator_init(&bit_it, key, key_size, true); + size_t pos; + while ( (pos = bit_iterator_next(&bit_it)) != SIZE_MAX ) { + size_t b = pos + 1; + if (bitset_expr_add_param(expr, b, false) != 0) + return -1; + } + + return 0; +} + +int +bitset_index_expr_any_set(struct bitset_expr *expr, const void *key, + size_t key_size) +{ + bitset_expr_clear(expr); + + struct bit_iterator bit_it; + bit_iterator_init(&bit_it, key, key_size, true); + size_t pos; + while ( (pos = bit_iterator_next(&bit_it)) != SIZE_MAX) { + size_t b = pos + 1; + if (bitset_expr_add_conj(expr) != 0) + return -1; + if (bitset_expr_add_param(expr, b, false) != 0) + return -1; + } + + return 0; +} + +int +bitset_index_expr_all_not_set(struct bitset_expr *expr, const void *key, + size_t key_size) { + bitset_expr_clear(expr); + + if (bitset_expr_add_conj(expr) != 0) + return -1; + + if (bitset_expr_add_param(expr, 0, false) != 0) + return -1; + + struct bit_iterator bit_it; + bit_iterator_init(&bit_it, key, key_size, true); + size_t pos; + while ( (pos = bit_iterator_next(&bit_it)) != SIZE_MAX) { + size_t b = pos + 1; + if (bitset_expr_add_param(expr, b, true) != 0) + return -1; + } + + return 0; +} + +int +bitset_index_init_iterator(struct bitset_index *index, + struct bitset_iterator *it, struct bitset_expr *expr) +{ + assert (index != NULL); + assert (it != NULL); + + /* Check that we have all required bitsets */ + size_t max = 0; + for (size_t c = 0; c < expr->size; c++) { + for (size_t b = 0; b < expr->conjs[c].size; b++) { + if (expr->conjs[c].bitset_ids[b] > max) { + max = expr->conjs[c].bitset_ids[b]; + } + } + } + + /* Resize the index with empty bitsets */ + if (bitset_index_reserve(index, max + 1) != 0) + return -1; + + return bitset_iterator_init(it, expr, index->bitsets, index->capacity); +} + +extern inline size_t +bitset_index_size(struct bitset_index *index); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 1fa92bbdb0..a2afb4259e 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -14,6 +14,8 @@ add_executable(bitset_basic_test bitset_basic.c) target_link_libraries(bitset_basic_test bitset) add_executable(bitset_iterator_test bitset_iterator.c) target_link_libraries(bitset_iterator_test bitset) +add_executable(bitset_index_test bitset_index.c) +target_link_libraries(bitset_index_test bitset) add_executable(objc_finally objc_finally.m) add_executable(objc_catchcxx objc_catchcxx.m) diff --git a/test/unit/bitset_index.c b/test/unit/bitset_index.c new file mode 100644 index 0000000000..d39fd22521 --- /dev/null +++ b/test/unit/bitset_index.c @@ -0,0 +1,287 @@ +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <limits.h> + +#include <lib/bitset/index.h> +#include "unit.h" + +enum { NUMS_SIZE = 1 << 16 }; + +static +void test_resize(void) +{ + header(); + + struct bitset_index index; + fail_unless(bitset_index_create(&index, realloc) == 0); + struct bitset_iterator it; + bitset_iterator_create(&it, realloc); + struct bitset_expr expr; + bitset_expr_create(&expr, realloc); + + size_t key = 23411111; + size_t value = 2321321; + + bitset_index_insert(&index, &key, sizeof(key), value); + + fail_unless(bitset_index_expr_equals(&expr, &key, sizeof(key)) == 0); + + fail_unless(bitset_index_init_iterator(&index, &it, &expr) == 0); + fail_unless(bitset_iterator_next(&it) == value); + fail_unless(bitset_iterator_next(&it) == SIZE_MAX); + + bitset_expr_destroy(&expr); + bitset_iterator_destroy(&it); + bitset_index_destroy(&index); + + footer(); +} + +static +void test_get_size(void) +{ + header(); + + struct bitset_index index; + fail_unless(bitset_index_create(&index, realloc) == 0); + + const size_t SET_SIZE = 1 << 10; + size_t key = 656906; + for(size_t i = 0; i < SET_SIZE; i++) { + bitset_index_insert(&index, &key, sizeof(key), i); + } + + fail_unless(bitset_index_size(&index) == SET_SIZE); + + bitset_index_destroy(&index); + + footer(); +} + +static +void check_keys(struct bitset_index *index, + size_t *keys, size_t *values, size_t size) +{ + struct bitset_iterator it; + bitset_iterator_create(&it, realloc); + struct bitset_expr expr; + bitset_expr_create(&expr, realloc); + + printf("Checking keys... "); + for (size_t i = 0; i < size; i++) { + /* ignore removed keys */ + if (keys[i] == SIZE_MAX) { + continue; + } + + fail_unless(bitset_index_expr_equals(&expr, &keys[i], + sizeof(keys[i])) == 0); + + fail_unless(bitset_index_init_iterator(index, &it, &expr) == 0); + + size_t pos; + + bool pair_found = false; + while ( (pos = bitset_iterator_next(&it)) != SIZE_MAX) { + if (pos == values[i]) { + pair_found = true; + break; + } + } + fail_unless(pair_found); + } + printf("ok\n"); + + bitset_iterator_destroy(&it); + bitset_expr_destroy(&expr); +} + +static +void test_insert_remove(void) +{ + header(); + + struct bitset_index index; + fail_unless(bitset_index_create(&index, realloc) == 0); + + size_t NUMS_SIZE = 1 << 11; + size_t *keys = malloc(NUMS_SIZE * sizeof(size_t)); + size_t *values = malloc(NUMS_SIZE * sizeof(size_t)); + + printf("Generating test set... "); + for(size_t i = 0; i < NUMS_SIZE; i++) { + keys[i] = rand(); + values[i] = rand(); + } + printf("ok\n"); + + printf("Inserting pairs... "); + for(size_t i = 0; i < NUMS_SIZE; i++) { + bitset_index_insert(&index, &keys[i], sizeof(keys[i]), + values[i]); + + } + printf("ok\n"); + + check_keys(&index, keys, values, NUMS_SIZE); + + printf("Removing random pairs... "); + for(size_t i = 0; i < NUMS_SIZE; i++) { + if (rand() % 5 == 0) { + bitset_index_remove_value(&index, values[i]); + keys[i] = SIZE_MAX; + } + } + printf("ok\n"); + + check_keys(&index, keys, values, NUMS_SIZE); + + bitset_index_destroy(&index); + + free(keys); + free(values); + + footer(); +} + + +static +void test_simple(int mode, size_t search_mask) +{ + fail_unless(mode >= 0 && mode < 3); + + struct bitset_index index; + fail_unless(bitset_index_create(&index, realloc) == 0); + struct bitset_iterator it; + bitset_iterator_create(&it, realloc); + struct bitset_expr expr; + bitset_expr_create(&expr, realloc); + + size_t check_count = 0; + for (size_t key = 0; key < NUMS_SIZE; key++) { + bitset_index_insert(&index, &key, sizeof(key), key); + if (mode == 0) { + check_count++; + } else if (mode == 1 && (key & search_mask) == search_mask) { + check_count++; + } else if (mode == 2 && (key & search_mask) != 0) { + check_count++; + } + } + + if (mode == 0) { + fail_unless(bitset_index_expr_all(&expr) == 0); + } else if (mode == 1) { + fail_unless(bitset_index_expr_all_set(&expr, + &search_mask, sizeof(search_mask)) == 0); + } else if (mode == 2) { + fail_unless(bitset_index_expr_any_set(&expr, + &search_mask, sizeof(search_mask)) == 0); + } + fail_unless(bitset_index_init_iterator(&index, &it, &expr) == 0); + + size_t found_count = 0; + for (size_t key = 0; key < NUMS_SIZE; key++) { + size_t r = bitset_iterator_next(&it); + if (mode == 0) { + fail_unless(key == r); + found_count++; + } else if (mode == 1 && (key & search_mask) == search_mask) { + found_count++; + } else if (mode == 2 && (key & search_mask) != 0){ + found_count++; + } + } + fail_unless(bitset_iterator_next(&it) == SIZE_MAX); + fail_unless(found_count == check_count); + + bitset_expr_destroy(&expr); + bitset_iterator_destroy(&it); + bitset_index_destroy(&index); +} + +static void +test_empty_simple(void) +{ + header(); + test_simple(1, 0); /* empty result */ + footer(); +} + +static void +test_all_simple(void) +{ + header(); + test_simple(0, 0); /* all */ + footer(); +} + +static void +test_all_set_simple(void) +{ + header(); + size_t search_mask = 66; /* 0b1000010 */ + test_simple(1, search_mask); /* all bits set */ + footer(); +} + +static void +test_any_set_simple(void) +{ + header(); + size_t search_mask = 66; /* 0b1000010 */ + test_simple(2, search_mask); /* any bits set */ + footer(); +} + +static +void test_equals_simple(void) +{ + header(); + + struct bitset_index index; + fail_unless(bitset_index_create(&index, realloc) == 0); + struct bitset_iterator it; + bitset_iterator_create(&it, realloc); + struct bitset_expr expr; + bitset_expr_create(&expr, realloc); + + size_t mask = ~((size_t ) 7); + for (size_t i = 0; i < NUMS_SIZE; i++) { + size_t key = i & mask; + size_t value = i; + bitset_index_insert(&index, &key, sizeof(key), value); + } + + size_t key1 = (rand() % NUMS_SIZE) & mask; + fail_unless(bitset_index_expr_equals(&expr, &key1, sizeof(key1)) == 0); + fail_unless(bitset_index_init_iterator(&index, &it, &expr) == 0); + + for (size_t i = key1; i <= (key1 + ~mask); i++) { + fail_unless(i == bitset_iterator_next(&it)); + } + fail_unless(bitset_iterator_next(&it) == SIZE_MAX); + + bitset_expr_destroy(&expr); + bitset_iterator_destroy(&it); + bitset_index_destroy(&index); + + footer(); +} + +int main(void) +{ + setbuf(stdout, NULL); + + test_get_size(); + test_resize(); + test_insert_remove(); + test_empty_simple(); + test_all_simple(); + test_all_set_simple(); + test_any_set_simple(); + test_equals_simple(); + + return 0; +} diff --git a/test/unit/bitset_index.result b/test/unit/bitset_index.result new file mode 100644 index 0000000000..35bdc6231b --- /dev/null +++ b/test/unit/bitset_index.result @@ -0,0 +1,22 @@ + *** test_get_size *** + *** test_get_size: done *** + *** test_resize *** + *** test_resize: done *** + *** test_insert_remove *** +Generating test set... ok +Inserting pairs... ok +Checking keys... ok +Removing random pairs... ok +Checking keys... ok + *** test_insert_remove: done *** + *** test_empty_simple *** + *** test_empty_simple: done *** + *** test_all_simple *** + *** test_all_simple: done *** + *** test_all_set_simple *** + *** test_all_set_simple: done *** + *** test_any_set_simple *** + *** test_any_set_simple: done *** + *** test_equals_simple *** + *** test_equals_simple: done *** + \ No newline at end of file diff --git a/test/unit/bitset_index.test b/test/unit/bitset_index.test new file mode 100644 index 0000000000..a7d9a5ec93 --- /dev/null +++ b/test/unit/bitset_index.test @@ -0,0 +1 @@ +run_test("bitset_index_test") -- GitLab