diff --git a/examples/multiset/multiset_operations.c b/examples/multiset/multiset_operations.c new file mode 100644 index 0000000..3208e5d --- /dev/null +++ b/examples/multiset/multiset_operations.c @@ -0,0 +1,119 @@ +/** + * multiset_operations.c + * + * Creation Date: 01/08/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ +#include +#include +#include +#include + +MULTISET_GENERATE(ms, multiset, , char) + +struct pair +{ + char value; + size_t mul; +}; + +int charcmp(char a, char b) +{ + return (a > b) - (a < b); +} + +size_t charhash(char a) +{ + return a; +} + +void print_set(multiset *M) +{ + cmc_assert_not_equals(ptr, NULL, M); + + size_t S = ms_count(M); + + printf("%s : ", ms_to_string(M).s); + + if (S == 0) + { + printf("{ EMPTY SET }\n"); + return; + } + + for (multiset_iter it = M->it_start(M); !ms_iter_end(&it); ms_iter_next(&it)) + { + size_t index = ms_iter_index(&it); + char value = ms_iter_value(&it); + size_t mul = ms_iter_multiplicity(&it); + + if (index == 0) + printf("{ %c:%" PRIuMAX ", ", value, mul); + else if (index == S - 1) + printf("%c:%" PRIuMAX " }\n", value, mul); + else + printf("%c:%" PRIuMAX ", ", value, mul); + } + +} + +int main(int argc, char const *argv[]) +{ + struct pair mset1[4] = {{'a', 2}, {'b', 1}, {'c', 3}, {'d', 1}}; + struct pair mset2[4] = {{'c', 1}, {'d', 3}, {'e', 1}, {'f', 2}}; + + multiset *A = ms_new(20, 0.6, charcmp, charhash); + multiset *B = ms_new(20, 0.6, charcmp, charhash); + + for (int i = 0; i < 4; i++) + { + cmc_assert(ms_insert_many(A, mset1[i].value, mset1[i].mul)); + cmc_assert(ms_insert_many(B, mset2[i].value, mset2[i].mul)); + } + + printf("Given two sets A and B:\n"); + print_set(A); + print_set(B); + + multiset *U = ms_union(A, B); + printf("\nA UNION B:\n"); + print_set(U); + + multiset *I = ms_intersection(A, B); + printf("\nA INTERSECTION B:\n"); + print_set(I); + + multiset *DA = ms_difference(A, B); + multiset *DB = ms_difference(B, A); + printf("\nA - B:\n"); + print_set(DA); + printf("\nB - A:\n"); + print_set(DB); + + multiset *AB = ms_summation(A, B); + printf("\nA + B:\n"); + print_set(AB); + + multiset *BA = ms_summation(B, A); + printf("\nB + A:\n"); + print_set(BA); + + multiset *SD = ms_symmetric_difference(A, B); + printf("\nA SYM DIFF B:\n"); + print_set(SD); + + ms_free(A); + ms_free(B); + ms_free(U); + ms_free(I); + ms_free(DA); + ms_free(DB); + ms_free(AB); + ms_free(BA); + ms_free(SD); + + return 0; +} diff --git a/examples/multiset/prime_cof.c b/examples/multiset/prime_cof.c deleted file mode 100644 index 16757a5..0000000 --- a/examples/multiset/prime_cof.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include "multiset.h" - -MULTISET_GENERATE(ms, multi_set, /* FMOD */, size_t) - -int cmp(size_t a, size_t b) -{ - if (a > b) - return 1; - else if (a < b) - return -1; - return 0; -} - -void prime_cof(const size_t number) -{ - multi_set *mset = ms_new(cmp); - - size_t num = number; - - for (size_t i = 2; num != 1; i++) - { - while (num % i == 0) - { - ms_insert(mset, i); - num /= i; - } - } - - printf("The factorization of %llu is given by:\n", number); - - multi_set_iter iter; - size_t result, mul, index; - for (ms_iter_new(&iter, mset); !ms_iter_end(&iter);) - { - if (!ms_iter_next(&iter, &result, &mul, &index)) - { - printf("ERROR\n"); - break; - } - - if (ms_count(mset) == 1) - printf("(%llu^%llu)\n", result, mul); - else if (index == 0) - printf("(%llu^%llu ", result, mul); - else if (index == ms_count(mset) - 1) - printf("* %llu^%llu)\n", result, mul); - else - printf("* %llu^%llu ", result, mul); - } - - printf("Set Cardinality: %llu\n\n", ms_cardinality(mset)); - - ms_free(mset); -} - -int main(int argc, char const *argv[]) -{ - prime_cof(360); - prime_cof(55777680); - prime_cof(4294967296); - prime_cof(31415926535); - prime_cof(27182818284); - prime_cof(16180339887); - - return 0; -} diff --git a/src/ext/multiset.h b/src/ext/multiset.h index eeacdbf..95a1ac3 100644 --- a/src/ext/multiset.h +++ b/src/ext/multiset.h @@ -8,829 +8,1052 @@ * */ -/*****************************************************************************/ -/****************************************************************** MULTISET */ -/*****************************************************************************/ +/** + * MultiSet + * + * 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. + */ #ifndef CMC_MULTISET_H #define CMC_MULTISET_H -#include #include +#include +#include +#include +#include "../utl/cmc_string.h" + +#ifndef CMC_HASH_TABLE_SETUP +#define CMC_HASH_TABLE_SETUP + +typedef enum cmc_entry_state_e +{ + CMC_ES_DELETED = -1, + CMC_ES_EMPTY = 0, + CMC_ES_FILLED = 1 +} cmc_entry_state; + +static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, + 3067, 6143, 12289, 24571, 49157, + 98299, 196613, 393209, 786431, + 1572869, 3145721, 6291449, + 12582917, 25165813, 50331653, + 100663291, 201326611, 402653189, + 805306357, 1610612741, + 3221225473, 6442450939, + 12884901893, 25769803799, + 51539607551, 103079215111, + 206158430209, 412316860441, + 824633720831, 1649267441651, + 3298534883309, 6597069766657, + 13194139533299, 26388279066623, + 52776558133303, 105553116266489, + 211106232532969, 422212465066001, + 844424930131963, + 1688849860263953, + 3377699720527861, + 6755399441055731, + 13510798882111483, + 27021597764222939, + 54043195528445957, + 108086391056891903, + 216172782113783773, + 432345564227567621, + 864691128455135207, + 1729382256910270481, + 3458764513820540933, + 6917529027641081903, + 13835058055282163729llu}; + +#endif /* CMC_HASH_TABLE_SETUP */ #define MULTISET_GENERATE(PFX, SNAME, FMOD, V) \ - MULTISET_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \ MULTISET_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ MULTISET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) -/* PRIVATE *******************************************************************/ -#define MULTISET_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, K, V) \ +#define MULTISET_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V) \ MULTISET_GENERATE_HEADER(PFX, SNAME, FMOD, V) -#define MULTISET_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, K, V) \ - MULTISET_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \ - MULTISET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ -/* PUBLIC ********************************************************************/ -#define MULTISET_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, K, V) \ - MULTISET_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \ - MULTISET_GENERATE_HEADER(PFX, SNAME, FMOD, V) -#define MULTISET_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \ - MULTISET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ -/* STRUCT ********************************************************************/ -#define MULTISET_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \ - \ - struct SNAME##_s \ - { \ - struct SNAME##_node_s *root; \ - size_t count; \ - size_t cardinality; \ - int (*cmp)(V, V); \ - }; \ - \ - struct SNAME##_node_s \ - { \ - V key; \ - size_t multiplicity; \ - unsigned char height; \ - struct SNAME##_node_s *right; \ - struct SNAME##_node_s *left; \ - struct SNAME##_node_s *parent; \ - }; \ - \ - struct SNAME##_iter_s \ - { \ - struct SNAME##_s *target; \ - struct SNAME##_node_s *cursor; \ - struct SNAME##_node_s *first; \ - struct SNAME##_node_s *last; \ - size_t index; \ - bool start; \ - bool end; \ - }; \ - \ + +#define MULTISET_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V) \ + MULTISET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) + /* HEADER ********************************************************************/ #define MULTISET_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ \ - typedef struct SNAME##_s SNAME; \ - typedef struct SNAME##_node_s SNAME##_node; \ - typedef struct SNAME##_iter_s SNAME##_iter; \ + /* Hashset Structure */ \ + typedef struct SNAME##_s \ + { \ + /* Array of Entries */ \ + struct SNAME##_entry_s *buffer; \ \ - FMOD SNAME *PFX##_new(int (*compare)(V, V)); \ + /* 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; \ + \ + /* Element comparison function */ \ + int (*cmp)(V, V); \ + \ + /* Element hash function */ \ + size_t (*hash)(V); \ + \ + /* Function that returns an iterator to the start of the hashset */ \ + struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ + \ + /* Function that returns an iterator to the end of the hashset */ \ + struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ + \ + } SNAME, *SNAME##_ptr; \ + \ + typedef struct SNAME##_entry_s \ + { \ + /* 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_e state; \ + \ + } SNAME##_entry, *SNAME##_entry_ptr; \ + \ + /* Hashset Iterator */ \ + typedef struct SNAME##_iter_s \ + { \ + /* Target Hashset */ \ + struct SNAME##_s *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; \ + \ + } SNAME##_iter, *SNAME##_iter_ptr; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ + FMOD SNAME *PFX##_new(size_t capacity, double load, int (*compare)(V, V), size_t (*hash)(V)); \ FMOD void PFX##_clear(SNAME *_set_); \ FMOD void PFX##_free(SNAME *_set_); \ + /* Collection Input and Output */ \ FMOD bool PFX##_insert(SNAME *_set_, V element); \ + FMOD bool PFX##_insert_many(SNAME *_set_, V element, size_t count); \ + FMOD bool PFX##_update(SNAME *_set_, V element, size_t multiplicity); \ FMOD bool PFX##_remove(SNAME *_set_, V element); \ + FMOD size_t PFX##_remove_all(SNAME *_set_, V element); \ + /* Conditional Input and Output */ \ FMOD bool PFX##_insert_if(SNAME *_set_, V element, bool condition); \ FMOD bool PFX##_remove_if(SNAME *_set_, V element, bool condition); \ - FMOD V PFX##_max(SNAME *_set_); \ - FMOD V PFX##_min(SNAME *_set_); \ + /* Element Access */ \ + FMOD bool PFX##_max(SNAME *_set_, V *value); \ + FMOD bool PFX##_min(SNAME *_set_, V *value); \ + FMOD size_t PFX##_multiplicity_of(SNAME *_set_, V element); \ + /* Collection State */ \ + FMOD bool PFX##_contains(SNAME *_set_, V element); \ FMOD bool PFX##_empty(SNAME *_set_); \ FMOD size_t PFX##_count(SNAME *_set_); \ FMOD size_t PFX##_cardinality(SNAME *_set_); \ + FMOD size_t PFX##_capacity(SNAME *_set_); \ + /* Collection Utility */ \ + FMOD cmc_string PFX##_to_string(SNAME *_set_); \ \ + /* Set Operations */ \ FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_); \ FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_); \ FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_); \ + FMOD SNAME *PFX##_summation(SNAME *_set1_, SNAME *_set2_); \ FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_); \ + FMOD bool PFX##_is_subset(SNAME *_set1_, SNAME *_set2_); \ + FMOD bool PFX##_is_superset(SNAME *_set1_, SNAME *_set2_); \ + FMOD bool PFX##_is_proper_subset(SNAME *_set1_, SNAME *_set2_); \ + FMOD bool PFX##_is_proper_superset(SNAME *_set1_, SNAME *_set2_); \ + FMOD bool PFX##_is_disjointset(SNAME *_set1_, SNAME *_set2_); \ \ - FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target); \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ + FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \ + FMOD void PFX##_iter_free(SNAME##_iter *iter); \ + /* Iterator Initialization */ \ + FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \ + /* Iterator State */ \ FMOD bool PFX##_iter_start(SNAME##_iter *iter); \ FMOD bool PFX##_iter_end(SNAME##_iter *iter); \ - FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \ - FMOD void PFX##_iter_toend(SNAME##_iter *iter); \ - FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *value, size_t *multiplicity, size_t *index); \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *value, size_t *multiplicity, size_t *index); \ + /* Iterator Movement */ \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \ + /* Iterator Access */ \ + FMOD V PFX##_iter_value(SNAME##_iter *iter); \ + FMOD size_t PFX##_iter_multiplicity(SNAME##_iter *iter); \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \ + \ + /* Default Value */ \ + static inline V PFX##_impl_default_value(void) \ + { \ + V _empty_value_; \ + \ + memset(&_empty_value_, 0, sizeof(V)); \ + \ + return _empty_value_; \ + } \ \ /* SOURCE ********************************************************************/ -#define MULTISET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ - \ - FMOD SNAME##_node *PFX##_new_node(V element); \ - FMOD SNAME##_node *PFX##_get_node(SNAME *_set_, V element); \ - FMOD unsigned char PFX##_h(SNAME##_node *node); \ - FMOD unsigned char PFX##_hupdate(SNAME##_node *node); \ - FMOD void PFX##_rotate_right(SNAME##_node **Z); \ - FMOD void PFX##_rotate_left(SNAME##_node **Z); \ - FMOD void PFX##_rebalance(SNAME *_set_, SNAME##_node *node); \ - \ - FMOD SNAME *PFX##_new(int (*compare)(V, V)) \ - { \ - SNAME *_set_ = malloc(sizeof(SNAME)); \ - \ - if (!_set_) \ - return NULL; \ - \ - _set_->count = 0; \ - _set_->cardinality = 0; \ - _set_->root = NULL; \ - _set_->cmp = compare; \ - \ - return _set_; \ - } \ - \ - FMOD void PFX##_clear(SNAME *_set_) \ - { \ - SNAME##_node *scan = _set_->root; \ - SNAME##_node *up = NULL; \ - \ - while (scan != NULL) \ - { \ - if (scan->left != NULL) \ - { \ - SNAME##_node *left = scan->left; \ - \ - scan->left = up; \ - up = scan; \ - scan = left; \ - } \ - else if (scan->right != NULL) \ - { \ - SNAME##_node *right = scan->right; \ - \ - scan->left = up; \ - scan->right = NULL; \ - up = scan; \ - scan = right; \ - } \ - else \ - { \ - if (up == NULL) \ - { \ - free(scan); \ - scan = NULL; \ - } \ - \ - while (up != NULL) \ - { \ - free(scan); \ - \ - if (up->right != NULL) \ - { \ - scan = up->right; \ - up->right = NULL; \ - break; \ - } \ - else \ - { \ - scan = up; \ - up = up->left; \ - } \ - } \ - } \ - } \ - \ - _set_->count = 0; \ - _set_->cardinality = 0; \ - _set_->root = NULL; \ - } \ - \ - FMOD void PFX##_free(SNAME *_set_) \ - { \ - PFX##_clear(_set_); \ - \ - free(_set_); \ - } \ - \ - FMOD bool PFX##_insert(SNAME *_set_, V element) \ - { \ - if (PFX##_empty(_set_)) \ - { \ - _set_->root = PFX##_new_node(element); \ - \ - if (!_set_->root) \ - return false; \ - } \ - else \ - { \ - SNAME##_node *scan = _set_->root; \ - SNAME##_node *parent = scan; \ - \ - while (scan != NULL) \ - { \ - parent = scan; \ - \ - if (_set_->cmp(scan->key, element) > 0) \ - scan = scan->left; \ - else if (_set_->cmp(scan->key, element) < 0) \ - scan = scan->right; \ - else \ - { \ - scan->multiplicity++; \ - _set_->cardinality++; \ - \ - return true; \ - } \ - } \ - \ - SNAME##_node *node; \ - \ - if (_set_->cmp(parent->key, element) > 0) \ - { \ - parent->left = PFX##_new_node(element); \ - \ - if (!parent->left) \ - return false; \ - \ - parent->left->parent = parent; \ - node = parent->left; \ - } \ - else \ - { \ - parent->right = PFX##_new_node(element); \ - \ - if (!parent->right) \ - return false; \ - \ - parent->right->parent = parent; \ - node = parent->right; \ - } \ - \ - PFX##_rebalance(_set_, node); \ - } \ - \ - _set_->count++; \ - _set_->cardinality++; \ - \ - return true; \ - } \ - \ - FMOD bool PFX##_remove(SNAME *_set_, V element) \ - { \ - SNAME##_node *node = PFX##_get_node(_set_, element); \ - \ - if (!node) \ - return false; \ - \ - if (node->multiplicity > 0) \ - { \ - node->multiplicity--; \ - _set_->cardinality--; \ - \ - return true; \ - } \ - \ - SNAME##_node *temp = NULL, *unbalanced = NULL; \ - \ - bool is_root = node->parent == NULL; \ - \ - if (node->left == NULL && node->right == NULL) \ - { \ - if (is_root) \ - _set_->root = NULL; \ - else \ - { \ - unbalanced = node->parent; \ - \ - if (node->parent->right == node) \ - node->parent->right = NULL; \ - else \ - node->parent->left = NULL; \ - } \ - \ - free(node); \ - } \ - else if (node->left == NULL) \ - { \ - if (is_root) \ - { \ - _set_->root = node->right; \ - _set_->root->parent = NULL; \ - } \ - else \ - { \ - unbalanced = node->parent; \ - \ - node->right->parent = node->parent; \ - \ - if (node->parent->right == node) \ - node->parent->right = node->right; \ - else \ - node->parent->left = node->right; \ - } \ - \ - free(node); \ - } \ - else if (node->right == NULL) \ - { \ - if (is_root) \ - { \ - _set_->root = node->left; \ - _set_->root->parent = NULL; \ - } \ - else \ - { \ - unbalanced = node->parent; \ - \ - node->left->parent = node->parent; \ - \ - if (node->parent->right == node) \ - node->parent->right = node->left; \ - else \ - node->parent->left = node->left; \ - } \ - \ - free(node); \ - } \ - else \ - { \ - temp = node->right; \ - while (temp->left != NULL) \ - temp = temp->left; \ - \ - V temp_key = temp->key; \ - \ - unbalanced = temp->parent; \ - \ - if (temp->left == NULL && temp->right == NULL) \ - { \ - if (temp->parent->right == temp) \ - temp->parent->right = NULL; \ - else \ - temp->parent->left = NULL; \ - } \ - else if (temp->left == NULL) \ - { \ - temp->right->parent = temp->parent; \ - \ - if (temp->parent->right == temp) \ - temp->parent->right = temp->right; \ - else \ - temp->parent->left = temp->right; \ - } \ - else if (temp->right == NULL) \ - { \ - temp->left->parent = temp->parent; \ - \ - if (temp->parent->right == temp) \ - temp->parent->right = temp->left; \ - else \ - temp->parent->left = temp->left; \ - } \ - \ - free(temp); \ - \ - node->key = temp_key; \ - } \ - \ - if (unbalanced != NULL) \ - PFX##_rebalance(_set_, unbalanced); \ - \ - _set_->count--; \ - _set_->cardinality--; \ - \ - return true; \ - } \ - \ - FMOD bool PFX##_insert_if(SNAME *_set_, V element, bool condition) \ - { \ - if (condition) \ - return PFX##_insert(_set_, element); \ - \ - return false; \ - } \ - \ - FMOD bool PFX##_remove_if(SNAME *_set_, V element, bool condition) \ - { \ - if (condition) \ - return PFX##_remove(_set_, element); \ - \ - return false; \ - } \ - \ - FMOD V PFX##_max(SNAME *_set_) \ - { \ - if (PFX##_empty(_set_)) \ - return 0; \ - \ - SNAME##_node *scan = _set_->root; \ - \ - while (scan->right != NULL) \ - scan = scan->right; \ - \ - return scan->key; \ - } \ - \ - FMOD V PFX##_min(SNAME *_set_) \ - { \ - if (PFX##_empty(_set_)) \ - return 0; \ - \ - SNAME##_node *scan = _set_->root; \ - \ - while (scan->left != NULL) \ - scan = scan->left; \ - \ - return scan->key; \ - } \ - \ - FMOD bool PFX##_empty(SNAME *_set_) \ - { \ - return _set_->count == 0; \ - } \ - \ - FMOD size_t PFX##_count(SNAME *_set_) \ - { \ - return _set_->count; \ - } \ - \ - FMOD size_t PFX##_cardinality(SNAME *_set_) \ - { \ - return _set_->cardinality; \ - } \ - \ - FMOD SNAME##_node *PFX##_new_node(V element) \ - { \ - SNAME##_node *node = malloc(sizeof(SNAME##_node)); \ - \ - if (!node) \ - return NULL; \ - \ - node->key = element; \ - node->right = NULL; \ - node->left = NULL; \ - node->parent = NULL; \ - node->height = 0; \ - node->multiplicity = 1; \ - \ - return node; \ - } \ - \ - FMOD SNAME##_node *PFX##_get_node(SNAME *_set_, V element) \ - { \ - if (PFX##_empty(_set_)) \ - return NULL; \ - \ - SNAME##_node *scan = _set_->root; \ - \ - while (scan != NULL) \ - { \ - if (_set_->cmp(scan->key, element) > 0) \ - scan = scan->left; \ - else if (_set_->cmp(scan->key, element) < 0) \ - scan = scan->right; \ - else \ - return scan; \ - } \ - \ - return NULL; \ - } \ - \ - FMOD unsigned char PFX##_h(SNAME##_node *node) \ - { \ - if (node == NULL) \ - return 0; \ - \ - return node->height; \ - } \ - \ - FMOD unsigned char PFX##_hupdate(SNAME##_node *node) \ - { \ - if (node == NULL) \ - return 0; \ - \ - unsigned char h_l = PFX##_h(node->left); \ - unsigned char h_r = PFX##_h(node->right); \ - \ - return 1 + (h_l > h_r ? h_l : h_r); \ - } \ - \ - FMOD void PFX##_rotate_right(SNAME##_node **Z) \ - { \ - SNAME##_node *root = *Z; \ - SNAME##_node *new_root = root->left; \ - \ - if (root->parent != NULL) \ - { \ - if (root->parent->left == root) \ - root->parent->left = new_root; \ - else \ - root->parent->right = new_root; \ - } \ - \ - new_root->parent = root->parent; \ - \ - root->parent = new_root; \ - root->left = new_root->right; \ - \ - if (root->left) \ - root->left->parent = root; \ - \ - new_root->right = root; \ - \ - root->height = PFX##_hupdate(root); \ - new_root->height = PFX##_hupdate(new_root); \ - \ - *Z = new_root; \ - } \ - \ - FMOD void PFX##_rotate_left(SNAME##_node **Z) \ - { \ - SNAME##_node *root = *Z; \ - SNAME##_node *new_root = root->right; \ - \ - if (root->parent != NULL) \ - { \ - if (root->parent->right == root) \ - root->parent->right = new_root; \ - else \ - root->parent->left = new_root; \ - } \ - \ - new_root->parent = root->parent; \ - \ - root->parent = new_root; \ - root->right = new_root->left; \ - \ - if (root->right) \ - root->right->parent = root; \ - \ - new_root->left = root; \ - \ - root->height = PFX##_hupdate(root); \ - new_root->height = PFX##_hupdate(new_root); \ - \ - *Z = new_root; \ - } \ - \ - FMOD void PFX##_rebalance(SNAME *_set_, SNAME##_node *node) \ - { \ - SNAME##_node *scan = node, *child = NULL; \ - \ - int balance; \ - bool is_root = false; \ - \ - while (scan != NULL) \ - { \ - if (scan->parent == NULL) \ - is_root = true; \ - \ - scan->height = PFX##_hupdate(scan); \ - balance = PFX##_h(scan->right) - PFX##_h(scan->left); \ - \ - if (balance >= 2) \ - { \ - child = scan->right; \ - \ - if (PFX##_h(child->right) < PFX##_h(child->left)) \ - PFX##_rotate_right(&(scan->right)); \ - \ - PFX##_rotate_left(&scan); \ - } \ - else if (balance <= -2) \ - { \ - child = scan->left; \ - \ - if (PFX##_h(child->left) < PFX##_h(child->right)) \ - PFX##_rotate_left(&(scan->left)); \ - \ - PFX##_rotate_right(&scan); \ - } \ - \ - if (is_root) \ - { \ - _set_->root = scan; \ - is_root = false; \ - } \ - \ - scan = scan->parent; \ - } \ - } \ - \ - FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_) \ - { \ - SNAME##_iter iter1, iter2; \ - size_t index, mul; \ - V value; \ - \ - SNAME *_set_r_ = PFX##_new(_set1_->cmp); \ - \ - if (!_set_r_) \ - return false; \ - \ - PFX##_iter_new(&iter1, _set1_); \ - PFX##_iter_new(&iter2, _set2_); \ - \ - for (PFX##_iter_tostart(&iter1); !PFX##_iter_end(&iter1);) \ - { \ - PFX##_iter_next(&iter1, &value, &mul, &index); \ - PFX##_insert(_set_r_, value); \ - } \ - \ - for (PFX##_iter_tostart(&iter2); !PFX##_iter_end(&iter2);) \ - { \ - PFX##_iter_next(&iter2, &value, &mul, &index); \ - PFX##_insert(_set_r_, value); \ - } \ - \ - return _set_r_; \ - } \ - \ - FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_) \ - { \ - SNAME##_iter iter; \ - size_t index, mul; \ - V value; \ - \ - SNAME *_set_r_ = PFX##_new(_set1_->cmp); \ - \ - if (!_set_r_) \ - return false; \ - \ - SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; \ - SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; \ - \ - PFX##_iter_new(&iter, _set_A_); \ - \ - for (PFX##_iter_tostart(&iter); !PFX##_iter_end(&iter);) \ - { \ - PFX##_iter_next(&iter, &value, &mul, &index); \ - if (PFX##_get_node(_set_B_, value) != NULL) \ - PFX##_insert(_set_r_, value); \ - } \ - \ - return _set_r_; \ - } \ - \ - FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_) \ - { \ - SNAME##_iter iter; \ - size_t index, mul; \ - V value; \ - \ - SNAME *_set_r_ = PFX##_new(_set1_->cmp); \ - \ - if (!_set_r_) \ - return false; \ - \ - PFX##_iter_new(&iter, _set1_); \ - \ - for (PFX##_iter_tostart(&iter); !PFX##_iter_end(&iter);) \ - { \ - PFX##_iter_next(&iter, &value, &mul, &index); \ - if (PFX##_get_node(_set2_, value) == NULL) \ - PFX##_insert(_set_r_, value); \ - } \ - \ - return _set_r_; \ - } \ - \ - FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_) \ - { \ - SNAME##_iter iter1, iter2; \ - size_t index, mul; \ - V value; \ - \ - SNAME *_set_r_ = PFX##_new(_set1_->cmp); \ - \ - if (!_set_r_) \ - return false; \ - \ - PFX##_iter_new(&iter1, _set1_); \ - PFX##_iter_new(&iter2, _set2_); \ - \ - for (PFX##_iter_tostart(&iter1); !PFX##_iter_end(&iter1);) \ - { \ - PFX##_iter_next(&iter1, &value, &mul, &index); \ - if (PFX##_get_node(_set2_, value) == NULL) \ - PFX##_insert(_set_r_, value); \ - } \ - \ - for (PFX##_iter_tostart(&iter2); !PFX##_iter_end(&iter2);) \ - { \ - PFX##_iter_next(&iter2, &value, &mul, &index); \ - if (PFX##_get_node(_set1_, value) == NULL) \ - PFX##_insert(_set_r_, value); \ - } \ - \ - return _set_r_; \ - } \ - \ - FMOD void PFX##_iter_new(SNAME##_iter *iter, SNAME *target) \ - { \ - iter->target = target; \ - iter->index = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(target); \ - \ - iter->cursor = target->root; \ - while (iter->cursor->left != NULL) \ - iter->cursor = iter->cursor->left; \ - \ - iter->first = iter->cursor; \ - \ - iter->last = target->root; \ - while (iter->last->right != NULL) \ - iter->last = iter->last->right; \ - } \ - \ - FMOD bool PFX##_iter_start(SNAME##_iter *iter) \ - { \ - return iter->start && iter->cursor == iter->first; \ - } \ - \ - FMOD bool PFX##_iter_end(SNAME##_iter *iter) \ - { \ - return iter->end && iter->cursor == iter->last; \ - } \ - \ - FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \ - { \ - iter->index = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(iter->target); \ - \ - iter->cursor = iter->first; \ - } \ - \ - FMOD void PFX##_iter_toend(SNAME##_iter *iter) \ - { \ - iter->index = iter->target->count - 1; \ - iter->start = PFX##_empty(iter->target); \ - iter->end = true; \ - \ - iter->cursor = iter->last; \ - } \ - \ - FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *value, size_t *multiplicity, size_t *index) \ - { \ - if (iter->end) \ - return false; \ - \ - *value = iter->cursor->key; \ - *multiplicity = iter->cursor->multiplicity; \ - *index = iter->index; \ - iter->start = false; \ - \ - if (iter->cursor->right != NULL) \ - { \ - iter->cursor = iter->cursor->right; \ - while (iter->cursor->left != NULL) \ - iter->cursor = iter->cursor->left; \ - \ - iter->index++; \ - \ - return true; \ - } \ - \ - while (true) \ - { \ - if (iter->cursor == iter->last) \ - { \ - iter->end = true; \ - \ - return true; \ - } \ - if (iter->cursor->parent->left == iter->cursor) \ - { \ - iter->cursor = iter->cursor->parent; \ - \ - iter->index++; \ - \ - return true; \ - } \ - \ - iter->cursor = iter->cursor->parent; \ - } \ - } \ - \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *value, size_t *multiplicity, size_t *index) \ - { \ - if (iter->start) \ - return false; \ - \ - *value = iter->cursor->key; \ - *multiplicity = iter->cursor->multiplicity; \ - *index = iter->index; \ - iter->end = false; \ - \ - if (iter->cursor->left != NULL) \ - { \ - iter->cursor = iter->cursor->left; \ - while (iter->cursor->right != NULL) \ - iter->cursor = iter->cursor->right; \ - \ - iter->index--; \ - \ - return true; \ - } \ - \ - while (true) \ - { \ - if (iter->cursor == iter->first) \ - { \ - iter->start = true; \ - \ - return true; \ - } \ - if (iter->cursor->parent->right == iter->cursor) \ - { \ - iter->cursor = iter->cursor->parent; \ - \ - iter->index--; \ - \ - return true; \ - } \ - \ - iter->cursor = iter->cursor->parent; \ - } \ +#define MULTISET_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ + \ + /* Implementation Detail Functions */ \ + static SNAME##_entry *PFX##_impl_insert_and_return(SNAME *_set_, V element, bool *new_node); \ + static bool PFX##_impl_grow(SNAME *_set_); \ + static SNAME##_entry *PFX##_impl_get_entry(SNAME *_set_, V element); \ + static size_t PFX##_impl_calculate_size(size_t required); \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_set_); \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_set_); \ + \ + FMOD SNAME *PFX##_new(size_t capacity, double load, int (*compare)(V, V), size_t (*hash)(V)) \ + { \ + if (capacity == 0 || load <= 0 || load >= 1) \ + return NULL; \ + \ + /* Prevent integer overflow */ \ + if (capacity >= UINTMAX_MAX * load) \ + return NULL; \ + \ + size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \ + \ + SNAME *_set_ = malloc(sizeof(SNAME)); \ + \ + if (!_set_) \ + return NULL; \ + \ + _set_->buffer = malloc(sizeof(SNAME##_entry) * real_capacity); \ + \ + if (!_set_->buffer) \ + { \ + free(_set_); \ + return NULL; \ + } \ + \ + memset(_set_->buffer, 0, sizeof(SNAME##_entry) * real_capacity); \ + \ + _set_->count = 0; \ + _set_->cardinality = 0; \ + _set_->capacity = real_capacity; \ + _set_->load = load; \ + _set_->cmp = compare; \ + _set_->hash = hash; \ + \ + _set_->it_start = PFX##_impl_it_start; \ + _set_->it_end = PFX##_impl_it_end; \ + \ + return _set_; \ + } \ + \ + FMOD void PFX##_clear(SNAME *_set_) \ + { \ + memset(_set_->buffer, 0, sizeof(SNAME##_entry) * _set_->capacity); \ + \ + _set_->count = 0; \ + } \ + \ + FMOD void PFX##_free(SNAME *_set_) \ + { \ + free(_set_->buffer); \ + free(_set_); \ + } \ + \ + FMOD bool PFX##_insert(SNAME *_set_, V element) \ + { \ + bool new_node; \ + \ + SNAME##_entry *entry = PFX##_impl_insert_and_return(_set_, element, &new_node); \ + \ + if (!entry) \ + return false; \ + \ + if (!new_node) \ + entry->multiplicity++; \ + \ + _set_->cardinality++; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_insert_many(SNAME *_set_, V element, size_t count) \ + { \ + if (count == 0) \ + return true; \ + \ + bool new_node; \ + \ + SNAME##_entry *entry = PFX##_impl_insert_and_return(_set_, element, &new_node); \ + \ + if (!entry) \ + return false; \ + \ + if (new_node) \ + entry->multiplicity = count; \ + else \ + entry->multiplicity += count; \ + \ + _set_->cardinality += count; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_update(SNAME *_set_, V element, size_t multiplicity) \ + { \ + if (multiplicity == 0) \ + return PFX##_remove_all(_set_, element); \ + \ + bool new_node; \ + \ + SNAME##_entry *entry = PFX##_impl_insert_and_return(_set_, element, &new_node); \ + \ + if (!entry) \ + return false; \ + \ + if (new_node) \ + _set_->cardinality++; \ + \ + _set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity; \ + \ + entry->multiplicity = multiplicity; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_remove(SNAME *_set_, V element) \ + { \ + SNAME##_entry *result = PFX##_impl_get_entry(_set_, element); \ + \ + if (result == NULL) \ + return false; \ + \ + if (result->multiplicity > 1) \ + result->multiplicity--; \ + else \ + { \ + result->value = PFX##_impl_default_value(); \ + result->multiplicity = 0; \ + result->dist = 0; \ + result->state = CMC_ES_DELETED; \ + \ + _set_->count--; \ + } \ + \ + _set_->cardinality--; \ + \ + return true; \ + } \ + \ + FMOD size_t PFX##_remove_all(SNAME *_set_, V element) \ + { \ + SNAME##_entry *result = PFX##_impl_get_entry(_set_, element); \ + \ + if (result == NULL) \ + return 0; \ + \ + size_t removed = result->multiplicity; \ + \ + result->value = PFX##_impl_default_value(); \ + result->multiplicity = 0; \ + result->dist = 0; \ + result->state = CMC_ES_DELETED; \ + \ + _set_->count--; \ + _set_->cardinality -= removed; \ + \ + return removed; \ + } \ + \ + FMOD bool PFX##_insert_if(SNAME *_set_, V element, bool condition) \ + { \ + if (condition) \ + return PFX##_insert(_set_, element); \ + \ + return false; \ + } \ + \ + FMOD bool PFX##_remove_if(SNAME *_set_, V element, bool condition) \ + { \ + if (condition) \ + return PFX##_remove(_set_, element); \ + \ + return false; \ + } \ + \ + FMOD bool PFX##_max(SNAME *_set_, V *value) \ + { \ + if (PFX##_empty(_set_)) \ + return false; \ + \ + SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V result = PFX##_iter_value(&iter); \ + size_t index = PFX##_iter_index(&iter); \ + \ + if (index == 0) \ + *value = result; \ + else if (_set_->cmp(result, *value) > 0) \ + *value = result; \ + } \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_min(SNAME *_set_, V *value) \ + { \ + if (PFX##_empty(_set_)) \ + return false; \ + \ + SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V result = PFX##_iter_value(&iter); \ + size_t index = PFX##_iter_index(&iter); \ + \ + if (index == 0) \ + *value = result; \ + else if (_set_->cmp(result, *value) < 0) \ + *value = result; \ + } \ + \ + return true; \ + } \ + \ + FMOD size_t PFX##_multiplicity_of(SNAME *_set_, V element) \ + { \ + SNAME##_entry *entry = PFX##_impl_get_entry(_set_, element); \ + \ + if (!entry) \ + return 0; \ + \ + return entry->multiplicity; \ + } \ + \ + FMOD bool PFX##_contains(SNAME *_set_, V element) \ + { \ + return PFX##_impl_get_entry(_set_, element) != NULL; \ + } \ + \ + FMOD bool PFX##_empty(SNAME *_set_) \ + { \ + return _set_->count == 0; \ + } \ + \ + FMOD size_t PFX##_count(SNAME *_set_) \ + { \ + return _set_->count; \ + } \ + \ + FMOD size_t PFX##_cardinality(SNAME *_set_) \ + { \ + return _set_->cardinality; \ + } \ + \ + FMOD size_t PFX##_capacity(SNAME *_set_) \ + { \ + return _set_->capacity; \ + } \ + \ + FMOD cmc_string PFX##_to_string(SNAME *_set_) \ + { \ + cmc_string str; \ + SNAME *s_ = _set_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, \ + name, s_, s_->buffer, s_->capacity, s_->count, s_->cardinality, s_->load, s_->cmp, s_->hash); \ + \ + return str; \ + } \ + \ + FMOD SNAME *PFX##_union(SNAME *_set1_, SNAME *_set2_) \ + { \ + SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \ + \ + if (!_set_r_) \ + return NULL; \ + \ + SNAME##_iter iter1, iter2; \ + PFX##_iter_init(&iter1, _set1_); \ + PFX##_iter_init(&iter2, _set2_); \ + \ + for (PFX##_iter_to_start(&iter1); !PFX##_iter_end(&iter1); PFX##_iter_next(&iter1)) \ + { \ + V value = PFX##_iter_value(&iter1); \ + \ + size_t m1 = PFX##_iter_multiplicity(&iter1); \ + size_t m2 = PFX##_multiplicity_of(_set2_, value); \ + size_t max_ = m1 > m2 ? m1 : m2; \ + \ + PFX##_update(_set_r_, value, max_); \ + } \ + \ + for (PFX##_iter_to_start(&iter2); !PFX##_iter_end(&iter2); PFX##_iter_next(&iter2)) \ + { \ + V value = PFX##_iter_value(&iter2); \ + \ + size_t m1 = PFX##_multiplicity_of(_set1_, value); \ + size_t m2 = PFX##_iter_multiplicity(&iter2); \ + size_t max_ = m1 > m2 ? m1 : m2; \ + \ + PFX##_update(_set_r_, value, max_); \ + } \ + \ + return _set_r_; \ + } \ + \ + FMOD SNAME *PFX##_intersection(SNAME *_set1_, SNAME *_set2_) \ + { \ + SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \ + \ + if (!_set_r_) \ + return NULL; \ + \ + SNAME *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; \ + SNAME *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; \ + \ + SNAME##_iter iter; \ + PFX##_iter_init(&iter, _set_A_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V value = PFX##_iter_value(&iter); \ + \ + size_t m1 = PFX##_iter_multiplicity(&iter); \ + size_t m2 = PFX##_multiplicity_of(_set_B_, value); \ + size_t max_ = m1 < m2 ? m1 : m2; \ + \ + PFX##_update(_set_r_, value, max_); \ + } \ + \ + return _set_r_; \ + } \ + \ + FMOD SNAME *PFX##_difference(SNAME *_set1_, SNAME *_set2_) \ + { \ + SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \ + \ + if (!_set_r_) \ + return NULL; \ + \ + SNAME##_iter iter; \ + PFX##_iter_init(&iter, _set1_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V value = PFX##_iter_value(&iter); \ + \ + size_t m1 = PFX##_iter_multiplicity(&iter); \ + size_t m2 = PFX##_multiplicity_of(_set2_, value); \ + \ + if (m1 > m2) \ + PFX##_update(_set_r_, value, m1 - m2); \ + } \ + \ + return _set_r_; \ + } \ + \ + FMOD SNAME *PFX##_summation(SNAME *_set1_, SNAME *_set2_) \ + { \ + SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \ + \ + if (!_set_r_) \ + return NULL; \ + \ + SNAME##_iter iter1, iter2; \ + PFX##_iter_init(&iter1, _set1_); \ + PFX##_iter_init(&iter2, _set2_); \ + \ + for (PFX##_iter_to_start(&iter1); !PFX##_iter_end(&iter1); PFX##_iter_next(&iter1)) \ + { \ + PFX##_insert_many(_set_r_, PFX##_iter_value(&iter1), PFX##_iter_multiplicity(&iter1)); \ + } \ + \ + for (PFX##_iter_to_start(&iter2); !PFX##_iter_end(&iter2); PFX##_iter_next(&iter2)) \ + { \ + PFX##_insert_many(_set_r_, PFX##_iter_value(&iter2), PFX##_iter_multiplicity(&iter2)); \ + } \ + \ + return _set_r_; \ + } \ + \ + FMOD SNAME *PFX##_symmetric_difference(SNAME *_set1_, SNAME *_set2_) \ + { \ + SNAME##_iter iter1, iter2; \ + \ + SNAME *_set_r_ = PFX##_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); \ + \ + if (!_set_r_) \ + return NULL; \ + \ + PFX##_iter_init(&iter1, _set1_); \ + PFX##_iter_init(&iter2, _set2_); \ + \ + for (PFX##_iter_to_start(&iter1); !PFX##_iter_end(&iter1); PFX##_iter_next(&iter1)) \ + { \ + V value = PFX##_iter_value(&iter1); \ + \ + size_t m1 = PFX##_iter_multiplicity(&iter1); \ + size_t m2 = PFX##_multiplicity_of(_set2_, value); \ + \ + if (m1 != m2) \ + { \ + if (m1 > m2) \ + PFX##_update(_set_r_, value, m1 - m2); \ + else \ + PFX##_update(_set_r_, value, m2 - m1); \ + } \ + } \ + \ + for (PFX##_iter_to_start(&iter2); !PFX##_iter_end(&iter2); PFX##_iter_next(&iter2)) \ + { \ + V value = PFX##_iter_value(&iter2); \ + \ + size_t m1 = PFX##_multiplicity_of(_set1_, value); \ + size_t m2 = PFX##_iter_multiplicity(&iter2); \ + \ + if (m1 != m2) \ + { \ + if (m1 > m2) \ + PFX##_update(_set_r_, value, m1 - m2); \ + else \ + PFX##_update(_set_r_, value, m2 - m1); \ + } \ + } \ + \ + return _set_r_; \ + } \ + \ + FMOD bool PFX##_is_subset(SNAME *_set1_, SNAME *_set2_) \ + { \ + if (PFX##_count(_set1_) > PFX##_count(_set2_)) \ + return false; \ + \ + if (PFX##_empty(_set1_)) \ + return true; \ + \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _set1_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V value = PFX##_iter_value(&iter); \ + \ + size_t m1 = PFX##_iter_multiplicity(&iter); \ + size_t m2 = PFX##_multiplicity_of(_set2_, value); \ + \ + if (m1 > m2) \ + return false; \ + } \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_is_superset(SNAME *_set1_, SNAME *_set2_) \ + { \ + return PFX##_is_subset(_set2_, _set1_); \ + } \ + \ + FMOD bool PFX##_is_proper_subset(SNAME *_set1_, SNAME *_set2_) \ + { \ + if (PFX##_count(_set1_) >= PFX##_count(_set2_)) \ + return false; \ + \ + if (PFX##_empty(_set1_)) \ + { \ + if (!PFX##_empty(_set2_)) \ + return true; \ + else \ + return false; \ + } \ + \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _set1_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V value = PFX##_iter_value(&iter); \ + \ + size_t m1 = PFX##_iter_multiplicity(&iter); \ + size_t m2 = PFX##_multiplicity_of(_set2_, value); \ + \ + if (m1 >= m2) \ + return false; \ + } \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_is_proper_superset(SNAME *_set1_, SNAME *_set2_) \ + { \ + return PFX##_is_proper_subset(_set2_, _set1_); \ + } \ + \ + FMOD bool PFX##_is_disjointset(SNAME *_set1_, SNAME *_set2_) \ + { \ + if (PFX##_empty(_set1_)) \ + return true; \ + \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _set1_); \ + \ + for (PFX##_iter_to_start(&iter); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + V value = PFX##_iter_value(&iter); \ + \ + if (PFX##_contains(_set2_, value)) \ + return false; \ + } \ + \ + return true; \ + } \ + \ + FMOD SNAME##_iter *PFX##_iter_new(SNAME *target) \ + { \ + SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ + \ + if (!iter) \ + return NULL; \ + \ + PFX##_iter_init(iter, target); \ + \ + return iter; \ + } \ + \ + FMOD void PFX##_iter_free(SNAME##_iter *iter) \ + { \ + free(iter); \ + } \ + \ + FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \ + { \ + iter->target = target; \ + iter->cursor = 0; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(target); \ + \ + if (!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; \ + } \ + } \ + } \ + } \ + \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->start; \ + } \ + \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->end; \ + } \ + \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \ + { \ + iter->cursor = iter->first; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(iter->target); \ + } \ + \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \ + { \ + iter->cursor = iter->last; \ + iter->index = iter->target->count - 1; \ + iter->start = PFX##_empty(iter->target); \ + iter->end = true; \ + } \ + \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter) \ + { \ + if (iter->end) \ + return false; \ + \ + SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (iter->cursor == iter->last) \ + iter->end = true; \ + else \ + { \ + iter->index++; \ + \ + while (1) \ + { \ + iter->cursor++; \ + scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (scan->state == CMC_ES_FILLED) \ + break; \ + } \ + } \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \ + { \ + if (iter->start) \ + return false; \ + \ + SNAME##_entry *scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (iter->cursor == iter->first) \ + iter->start = true; \ + else \ + { \ + iter->index--; \ + \ + while (1) \ + { \ + iter->cursor--; \ + scan = &(iter->target->buffer[iter->cursor]); \ + \ + if (scan->state == CMC_ES_FILLED) \ + break; \ + } \ + } \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + return true; \ + } \ + \ + FMOD V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return PFX##_impl_default_value(); \ + \ + return iter->target->buffer[iter->cursor].value; \ + } \ + \ + FMOD size_t PFX##_iter_multiplicity(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ + return iter->target->buffer[iter->cursor].multiplicity; \ + } \ + \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + static SNAME##_entry *PFX##_impl_insert_and_return(SNAME *_set_, V element, 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 element */ \ + \ + *new_node = false; \ + \ + SNAME##_entry *entry = PFX##_impl_get_entry(_set_, element); \ + \ + if (entry != NULL) \ + return entry; \ + \ + *new_node = true; \ + \ + if ((double)_set_->capacity * _set_->load <= (double)_set_->count) \ + { \ + if (!PFX##_impl_grow(_set_)) \ + return NULL; \ + } \ + \ + size_t hash = _set_->hash(element); \ + 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; \ + \ + SNAME##_entry *target = &(_set_->buffer[pos]); \ + \ + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) \ + { \ + target->value = element; \ + target->multiplicity = curr_mul; \ + target->dist = pos - original_pos; \ + 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 = element; \ + target->multiplicity = curr_mul; \ + target->dist = pos - original_pos; \ + target->state = CMC_ES_FILLED; \ + \ + 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 = element; \ + target->dist = pos - original_pos; \ + target->multiplicity = curr_mul; \ + \ + element = tmp; \ + original_pos = pos - tmp_dist; \ + curr_mul = tmp_mul; \ + } \ + } \ + } \ + \ + _set_->count++; \ + \ + return target; \ + } \ + \ + static bool PFX##_impl_grow(SNAME *_set_) \ + { \ + size_t new_size = PFX##_impl_calculate_size(_set_->capacity + _set_->capacity / 2); \ + \ + SNAME *_new_set_ = PFX##_new(new_size, _set_->load, _set_->cmp, _set_->hash); \ + \ + if (!_new_set_) \ + return false; \ + \ + SNAME##_iter iter; \ + \ + for (PFX##_iter_init(&iter, _set_); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \ + { \ + PFX##_insert_many(_new_set_, PFX##_iter_value(&iter), PFX##_iter_multiplicity(&iter)); \ + } \ + \ + if (_set_->count != _new_set_->count) \ + { \ + PFX##_free(_new_set_); \ + \ + return false; \ + } \ + \ + SNAME##_entry *tmp = _set_->buffer; \ + _set_->buffer = _new_set_->buffer; \ + _new_set_->buffer = tmp; \ + \ + _set_->capacity = _new_set_->capacity; \ + \ + PFX##_free(_new_set_); \ + \ + return true; \ + } \ + \ + static SNAME##_entry *PFX##_impl_get_entry(SNAME *_set_, V element) \ + { \ + size_t hash = _set_->hash(element); \ + size_t pos = hash % _set_->capacity; \ + \ + SNAME##_entry *target = &(_set_->buffer[pos]); \ + \ + while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED) \ + { \ + if (_set_->cmp(target->value, element) == 0) \ + return target; \ + \ + pos++; \ + target = &(_set_->buffer[pos % _set_->capacity]); \ + } \ + \ + return NULL; \ + } \ + \ + static size_t 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]; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_set_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _set_); \ + \ + return iter; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_set_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _set_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_MULTISET_H */ diff --git a/src/utl/cmc_string.h b/src/utl/cmc_string.h index c7dac27..7169330 100644 --- a/src/utl/cmc_string.h +++ b/src/utl/cmc_string.h @@ -23,7 +23,7 @@ typedef struct cmc_string_s char s[200]; } cmc_string; -/* To string formatting */ +/* to_string formats */ static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }"; static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }"; @@ -32,7 +32,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }"; static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }"; static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }"; -static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p, }"; -static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p, }"; +static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }"; +static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }"; + +static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";; #endif /* CMC_STRING_H */ diff --git a/tests/main/main.c b/tests/main/main.c index 0aafb55..4678ab3 100644 --- a/tests/main/main.c +++ b/tests/main/main.c @@ -11,6 +11,7 @@ #include "unt/linkedqueue.c" #include "unt/multimap.c" +#include "unt/multiset.c" int main(void) { @@ -28,6 +29,7 @@ int main(void) /* ext */ linkedqueue_test(); multimap_test(); + multiset_test(); return 0; } diff --git a/tests/main/src/multiset.c b/tests/main/src/multiset.c new file mode 100644 index 0000000..708b915 --- /dev/null +++ b/tests/main/src/multiset.c @@ -0,0 +1,655 @@ +#include "ext/multiset.h" + +//MULTISET_GENERATE(ms, multiset, , size_t) + +typedef struct multiset_s +{ + struct multiset_entry_s *buffer; + size_t capacity; + size_t count; + size_t cardinality; + double load; + int (*cmp)(size_t, size_t); + size_t (*hash)(size_t); + struct multiset_iter_s (*it_start)(struct multiset_s *); + struct multiset_iter_s (*it_end)(struct multiset_s *); +} multiset, *multiset_ptr; +typedef struct multiset_entry_s +{ + size_t value; + size_t multiplicity; + size_t dist; + enum cmc_entry_state_e state; +} multiset_entry, *multiset_entry_ptr; +typedef struct multiset_iter_s +{ + struct multiset_s *target; + size_t cursor; + size_t index; + size_t first; + size_t last; + bool start; + bool end; +} multiset_iter, *multiset_iter_ptr; +multiset *ms_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t)); +void ms_clear(multiset *_set_); +void ms_free(multiset *_set_); +bool ms_insert(multiset *_set_, size_t element); +bool ms_insert_many(multiset *_set_, size_t element, size_t count); +bool ms_update(multiset *_set_, size_t element, size_t multiplicity); +bool ms_remove(multiset *_set_, size_t element); +size_t ms_remove_all(multiset *_set_, size_t element); +bool ms_insert_if(multiset *_set_, size_t element, bool condition); +bool ms_remove_if(multiset *_set_, size_t element, bool condition); +bool ms_max(multiset *_set_, size_t *value); +bool ms_min(multiset *_set_, size_t *value); +size_t ms_multiplicity_of(multiset *_set_, size_t element); +bool ms_contains(multiset *_set_, size_t element); +bool ms_empty(multiset *_set_); +size_t ms_count(multiset *_set_); +size_t ms_cardinality(multiset *_set_); +size_t ms_capacity(multiset *_set_); +cmc_string ms_to_string(multiset *_set_); +multiset *ms_union(multiset *_set1_, multiset *_set2_); +multiset *ms_intersection(multiset *_set1_, multiset *_set2_); +multiset *ms_difference(multiset *_set1_, multiset *_set2_); +multiset *ms_summation(multiset *_set1_, multiset *_set2_); +multiset *ms_symmetric_difference(multiset *_set1_, multiset *_set2_); +bool ms_is_subset(multiset *_set1_, multiset *_set2_); +bool ms_is_superset(multiset *_set1_, multiset *_set2_); +bool ms_is_proper_subset(multiset *_set1_, multiset *_set2_); +bool ms_is_proper_superset(multiset *_set1_, multiset *_set2_); +bool ms_is_disjointset(multiset *_set1_, multiset *_set2_); +multiset_iter *ms_iter_new(multiset *target); +void ms_iter_free(multiset_iter *iter); +void ms_iter_init(multiset_iter *iter, multiset *target); +bool ms_iter_start(multiset_iter *iter); +bool ms_iter_end(multiset_iter *iter); +void ms_iter_to_start(multiset_iter *iter); +void ms_iter_to_end(multiset_iter *iter); +bool ms_iter_next(multiset_iter *iter); +bool ms_iter_prev(multiset_iter *iter); +size_t ms_iter_value(multiset_iter *iter); +size_t ms_iter_multiplicity(multiset_iter *iter); +size_t ms_iter_index(multiset_iter *iter); +static inline size_t ms_impl_default_value(void) +{ + size_t _empty_value_; + memset(&_empty_value_, 0, sizeof(size_t)); + return _empty_value_; +} +static multiset_entry *ms_impl_insert_and_return(multiset *_set_, size_t element, bool *new_node); +static bool ms_impl_grow(multiset *_set_); +static multiset_entry *ms_impl_get_entry(multiset *_set_, size_t element); +static size_t ms_impl_calculate_size(size_t required); +static multiset_iter ms_impl_it_start(multiset *_set_); +static multiset_iter ms_impl_it_end(multiset *_set_); +multiset *ms_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t)) +{ + if (capacity == 0 || load <= 0 || load >= 1) + return NULL; + if (capacity >= UINTMAX_MAX * load) + return NULL; + size_t real_capacity = ms_impl_calculate_size(capacity / load); + multiset *_set_ = malloc(sizeof(multiset)); + if (!_set_) + return NULL; + _set_->buffer = malloc(sizeof(multiset_entry) * real_capacity); + if (!_set_->buffer) + { + free(_set_); + return NULL; + } + memset(_set_->buffer, 0, sizeof(multiset_entry) * real_capacity); + _set_->count = 0; + _set_->cardinality = 0; + _set_->capacity = real_capacity; + _set_->load = load; + _set_->cmp = compare; + _set_->hash = hash; + _set_->it_start = ms_impl_it_start; + _set_->it_end = ms_impl_it_end; + return _set_; +} +void ms_clear(multiset *_set_) +{ + memset(_set_->buffer, 0, sizeof(multiset_entry) * _set_->capacity); + _set_->count = 0; +} +void ms_free(multiset *_set_) +{ + free(_set_->buffer); + free(_set_); +} +bool ms_insert(multiset *_set_, size_t element) +{ + bool new_node; + multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node); + if (!entry) + return false; + if (!new_node) + entry->multiplicity++; + _set_->cardinality++; + return true; +} +bool ms_insert_many(multiset *_set_, size_t element, size_t count) +{ + if (count == 0) + return true; + bool new_node; + multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node); + if (!entry) + return false; + if (new_node) + entry->multiplicity = count; + else + entry->multiplicity += count; + _set_->cardinality += count; + return true; +} +bool ms_update(multiset *_set_, size_t element, size_t multiplicity) +{ + if (multiplicity == 0) + return ms_remove_all(_set_, element); + bool new_node; + multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node); + if (!entry) + return false; + if (new_node) + _set_->cardinality++; + _set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity; + entry->multiplicity = multiplicity; + return true; +} +bool ms_remove(multiset *_set_, size_t element) +{ + multiset_entry *result = ms_impl_get_entry(_set_, element); + if (result == NULL) + return false; + if (result->multiplicity > 1) + result->multiplicity--; + else + { + result->value = ms_impl_default_value(); + result->multiplicity = 0; + result->dist = 0; + result->state = CMC_ES_DELETED; + _set_->count--; + } + _set_->cardinality--; + return true; +} +size_t ms_remove_all(multiset *_set_, size_t element) +{ + multiset_entry *result = ms_impl_get_entry(_set_, element); + if (result == NULL) + return 0; + size_t removed = result->multiplicity; + result->value = ms_impl_default_value(); + result->multiplicity = 0; + result->dist = 0; + result->state = CMC_ES_DELETED; + _set_->count--; + _set_->cardinality -= removed; + return removed; +} +bool ms_insert_if(multiset *_set_, size_t element, bool condition) +{ + if (condition) + return ms_insert(_set_, element); + return false; +} +bool ms_remove_if(multiset *_set_, size_t element, bool condition) +{ + if (condition) + return ms_remove(_set_, element); + return false; +} +bool ms_max(multiset *_set_, size_t *value) +{ + if (ms_empty(_set_)) + return false; + multiset_iter iter; + for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t result = ms_iter_value(&iter); + size_t index = ms_iter_index(&iter); + if (index == 0) + *value = result; + else if (_set_->cmp(result, *value) > 0) + *value = result; + } + return true; +} +bool ms_min(multiset *_set_, size_t *value) +{ + if (ms_empty(_set_)) + return false; + multiset_iter iter; + for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t result = ms_iter_value(&iter); + size_t index = ms_iter_index(&iter); + if (index == 0) + *value = result; + else if (_set_->cmp(result, *value) < 0) + *value = result; + } + return true; +} +size_t ms_multiplicity_of(multiset *_set_, size_t element) +{ + multiset_entry *entry = ms_impl_get_entry(_set_, element); + if (!entry) + return 0; + return entry->multiplicity; +} +bool ms_contains(multiset *_set_, size_t element) { return ms_impl_get_entry(_set_, element) != NULL; } +bool ms_empty(multiset *_set_) { return _set_->count == 0; } +size_t ms_count(multiset *_set_) { return _set_->count; } +size_t ms_cardinality(multiset *_set_) { return _set_->cardinality; } +size_t ms_capacity(multiset *_set_) { return _set_->capacity; } +cmc_string ms_to_string(multiset *_set_) +{ + cmc_string str; + multiset *s_ = _set_; + const char *name = "multiset"; + snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, name, s_, s_->buffer, s_->capacity, s_->count, s_->cardinality, s_->load, s_->cmp, s_->hash); + return str; +} +multiset *ms_union(multiset *_set1_, multiset *_set2_) +{ + multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); + if (!_set_r_) + return NULL; + multiset_iter iter1, iter2; + ms_iter_init(&iter1, _set1_); + ms_iter_init(&iter2, _set2_); + for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1)) + { + size_t value = ms_iter_value(&iter1); + size_t m1 = ms_iter_multiplicity(&iter1); + size_t m2 = ms_multiplicity_of(_set2_, value); + size_t max_ = m1 > m2 ? m1 : m2; + ms_update(_set_r_, value, max_); + } + for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2)) + { + size_t value = ms_iter_value(&iter2); + size_t m1 = ms_multiplicity_of(_set1_, value); + size_t m2 = ms_iter_multiplicity(&iter2); + size_t max_ = m1 > m2 ? m1 : m2; + ms_update(_set_r_, value, max_); + } + return _set_r_; +} +multiset *ms_intersection(multiset *_set1_, multiset *_set2_) +{ + multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); + if (!_set_r_) + return NULL; + multiset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; + multiset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; + multiset_iter iter; + ms_iter_init(&iter, _set_A_); + for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t value = ms_iter_value(&iter); + size_t m1 = ms_iter_multiplicity(&iter); + size_t m2 = ms_multiplicity_of(_set_B_, value); + size_t max_ = m1 < m2 ? m1 : m2; + ms_update(_set_r_, value, max_); + } + return _set_r_; +} +multiset *ms_difference(multiset *_set1_, multiset *_set2_) +{ + multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); + if (!_set_r_) + return NULL; + multiset_iter iter; + ms_iter_init(&iter, _set1_); + for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t value = ms_iter_value(&iter); + size_t m1 = ms_iter_multiplicity(&iter); + size_t m2 = ms_multiplicity_of(_set2_, value); + if (m1 > m2) + ms_update(_set_r_, value, m1 - m2); + } + return _set_r_; +} +multiset *ms_summation(multiset *_set1_, multiset *_set2_) +{ + multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); + if (!_set_r_) + return NULL; + multiset_iter iter1, iter2; + ms_iter_init(&iter1, _set1_); + ms_iter_init(&iter2, _set2_); + for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1)) + { + ms_insert_many(_set_r_, ms_iter_value(&iter1), ms_iter_multiplicity(&iter1)); + } + for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2)) + { + ms_insert_many(_set_r_, ms_iter_value(&iter2), ms_iter_multiplicity(&iter2)); + } + return _set_r_; +} +multiset *ms_symmetric_difference(multiset *_set1_, multiset *_set2_) +{ + multiset_iter iter1, iter2; + multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash); + if (!_set_r_) + return NULL; + ms_iter_init(&iter1, _set1_); + ms_iter_init(&iter2, _set2_); + for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1)) + { + size_t value = ms_iter_value(&iter1); + size_t m1 = ms_iter_multiplicity(&iter1); + size_t m2 = ms_multiplicity_of(_set2_, value); + if (m1 != m2) + { + if (m1 > m2) + ms_update(_set_r_, value, m1 - m2); + else + ms_update(_set_r_, value, m2 - m1); + } + } + for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2)) + { + size_t value = ms_iter_value(&iter2); + size_t m1 = ms_multiplicity_of(_set1_, value); + size_t m2 = ms_iter_multiplicity(&iter2); + if (m1 != m2) + { + if (m1 > m2) + ms_update(_set_r_, value, m1 - m2); + else + ms_update(_set_r_, value, m2 - m1); + } + } + return _set_r_; +} +bool ms_is_subset(multiset *_set1_, multiset *_set2_) +{ + if (ms_count(_set1_) > ms_count(_set2_)) + return false; + if (ms_empty(_set1_)) + return true; + multiset_iter iter; + ms_iter_init(&iter, _set1_); + for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t value = ms_iter_value(&iter); + size_t m1 = ms_iter_multiplicity(&iter); + size_t m2 = ms_multiplicity_of(_set2_, value); + if (m1 > m2) + return false; + } + return true; +} +bool ms_is_superset(multiset *_set1_, multiset *_set2_) { return ms_is_subset(_set2_, _set1_); } +bool ms_is_proper_subset(multiset *_set1_, multiset *_set2_) +{ + if (ms_count(_set1_) >= ms_count(_set2_)) + return false; + if (ms_empty(_set1_)) + { + if (!ms_empty(_set2_)) + return true; + else + return false; + } + multiset_iter iter; + ms_iter_init(&iter, _set1_); + for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t value = ms_iter_value(&iter); + size_t m1 = ms_iter_multiplicity(&iter); + size_t m2 = ms_multiplicity_of(_set2_, value); + if (m1 >= m2) + return false; + } + return true; +} +bool ms_is_proper_superset(multiset *_set1_, multiset *_set2_) { return ms_is_proper_subset(_set2_, _set1_); } +bool ms_is_disjointset(multiset *_set1_, multiset *_set2_) +{ + if (ms_empty(_set1_)) + return true; + multiset_iter iter; + ms_iter_init(&iter, _set1_); + for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + size_t value = ms_iter_value(&iter); + if (ms_contains(_set2_, value)) + return false; + } + return true; +} +multiset_iter *ms_iter_new(multiset *target) +{ + multiset_iter *iter = malloc(sizeof(multiset_iter)); + if (!iter) + return NULL; + ms_iter_init(iter, target); + return iter; +} +void ms_iter_free(multiset_iter *iter) { free(iter); } +void ms_iter_init(multiset_iter *iter, multiset *target) +{ + iter->target = target; + iter->cursor = 0; + iter->index = 0; + iter->start = true; + iter->end = ms_empty(target); + if (!ms_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; + } + } + } +} +bool ms_iter_start(multiset_iter *iter) { return ms_empty(iter->target) || iter->start; } +bool ms_iter_end(multiset_iter *iter) { return ms_empty(iter->target) || iter->end; } +void ms_iter_to_start(multiset_iter *iter) +{ + iter->cursor = iter->first; + iter->index = 0; + iter->start = true; + iter->end = ms_empty(iter->target); +} +void ms_iter_to_end(multiset_iter *iter) +{ + iter->cursor = iter->last; + iter->index = iter->target->count - 1; + iter->start = ms_empty(iter->target); + iter->end = true; +} +bool ms_iter_next(multiset_iter *iter) +{ + if (iter->end) + return false; + multiset_entry *scan = &(iter->target->buffer[iter->cursor]); + if (iter->cursor == iter->last) + iter->end = true; + else + { + iter->index++; + while (1) + { + iter->cursor++; + scan = &(iter->target->buffer[iter->cursor]); + if (scan->state == CMC_ES_FILLED) + break; + } + } + iter->start = ms_empty(iter->target); + return true; +} +bool ms_iter_prev(multiset_iter *iter) +{ + if (iter->start) + return false; + multiset_entry *scan = &(iter->target->buffer[iter->cursor]); + if (iter->cursor == iter->first) + iter->start = true; + else + { + iter->index--; + while (1) + { + iter->cursor--; + scan = &(iter->target->buffer[iter->cursor]); + if (scan->state == CMC_ES_FILLED) + break; + } + } + iter->end = ms_empty(iter->target); + return true; +} +size_t ms_iter_value(multiset_iter *iter) +{ + if (ms_empty(iter->target)) + return ms_impl_default_value(); + return iter->target->buffer[iter->cursor].value; +} +size_t ms_iter_multiplicity(multiset_iter *iter) +{ + if (ms_empty(iter->target)) + return 0; + return iter->target->buffer[iter->cursor].multiplicity; +} +size_t ms_iter_index(multiset_iter *iter) { return iter->index; } +static multiset_entry *ms_impl_insert_and_return(multiset *_set_, size_t element, bool *new_node) +{ + *new_node = false; + multiset_entry *entry = ms_impl_get_entry(_set_, element); + if (entry != NULL) + return entry; + *new_node = true; + if ((double)_set_->capacity * _set_->load <= (double)_set_->count) + { + if (!ms_impl_grow(_set_)) + return NULL; + } + size_t hash = _set_->hash(element); + size_t original_pos = hash % _set_->capacity; + size_t pos = original_pos; + size_t curr_mul = 1; + multiset_entry *target = &(_set_->buffer[pos]); + if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED) + { + target->value = element; + target->multiplicity = curr_mul; + target->dist = pos - original_pos; + 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 = element; + target->multiplicity = curr_mul; + target->dist = pos - original_pos; + target->state = CMC_ES_FILLED; + break; + } + else if (target->dist < pos - original_pos) + { + size_t tmp = target->value; + size_t tmp_dist = target->dist; + size_t tmp_mul = target->multiplicity; + target->value = element; + target->dist = pos - original_pos; + target->multiplicity = curr_mul; + element = tmp; + original_pos = pos - tmp_dist; + curr_mul = tmp_mul; + } + } + } + _set_->count++; + return target; +} +static bool ms_impl_grow(multiset *_set_) +{ + size_t new_size = ms_impl_calculate_size(_set_->capacity + _set_->capacity / 2); + multiset *_new_set_ = ms_new(new_size, _set_->load, _set_->cmp, _set_->hash); + if (!_new_set_) + return false; + multiset_iter iter; + for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter)) + { + ms_insert_many(_new_set_, ms_iter_value(&iter), ms_iter_multiplicity(&iter)); + } + if (_set_->count != _new_set_->count) + { + ms_free(_new_set_); + return false; + } + multiset_entry *tmp = _set_->buffer; + _set_->buffer = _new_set_->buffer; + _new_set_->buffer = tmp; + _set_->capacity = _new_set_->capacity; + ms_free(_new_set_); + return true; +} +static multiset_entry *ms_impl_get_entry(multiset *_set_, size_t element) +{ + size_t hash = _set_->hash(element); + size_t pos = hash % _set_->capacity; + multiset_entry *target = &(_set_->buffer[pos]); + while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED) + { + if (_set_->cmp(target->value, element) == 0) + return target; + pos++; + target = &(_set_->buffer[pos % _set_->capacity]); + } + return NULL; +} +static size_t ms_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]; +} +static multiset_iter ms_impl_it_start(multiset *_set_) +{ + multiset_iter iter; + ms_iter_init(&iter, _set_); + return iter; +} +static multiset_iter ms_impl_it_end(multiset *_set_) +{ + multiset_iter iter; + ms_iter_init(&iter, _set_); + ms_iter_to_end(&iter); + return iter; +} diff --git a/tests/main/unt/multiset.c b/tests/main/unt/multiset.c new file mode 100644 index 0000000..48f27a9 --- /dev/null +++ b/tests/main/unt/multiset.c @@ -0,0 +1,102 @@ +#include "utl/assert.h" +#include "utl/test.h" +#include "../src/multiset.c" + +#include "utl.c" + +CMC_CREATE_UNIT(multiset_test, true, { + CMC_CREATE_TEST(new, { + multiset *set = ms_new(943722, 0.6, cmp, hash); + + bool passed = (set->capacity >= (943722 / 0.6)) && set->count == 0 && set->buffer; + + cmc_assert_not_equals(ptr, NULL, set); + cmc_assert(ms_capacity(set) > (943722 / 0.6)); + + CMC_TEST_PASS_ELSE_FAIL(passed); + + ms_free(set); + }); + + CMC_CREATE_TEST(new[edge_case:capacity = 0], { + multiset *set = ms_new(0, 0.6, cmp, hash); + + cmc_assert_equals(ptr, NULL, set); + + CMC_TEST_PASS_ELSE_FAIL(set == NULL); + }); + + CMC_CREATE_TEST(new[edge_case:capacity = UINTMAX_MAX], { + multiset *set = ms_new(UINTMAX_MAX, 0.99, cmp, hash); + + cmc_assert_equals(ptr, NULL, set); + + CMC_TEST_PASS_ELSE_FAIL(set == NULL); + }); + + CMC_CREATE_TEST(clear[count capacity], { + multiset *set = ms_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 50; i++) + cmc_assert(ms_insert(set, i)); + + cmc_assert_equals(size_t, 50, ms_count(set)); + + ms_clear(set); + + cmc_assert_equals(size_t, 0, ms_count(set)); + + CMC_TEST_PASS_ELSE_FAIL(ms_count(set) == 0); + + ms_free(set); + }); + + CMC_CREATE_TEST(insert[count cardinality multiplicity], { + multiset *set = ms_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, set); + + cmc_assert(ms_insert(set, 1)); + cmc_assert(ms_insert(set, 2)); + cmc_assert(ms_insert(set, 2)); + cmc_assert(ms_insert(set, 3)); + cmc_assert(ms_insert(set, 3)); + cmc_assert(ms_insert(set, 3)); + + cmc_assert_equals(size_t, 3, ms_count(set)); + cmc_assert_equals(size_t, 6, ms_cardinality(set)); + + bool passed = ms_count(set) == 3 && ms_cardinality(set) == 6; + + for (size_t i = 0; i <= 3; i++) + passed = passed && ms_multiplicity_of(set, i) == i; + + CMC_TEST_PASS_ELSE_FAIL(passed); + + ms_free(set); + }); + + CMC_CREATE_TEST(multiplicity, { + multiset *set = ms_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 100; i++) + cmc_assert(ms_insert(set, i % 20)); + + cmc_assert_equals(size_t, 20, ms_count(set)); + cmc_assert_equals(size_t, 100, ms_cardinality(set)); + + bool passed = ms_count(set) == 20 && ms_cardinality(set) == 100; + + for (size_t i = 0; i < 20; i++) + passed = passed && ms_multiplicity_of(set, i) == 5; + + CMC_TEST_PASS_ELSE_FAIL(passed); + + ms_free(set); + }); + +});