diff --git a/.github/workflows/test_suit.yml b/.github/workflows/test_suit.yml index 9be60d5..b7c43f7 100644 --- a/.github/workflows/test_suit.yml +++ b/.github/workflows/test_suit.yml @@ -17,7 +17,7 @@ jobs: make --version \ valgrind --version \ - name: Test Suite - run: make tests + run: make tests --always-make - name: Upload Coverage uses: codecov/codecov-action@v3 with: diff --git a/benchmarks/comparisons/hashtable/Makefile b/benchmarks/comparisons/hashtable/Makefile index 7fbe732..38cf60e 100644 --- a/benchmarks/comparisons/hashtable/Makefile +++ b/benchmarks/comparisons/hashtable/Makefile @@ -1,5 +1,5 @@ INCLUDE=-I ../../../src -CFLAGS=-O3 -Wall -DCOUNT=20000000 -DCMC_NO_CALLBACKS +CFLAGS=-O3 -Wall -Wextra -Werror -DCOUNT=20000000 -DCMC_NO_CALLBACKS # Install hyperfine # https://github.com/sharkdp/hyperfine diff --git a/src/cmc/cmc/hashmap/ext/struct.h b/src/cmc/cmc/hashmap/ext/struct.h index d55996b..926b225 100644 --- a/src/cmc/cmc/hashmap/ext/struct.h +++ b/src/cmc/cmc/hashmap/ext/struct.h @@ -25,7 +25,7 @@ /** * ITER * - * List bi-directional iterator. + * Hashmap bi-directional iterator. */ #ifdef CMC_EXT_HASHMAP_ITER diff --git a/src/cmc/cmc/hashmultiset/code.h b/src/cmc/cmc/hashmultiset/code.h new file mode 100644 index 0000000..db50f0f --- /dev/null +++ b/src/cmc/cmc/hashmultiset/code.h @@ -0,0 +1,728 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Implementation Detail Functions */ +static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value); +static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node); +static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value); +static size_t CMC_(PFX, _impl_calculate_size)(size_t required); + +struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val) +{ + return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL); +} + +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (capacity == 0 || load <= 0 || load >= 1) + return NULL; + + /* Prevent integer overflow */ + if (capacity >= UINTMAX_MAX * load) + return NULL; + + if (!f_val) + return NULL; + + size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load); + + if (!alloc) + alloc = &cmc_alloc_node_default; + + struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); + + if (!_set_) + return NULL; + + _set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME))); + + if (!_set_->buffer) + { + alloc->free(_set_); + return NULL; + } + + _set_->count = 0; + _set_->cardinality = 0; + _set_->capacity = real_capacity; + _set_->load = load; + _set_->flag = CMC_FLAG_OK; + _set_->f_val = f_val; + _set_->alloc = alloc; + CMC_CALLBACKS_ASSIGN(_set_, callbacks); + + return _set_; +} + +void CMC_(PFX, _clear)(struct SNAME *_set_) +{ + if (_set_->f_val->free) + { + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]); + + if (entry->state == CMC_ES_FILLED) + { + _set_->f_val->free(entry->value); + } + } + } + + memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity); + + _set_->count = 0; + _set_->flag = CMC_FLAG_OK; +} + +void CMC_(PFX, _free)(struct SNAME *_set_) +{ + if (_set_->f_val->free) + { + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]); + + if (entry->state == CMC_ES_FILLED) + { + _set_->f_val->free(entry->value); + } + } + } + + _set_->alloc->free(_set_->buffer); + _set_->alloc->free(_set_); +} + +void CMC_(PFX, _customize)(struct SNAME *_set_, struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (!alloc) + _set_->alloc = &cmc_alloc_node_default; + else + _set_->alloc = alloc; + + CMC_CALLBACKS_ASSIGN(_set_, callbacks); + + _set_->flag = CMC_FLAG_OK; +} + +bool CMC_(PFX, _insert)(struct SNAME *_set_, V value) +{ + bool new_node; + + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node); + + if (!entry) + { + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + if (!new_node) + entry->multiplicity++; + + _set_->cardinality++; + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, create); + + return true; +} + +bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count) +{ + if (count == 0) + goto success; + + bool new_node; + + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node); + + if (!entry) + { + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + if (new_node) + entry->multiplicity = count; + else + entry->multiplicity += count; + + _set_->cardinality += count; + +success: + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, create); + + return true; +} + +bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity) +{ + if (multiplicity == 0) + { + /* Effectively delete the entry */ + struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value); + + if (!result) + /* If no entry was found then its multiplicity is already 0 */ + goto success; + + _set_->count--; + _set_->cardinality -= result->multiplicity; + + result->value = (V){ 0 }; + result->multiplicity = 0; + result->dist = 0; + result->state = CMC_ES_DELETED; + + goto success; + } + + bool new_node; + + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_set_, value, &new_node); + + if (!entry) + return false; + + if (new_node) + _set_->cardinality++; + + _set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity; + + entry->multiplicity = multiplicity; + +success: + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, update); + + return true; +} + +bool CMC_(PFX, _remove)(struct SNAME *_set_, V value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value); + + if (!result) + { + _set_->flag = CMC_FLAG_NOT_FOUND; + return false; + } + + if (result->multiplicity > 1) + result->multiplicity--; + else + { + result->value = (V){ 0 }; + result->multiplicity = 0; + result->dist = 0; + result->state = CMC_ES_DELETED; + + _set_->count--; + } + + _set_->cardinality--; + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, delete); + + return true; +} + +size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value); + + if (!result) + { + _set_->flag = CMC_FLAG_NOT_FOUND; + return 0; + } + + size_t removed = result->multiplicity; + + result->value = (V){ 0 }; + result->multiplicity = 0; + result->dist = 0; + result->state = CMC_ES_DELETED; + + _set_->count--; + _set_->cardinality -= removed; + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, delete); + + return removed; +} + +bool CMC_(PFX, _max)(struct SNAME *_set_, V *value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + bool first = true; + V max_val = (V){ 0 }; + + for (size_t i = 0; i < _set_->capacity; i++) + { + if (_set_->buffer[i].state == CMC_ES_FILLED) + { + if (first) + { + max_val = _set_->buffer[i].value; + first = false; + } + else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0) + { + max_val = _set_->buffer[i].value; + } + } + } + + if (value) + *value = max_val; + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, read); + + return true; +} + +bool CMC_(PFX, _min)(struct SNAME *_set_, V *value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + bool first = true; + V min_val = (V){ 0 }; + + for (size_t i = 0; i < _set_->capacity; i++) + { + if (_set_->buffer[i].state == CMC_ES_FILLED) + { + if (first) + { + min_val = _set_->buffer[i].value; + first = false; + } + else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0) + { + min_val = _set_->buffer[i].value; + } + } + } + + if (value) + *value = min_val; + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, read); + + return true; +} + +size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value) +{ + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value); + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, read); + + if (!entry) + return 0; + + return entry->multiplicity; +} + +bool CMC_(PFX, _contains)(struct SNAME *_set_, V value) +{ + _set_->flag = CMC_FLAG_OK; + + bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL; + + CMC_CALLBACKS_CALL(_set_, read); + + return result; +} + +bool CMC_(PFX, _empty)(struct SNAME *_set_) +{ + return _set_->count == 0; +} + +bool CMC_(PFX, _full)(struct SNAME *_set_) +{ + return (double)_set_->capacity * _set_->load <= (double)_set_->count; +} + +size_t CMC_(PFX, _count)(struct SNAME *_set_) +{ + return _set_->count; +} + +size_t CMC_(PFX, _cardinality)(struct SNAME *_set_) +{ + return _set_->cardinality; +} + +size_t CMC_(PFX, _capacity)(struct SNAME *_set_) +{ + return _set_->capacity; +} + +double CMC_(PFX, _load)(struct SNAME *_set_) +{ + return _set_->load; +} + +int CMC_(PFX, _flag)(struct SNAME *_set_) +{ + return _set_->flag; +} + +bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity) +{ + _set_->flag = CMC_FLAG_OK; + + if (_set_->capacity == capacity) + goto success; + + if (_set_->capacity > capacity / _set_->load) + goto success; + + /* Prevent integer overflow */ + if (capacity >= UINTMAX_MAX * _set_->load) + { + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + /* Calculate required capacity based on the prime numbers */ + size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity); + + /* Not possible to shrink with current available prime numbers */ + if (theoretical_size < _set_->count / _set_->load) + { + _set_->flag = CMC_FLAG_INVALID; + return false; + } + + /* No callbacks since _new_set_ is just a temporary hashtable */ + struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL); + + if (!_new_set_) + { + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + for (size_t i = 0; i < _set_->capacity; i++) + { + if (_set_->buffer[i].state == CMC_ES_FILLED) + { + V value = _set_->buffer[i].value; + size_t multiplicity = _set_->buffer[i].multiplicity; + + /* TODO check this for possible errors where entry == NULL */ + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_insert_and_return)(_new_set_, value, NULL); + + entry->multiplicity = multiplicity; + /* Setting cardinality not required, _new_set_ is temporary */ + } + } + + if (_set_->count != _new_set_->count) + { + CMC_(PFX, _free)(_new_set_); + + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer; + _set_->buffer = _new_set_->buffer; + _new_set_->buffer = tmp_b; + + size_t tmp_c = _set_->capacity; + _set_->capacity = _new_set_->capacity; + _new_set_->capacity = tmp_c; + + /* Prevent the set from freeing the data */ + _new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ NULL }; + + CMC_(PFX, _free)(_new_set_); + +success: + + CMC_CALLBACKS_CALL(_set_, resize); + + return true; +} + +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_) +{ + struct SNAME *result = + CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL); + + if (!result) + { + _set_->flag = CMC_FLAG_ERROR; + return NULL; + } + + CMC_CALLBACKS_ASSIGN(result, _set_->callbacks); + + if (_set_->f_val->cpy) + { + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]); + + if (scan->state != CMC_ES_EMPTY) + { + struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]); + + if (scan->state == CMC_ES_DELETED) + target->state = CMC_ES_DELETED; + else + { + target->state = scan->state; + target->dist = scan->dist; + target->multiplicity = scan->multiplicity; + + target->value = _set_->f_val->cpy(scan->value); + } + } + } + } + else + memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity); + + result->count = _set_->count; + result->cardinality = _set_->cardinality; + + _set_->flag = CMC_FLAG_OK; + + return result; +} + +bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + _set1_->flag = CMC_FLAG_OK; + _set2_->flag = CMC_FLAG_OK; + + if (_set1_->count != _set2_->count) + return false; + + if (_set1_->cardinality != _set2_->cardinality) + return false; + + if (_set1_->count == 0) + return true; + + /* Optimize loop using the smallest hashtable */ + struct SNAME *_set_a_; + struct SNAME *_set_b_; + + _set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_; + _set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_; + + for (size_t i = 0; i < _set_a_->capacity; i++) + { + if (_set_a_->buffer[i].state == CMC_ES_FILLED) + { + struct CMC_DEF_ENTRY(SNAME) *entry_a = &(_set_a_->buffer[i]); + struct CMC_DEF_ENTRY(SNAME) *entry_b = CMC_(PFX, _impl_get_entry)(_set_b_, entry_a->value); + + if (!entry_b) + return false; + + if (entry_a->multiplicity != entry_b->multiplicity) + return false; + } + } + + return true; +} + +static size_t CMC_(PFX, _impl_multiplicity_of)(struct SNAME *_set_, V value) +{ + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value); + + if (!entry) + return 0; + + return entry->multiplicity; +} + +static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_insert_and_return)(struct SNAME *_set_, V value, bool *new_node) +{ + /* If the entry already exists simply return it as we might do */ + /* something with it. This function only guarantees that there is */ + /* a valid entry for a given value */ + + if (new_node) + *new_node = false; + + struct CMC_DEF_ENTRY(SNAME) *entry = CMC_(PFX, _impl_get_entry)(_set_, value); + + if (entry != NULL) + return entry; + + if (new_node) + *new_node = true; + + if (CMC_(PFX, _full)(_set_)) + { + if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1)) + return NULL; + } + + size_t hash = _set_->f_val->hash(value); + size_t original_pos = hash % _set_->capacity; + size_t pos = original_pos; + /* Current multiplicity. Might change due to robin hood hashing */ + size_t curr_mul = 1; + + struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]); + struct CMC_DEF_ENTRY(SNAME) *to_return = NULL; + + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) + { + target->value = value; + target->multiplicity = curr_mul; + target->dist = pos - original_pos; + target->state = CMC_ES_FILLED; + + to_return = target; + } + else + { + while (true) + { + pos++; + target = &(_set_->buffer[pos % _set_->capacity]); + + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) + { + target->value = value; + target->multiplicity = curr_mul; + target->dist = pos - original_pos; + target->state = CMC_ES_FILLED; + + if (!to_return) + to_return = target; + + break; + } + else if (target->dist < pos - original_pos) + { + /* Swap everything */ + V tmp = target->value; + size_t tmp_dist = target->dist; + size_t tmp_mul = target->multiplicity; + + target->value = value; + target->dist = pos - original_pos; + target->multiplicity = curr_mul; + + value = tmp; + original_pos = pos - tmp_dist; + curr_mul = tmp_mul; + + if (!to_return) + to_return = target; + } + } + } + + _set_->count++; + + return to_return; +} + +static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value) +{ + size_t hash = _set_->f_val->hash(value); + size_t pos = hash % _set_->capacity; + + struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]); + + while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED) + { + if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0) + return target; + + pos++; + target = &(_set_->buffer[pos % _set_->capacity]); + } + + return NULL; +} + +static size_t CMC_(PFX, _impl_calculate_size)(size_t required) +{ + const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); + + if (cmc_hashtable_primes[count - 1] < required) + return required; + + size_t i = 0; + while (cmc_hashtable_primes[i] < required) + i++; + + return cmc_hashtable_primes[i]; +} diff --git a/src/cmc/cmc/hashmultiset/ext/code.h b/src/cmc/cmc/hashmultiset/ext/code.h new file mode 100644 index 0000000..4016523 --- /dev/null +++ b/src/cmc/cmc/hashmultiset/ext/code.h @@ -0,0 +1,621 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_HASHMULTISET_INIT + +#endif /* CMC_EXT_HASHMULTISET_INIT */ + +/** + * ITER + * + * List bi-directional iterator. + */ +#ifdef CMC_EXT_HASHMULTISET_ITER + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = true; + iter.end = CMC_(PFX, _empty)(target); + + if (!CMC_(PFX, _empty)(target)) + { + for (size_t i = 0; i < target->capacity; i++) + { + if (target->buffer[i].state == CMC_ES_FILLED) + { + iter.first = i; + break; + } + } + + iter.cursor = iter.first; + + for (size_t i = target->capacity; i > 0; i--) + { + if (target->buffer[i - 1].state == CMC_ES_FILLED) + { + iter.last = i - 1; + break; + } + } + } + + return iter; +} + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = CMC_(PFX, _empty)(target); + iter.end = true; + + if (!CMC_(PFX, _empty)(target)) + { + for (size_t i = 0; i < target->capacity; i++) + { + if (target->buffer[i].state == CMC_ES_FILLED) + { + iter.first = i; + break; + } + } + + for (size_t i = target->capacity; i > 0; i--) + { + if (target->buffer[i - 1].state == CMC_ES_FILLED) + { + iter.last = i - 1; + break; + } + } + + iter.cursor = iter.last; + iter.index = target->count - 1; + } + + return iter; +} + +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->start; +} + +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->end; +} + +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = iter->first; + iter->index = 0; + iter->start = true; + iter->end = CMC_(PFX, _empty)(iter->target); + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = iter->last; + iter->index = iter->target->count - 1; + iter->start = CMC_(PFX, _empty)(iter->target); + iter->end = true; + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->end) + return false; + + if (iter->index + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + iter->start = CMC_(PFX, _empty)(iter->target); + + struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]); + + iter->index++; + + while (1) + { + iter->cursor++; + scan = &(iter->target->buffer[iter->cursor]); + + if (scan->state == CMC_ES_FILLED) + break; + } + + return true; +} + +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->start) + return false; + + if (iter->index == 0) + { + iter->start = true; + return false; + } + + iter->end = CMC_(PFX, _empty)(iter->target); + + struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]); + + iter->index--; + + while (1) + { + iter->cursor--; + scan = &(iter->target->buffer[iter->cursor]); + + if (scan->state == CMC_ES_FILLED) + break; + } + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->end) + return false; + + if (iter->index + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + if (steps == 0 || iter->index + steps >= iter->target->count) + return false; + + for (size_t i = 0; i < steps; i++) + CMC_(PFX, _iter_next)(iter); + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->start) + return false; + + if (iter->index == 0) + { + iter->start = true; + return false; + } + + if (steps == 0 || iter->index < steps) + return false; + + for (size_t i = 0; i < steps; i++) + CMC_(PFX, _iter_prev)(iter); + + return true; +} + +/* Returns true only if the iterator was able to be positioned at the */ +/* given index */ +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index) +{ + if (index >= iter->target->count) + return false; + + if (iter->index > index) + return CMC_(PFX, _iter_rewind)(iter, iter->index - index); + else if (iter->index < index) + return CMC_(PFX, _iter_advance)(iter, index - iter->index); + + return true; +} + +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (CMC_(PFX, _empty)(iter->target)) + return (V){ 0 }; + + return iter->target->buffer[iter->cursor].value; +} + +size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (CMC_(PFX, _empty)(iter->target)) + return 0; + + return iter->target->buffer[iter->cursor].multiplicity; +} + +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return iter->index; +} + +#endif /* CMC_EXT_HASHMULTISET_ITER */ + +/** + * SETF + * + * Set functions + */ +#ifdef CMC_EXT_HASHMULTISET_SETF + +struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + return NULL; + + struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_); + struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_); + + for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1)) + { + V value = CMC_(PFX, _iter_value)(&iter1); + + size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1); + size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value); + size_t max_ = m1 > m2 ? m1 : m2; + + CMC_(PFX, _update)(_set_r_, value, max_); + } + + for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2)) + { + V value = CMC_(PFX, _iter_value)(&iter2); + + size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value); + size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2); + size_t max_ = m1 > m2 ? m1 : m2; + + CMC_(PFX, _update)(_set_r_, value, max_); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + return NULL; + + struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; + struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter); + size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set_B_, value); + size_t max_ = m1 < m2 ? m1 : m2; + + CMC_(PFX, _update)(_set_r_, value, max_); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + return NULL; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter); + size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value); + + if (m1 > m2) + CMC_(PFX, _update)(_set_r_, value, m1 - m2); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + return NULL; + + struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_); + struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_); + + for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1)) + { + CMC_(PFX, _insert_many) + (_set_r_, CMC_(PFX, _iter_value)(&iter1), CMC_(PFX, _iter_multiplicity)(&iter1)); + } + + for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2)) + { + CMC_(PFX, _insert_many) + (_set_r_, CMC_(PFX, _iter_value)(&iter2), CMC_(PFX, _iter_multiplicity)(&iter2)); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + return NULL; + struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_); + struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_); + + for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1)) + { + V value = CMC_(PFX, _iter_value)(&iter1); + + size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter1); + size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value); + + if (m1 != m2) + { + if (m1 > m2) + CMC_(PFX, _update)(_set_r_, value, m1 - m2); + else + CMC_(PFX, _update)(_set_r_, value, m2 - m1); + } + } + + for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2)) + { + V value = CMC_(PFX, _iter_value)(&iter2); + + size_t m1 = CMC_(PFX, _impl_multiplicity_of)(_set1_, value); + size_t m2 = CMC_(PFX, _iter_multiplicity)(&iter2); + + if (m1 != m2) + { + if (m1 > m2) + CMC_(PFX, _update)(_set_r_, value, m1 - m2); + else + CMC_(PFX, _update)(_set_r_, value, m2 - m1); + } + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + if (_set1_->count > _set2_->count) + return false; + + if (CMC_(PFX, _empty)(_set1_)) + return true; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter); + size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value); + + if (m1 > m2) + return false; + } + + return true; +} + +bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + return CMC_(PFX, _is_subset)(_set2_, _set1_); +} + +bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + if (_set1_->count >= _set2_->count) + return false; + + if (CMC_(PFX, _empty)(_set1_)) + { + if (!CMC_(PFX, _empty)(_set2_)) + return true; + else + return false; + } + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + size_t m1 = CMC_(PFX, _iter_multiplicity)(&iter); + size_t m2 = CMC_(PFX, _impl_multiplicity_of)(_set2_, value); + + if (m1 >= m2) + return false; + } + + return true; +} + +bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + return CMC_(PFX, _is_proper_subset)(_set2_, _set1_); +} + +bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + if (CMC_(PFX, _empty)(_set1_)) + return true; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL) + return false; + } + + return true; +} + +#endif /* CMC_EXT_HASHMULTISET_SETF */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_HASHMULTISET_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr) +{ + struct SNAME *s_ = _set_; + + return 0 <= fprintf(fptr, + "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "cardinality:%" PRIuMAX ", " + "load:%lf, " + "flag:%d, " + "f_val:%p, " + "alloc:%p, " + "callbacks:%p }", + CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count, + s_->cardinality, s_->load, s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_)); +} + +bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end, + const char *val_mul_sep) +{ + fprintf(fptr, "%s", start); + + size_t last = 0; + for (size_t i = _set_->capacity; i > 0; i--) + { + if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED) + { + last = i - 1; + break; + } + } + + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]); + + if (entry->state == CMC_ES_FILLED) + { + if (!_set_->f_val->str(fptr, entry->value)) + return false; + + fprintf(fptr, "%s", val_mul_sep); + + if (fprintf(fptr, "%" PRIuMAX "", entry->multiplicity) < 0) + return false; + + if (i + 1 < last) + fprintf(fptr, "%s", separator); + } + } + + fprintf(fptr, "%s", end); + + return true; +} + +#endif /* CMC_EXT_HASHMULTISET_STR */ diff --git a/src/cmc/cmc/hashmultiset/ext/header.h b/src/cmc/cmc/hashmultiset/ext/header.h new file mode 100644 index 0000000..82670c8 --- /dev/null +++ b/src/cmc/cmc/hashmultiset/ext/header.h @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_HASHMULTISET_INIT + +#endif /* CMC_EXT_HASHMULTISET_INIT */ + +/** + * ITER + * + * List bi-directional iterator. + */ +#ifdef CMC_EXT_HASHMULTISET_ITER + +/* Iterator Initialization */ +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target); +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target); +/* Iterator State */ +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter); +/* Iterator Movement */ +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index); +/* Iterator Access */ +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter); +size_t CMC_(PFX, _iter_multiplicity)(struct CMC_DEF_ITER(SNAME) * iter); +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter); + +#endif /* CMC_EXT_HASHMULTISET_ITER */ + +/** + * SETF + * + * Set functions + */ +#ifdef CMC_EXT_HASHMULTISET_SETF + +/* Set Operations */ +struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _summation)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_); + +#endif /* CMC_EXT_HASHMULTISET_SETF */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_HASHMULTISET_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr); +bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end, + const char *key_val_sep); + +#endif /* CMC_EXT_HASHMULTISET_STR */ diff --git a/src/cmc/cmc/hashmultiset/ext/struct.h b/src/cmc/cmc/hashmultiset/ext/struct.h new file mode 100644 index 0000000..915c7a6 --- /dev/null +++ b/src/cmc/cmc/hashmultiset/ext/struct.h @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * ITER + * + * Hashmultiset bi-directional iterator. + */ +#ifdef CMC_EXT_HASHMULTISET_ITER + +/* HashMultiSet Iterator */ +struct CMC_DEF_ITER(SNAME) +{ + /* Target HashMultiset */ + struct SNAME *target; + + /* Cursor's position (index) */ + size_t cursor; + + /* Keeps track of relative index to the iteration of elements */ + size_t index; + + /* The index of the first element */ + size_t first; + + /* The index of the last element */ + size_t last; + + /* If the iterator has reached the start of the iteration */ + bool start; + + /* If the iterator has reached the end of the iteration */ + bool end; +}; + +#endif /* CMC_EXT_HASHMULTISET_ITER */ diff --git a/src/cmc/cmc/hashmultiset/header.h b/src/cmc/cmc/hashmultiset/header.h new file mode 100644 index 0000000..4475af4 --- /dev/null +++ b/src/cmc/cmc/hashmultiset/header.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Value struct function table */ +struct CMC_DEF_FVAL(SNAME) +{ + /* Comparator function */ + CMC_DEF_FTAB_CMP(V); + /* Copy function */ + CMC_DEF_FTAB_CPY(V); + /* To string function */ + CMC_DEF_FTAB_STR(V); + /* Free from memory function */ + CMC_DEF_FTAB_FREE(V); + /* Hash function */ + CMC_DEF_FTAB_HASH(V); + /* Priority function */ + CMC_DEF_FTAB_PRI(V); +}; + +/* Collection Allocation and Deallocation */ +struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val); +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks); +void CMC_(PFX, _clear)(struct SNAME *_set_); +void CMC_(PFX, _free)(struct SNAME *_set_); +/* Customization of Allocation and Callbacks */ +void CMC_(PFX, _customize)(struct SNAME *_set_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +/* Collection Input and Output */ +bool CMC_(PFX, _insert)(struct SNAME *_set_, V value); +bool CMC_(PFX, _insert_many)(struct SNAME *_set_, V value, size_t count); +bool CMC_(PFX, _update)(struct SNAME *_set_, V value, size_t multiplicity); +bool CMC_(PFX, _remove)(struct SNAME *_set_, V value); +size_t CMC_(PFX, _remove_all)(struct SNAME *_set_, V value); +/* Element Access */ +bool CMC_(PFX, _max)(struct SNAME *_set_, V *value); +bool CMC_(PFX, _min)(struct SNAME *_set_, V *value); +size_t CMC_(PFX, _multiplicity_of)(struct SNAME *_set_, V value); +/* Collection State */ +bool CMC_(PFX, _contains)(struct SNAME *_set_, V value); +bool CMC_(PFX, _empty)(struct SNAME *_set_); +bool CMC_(PFX, _full)(struct SNAME *_set_); +size_t CMC_(PFX, _count)(struct SNAME *_set_); +size_t CMC_(PFX, _cardinality)(struct SNAME *_set_); +size_t CMC_(PFX, _capacity)(struct SNAME *_set_); +double CMC_(PFX, _load)(struct SNAME *_set_); +int CMC_(PFX, _flag)(struct SNAME *_set_); +/* Collection Utility */ +bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity); +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_); +bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_); diff --git a/src/cmc/cmc/hashmultiset/struct.h b/src/cmc/cmc/hashmultiset/struct.h new file mode 100644 index 0000000..f469ac0 --- /dev/null +++ b/src/cmc/cmc/hashmultiset/struct.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +struct SNAME +{ + /* Array of Entries */ + struct CMC_DEF_ENTRY(SNAME) * buffer; + /* Current Array Capcity */ + size_t capacity; + /* Current amount of unique elements */ + size_t count; + /* Total amount of elements taking into account their multiplicity */ + size_t cardinality; + /* Load factor in range (0.0, 1.0) */ + double load; + /* Flags indicating errors or success */ + int flag; + /* Key function table */ + struct CMC_DEF_FVAL(SNAME) * f_val; + /* Custom allocation functions */ + struct CMC_ALLOC_NODE_NAME *alloc; + /* Custom callback functions */ + CMC_CALLBACKS_DECL; +}; + +struct CMC_DEF_ENTRY(SNAME) +{ + /* Entry element */ + V value; + /* The element's multiplicity */ + size_t multiplicity; + /* The distance of this node to its original position, used by */ + /* robin-hood hashing */ + size_t dist; + /* The sate of this node (DELETED, EMPTY, FILLED) */ + enum cmc_entry_state state; +}; diff --git a/src/cmc/cmc/hashset/code.h b/src/cmc/cmc/hashset/code.h new file mode 100644 index 0000000..dafaa8c --- /dev/null +++ b/src/cmc/cmc/hashset/code.h @@ -0,0 +1,518 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Implementation Detail Functions */ +static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value); +static size_t CMC_(PFX, _impl_calculate_size)(size_t required); + +struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val) +{ + return CMC_(PFX, _new_custom)(capacity, load, f_val, NULL, NULL); +} + +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (capacity == 0 || load <= 0 || load >= 1) + return NULL; + + /* Prevent integer overflow */ + if (capacity >= UINTMAX_MAX * load) + return NULL; + + if (!f_val) + return NULL; + + size_t real_capacity = CMC_(PFX, _impl_calculate_size)(capacity / load); + + if (!alloc) + alloc = &cmc_alloc_node_default; + + struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); + + if (!_set_) + return NULL; + + _set_->buffer = alloc->calloc(real_capacity, sizeof(struct CMC_DEF_ENTRY(SNAME))); + + if (!_set_->buffer) + { + alloc->free(_set_); + return NULL; + } + + _set_->count = 0; + _set_->capacity = real_capacity; + _set_->load = load; + _set_->flag = CMC_FLAG_OK; + _set_->f_val = f_val; + _set_->alloc = alloc; + CMC_CALLBACKS_ASSIGN(_set_, callbacks); + + return _set_; +} + +void CMC_(PFX, _clear)(struct SNAME *_set_) +{ + if (_set_->f_val->free) + { + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]); + + if (entry->state == CMC_ES_FILLED) + { + _set_->f_val->free(entry->value); + } + } + } + + memset(_set_->buffer, 0, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity); + + _set_->count = 0; + _set_->flag = CMC_FLAG_OK; +} + +void CMC_(PFX, _free)(struct SNAME *_set_) +{ + if (_set_->f_val->free) + { + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]); + + if (entry->state == CMC_ES_FILLED) + { + _set_->f_val->free(entry->value); + } + } + } + + _set_->alloc->free(_set_->buffer); + _set_->alloc->free(_set_); +} + +void CMC_(PFX, _customize)(struct SNAME *_set_, struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks) +{ + CMC_CALLBACKS_MAYBE_UNUSED(callbacks); + + if (!alloc) + _set_->alloc = &cmc_alloc_node_default; + else + _set_->alloc = alloc; + + CMC_CALLBACKS_ASSIGN(_set_, callbacks); + + _set_->flag = CMC_FLAG_OK; +} + +bool CMC_(PFX, _insert)(struct SNAME *_set_, V value) +{ + if (CMC_(PFX, _full)(_set_)) + { + if (!CMC_(PFX, _resize)(_set_, _set_->capacity + 1)) + return false; + } + + if (CMC_(PFX, _impl_get_entry)(_set_, value) != NULL) + { + _set_->flag = CMC_FLAG_DUPLICATE; + return false; + } + + size_t hash = _set_->f_val->hash(value); + size_t original_pos = hash % _set_->capacity; + size_t pos = original_pos; + + struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]); + + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) + { + target->value = value; + target->dist = 0; + target->state = CMC_ES_FILLED; + } + else + { + while (true) + { + pos++; + target = &(_set_->buffer[pos % _set_->capacity]); + + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) + { + target->value = value; + target->dist = pos - original_pos; + target->state = CMC_ES_FILLED; + + break; + } + else if (target->dist < pos - original_pos) + { + V tmp = target->value; + size_t tmp_dist = target->dist; + + target->value = value; + target->dist = pos - original_pos; + + value = tmp; + original_pos = pos - tmp_dist; + } + } + } + + _set_->count++; + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, create); + + return true; +} + +bool CMC_(PFX, _remove)(struct SNAME *_set_, V value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + struct CMC_DEF_ENTRY(SNAME) *result = CMC_(PFX, _impl_get_entry)(_set_, value); + + if (result == NULL) + { + _set_->flag = CMC_FLAG_NOT_FOUND; + return false; + } + + result->value = (V){ 0 }; + result->dist = 0; + result->state = CMC_ES_DELETED; + + _set_->count--; + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, delete); + + return true; +} + +bool CMC_(PFX, _max)(struct SNAME *_set_, V *value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + bool first = true; + V max_val = (V){ 0 }; + + for (size_t i = 0; i < _set_->capacity; i++) + { + if (_set_->buffer[i].state == CMC_ES_FILLED) + { + if (first) + { + max_val = _set_->buffer[i].value; + first = false; + } + else if (_set_->f_val->cmp(_set_->buffer[i].value, max_val) > 0) + { + max_val = _set_->buffer[i].value; + } + } + } + + if (value) + *value = max_val; + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, read); + + return true; +} + +bool CMC_(PFX, _min)(struct SNAME *_set_, V *value) +{ + if (CMC_(PFX, _empty)(_set_)) + { + _set_->flag = CMC_FLAG_EMPTY; + return false; + } + + bool first = true; + V min_val = (V){ 0 }; + + for (size_t i = 0; i < _set_->capacity; i++) + { + if (_set_->buffer[i].state == CMC_ES_FILLED) + { + if (first) + { + min_val = _set_->buffer[i].value; + first = false; + } + else if (_set_->f_val->cmp(_set_->buffer[i].value, min_val) < 0) + { + min_val = _set_->buffer[i].value; + } + } + } + + if (value) + *value = min_val; + + _set_->flag = CMC_FLAG_OK; + + CMC_CALLBACKS_CALL(_set_, read); + + return true; +} + +bool CMC_(PFX, _contains)(struct SNAME *_set_, V value) +{ + _set_->flag = CMC_FLAG_OK; + + bool result = CMC_(PFX, _impl_get_entry)(_set_, value) != NULL; + + CMC_CALLBACKS_CALL(_set_, read); + + return result; +} + +bool CMC_(PFX, _empty)(struct SNAME *_set_) +{ + return _set_->count == 0; +} + +bool CMC_(PFX, _full)(struct SNAME *_set_) +{ + return (double)_set_->capacity * _set_->load <= (double)_set_->count; +} + +size_t CMC_(PFX, _count)(struct SNAME *_set_) +{ + return _set_->count; +} + +size_t CMC_(PFX, _capacity)(struct SNAME *_set_) +{ + return _set_->capacity; +} + +double CMC_(PFX, _load)(struct SNAME *_set_) +{ + return _set_->load; +} + +int CMC_(PFX, _flag)(struct SNAME *_set_) +{ + return _set_->flag; +} + +bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity) +{ + _set_->flag = CMC_FLAG_OK; + + if (_set_->capacity == capacity) + goto success; + + if (_set_->capacity > capacity / _set_->load) + goto success; + + /* Prevent integer overflow */ + if (capacity >= UINTMAX_MAX * _set_->load) + { + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + /* Calculate required capacity based on the prime numbers */ + size_t theoretical_size = CMC_(PFX, _impl_calculate_size)(capacity); + + /* Not possible to shrink with current available prime numbers */ + if (theoretical_size < _set_->count / _set_->load) + { + _set_->flag = CMC_FLAG_INVALID; + return false; + } + + /* No callbacks since _new_set_ is just a temporary hashtable */ + struct SNAME *_new_set_ = CMC_(PFX, _new_custom)(capacity, _set_->load, _set_->f_val, _set_->alloc, NULL); + + if (!_new_set_) + { + _set_->flag = CMC_FLAG_ALLOC; + return false; + } + + for (size_t i = 0; i < _set_->capacity; i++) + { + if (_set_->buffer[i].state == CMC_ES_FILLED) + { + V value = _set_->buffer[i].value; + + /* TODO check this for possible errors */ + CMC_(PFX, _insert)(_new_set_, value); + } + } + + /* Unlikely */ + if (_set_->count != _new_set_->count) + { + CMC_(PFX, _free)(_new_set_); + + _set_->flag = CMC_FLAG_ERROR; + return false; + } + + struct CMC_DEF_ENTRY(SNAME) *tmp_b = _set_->buffer; + _set_->buffer = _new_set_->buffer; + _new_set_->buffer = tmp_b; + + size_t tmp_c = _set_->capacity; + _set_->capacity = _new_set_->capacity; + _new_set_->capacity = tmp_c; + + /* Prevent the set from freeing the data */ + _new_set_->f_val = &(struct CMC_DEF_FVAL(SNAME)){ NULL }; + + CMC_(PFX, _free)(_new_set_); + +success: + + CMC_CALLBACKS_CALL(_set_, resize); + + return true; +} + +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_) +{ + struct SNAME *result = + CMC_(PFX, _new_custom)(_set_->capacity * _set_->load, _set_->load, _set_->f_val, _set_->alloc, NULL); + + if (!result) + { + _set_->flag = CMC_FLAG_ERROR; + return NULL; + } + + CMC_CALLBACKS_ASSIGN(result, _set_->callbacks); + + if (_set_->f_val->cpy) + { + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *scan = &(_set_->buffer[i]); + + if (scan->state != CMC_ES_EMPTY) + { + struct CMC_DEF_ENTRY(SNAME) *target = &(result->buffer[i]); + + if (scan->state == CMC_ES_DELETED) + target->state = CMC_ES_DELETED; + else + { + target->state = scan->state; + target->dist = scan->dist; + + target->value = _set_->f_val->cpy(scan->value); + } + } + } + } + else + memcpy(result->buffer, _set_->buffer, sizeof(struct CMC_DEF_ENTRY(SNAME)) * _set_->capacity); + + result->count = _set_->count; + + _set_->flag = CMC_FLAG_OK; + + return result; +} + +bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + _set1_->flag = CMC_FLAG_OK; + _set2_->flag = CMC_FLAG_OK; + + if (_set1_->count != _set2_->count) + return false; + + /* Optimize loop using the smallest hashtable */ + struct SNAME *_set_a_; + struct SNAME *_set_b_; + + _set_a_ = _set1_->capacity < _set2_->capacity ? _set1_ : _set2_; + _set_b_ = _set_a_ == _set1_ ? _set2_ : _set1_; + + for (size_t i = 0; i < _set_a_->capacity; i++) + { + if (_set_a_->buffer[i].state == CMC_ES_FILLED) + { + + if (!CMC_(PFX, _impl_get_entry)(_set_b_, _set_a_->buffer[i].value)) + return false; + } + } + + return true; +} + +static struct CMC_DEF_ENTRY(SNAME) * CMC_(PFX, _impl_get_entry)(struct SNAME *_set_, V value) +{ + size_t hash = _set_->f_val->hash(value); + size_t pos = hash % _set_->capacity; + + struct CMC_DEF_ENTRY(SNAME) *target = &(_set_->buffer[pos]); + + while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED) + { + if (target->state != CMC_ES_DELETED && _set_->f_val->cmp(target->value, value) == 0) + return target; + + pos++; + target = &(_set_->buffer[pos % _set_->capacity]); + } + + return NULL; +} + +static size_t CMC_(PFX, _impl_calculate_size)(size_t required) +{ + const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]); + + if (cmc_hashtable_primes[count - 1] < required) + return required; + + size_t i = 0; + while (cmc_hashtable_primes[i] < required) + i++; + + return cmc_hashtable_primes[i]; +} diff --git a/src/cmc/cmc/hashset/ext/code.h b/src/cmc/cmc/hashset/ext/code.h new file mode 100644 index 0000000..62b9508 --- /dev/null +++ b/src/cmc/cmc/hashset/ext/code.h @@ -0,0 +1,591 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_HASHSET_INIT + +#endif /* CMC_EXT_HASHSET_INIT */ + +/** + * ITER + * + * Hashset bi-directional iterator. + */ +#ifdef CMC_EXT_HASHSET_ITER + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = true; + iter.end = CMC_(PFX, _empty)(target); + + if (!CMC_(PFX, _empty)(target)) + { + for (size_t i = 0; i < target->capacity; i++) + { + if (target->buffer[i].state == CMC_ES_FILLED) + { + iter.first = i; + break; + } + } + + iter.cursor = iter.first; + + for (size_t i = target->capacity; i > 0; i--) + { + if (target->buffer[i - 1].state == CMC_ES_FILLED) + { + iter.last = i - 1; + break; + } + } + } + + return iter; +} + +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target) +{ + struct CMC_DEF_ITER(SNAME) iter; + + iter.target = target; + iter.cursor = 0; + iter.index = 0; + iter.first = 0; + iter.last = 0; + iter.start = CMC_(PFX, _empty)(target); + iter.end = true; + + if (!CMC_(PFX, _empty)(target)) + { + for (size_t i = 0; i < target->capacity; i++) + { + if (target->buffer[i].state == CMC_ES_FILLED) + { + iter.first = i; + break; + } + } + + for (size_t i = target->capacity; i > 0; i--) + { + if (target->buffer[i - 1].state == CMC_ES_FILLED) + { + iter.last = i - 1; + break; + } + } + + iter.cursor = iter.last; + iter.index = target->count - 1; + } + + return iter; +} + +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->start; +} + +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return CMC_(PFX, _empty)(iter->target) || iter->end; +} + +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = iter->first; + iter->index = 0; + iter->start = true; + iter->end = CMC_(PFX, _empty)(iter->target); + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (!CMC_(PFX, _empty)(iter->target)) + { + iter->cursor = iter->last; + iter->index = iter->target->count - 1; + iter->start = CMC_(PFX, _empty)(iter->target); + iter->end = true; + + return true; + } + + return false; +} + +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->end) + return false; + + if (iter->index + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + iter->start = CMC_(PFX, _empty)(iter->target); + + struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]); + + iter->index++; + + while (1) + { + iter->cursor++; + scan = &(iter->target->buffer[iter->cursor]); + + if (scan->state == CMC_ES_FILLED) + break; + } + + return true; +} + +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (iter->start) + return false; + + if (iter->index == 0) + { + iter->start = true; + return false; + } + + iter->end = CMC_(PFX, _empty)(iter->target); + + struct CMC_DEF_ENTRY(SNAME) *scan = &(iter->target->buffer[iter->cursor]); + + iter->index--; + + while (1) + { + iter->cursor--; + scan = &(iter->target->buffer[iter->cursor]); + + if (scan->state == CMC_ES_FILLED) + break; + } + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->end) + return false; + + if (iter->index + 1 == iter->target->count) + { + iter->end = true; + return false; + } + + if (steps == 0 || iter->index + steps >= iter->target->count) + return false; + + for (size_t i = 0; i < steps; i++) + CMC_(PFX, _iter_next)(iter); + + return true; +} + +/* Returns true only if the iterator moved */ +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps) +{ + if (iter->start) + return false; + + if (iter->index == 0) + { + iter->start = true; + return false; + } + + if (steps == 0 || iter->index < steps) + return false; + + for (size_t i = 0; i < steps; i++) + CMC_(PFX, _iter_prev)(iter); + + return true; +} + +/* Returns true only if the iterator was able to be positioned at the */ +/* given index */ +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index) +{ + if (index >= iter->target->count) + return false; + + if (iter->index > index) + return CMC_(PFX, _iter_rewind)(iter, iter->index - index); + else if (iter->index < index) + return CMC_(PFX, _iter_advance)(iter, index - iter->index); + + return true; +} + +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter) +{ + if (CMC_(PFX, _empty)(iter->target)) + return (V){ 0 }; + + return iter->target->buffer[iter->cursor].value; +} + +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter) +{ + return iter->index; +} + +#endif /* CMC_EXT_HASHSET_ITER */ + +/** + * SETF + * + * Set functions + */ +#ifdef CMC_EXT_HASHSET_SETF + +struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + { + _set1_->flag = CMC_FLAG_ALLOC; + _set2_->flag = CMC_FLAG_ALLOC; + return NULL; + } + + struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_); + struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_); + + /* TODO turn this into a normal loop and check for errors */ + for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1)) + { + CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter1)); + } + + for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2)) + { + CMC_(PFX, _insert)(_set_r_, CMC_(PFX, _iter_value)(&iter2)); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + { + _set1_->flag = CMC_FLAG_ALLOC; + _set2_->flag = CMC_FLAG_ALLOC; + return NULL; + } + + struct SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; + struct SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set_A_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + if (CMC_(PFX, _impl_get_entry)(_set_B_, value) != NULL) + CMC_(PFX, _insert)(_set_r_, value); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + { + _set1_->flag = CMC_FLAG_ALLOC; + _set2_->flag = CMC_FLAG_ALLOC; + return NULL; + } + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL) + CMC_(PFX, _insert)(_set_r_, value); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + /* Callbacks are added later */ + struct SNAME *_set_r_ = CMC_(PFX, _new_custom)(_set1_->capacity, _set1_->load, _set1_->f_val, _set1_->alloc, NULL); + + if (!_set_r_) + { + _set1_->flag = CMC_FLAG_ALLOC; + _set2_->flag = CMC_FLAG_ALLOC; + return NULL; + } + + struct CMC_DEF_ITER(SNAME) iter1 = CMC_(PFX, _iter_start)(_set1_); + struct CMC_DEF_ITER(SNAME) iter2 = CMC_(PFX, _iter_start)(_set2_); + + for (; !CMC_(PFX, _iter_at_end)(&iter1); CMC_(PFX, _iter_next)(&iter1)) + { + V value = CMC_(PFX, _iter_value)(&iter1); + + if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL) + CMC_(PFX, _insert)(_set_r_, value); + } + + for (; !CMC_(PFX, _iter_at_end)(&iter2); CMC_(PFX, _iter_next)(&iter2)) + { + V value = CMC_(PFX, _iter_value)(&iter2); + + if (CMC_(PFX, _impl_get_entry)(_set1_, value) == NULL) + CMC_(PFX, _insert)(_set_r_, value); + } + + CMC_CALLBACKS_ASSIGN(_set_r_, _set1_->callbacks); + + return _set_r_; +} + +/* Is _set1_ a subset of _set2_ ? */ +/* A set X is a subset of a set Y when: X <= Y */ +/* If X is a subset of Y, then Y is a superset of X */ +bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + _set1_->flag = CMC_FLAG_OK; + _set2_->flag = CMC_FLAG_OK; + + /* If the cardinality of _set1_ is greater than that of _set2_, */ + /* then it is safe to say that _set1_ can't be a subset of _set2_ */ + if (_set1_->count > _set2_->count) + return false; + + /* The empty set is a subset of all sets */ + if (CMC_(PFX, _empty)(_set1_)) + return true; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL) + return false; + } + + return true; +} + +/* Is _set1_ a superset of _set2_ ? */ +/* A set X is a superset of a set Y when: X >= Y */ +/* If X is a superset of Y, then Y is a subset of X */ +bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + return CMC_(PFX, _is_subset)(_set2_, _set1_); +} + +/* Is _set1_ a proper subset of _set2_ ? */ +/* A set X is a proper subset of a set Y when: X < Y */ +/* If X is a proper subset of Y, then Y is a proper superset of X */ +bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + _set1_->flag = CMC_FLAG_OK; + _set2_->flag = CMC_FLAG_OK; + + /* If the cardinality of _set1_ is greater than or equal to that of */ + /* _set2_, then it is safe to say that _set1_ can't be a proper */ + /* subset of _set2_ */ + if (_set1_->count >= _set2_->count) + return false; + + if (CMC_(PFX, _empty)(_set1_)) + { + /* The empty set is a proper subset of all non-empty sets */ + if (!CMC_(PFX, _empty)(_set2_)) + return true; + /* The empty set is not a proper subset of itself (this is true */ + /* for any set) */ + else + return false; + } + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + if (CMC_(PFX, _impl_get_entry)(_set2_, value) == NULL) + return false; + } + + return true; +} + +/* Is _set1_ a proper superset of _set2_ ? */ +/* A set X is a proper superset of a set Y when: X > Y */ +/* If X is a proper superset of Y, then Y is a proper subset of X */ +bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + return CMC_(PFX, _is_proper_subset)(_set2_, _set1_); +} + +/* Is _set1_ a disjointset of _set2_ ? */ +/* A set X is a disjointset of a set Y if their intersection is empty, */ +/* that is, if there are no elements in common between the two */ +bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_) +{ + _set1_->flag = CMC_FLAG_OK; + _set2_->flag = CMC_FLAG_OK; + + /* The intersection of an empty set with any other set will result */ + /* in an empty set */ + if (CMC_(PFX, _empty)(_set1_)) + return true; + + struct CMC_DEF_ITER(SNAME) iter = CMC_(PFX, _iter_start)(_set1_); + + for (; !CMC_(PFX, _iter_at_end)(&iter); CMC_(PFX, _iter_next)(&iter)) + { + V value = CMC_(PFX, _iter_value)(&iter); + + if (CMC_(PFX, _impl_get_entry)(_set2_, value) != NULL) + return false; + } + + return true; +} + +#endif /* CMC_EXT_HASHSET_SETF */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_HASHSET_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr) +{ + struct SNAME *s_ = _set_; + + return 0 <= fprintf(fptr, + "struct %s<%s> " + "at %p { " + "buffer:%p, " + "capacity:%" PRIuMAX ", " + "count:%" PRIuMAX ", " + "load:%lf, " + "flag:%d, " + "f_val:%p, " + "alloc:%p, " + "callbacks: %p }", + CMC_TO_STRING(SNAME), CMC_TO_STRING(V), s_, s_->buffer, s_->capacity, s_->count, s_->load, + s_->flag, s_->f_val, s_->alloc, CMC_CALLBACKS_GET(s_)); +} + +bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end) +{ + fprintf(fptr, "%s", start); + + size_t last = 0; + for (size_t i = _set_->capacity; i > 0; i--) + { + if ((_set_->buffer[i - 1]).state == CMC_ES_FILLED) + { + last = i - 1; + break; + } + } + + for (size_t i = 0; i < _set_->capacity; i++) + { + struct CMC_DEF_ENTRY(SNAME) *entry = &(_set_->buffer[i]); + + if (entry->state == CMC_ES_FILLED) + { + if (!_set_->f_val->str(fptr, entry->value)) + return false; + + if (i + 1 < last) + fprintf(fptr, "%s", separator); + } + } + + fprintf(fptr, "%s", end); + + return true; +} + +#endif /* CMC_EXT_HASHSET_STR */ diff --git a/src/cmc/cmc/hashset/ext/header.h b/src/cmc/cmc/hashset/ext/header.h new file mode 100644 index 0000000..6a0b694 --- /dev/null +++ b/src/cmc/cmc/hashset/ext/header.h @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * INIT + * + * The part 'INIT' gives a new way of initializing a collection. The collection + * struct is not heap allocated, only its internal structure (nodes, buffers). + */ +#ifdef CMC_EXT_HASHSET_INIT + +#endif /* CMC_EXT_HASHSET_INIT */ + +/** + * ITER + * + * List bi-directional iterator. + */ +#ifdef CMC_EXT_HASHSET_ITER + +/* Iterator Initialization */ +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target); +struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target); +/* Iterator State */ +bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter); +/* Iterator Movement */ +bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter); +bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps); +bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index); +/* Iterator Access */ +V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter); +size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter); + +#endif /* CMC_EXT_HASHSET_ITER */ + +/** + * SETF + * + * Set functions + */ +#ifdef CMC_EXT_HASHSET_SETF + +/* Set Operations */ +struct SNAME *CMC_(PFX, _union)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _intersection)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _difference)(struct SNAME *_set1_, struct SNAME *_set2_); +struct SNAME *CMC_(PFX, _symmetric_difference)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_subset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_superset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_proper_subset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_proper_superset)(struct SNAME *_set1_, struct SNAME *_set2_); +bool CMC_(PFX, _is_disjointset)(struct SNAME *_set1_, struct SNAME *_set2_); + +#endif /* CMC_EXT_HASHSET_SETF */ + +/** + * STR + * + * Print helper functions. + */ +#ifdef CMC_EXT_HASHSET_STR + +bool CMC_(PFX, _to_string)(struct SNAME *_set_, FILE *fptr); +bool CMC_(PFX, _print)(struct SNAME *_set_, FILE *fptr, const char *start, const char *separator, const char *end); + +#endif /* CMC_EXT_HASHSET_STR */ diff --git a/src/cmc/cmc/hashset/ext/struct.h b/src/cmc/cmc/hashset/ext/struct.h new file mode 100644 index 0000000..53e6c56 --- /dev/null +++ b/src/cmc/cmc/hashset/ext/struct.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * ITER + * + * Hashset bi-directional iterator. + */ +#ifdef CMC_EXT_HASHSET_ITER + +/* HashSet Iterator */ +struct CMC_DEF_ITER(SNAME) +{ + /* Target HashSet */ + struct SNAME *target; + /* Cursor's position (index) */ + size_t cursor; + /* Keeps track of relative index to the iteration of elements */ + size_t index; + /* The index of the first element */ + size_t first; + /* The index of the last element */ + size_t last; + /* If the iterator has reached the start of the iteration */ + bool start; + /* If the iterator has reached the end of the iteration */ + bool end; +}; + +#endif /* CMC_EXT_HASHSET_ITER */ diff --git a/src/cmc/cmc/hashset/header.h b/src/cmc/cmc/hashset/header.h new file mode 100644 index 0000000..23f266b --- /dev/null +++ b/src/cmc/cmc/hashset/header.h @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Value struct function table */ +struct CMC_DEF_FVAL(SNAME) +{ + /* Comparator function */ + CMC_DEF_FTAB_CMP(V); + /* Copy function */ + CMC_DEF_FTAB_CPY(V); + /* To string function */ + CMC_DEF_FTAB_STR(V); + /* Free from memory function */ + CMC_DEF_FTAB_FREE(V); + /* Hash function */ + CMC_DEF_FTAB_HASH(V); + /* Priority function */ + CMC_DEF_FTAB_PRI(V); +}; + +/* Collection Allocation and Deallocation */ +struct SNAME *CMC_(PFX, _new)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val); +struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, double load, struct CMC_DEF_FVAL(SNAME) * f_val, + struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks); +void CMC_(PFX, _clear)(struct SNAME *_set_); +void CMC_(PFX, _free)(struct SNAME *_set_); +/* Customization of Allocation and Callbacks */ +void CMC_(PFX, _customize)(struct SNAME *_set_, struct CMC_ALLOC_NODE_NAME *alloc, + struct CMC_CALLBACKS_NAME *callbacks); +/* Collection Input and Output */ +bool CMC_(PFX, _insert)(struct SNAME *_set_, V value); +bool CMC_(PFX, _remove)(struct SNAME *_set_, V value); +/* Element Access */ +bool CMC_(PFX, _max)(struct SNAME *_set_, V *value); +bool CMC_(PFX, _min)(struct SNAME *_set_, V *value); +/* Collection State */ +bool CMC_(PFX, _contains)(struct SNAME *_set_, V value); +bool CMC_(PFX, _empty)(struct SNAME *_set_); +bool CMC_(PFX, _full)(struct SNAME *_set_); +size_t CMC_(PFX, _count)(struct SNAME *_set_); +size_t CMC_(PFX, _capacity)(struct SNAME *_set_); +double CMC_(PFX, _load)(struct SNAME *_set_); +int CMC_(PFX, _flag)(struct SNAME *_set_); +/* Collection Utility */ +bool CMC_(PFX, _resize)(struct SNAME *_set_, size_t capacity); +struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_set_); +bool CMC_(PFX, _equals)(struct SNAME *_set1_, struct SNAME *_set2_); diff --git a/src/cmc/cmc/hashset/struct.h b/src/cmc/cmc/hashset/struct.h new file mode 100644 index 0000000..e36c377 --- /dev/null +++ b/src/cmc/cmc/hashset/struct.h @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* Hashset Structure */ +struct SNAME +{ + /* Array of Entries */ + struct CMC_DEF_ENTRY(SNAME) * buffer; + /* Current Array Capcity */ + size_t capacity; + /* Current amount of elements */ + size_t count; + /* Load factor in range (0.0, 1.0) */ + double load; + /* Flags indicating errors or success */ + int flag; + /* Value function table */ + struct CMC_DEF_FVAL(SNAME) * f_val; + /* Custom allocation functions */ + struct CMC_ALLOC_NODE_NAME *alloc; + /* Custom callback functions */ + CMC_CALLBACKS_DECL; +}; + +struct CMC_DEF_ENTRY(SNAME) +{ + /* Entry value */ + V value; + /* The distance of this node to its original position, used by */ + /* robin-hood hashing */ + size_t dist; + /* The sate of this node (DELETED, EMPTY, FILLED) */ + enum cmc_entry_state state; +}; diff --git a/src/cmc/cor/undef.h b/src/cmc/cor/undef.h index 743eb7c..d2097a7 100644 --- a/src/cmc/cor/undef.h +++ b/src/cmc/cor/undef.h @@ -54,6 +54,28 @@ #undef CMC_EXT_HASHBIDIMAP_ITER #undef CMC_EXT_HASHBIDIMAP_STR +/* Hashmap */ +#undef CMC_EXT_HASHMAP_INIT +#undef CMC_EXT_HASHMAP_ITER +#undef CMC_EXT_HASHMAP_STR + +/* Hashmultimap */ +#undef CMC_EXT_HASHMULTIMAP_INIT +#undef CMC_EXT_HASHMULTIMAP_ITER +#undef CMC_EXT_HASHMULTIMAP_STR + +/* Hashmultiset */ +#undef CMC_EXT_HASHMULTISET_INIT +#undef CMC_EXT_HASHMULTISET_ITER +#undef CMC_EXT_HASHMULTISET_SETF +#undef CMC_EXT_HASHMULTISET_STR + +/* Hashset */ +#undef CMC_EXT_HASHMSET_INIT +#undef CMC_EXT_HASHMSET_ITER +#undef CMC_EXT_HASHMSET_SETF +#undef CMC_EXT_HASHMSET_STR + /* List */ #undef CMC_EXT_LIST_INIT #undef CMC_EXT_LIST_ITER diff --git a/src/cmc/hashmultimap.h b/src/cmc/hashmultimap.h index 03cc759..2b63c08 100644 --- a/src/cmc/hashmultimap.h +++ b/src/cmc/hashmultimap.h @@ -70,8 +70,8 @@ /** * Used values - * K - hashmap key data type - * V - hashmap value data type + * K - hashmultimap key data type + * V - hashmultimap value data type * SNAME - struct name and prefix of other related structs * PFX - functions prefix */ diff --git a/src/cmc/hashmultiset.h b/src/cmc/hashmultiset.h new file mode 100644 index 0000000..d5e1018 --- /dev/null +++ b/src/cmc/hashmultiset.h @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * hashmultiset.h + * + * Creation Date: 10/04/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * HashMultiSet + * + * In mathematics, a multiset is a modification of the concept of a set that, + * unlike a set, allows for multiple instances for each of its elements. The + * positive integer number of instances, given for each element is called the + * multiplicity of this element in the multiset. A multiSet also has a + * cardinality which equals the sum of the multiplicities of its elements. + * + * Implementation + * + * In this implementation, the values are stored in a flat hashtable and are + * mapped to their multiplicity. + */ + +#include "cor/core.h" +#include "cor/hashtable.h" + +/** + * Used values + * V - hashmultiset value data type + * SNAME - struct name and prefix of other related structs + * PFX - functions prefix + */ + +/* Structs definition */ +#include "cmc/hashmultiset/struct.h" + +/* Function declaration */ +#include "cmc/hashmultiset/header.h" + +/* Function implementation */ +#include "cmc/hashmultiset/code.h" + +/** + * Extensions + * + * INIT - Initializes the struct on the stack + * ITER - hashmultiset iterator + * STR - Print helper functions + */ +#define CMC_EXT_HASHMULTISET_PARTS INIT, ITER, SETF, STR +/**/ +#include "cmc/hashmultiset/ext/struct.h" +/**/ +#include "cmc/hashmultiset/ext/header.h" +/**/ +#include "cmc/hashmultiset/ext/code.h" + +#include "cor/undef.h" diff --git a/src/cmc/hashset.h b/src/cmc/hashset.h new file mode 100644 index 0000000..25b7617 --- /dev/null +++ b/src/cmc/hashset.h @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2019 Leonardo Vencovsky + * + * This file is part of the C Macro Collections Libray. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * hashset.h + * + * Creation Date: 01/04/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * HashSet + * + * A HashSet is an implementation of a Set with unique keys. The keys are not + * sorted. It is implemented as a flat hashtable with linear probing and robin + * hood hashing. + */ + +#include "cor/core.h" +#include "cor/hashtable.h" + +/** + * Used values + * V - hashset value data type + * SNAME - struct name and prefix of other related structs + * PFX - functions prefix + */ + +/* Structs definition */ +#include "cmc/hashset/struct.h" + +/* Function declaration */ +#include "cmc/hashset/header.h" + +/* Function implementation */ +#include "cmc/hashset/code.h" + +/** + * Extensions + * + * INIT - Initializes the struct on the stack + * ITER - hashset iterator + * STR - Print helper functions + */ +#define CMC_EXT_HASHSET_PARTS ITER, SETF, STR +/**/ +#include "cmc/hashset/ext/struct.h" +/**/ +#include "cmc/hashset/ext/header.h" +/**/ +#include "cmc/hashset/ext/code.h" + +#include "cor/undef.h" diff --git a/tests/Makefile b/tests/Makefile index 6fdcc30..4baee3d 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,5 @@ CC=gcc -CFLAGS=-Wall -fprofile-arcs -ftest-coverage -g -O0 +CFLAGS=-Wall -Wextra -Werror -fprofile-arcs -ftest-coverage -g -O0 INCLUDE=-I ../src main: diff --git a/tests/main.c b/tests/main.c index 6ef88f7..70bae83 100644 --- a/tests/main.c +++ b/tests/main.c @@ -6,8 +6,8 @@ #include "unt_hashbidimap.h" #include "unt_hashmap.h" #include "unt_hashmultimap.h" -// #include "unt_hashmultiset.h" -// #include "unt_hashset.h" +#include "unt_hashmultiset.h" +#include "unt_hashset.h" // #include "unt_heap.h" // #include "unt_intervalheap.h" // #include "unt_linkedlist.h" @@ -62,10 +62,10 @@ int main(void) cmc_run(CMCHashMapIter, units, tests); cmc_run(CMCHashMultiMap, units, tests); cmc_run(CMCHashMultiMapIter, units, tests); - // cmc_run(CMCHashMultiSet, units, tests); - // cmc_run(CMCHashMultiSetIter, units, tests); - // cmc_run(CMCHashSet, units, tests); - // cmc_run(CMCHashSetIter, units, tests); + cmc_run(CMCHashMultiSet, units, tests); + cmc_run(CMCHashMultiSetIter, units, tests); + cmc_run(CMCHashSet, units, tests); + cmc_run(CMCHashSetIter, units, tests); // cmc_run(CMCHeap, units, tests); // cmc_run(CMCHeapIter, units, tests); // cmc_run(CMCIntervalHeap, units, tests); diff --git a/tests/unt_hashmultiset.h b/tests/unt_hashmultiset.h new file mode 100644 index 0000000..6bddbfd --- /dev/null +++ b/tests/unt_hashmultiset.h @@ -0,0 +1,871 @@ +#ifndef CMC_TESTS_UNT_HASHMULTISET_H +#define CMC_TESTS_UNT_HASHMULTISET_H + +#include "utl.h" + +#define V size_t +#define PFX hms +#define SNAME hashmultiset +#define CMC_EXT_HASHMULTISET_INIT +#define CMC_EXT_HASHMULTISET_ITER +#define CMC_EXT_HASHMULTISET_SETF +#define CMC_EXT_HASHMULTISET_STR +#include "cmc/hashmultiset.h" + +struct hashmultiset_fval *hms_fval = &(struct hashmultiset_fval){ + .cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp +}; + +struct hashmultiset_fval *hms_fval_counter = &(struct hashmultiset_fval){ + .cmp = v_c_cmp, .cpy = v_c_cpy, .str = v_c_str, .free = v_c_free, .hash = v_c_hash, .pri = v_c_pri +}; + +struct cmc_alloc_node *hms_alloc_node = + &(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free }; + +CMC_CREATE_UNIT(CMCHashMultiSet, true, { + CMC_CREATE_TEST(PFX##_new(), { + struct hashmultiset *set = hms_new(943722, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_not_equals(ptr, NULL, set->buffer); + cmc_assert_equals(size_t, 0, set->count); + cmc_assert_equals(double, 0.6, set->load); + cmc_assert_equals(int32_t, CMC_FLAG_OK, set->flag); + cmc_assert_equals(ptr, hms_fval, set->f_val); + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, set->alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, set->alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, set->alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, set->alloc->free); + cmc_assert_equals(ptr, NULL, set->callbacks); + + cmc_assert_greater_equals(size_t, (943722 / 0.6), hms_capacity(set)); + + hms_free(set); + + set = hms_new(0, 0.6, hms_fval); + cmc_assert_equals(ptr, NULL, set); + + set = hms_new(UINT64_MAX, 0.99, hms_fval); + cmc_assert_equals(ptr, NULL, set); + + set = hms_new(1000, 0.6, NULL); + cmc_assert_equals(ptr, NULL, set); + + set = hms_new(1000, 0.6, NULL); + cmc_assert_equals(ptr, NULL, set); + }); + + CMC_CREATE_TEST(PFX##_new_custom(), { + struct hashmultiset *set = hms_new_custom(943722, 0.6, hms_fval, hms_alloc_node, callbacks); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_not_equals(ptr, NULL, set->buffer); + cmc_assert_equals(size_t, 0, set->count); + cmc_assert_equals(double, 0.6, set->load); + cmc_assert_equals(int32_t, CMC_FLAG_OK, set->flag); + cmc_assert_equals(ptr, hms_fval, set->f_val); + cmc_assert_equals(ptr, hms_alloc_node, set->alloc); + cmc_assert_equals(ptr, callbacks, set->callbacks); + + cmc_assert_greater_equals(size_t, (943722 / 0.6), hms_capacity(set)); + + hms_free(set); + + set = hms_new_custom(0, 0.6, hms_fval, NULL, NULL); + cmc_assert_equals(ptr, NULL, set); + + set = hms_new_custom(UINT64_MAX, 0.99, hms_fval, NULL, NULL); + cmc_assert_equals(ptr, NULL, set); + + set = hms_new_custom(1000, 0.6, NULL, NULL, NULL); + cmc_assert_equals(ptr, NULL, set); + }); + + CMC_CREATE_TEST(PFX##_clear(), { + v_total_free = 0; + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_counter); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i <= 1000; i++) + hms_insert(set, i); + + cmc_assert_equals(size_t, 1000, set->count); + + set->flag = CMC_FLAG_ERROR; + hms_clear(set); + + cmc_assert_equals(size_t, 0, set->count); + cmc_assert_equals(int32_t, CMC_FLAG_OK, set->flag); + cmc_assert_equals(int32_t, 1000, v_total_free); + + hms_free(set); + v_total_free = 0; + }); + + CMC_CREATE_TEST(PFX##_free(), { + v_total_free = 0; + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_counter); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i <= 1000; i++) + hms_insert(set, i); + + cmc_assert_equals(size_t, 1000, set->count); + + hms_free(set); + + cmc_assert_equals(int32_t, 1000, v_total_free); + + set = hms_new(1000, 0.6, hms_fval_counter); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_not_equals(ptr, NULL, set->buffer); + + hms_free(set); + + cmc_assert_equals(int32_t, 1000, v_total_free); + v_total_free = 0; + }); + + CMC_CREATE_TEST(insert[count cardinality multiplicity], { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 3)); + cmc_assert(hms_insert(set, 3)); + cmc_assert(hms_insert(set, 3)); + + cmc_assert_equals(size_t, 3, hms_count(set)); + cmc_assert_equals(size_t, 6, hms_cardinality(set)); + + for (size_t i = 0; i <= 3; i++) + cmc_assert_equals(size_t, i, hms_multiplicity_of(set, i)); + + hms_free(set); + }); + + CMC_CREATE_TEST(remove[count cardinality multiplicity], { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 3)); + cmc_assert(hms_insert(set, 3)); + cmc_assert(hms_insert(set, 3)); + + cmc_assert_equals(size_t, 3, hms_count(set)); + cmc_assert_equals(size_t, 6, hms_cardinality(set)); + + for (size_t i = 0; i <= 3; i++) + cmc_assert_equals(size_t, i, hms_multiplicity_of(set, i)); + + cmc_assert(hms_remove(set, 1)); + cmc_assert(hms_remove(set, 2)); + cmc_assert(hms_remove(set, 3)); + + cmc_assert_equals(size_t, 2, hms_count(set)); + cmc_assert_equals(size_t, 3, hms_cardinality(set)); + + cmc_assert_equals(size_t, 0, hms_multiplicity_of(set, 0)); + cmc_assert_equals(size_t, 0, hms_multiplicity_of(set, 1)); + cmc_assert_equals(size_t, 1, hms_multiplicity_of(set, 2)); + cmc_assert_equals(size_t, 2, hms_multiplicity_of(set, 3)); + + hms_free(set); + }); + + CMC_CREATE_TEST(remove_all[count cardinality multiplicity], { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 3)); + cmc_assert(hms_insert(set, 3)); + cmc_assert(hms_insert(set, 3)); + + cmc_assert_equals(size_t, 3, hms_count(set)); + cmc_assert_equals(size_t, 6, hms_cardinality(set)); + + for (size_t i = 0; i <= 3; i++) + cmc_assert_equals(size_t, i, hms_multiplicity_of(set, i)); + + cmc_assert(hms_remove_all(set, 1)); + cmc_assert(hms_remove_all(set, 3)); + + cmc_assert_equals(size_t, 1, hms_count(set)); + cmc_assert_equals(size_t, 2, hms_cardinality(set)); + + cmc_assert_equals(size_t, 0, hms_multiplicity_of(set, 0)); + cmc_assert_equals(size_t, 0, hms_multiplicity_of(set, 1)); + cmc_assert_equals(size_t, 2, hms_multiplicity_of(set, 2)); + cmc_assert_equals(size_t, 0, hms_multiplicity_of(set, 3)); + + hms_free(set); + }); + + CMC_CREATE_TEST(multiplicity, { + struct hashmultiset *set = hms_new(50, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 1000; i++) + cmc_assert(hms_insert(set, i % 20)); + + cmc_assert_equals(size_t, 20, hms_count(set)); + cmc_assert_equals(size_t, 1000, hms_cardinality(set)); + + for (size_t i = 0; i < 20; i++) + cmc_assert_equals(size_t, 50, hms_multiplicity_of(set, i)); + + hms_free(set); + }); + + CMC_CREATE_TEST(flags, { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // clear + set->flag = CMC_FLAG_ERROR; + hms_clear(set); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // customize + set->flag = CMC_FLAG_ERROR; + hms_customize(set, NULL, NULL); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // insert + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_insert(set, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_insert(set, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // insert_many + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_insert_many(set, 1, 0)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_insert_many(set, 1, 2)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // update + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_update(set, 1, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_update(set, 10, 0)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // remove + cmc_assert(!hms_remove(set, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hms_flag(set)); + + cmc_assert(hms_remove(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // remove_all + cmc_assert_equals(size_t, 0, hms_remove_all(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hms_flag(set)); + + cmc_assert(hms_insert_many(set, 1, 10)); + cmc_assert_equals(size_t, 0, hms_remove_all(set, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hms_flag(set)); + + cmc_assert_equals(size_t, 10, hms_remove_all(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // max min + cmc_assert(!hms_max(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hms_flag(set)); + set->flag = CMC_FLAG_ERROR; + cmc_assert(!hms_min(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hms_flag(set)); + + cmc_assert(hms_insert(set, 1)); + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_max(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + set->flag = CMC_FLAG_ERROR; + cmc_assert(hms_min(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // multiplicity_of + set->flag = CMC_FLAG_ERROR; + cmc_assert_equals(size_t, 0, hms_multiplicity_of(set, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // contains + set->flag = CMC_FLAG_ERROR; + cmc_assert(!hms_contains(set, 10)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + + // copy_of + set->flag = CMC_FLAG_ERROR; + struct hashmultiset *set2 = hms_copy_of(set); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set2)); + + // equals + set->flag = CMC_FLAG_ERROR; + set2->flag = CMC_FLAG_ERROR; + cmc_assert(hms_equals(set, set2)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hms_flag(set2)); + + hms_free(set); + hms_free(set2); + }); + + CMC_CREATE_TEST(callbacks, { + struct hashmultiset *set = hms_new_custom(100, 0.8, hms_fval, NULL, callbacks); + + cmc_assert_not_equals(ptr, NULL, set); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + + cmc_assert(hms_insert(set, 1)); + cmc_assert_equals(int32_t, 1, total_create); + + cmc_assert(hms_insert_many(set, 1, 3)); + cmc_assert_equals(int32_t, 2, total_create); + + cmc_assert(hms_update(set, 1, 0)); + cmc_assert_equals(int32_t, 1, total_update); + + cmc_assert(hms_update(set, 1, 10)); + cmc_assert_equals(int32_t, 2, total_update); + + cmc_assert(hms_remove(set, 1)); + cmc_assert_equals(int32_t, 1, total_delete); + + cmc_assert(hms_remove_all(set, 1)); + cmc_assert_equals(int32_t, 2, total_delete); + + cmc_assert(hms_update(set, 1, 10)); + cmc_assert_equals(int32_t, 3, total_update); + + cmc_assert(hms_max(set, NULL)); + cmc_assert_equals(int32_t, 1, total_read); + + cmc_assert(hms_min(set, NULL)); + cmc_assert_equals(int32_t, 2, total_read); + + cmc_assert(hms_contains(set, 1)); + cmc_assert_equals(int32_t, 3, total_read); + + cmc_assert(hms_resize(set, 1000)); + cmc_assert_equals(int32_t, 1, total_resize); + + cmc_assert(hms_resize(set, 100)); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(int32_t, 2, total_create); + cmc_assert_equals(int32_t, 3, total_read); + cmc_assert_equals(int32_t, 3, total_update); + cmc_assert_equals(int32_t, 2, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + hms_customize(set, NULL, NULL); + + cmc_assert_equals(ptr, NULL, set->callbacks); + + hms_clear(set); + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert_many(set, 1, 3)); + cmc_assert(hms_update(set, 1, 0)); + cmc_assert(hms_update(set, 1, 10)); + cmc_assert(hms_remove(set, 1)); + cmc_assert(hms_remove_all(set, 1)); + cmc_assert(hms_update(set, 1, 10)); + cmc_assert(hms_max(set, NULL)); + cmc_assert(hms_min(set, NULL)); + cmc_assert(hms_contains(set, 1)); + cmc_assert(hms_resize(set, 1000)); + cmc_assert(hms_resize(set, 100)); + + cmc_assert_equals(int32_t, 2, total_create); + cmc_assert_equals(int32_t, 3, total_read); + cmc_assert_equals(int32_t, 3, total_update); + cmc_assert_equals(int32_t, 2, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(ptr, NULL, set->callbacks); + + hms_free(set); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + }); +}); + +struct hashmultiset_fval *hms_fval_numhash = &(struct hashmultiset_fval){ + .cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = numhash, .pri = cmc_size_cmp +}; + +CMC_CREATE_UNIT(CMCHashMultiSetIter, true, { + CMC_CREATE_TEST(PFX##_iter_start(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_start(set); + + cmc_assert_equals(ptr, set, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(size_t, 0, it.index); + cmc_assert_equals(size_t, 0, it.first); + cmc_assert_equals(size_t, 0, it.last); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(hms_iter_at_start(&it)); + cmc_assert(hms_iter_at_end(&it)); + + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 3)); + + it = hms_iter_start(set); + + cmc_assert_equals(size_t, 0, it.index); + + cmc_assert_equals(size_t, 1, it.cursor); + cmc_assert_equals(size_t, 1, it.first); + cmc_assert_equals(size_t, 3, it.last); + cmc_assert_equals(bool, false, it.end); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_end(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + + cmc_assert_equals(ptr, set, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(size_t, 0, it.index); + cmc_assert_equals(size_t, 0, it.first); + cmc_assert_equals(size_t, 0, it.last); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(hms_iter_at_start(&it)); + cmc_assert(hms_iter_at_end(&it)); + + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + cmc_assert(hms_insert(set, 3)); + + it = hms_iter_end(set); + + cmc_assert_equals(size_t, set->count - 1, it.index); + + cmc_assert_equals(size_t, 3, it.cursor); + cmc_assert_equals(size_t, 1, it.first); + cmc_assert_equals(size_t, 3, it.last); + cmc_assert_equals(bool, false, it.start); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_at_start(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_start(set); + + // Empty checks + cmc_assert(hms_iter_at_start(&it)); + it = hms_iter_end(set); + cmc_assert(hms_iter_at_start(&it)); + + // Non-empty checks + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + it = hms_iter_end(set); + cmc_assert(!hms_iter_at_start(&it)); + it = hms_iter_start(set); + cmc_assert(hms_iter_at_start(&it)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_at_end(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_start(set); + + // Empty check + cmc_assert(hms_iter_at_end(&it)); + it = hms_iter_end(set); + cmc_assert(hms_iter_at_end(&it)); + + // Non-empty checks + cmc_assert(hms_insert(set, 1)); + cmc_assert(hms_insert(set, 2)); + it = hms_iter_end(set); + cmc_assert(hms_iter_at_end(&it)); + it = hms_iter_start(set); + cmc_assert(!hms_iter_at_end(&it)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_to_start(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_start(set); + + cmc_assert(!hms_iter_to_start(&it)); + + for (size_t i = 1; i <= 100; i++) + hms_insert(set, i); + + cmc_assert_equals(size_t, 100, set->count); + + it = hms_iter_end(set); + + cmc_assert(!hms_iter_at_start(&it)); + cmc_assert(hms_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hms_iter_value(&it)); + + cmc_assert(hms_iter_to_start(&it)); + + cmc_assert(hms_iter_at_start(&it)); + cmc_assert(!hms_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hms_iter_value(&it)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_to_end(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + + cmc_assert(!hms_iter_to_end(&it)); + + for (size_t i = 1; i <= 100; i++) + hms_insert(set, i); + + it = hms_iter_start(set); + + cmc_assert(hms_iter_at_start(&it)); + cmc_assert(!hms_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hms_iter_value(&it)); + + cmc_assert(hms_iter_to_end(&it)); + + cmc_assert(!hms_iter_at_start(&it)); + cmc_assert(hms_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hms_iter_value(&it)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_next(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_start(set); + + cmc_assert(!hms_iter_next(&it)); + + for (size_t i = 1; i <= 1000; i++) + hms_insert(set, i); + + size_t sum = 0; + for (it = hms_iter_start(set); !hms_iter_at_end(&it); hms_iter_next(&it)) + { + sum += hms_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hms_iter_to_start(&it); + do + { + sum += hms_iter_value(&it); + } while (hms_iter_next(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_prev(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + + cmc_assert(!hms_iter_prev(&it)); + + for (size_t i = 1; i <= 1000; i++) + hms_insert(set, i); + + size_t sum = 0; + for (it = hms_iter_end(set); !hms_iter_at_start(&it); hms_iter_prev(&it)) + { + sum += hms_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hms_iter_to_end(&it); + do + { + sum += hms_iter_value(&it); + } while (hms_iter_prev(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_advance(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_start(set); + + cmc_assert(!hms_iter_advance(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hms_insert(set, i); + + it = hms_iter_start(set); + + cmc_assert(!hms_iter_advance(&it, 0)); + cmc_assert(!hms_iter_advance(&it, set->count)); + + size_t sum = 0; + for (it = hms_iter_start(set);;) + { + sum += hms_iter_value(&it); + + if (!hms_iter_advance(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hms_iter_to_start(&it); + cmc_assert(hms_iter_advance(&it, set->count - 1)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_rewind(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + + cmc_assert(!hms_iter_rewind(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hms_insert(set, i); + + it = hms_iter_end(set); + + cmc_assert(!hms_iter_rewind(&it, 0)); + cmc_assert(!hms_iter_rewind(&it, set->count)); + + size_t sum = 0; + for (it = hms_iter_end(set);;) + { + sum += hms_iter_value(&it); + + if (!hms_iter_rewind(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hms_iter_to_end(&it); + cmc_assert(hms_iter_rewind(&it, set->count - 1)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_go_to(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + cmc_assert(!hms_iter_go_to(&it, 0)); + + it = hms_iter_start(set); + cmc_assert(!hms_iter_go_to(&it, 0)); + + for (size_t i = 0; i <= 1000; i++) + hms_insert(set, i); + + it = hms_iter_start(set); + + size_t sum = 0; + for (size_t i = 0; i < 1001; i++) + { + hms_iter_go_to(&it, i); + + sum += hms_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 1001; i > 0; i--) + { + cmc_assert(hms_iter_go_to(&it, i - 1)); + + sum += hms_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 0; i < 1001; i += 100) + { + cmc_assert(hms_iter_go_to(&it, i)); + cmc_assert_equals(size_t, i, hms_iter_index(&it)); + + sum += hms_iter_value(&it); + } + + cmc_assert_equals(size_t, 5500, sum); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_value(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + + cmc_assert_equals(size_t, (size_t){ 0 }, hms_iter_value(&it)); + + cmc_assert(hms_insert(set, 10)); + + it = hms_iter_start(set); + + cmc_assert_equals(size_t, 10, hms_iter_value(&it)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_multiplicity(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashmultiset_iter it = hms_iter_end(set); + + cmc_assert_equals(size_t, (size_t){ 0 }, hms_iter_multiplicity(&it)); + + cmc_assert(hms_insert_many(set, 10, 5)); + + it = hms_iter_start(set); + cmc_assert_equals(size_t, 5, hms_iter_multiplicity(&it)); + + it = hms_iter_end(set); + cmc_assert_equals(size_t, 5, hms_iter_multiplicity(&it)); + + hms_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_index(), { + struct hashmultiset *set = hms_new(100, 0.6, hms_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i <= 1000; i++) + hms_insert(set, i); + + struct hashmultiset_iter it = hms_iter_start(set); + + for (size_t i = 0; i < 1001; i++) + { + cmc_assert_equals(size_t, i, hms_iter_index(&it)); + hms_iter_next(&it); + } + + it = hms_iter_end(set); + for (size_t i = 1001; i > 0; i--) + { + cmc_assert_equals(size_t, i - 1, hms_iter_index(&it)); + hms_iter_prev(&it); + } + + hms_free(set); + }); +}); + +#ifdef CMC_TEST_MAIN +int main(void) +{ + int result = CMCHashMultiSet() + CMCHashMultiSetIter(); + + printf(" +---------------------------------------------------------------+"); + printf("\n"); + printf(" | CMCHashMultiSet Suit : %-41s |\n", result == 0 ? "PASSED" : "FAILED"); + printf(" +---------------------------------------------------------------+"); + printf("\n\n\n"); + + return result; +} +#endif + +#endif /* CMC_TESTS_UNT_HASHMULTISET_H */ diff --git a/tests/unt_hashset.h b/tests/unt_hashset.h new file mode 100644 index 0000000..b381f97 --- /dev/null +++ b/tests/unt_hashset.h @@ -0,0 +1,1051 @@ +#ifndef CMC_TESTS_UNT_HASHSET_H +#define CMC_TESTS_UNT_HASHSET_H + +#include "utl.h" + +#define V size_t +#define PFX hs +#define SNAME hashset +#define CMC_EXT_HASHSET_INIT +#define CMC_EXT_HASHSET_ITER +#define CMC_EXT_HASHSET_SETF +#define CMC_EXT_HASHSET_STR +#include "cmc/hashset.h" + +struct hashset_fval *hs_fval = &(struct hashset_fval){ + .cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = cmc_size_hash, .pri = cmc_size_cmp +}; + +struct hashset_fval *hs_fval_counter = &(struct hashset_fval){ + .cmp = v_c_cmp, .cpy = v_c_cpy, .str = v_c_str, .free = v_c_free, .hash = v_c_hash, .pri = v_c_pri +}; + +struct cmc_alloc_node *hs_alloc_node = + &(struct cmc_alloc_node){ .malloc = malloc, .calloc = calloc, .realloc = realloc, .free = free }; + +CMC_CREATE_UNIT(CMCHashSet, true, { + CMC_CREATE_TEST(PFX##_new(), { + struct hashset *set = hs_new(943722, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_not_equals(ptr, NULL, set->buffer); + cmc_assert_equals(size_t, 0, set->count); + cmc_assert_equals(double, 0.6, set->load); + cmc_assert_equals(int32_t, CMC_FLAG_OK, set->flag); + cmc_assert_equals(ptr, hs_fval, set->f_val); + cmc_assert_equals(ptr, cmc_alloc_node_default.malloc, set->alloc->malloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.calloc, set->alloc->calloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.realloc, set->alloc->realloc); + cmc_assert_equals(ptr, cmc_alloc_node_default.free, set->alloc->free); + cmc_assert_equals(ptr, NULL, set->callbacks); + + cmc_assert_greater_equals(size_t, (943722 / 0.6), hs_capacity(set)); + + hs_free(set); + + set = hs_new(0, 0.6, hs_fval); + cmc_assert_equals(ptr, NULL, set); + + set = hs_new(UINT64_MAX, 0.99, hs_fval); + cmc_assert_equals(ptr, NULL, set); + + set = hs_new(1000, 0.6, NULL); + cmc_assert_equals(ptr, NULL, set); + + set = hs_new(1000, 0.6, NULL); + cmc_assert_equals(ptr, NULL, set); + }); + + CMC_CREATE_TEST(PFX##_new_custom(), { + struct hashset *set = hs_new_custom(943722, 0.6, hs_fval, hs_alloc_node, callbacks); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_not_equals(ptr, NULL, set->buffer); + cmc_assert_equals(size_t, 0, set->count); + cmc_assert_equals(double, 0.6, set->load); + cmc_assert_equals(int32_t, CMC_FLAG_OK, set->flag); + cmc_assert_equals(ptr, hs_fval, set->f_val); + cmc_assert_equals(ptr, hs_alloc_node, set->alloc); + cmc_assert_equals(ptr, callbacks, set->callbacks); + + cmc_assert_greater_equals(size_t, (943722 / 0.6), hs_capacity(set)); + + hs_free(set); + + set = hs_new_custom(0, 0.6, hs_fval, NULL, NULL); + cmc_assert_equals(ptr, NULL, set); + + set = hs_new_custom(UINT64_MAX, 0.99, hs_fval, NULL, NULL); + cmc_assert_equals(ptr, NULL, set); + + set = hs_new_custom(1000, 0.6, NULL, NULL, NULL); + cmc_assert_equals(ptr, NULL, set); + }); + + CMC_CREATE_TEST(PFX##_clear(), { + v_total_free = 0; + struct hashset *set = hs_new(100, 0.6, hs_fval_counter); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i <= 1000; i++) + hs_insert(set, i); + + cmc_assert_equals(size_t, 1000, set->count); + + set->flag = CMC_FLAG_ERROR; + hs_clear(set); + + cmc_assert_equals(size_t, 0, set->count); + cmc_assert_equals(int32_t, CMC_FLAG_OK, set->flag); + cmc_assert_equals(int32_t, 1000, v_total_free); + + hs_free(set); + v_total_free = 0; + }); + + CMC_CREATE_TEST(PFX##_free(), { + v_total_free = 0; + struct hashset *set = hs_new(100, 0.6, hs_fval_counter); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i <= 1000; i++) + hs_insert(set, i); + + cmc_assert_equals(size_t, 1000, set->count); + + hs_free(set); + + cmc_assert_equals(int32_t, 1000, v_total_free); + + set = hs_new(1000, 0.6, hs_fval_counter); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_not_equals(ptr, NULL, set->buffer); + + hs_free(set); + + cmc_assert_equals(int32_t, 1000, v_total_free); + v_total_free = 0; + }); + + CMC_CREATE_TEST(insert, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(hs_insert(set, 1)); + cmc_assert_equals(size_t, 1, hs_count(set)); + + hs_free(set); + }); + + CMC_CREATE_TEST(insert[smallest capacity], { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set)); + cmc_assert(hs_insert(set, 1)); + + hs_free(set); + }); + + CMC_CREATE_TEST(insert[element position], { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + // Temporary change + // Using the numhash the key is the hash itself + hs_fval->hash = numhash; + + cmc_assert_not_equals(ptr, NULL, set); + + size_t capacity = hs_capacity(set); + + cmc_assert_greater(size_t, 0, capacity); + + cmc_assert(hs_insert(set, capacity - 1)); + cmc_assert(hs_insert(set, capacity)); + + cmc_assert_equals(size_t, capacity - 1, set->buffer[capacity - 1].value); + cmc_assert_equals(size_t, capacity, set->buffer[0].value); + + hs_fval->hash = cmc_size_hash; + + hs_free(set); + }); + + CMC_CREATE_TEST(insert[distance], { + struct hashset *set = hs_new(500, 0.6, hs_fval); + + // Temporary change + hs_fval->hash = hash0; + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 200; i++) + cmc_assert(hs_insert(set, i)); + + // Everything is hashed to 0 so key 0 should have dist 0, key 1 dist 1, + // etc + for (size_t i = 0; i < 200; i++) + cmc_assert_equals(size_t, i, set->buffer[i].dist); + + hs_fval->hash = cmc_size_hash; + + hs_free(set); + }); + + CMC_CREATE_TEST(insert[distance wrap], { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + // Temporary change + hs_fval->hash = hashcapminus1; + + cmc_assert_not_equals(ptr, NULL, set); + + size_t capacity = hs_capacity(set); + + // Just to be sure, not part of the test + cmc_assert_equals(size_t, cmc_hashtable_primes[0] - 1, hashcapminus1(0)); + cmc_assert_equals(size_t, capacity - 1, hashcapminus1(0)); + + cmc_assert(hs_insert(set, 0)); + cmc_assert(hs_insert(set, 1)); + + cmc_assert_equals(size_t, 0, set->buffer[capacity - 1].dist); + cmc_assert_equals(size_t, 1, set->buffer[0].dist); + + hs_fval->hash = cmc_size_hash; + + hs_free(set); + }); + + CMC_CREATE_TEST(insert[distances], { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + // Temporary change + hs_fval->hash = hashcapminus4; + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set)); + + for (size_t i = 0; i < 6; i++) + cmc_assert(hs_insert(set, i)); + + // for (size_t i = 0; i < 6; i++) + // cmc_assert_equals(size_t, i, hs_impl_get_entry(set, i)->dist); + + hs_fval->hash = cmc_size_hash; + + hs_free(set); + }); + + CMC_CREATE_TEST(insert[buffer growth and item preservation], { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set)); + + size_t p = 0; + for (size_t i = 0; i < 100000; i++) + { + if (hs_full(set)) + p++; + + cmc_assert(hs_insert(set, i)); + } + + cmc_assert_equals(size_t, cmc_hashtable_primes[p], hs_capacity(set)); + + for (size_t i = 0; i < 100000; i++) + cmc_assert(hs_contains(set, i)); + + hs_free(set); + }); + + CMC_CREATE_TEST(remove, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hs_insert(set, i)); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hs_remove(set, i)); + + hs_free(set); + }); + + CMC_CREATE_TEST(remove[count = 0], { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 100; i < 200; i++) + cmc_assert(!hs_remove(set, i)); + + hs_free(set); + }); + + CMC_CREATE_TEST(remove[key not found], { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hs_insert(set, i)); + + for (size_t i = 100; i < 200; i++) + cmc_assert(!hs_remove(set, i)); + + hs_free(set); + }); + + CMC_CREATE_TEST(max, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(hs_insert(set, i)); + + size_t val; + cmc_assert(hs_max(set, &val)); + + cmc_assert_equals(size_t, 100, val); + + hs_free(set); + }); + + CMC_CREATE_TEST(max[count = 0], { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(!hs_min(set, NULL)); + + hs_free(set); + }); + + CMC_CREATE_TEST(min, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(hs_insert(set, i)); + + size_t val; + cmc_assert(hs_min(set, &val)); + + cmc_assert_equals(size_t, 1, val); + + hs_free(set); + }); + + CMC_CREATE_TEST(min[count = 0], { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(!hs_min(set, NULL)); + + hs_free(set); + }); + + CMC_CREATE_TEST(contains, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(hs_insert(set, 987654321)); + + cmc_assert(hs_contains(set, 987654321)); + + hs_free(set); + }); + + CMC_CREATE_TEST(contains[count = 0], { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(!hs_contains(set, 987654321)); + + hs_free(set); + }); + + CMC_CREATE_TEST(contains[sum], { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 101; i <= 200; i++) + cmc_assert(hs_insert(set, i)); + + size_t sum = 0; + for (size_t i = 1; i <= 300; i++) + if (hs_contains(set, i)) + sum += i; + + cmc_assert_equals(size_t, 15050, sum); + + hs_free(set); + }); + + CMC_CREATE_TEST(empty, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(hs_empty(set)); + + cmc_assert(hs_insert(set, 1)); + + cmc_assert(!hs_empty(set)); + + hs_free(set); + }); + + CMC_CREATE_TEST(full, { + struct hashset *set = hs_new(cmc_hashtable_primes[0], 0.99999, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set)); + + for (size_t i = 0; i < hs_capacity(set); i++) + cmc_assert(hs_insert(set, i)); + + cmc_assert(hs_full(set)); + + cmc_assert(hs_insert(set, 10000)); + + cmc_assert_equals(size_t, cmc_hashtable_primes[1], hs_capacity(set)); + + cmc_assert(!hs_full(set)); + + hs_free(set); + }); + + CMC_CREATE_TEST(count, { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 1; i < 100; i++) + { + cmc_assert(hs_insert(set, i)); + cmc_assert_equals(size_t, i, hs_count(set)); + } + + hs_free(set); + }); + + CMC_CREATE_TEST(capacity, { + struct hashset *set = hs_new(2500, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_greater_equals(size_t, (size_t)(2500 / 0.6), hs_capacity(set)); + + hs_free(set); + }); + + CMC_CREATE_TEST(capacity[small], { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hs_capacity(set)); + + hs_free(set); + }); + + CMC_CREATE_TEST(load, { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert_in_range(double, 0.99 - 0.0001, 0.99 + 0.0001, hs_load(set)); + + hs_free(set); + }); + + CMC_CREATE_TEST(flags, { + struct hashset *set = hs_new(1, 0.99, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + + // insert + cmc_assert(hs_insert(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + cmc_assert(!hs_insert(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_DUPLICATE, hs_flag(set)); + + // clear + hs_clear(set); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + + cmc_assert(hs_insert(set, 1)); + + // remove + cmc_assert(!hs_remove(set, 2)); + cmc_assert_equals(int32_t, CMC_FLAG_NOT_FOUND, hs_flag(set)); + + cmc_assert(hs_remove(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + + cmc_assert(!hs_remove(set, 1)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hs_flag(set)); + + // max + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_max(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + + cmc_assert(hs_remove(set, 1)); + cmc_assert(!hs_max(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hs_flag(set)); + + // min + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_min(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + + cmc_assert(hs_remove(set, 1)); + cmc_assert(!hs_min(set, NULL)); + cmc_assert_equals(int32_t, CMC_FLAG_EMPTY, hs_flag(set)); + + // contains + hs_contains(set, 1); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + + // copy + set->flag = CMC_FLAG_ERROR; + struct hashset *set2 = hs_copy_of(set); + + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set2)); + + size_t tmp = set->capacity; + set->capacity = 0; + + struct hashset *set3 = hs_copy_of(set); + cmc_assert_equals(ptr, NULL, set3); + + cmc_assert_equals(int32_t, CMC_FLAG_ERROR, hs_flag(set)); + + set->capacity = tmp; + + cmc_assert(hs_equals(set, set2)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set)); + cmc_assert_equals(int32_t, CMC_FLAG_OK, hs_flag(set2)); + + hs_free(set); + hs_free(set2); + }); + + CMC_CREATE_TEST(callbacks, { + struct hashset *set = hs_new_custom(100, 0.6, hs_fval, NULL, callbacks); + + cmc_assert_not_equals(ptr, NULL, set); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + + cmc_assert(hs_insert(set, 1)); + cmc_assert_equals(int32_t, 1, total_create); + + cmc_assert(hs_remove(set, 1)); + cmc_assert_equals(int32_t, 1, total_delete); + + cmc_assert(hs_insert(set, 1)); + cmc_assert_equals(int32_t, 2, total_create); + + cmc_assert(hs_max(set, NULL)); + cmc_assert_equals(int32_t, 1, total_read); + + cmc_assert(hs_min(set, NULL)); + cmc_assert_equals(int32_t, 2, total_read); + + cmc_assert(hs_contains(set, 1)); + cmc_assert_equals(int32_t, 3, total_read); + + cmc_assert(hs_resize(set, 10000)); + cmc_assert_equals(int32_t, 1, total_resize); + + cmc_assert(hs_resize(set, 500)); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(int32_t, 2, total_create); + cmc_assert_equals(int32_t, 3, total_read); + cmc_assert_equals(int32_t, 0, total_update); + cmc_assert_equals(int32_t, 1, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + hs_customize(set, NULL, NULL); + + cmc_assert_equals(ptr, NULL, set->callbacks); + + hs_clear(set); + cmc_assert(hs_resize(set, 10000)); + cmc_assert(hs_resize(set, 500)); + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_remove(set, 1)); + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_max(set, NULL)); + cmc_assert(hs_min(set, NULL)); + cmc_assert(hs_contains(set, 1)); + + cmc_assert_equals(int32_t, 2, total_create); + cmc_assert_equals(int32_t, 3, total_read); + cmc_assert_equals(int32_t, 0, total_update); + cmc_assert_equals(int32_t, 1, total_delete); + cmc_assert_equals(int32_t, 2, total_resize); + + cmc_assert_equals(ptr, NULL, set->callbacks); + + hs_free(set); + + total_create = 0; + total_read = 0; + total_update = 0; + total_delete = 0; + total_resize = 0; + }); +}); + +struct hashset_fval *hs_fval_numhash = &(struct hashset_fval){ + .cmp = cmc_size_cmp, .cpy = NULL, .str = cmc_size_str, .free = NULL, .hash = numhash, .pri = cmc_size_cmp +}; + +CMC_CREATE_UNIT(CMCHashSetIter, true, { + CMC_CREATE_TEST(PFX##_iter_start(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_start(set); + + cmc_assert_equals(ptr, set, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(size_t, 0, it.index); + cmc_assert_equals(size_t, 0, it.first); + cmc_assert_equals(size_t, 0, it.last); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(hs_iter_at_start(&it)); + cmc_assert(hs_iter_at_end(&it)); + + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_insert(set, 2)); + cmc_assert(hs_insert(set, 3)); + + it = hs_iter_start(set); + + cmc_assert_equals(size_t, 0, it.index); + + cmc_assert_equals(size_t, 1, it.cursor); + cmc_assert_equals(size_t, 1, it.first); + cmc_assert_equals(size_t, 3, it.last); + cmc_assert_equals(bool, false, it.end); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_end(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_end(set); + + cmc_assert_equals(ptr, set, it.target); + cmc_assert_equals(size_t, 0, it.cursor); + cmc_assert_equals(size_t, 0, it.index); + cmc_assert_equals(size_t, 0, it.first); + cmc_assert_equals(size_t, 0, it.last); + cmc_assert_equals(bool, true, it.start); + cmc_assert_equals(bool, true, it.end); + + cmc_assert(hs_iter_at_start(&it)); + cmc_assert(hs_iter_at_end(&it)); + + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_insert(set, 2)); + cmc_assert(hs_insert(set, 3)); + + it = hs_iter_end(set); + + cmc_assert_equals(size_t, set->count - 1, it.index); + + cmc_assert_equals(size_t, 3, it.cursor); + cmc_assert_equals(size_t, 1, it.first); + cmc_assert_equals(size_t, 3, it.last); + cmc_assert_equals(bool, false, it.start); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_at_start(), { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_start(set); + + // Empty checks + cmc_assert(hs_iter_at_start(&it)); + it = hs_iter_end(set); + cmc_assert(hs_iter_at_start(&it)); + + // Non-empty checks + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_insert(set, 2)); + it = hs_iter_end(set); + cmc_assert(!hs_iter_at_start(&it)); + it = hs_iter_start(set); + cmc_assert(hs_iter_at_start(&it)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_at_end(), { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_start(set); + + // Empty check + cmc_assert(hs_iter_at_end(&it)); + it = hs_iter_end(set); + cmc_assert(hs_iter_at_end(&it)); + + // Non-empty checks + cmc_assert(hs_insert(set, 1)); + cmc_assert(hs_insert(set, 2)); + it = hs_iter_end(set); + cmc_assert(hs_iter_at_end(&it)); + it = hs_iter_start(set); + cmc_assert(!hs_iter_at_end(&it)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_to_start(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_start(set); + + cmc_assert(!hs_iter_to_start(&it)); + + for (size_t i = 1; i <= 100; i++) + hs_insert(set, i); + + cmc_assert_equals(size_t, 100, set->count); + + it = hs_iter_end(set); + + cmc_assert(!hs_iter_at_start(&it)); + cmc_assert(hs_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hs_iter_value(&it)); + + cmc_assert(hs_iter_to_start(&it)); + + cmc_assert(hs_iter_at_start(&it)); + cmc_assert(!hs_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hs_iter_value(&it)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_to_end(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_end(set); + + cmc_assert(!hs_iter_to_end(&it)); + + for (size_t i = 1; i <= 100; i++) + hs_insert(set, i); + + it = hs_iter_start(set); + + cmc_assert(hs_iter_at_start(&it)); + cmc_assert(!hs_iter_at_end(&it)); + + cmc_assert_equals(size_t, 1, hs_iter_value(&it)); + + cmc_assert(hs_iter_to_end(&it)); + + cmc_assert(!hs_iter_at_start(&it)); + cmc_assert(hs_iter_at_end(&it)); + + cmc_assert_equals(size_t, 100, hs_iter_value(&it)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_next(), { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_start(set); + + cmc_assert(!hs_iter_next(&it)); + + for (size_t i = 1; i <= 1000; i++) + hs_insert(set, i); + + size_t sum = 0; + for (it = hs_iter_start(set); !hs_iter_at_end(&it); hs_iter_next(&it)) + { + sum += hs_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hs_iter_to_start(&it); + do + { + sum += hs_iter_value(&it); + } while (hs_iter_next(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_prev(), { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_end(set); + + cmc_assert(!hs_iter_prev(&it)); + + for (size_t i = 1; i <= 1000; i++) + hs_insert(set, i); + + size_t sum = 0; + for (it = hs_iter_end(set); !hs_iter_at_start(&it); hs_iter_prev(&it)) + { + sum += hs_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + + hs_iter_to_end(&it); + do + { + sum += hs_iter_value(&it); + } while (hs_iter_prev(&it)); + + cmc_assert_equals(size_t, 500500, sum); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_advance(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_start(set); + + cmc_assert(!hs_iter_advance(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hs_insert(set, i); + + it = hs_iter_start(set); + + cmc_assert(!hs_iter_advance(&it, 0)); + cmc_assert(!hs_iter_advance(&it, set->count)); + + size_t sum = 0; + for (it = hs_iter_start(set);;) + { + sum += hs_iter_value(&it); + + if (!hs_iter_advance(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hs_iter_to_start(&it); + cmc_assert(hs_iter_advance(&it, set->count - 1)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_rewind(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_end(set); + + cmc_assert(!hs_iter_rewind(&it, 1)); + + for (size_t i = 0; i <= 1000; i++) + hs_insert(set, i); + + it = hs_iter_end(set); + + cmc_assert(!hs_iter_rewind(&it, 0)); + cmc_assert(!hs_iter_rewind(&it, set->count)); + + size_t sum = 0; + for (it = hs_iter_end(set);;) + { + sum += hs_iter_value(&it); + + if (!hs_iter_rewind(&it, 2)) + break; + } + + cmc_assert_equals(size_t, 250500, sum); + + hs_iter_to_end(&it); + cmc_assert(hs_iter_rewind(&it, set->count - 1)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_go_to(), { + struct hashset *set = hs_new(100, 0.6, hs_fval_numhash); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_end(set); + cmc_assert(!hs_iter_go_to(&it, 0)); + + it = hs_iter_start(set); + cmc_assert(!hs_iter_go_to(&it, 0)); + + for (size_t i = 0; i <= 1000; i++) + hs_insert(set, i); + + it = hs_iter_start(set); + + size_t sum = 0; + for (size_t i = 0; i < 1001; i++) + { + hs_iter_go_to(&it, i); + + sum += hs_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 1001; i > 0; i--) + { + cmc_assert(hs_iter_go_to(&it, i - 1)); + + sum += hs_iter_value(&it); + } + + cmc_assert_equals(size_t, 500500, sum); + + sum = 0; + for (size_t i = 0; i < 1001; i += 100) + { + cmc_assert(hs_iter_go_to(&it, i)); + cmc_assert_equals(size_t, i, hs_iter_index(&it)); + + sum += hs_iter_value(&it); + } + + cmc_assert_equals(size_t, 5500, sum); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_value(), { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + struct hashset_iter it = hs_iter_end(set); + + cmc_assert_equals(size_t, (size_t){ 0 }, hs_iter_value(&it)); + + cmc_assert(hs_insert(set, 10)); + + it = hs_iter_start(set); + + cmc_assert_equals(size_t, 10, hs_iter_value(&it)); + + hs_free(set); + }); + + CMC_CREATE_TEST(PFX##_iter_index(), { + struct hashset *set = hs_new(100, 0.6, hs_fval); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i <= 1000; i++) + hs_insert(set, i); + + struct hashset_iter it = hs_iter_start(set); + + for (size_t i = 0; i < 1001; i++) + { + cmc_assert_equals(size_t, i, hs_iter_index(&it)); + hs_iter_next(&it); + } + + it = hs_iter_end(set); + for (size_t i = 1001; i > 0; i--) + { + cmc_assert_equals(size_t, i - 1, hs_iter_index(&it)); + hs_iter_prev(&it); + } + + hs_free(set); + }); +}); + +#ifdef CMC_TEST_MAIN +int main(void) +{ + int result = CMCHashSet() + CMCHashSetIter(); + + printf(" +---------------------------------------------------------------+"); + printf("\n"); + printf(" | CMCHashSet Suit : %-46s |\n", result == 0 ? "PASSED" : "FAILED"); + printf(" +---------------------------------------------------------------+"); + printf("\n\n\n"); + + return result; +} +#endif + +#endif /* CMC_TESTS_UNT_HASHSET_H */