Adding functions table to multimap and multiset

This commit is contained in:
Leonardo committed 2020-02-08 00:01:46 -03:00
1 parent 683decfa64
commit 147e622580
4 files changed
+326 -231

No files matched your search

+157 -100
View File
@@ -160,8 +160,9 @@ static const char *cmc_string_fmt_multimap = "struct %s<%s, %s> "
"capacity:%" PRIuMAX ", "
"count:%" PRIuMAX ", "
"load:%lf, "
"cmp:%p, "
"hash:%p, "
"flag:%d, "
"f_key:%p, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }";
@@ -210,23 +211,26 @@ struct cmc_callbacks_multimap
/* Load factor in range (0.0, infinity) */ \
double load; \
\
/* Key comparison functions */ \
int (*cmp)(K, K); \
/* Flags indicating errors or success */ \
int flag; \
\
/* Key hash function */ \
size_t (*hash)(K); \
/* Key function table */ \
struct SNAME##_ftab_key *f_key; \
\
/* Function that returns an iterator to the start of the multimap */ \
struct SNAME##_iter (*it_start)(struct SNAME *); \
\
/* Function that returns an iterator to the end of the multimap */ \
struct SNAME##_iter (*it_end)(struct SNAME *); \
/* Value function table */ \
struct SNAME##_ftab_val *f_val; \
\
/* Custom allocation functions */ \
struct cmc_alloc_node *alloc; \
\
/* Custom callback functions */ \
struct cmc_callbacks_multimap *callbacks; \
\
/* Function that returns an iterator to the start of the multimap */ \
struct SNAME##_iter (*it_start)(struct SNAME *); \
\
/* Function that returns an iterator to the end of the multimap */ \
struct SNAME##_iter (*it_end)(struct SNAME *); \
}; \
\
/* Multimap Entry */ \
@@ -245,6 +249,50 @@ struct cmc_callbacks_multimap
struct SNAME##_entry *prev; \
}; \
\
/* Key struct function table */ \
struct SNAME##_ftab_key \
{ \
/* Comparator function */ \
int (*cmp)(K, K); \
\
/* Copy function */ \
K (*cpy)(K); \
\
/* To string function */ \
bool (*str)(FILE *, K); \
\
/* Free from memory function */ \
void (*free)(K); \
\
/* Hash function */ \
size_t (*hash)(K); \
\
/* Priority function */ \
int (*pri)(K, K); \
}; \
\
/* Value struct function table */ \
struct SNAME##_ftab_val \
{ \
/* Comparator function */ \
int (*cmp)(V, V); \
\
/* Copy function */ \
V (*cpy)(V); \
\
/* To string function */ \
bool (*str)(FILE *, V); \
\
/* Free from memory function */ \
void (*free)(V); \
\
/* Hash function */ \
size_t (*hash)(V); \
\
/* Priority function */ \
int (*pri)(V, V); \
}; \
\
struct SNAME##_iter \
{ \
/* Target multimap */ \
@@ -275,13 +323,14 @@ struct cmc_callbacks_multimap
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
struct SNAME *PFX##_new(size_t capacity, double load, \
int (*compare)(K, K), size_t (*hash)(K)); \
struct SNAME *PFX##_new_custom(size_t capacity, double load, \
int (*compare)(K, K), size_t (*hash)(K), \
struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multimap *callbacks); \
void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)); \
void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)); \
struct SNAME##_ftab_key *f_key, \
struct SNAME##_ftab_val *f_val); \
struct SNAME *PFX##_new_custom( \
size_t capacity, double load, struct SNAME##_ftab_key *f_key, \
struct SNAME##_ftab_val *f_val, struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multimap *callbacks); \
void PFX##_clear(struct SNAME *_map_); \
void PFX##_free(struct SNAME *_map_); \
/* Customization of Allocation and Callbacks */ \
void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multimap *callbacks); \
@@ -307,8 +356,7 @@ struct cmc_callbacks_multimap
double PFX##_load(struct SNAME *_map_); \
/* Collection Utility */ \
bool PFX##_resize(struct SNAME *_map_, size_t capacity); \
struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), \
V (*value_copy_func)(V)); \
struct SNAME *PFX##_copy_of(struct SNAME *_map_); \
bool PFX##_equals(struct SNAME *_map1_, struct SNAME *_map2_, \
bool ignore_key_count); \
struct cmc_string PFX##_to_string(struct SNAME *_map_); \
@@ -350,7 +398,8 @@ struct cmc_callbacks_multimap
static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_map_); \
\
struct SNAME *PFX##_new(size_t capacity, double load, \
int (*compare)(K, K), size_t (*hash)(K)) \
struct SNAME##_ftab_key *f_key, \
struct SNAME##_ftab_val *f_val) \
{ \
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
\
@@ -361,6 +410,9 @@ struct cmc_callbacks_multimap
if (capacity >= UINTMAX_MAX * load) \
return NULL; \
\
if (!f_key || !f_val) \
return NULL; \
\
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
\
struct SNAME *_map_ = alloc->malloc(sizeof(struct SNAME)); \
@@ -380,22 +432,21 @@ struct cmc_callbacks_multimap
_map_->count = 0; \
_map_->capacity = real_capacity; \
_map_->load = load; \
_map_->cmp = compare; \
_map_->hash = hash; \
\
_map_->it_start = PFX##_impl_it_start; \
_map_->it_end = PFX##_impl_it_end; \
\
_map_->flag = cmc_flags.OK; \
_map_->f_key = f_key; \
_map_->f_val = f_val; \
_map_->alloc = alloc; \
_map_->callbacks = NULL; \
_map_->it_end = PFX##_impl_it_end; \
_map_->it_start = PFX##_impl_it_start; \
\
return _map_; \
} \
\
struct SNAME *PFX##_new_custom(size_t capacity, double load, \
int (*compare)(K, K), size_t (*hash)(K), \
struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multimap *callbacks) \
struct SNAME *PFX##_new_custom( \
size_t capacity, double load, struct SNAME##_ftab_key *f_key, \
struct SNAME##_ftab_val *f_val, struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multimap *callbacks) \
{ \
if (capacity == 0 || load <= 0) \
return NULL; \
@@ -404,6 +455,9 @@ struct cmc_callbacks_multimap
if (capacity >= UINTMAX_MAX * load) \
return NULL; \
\
if (!f_key || !f_val) \
return NULL; \
\
if (!alloc) \
alloc = &cmc_alloc_node_default; \
\
@@ -426,35 +480,35 @@ struct cmc_callbacks_multimap
_map_->count = 0; \
_map_->capacity = real_capacity; \
_map_->load = load; \
_map_->cmp = compare; \
_map_->hash = hash; \
\
_map_->it_start = PFX##_impl_it_start; \
_map_->it_end = PFX##_impl_it_end; \
\
_map_->flag = cmc_flags.OK; \
_map_->f_key = f_key; \
_map_->f_val = f_val; \
_map_->alloc = alloc; \
_map_->callbacks = callbacks; \
_map_->it_start = PFX##_impl_it_start; \
_map_->it_end = PFX##_impl_it_end; \
\
return _map_; \
} \
\
void PFX##_clear(struct SNAME *_map_, void (*deallocator)(K, V)) \
void PFX##_clear(struct SNAME *_map_) \
{ \
size_t index = 0; \
struct SNAME##_entry *scan; \
\
while (index < _map_->capacity) \
{ \
scan = _map_->buffer[index][0]; \
struct SNAME##_entry *scan = _map_->buffer[index][0]; \
\
if (scan != NULL) \
{ \
if (scan->next == NULL && scan->prev == NULL) \
{ \
if (deallocator) \
deallocator(scan->key, scan->value); \
if (_map_->f_key->free) \
_map_->f_key->free(scan->key); \
if (_map_->f_val->free) \
_map_->f_val->free(scan->value); \
\
free(scan); \
_map_->alloc->free(scan); \
} \
else \
{ \
@@ -464,10 +518,12 @@ struct cmc_callbacks_multimap
\
scan = scan->next; \
\
if (deallocator) \
deallocator(tmp->key, tmp->value); \
if (_map_->f_key->free) \
_map_->f_key->free(tmp->key); \
if (_map_->f_val->free) \
_map_->f_val->free(tmp->value); \
\
free(tmp); \
_map_->alloc->free(tmp); \
} \
} \
} \
@@ -481,19 +537,25 @@ struct cmc_callbacks_multimap
_map_->count = 0; \
} \
\
void PFX##_free(struct SNAME *_map_, void (*deallocator)(K, V)) \
void PFX##_free(struct SNAME *_map_) \
{ \
size_t index = 0; \
struct SNAME##_entry *scan; \
\
while (index < _map_->capacity) \
{ \
scan = _map_->buffer[index][0]; \
struct SNAME##_entry *scan = _map_->buffer[index][0]; \
\
if (scan != NULL) \
{ \
if (scan->next == NULL && scan->prev == NULL) \
free(scan); \
{ \
if (_map_->f_key->free) \
_map_->f_key->free(scan->key); \
if (_map_->f_val->free) \
_map_->f_val->free(scan->value); \
\
_map_->alloc->free(scan); \
} \
else \
{ \
while (scan != NULL) \
@@ -502,10 +564,12 @@ struct cmc_callbacks_multimap
\
scan = scan->next; \
\
if (deallocator) \
deallocator(tmp->key, tmp->value); \
if (_map_->f_key->free) \
_map_->f_key->free(tmp->key); \
if (_map_->f_val->free) \
_map_->f_val->free(tmp->value); \
\
free(tmp); \
_map_->alloc->free(tmp); \
} \
} \
} \
@@ -513,8 +577,8 @@ struct cmc_callbacks_multimap
index++; \
} \
\
free(_map_->buffer); \
free(_map_); \
_map_->alloc->free(_map_->buffer); \
_map_->alloc->free(_map_); \
} \
\
void PFX##_customize(struct SNAME *_map_, struct cmc_alloc_node *alloc, \
@@ -535,7 +599,7 @@ struct cmc_callbacks_multimap
return false; \
} \
\
size_t hash = _map_->hash(key); \
size_t hash = _map_->f_key->hash(key); \
size_t pos = hash % _map_->capacity; \
\
struct SNAME##_entry *entry = PFX##_impl_new_entry(_map_, key, value); \
@@ -590,14 +654,14 @@ struct cmc_callbacks_multimap
return false; \
} \
\
size_t hash = _map_->hash(key); \
size_t hash = _map_->f_key->hash(key); \
\
struct SNAME##_entry *entry = \
_map_->buffer[hash % _map_->capacity][0]; \
\
while (entry != NULL) \
{ \
if (_map_->cmp(entry->key, key) == 0) \
if (_map_->f_key->cmp(entry->key, key) == 0) \
{ \
if (old_values) \
(*old_values)[index++] = entry->value; \
@@ -613,7 +677,7 @@ struct cmc_callbacks_multimap
\
bool PFX##_remove(struct SNAME *_map_, K key, V *out_value) \
{ \
size_t hash = _map_->hash(key); \
size_t hash = _map_->f_key->hash(key); \
\
struct SNAME##_entry **head = \
&(_map_->buffer[hash % _map_->capacity][0]); \
@@ -627,7 +691,7 @@ struct cmc_callbacks_multimap
\
if (entry->next == NULL && entry->prev == NULL) \
{ \
if (_map_->cmp(entry->key, key) == 0) \
if (_map_->f_key->cmp(entry->key, key) == 0) \
{ \
*head = NULL; \
*tail = NULL; \
@@ -644,7 +708,7 @@ struct cmc_callbacks_multimap
\
while (entry != NULL) \
{ \
if (_map_->cmp(entry->key, key) == 0) \
if (_map_->f_key->cmp(entry->key, key) == 0) \
{ \
if (*head == entry) \
*head = entry->next; \
@@ -671,7 +735,7 @@ struct cmc_callbacks_multimap
return false; \
} \
\
free(entry); \
_map_->alloc->free(entry); \
\
_map_->count--; \
\
@@ -680,7 +744,7 @@ struct cmc_callbacks_multimap
\
size_t PFX##_remove_all(struct SNAME *_map_, K key, V **out_values) \
{ \
size_t hash = _map_->hash(key); \
size_t hash = _map_->f_key->hash(key); \
\
struct SNAME##_entry **head = \
&(_map_->buffer[hash % _map_->capacity][0]); \
@@ -707,13 +771,13 @@ struct cmc_callbacks_multimap
if (out_values) \
(*out_values)[index++] = entry->value; \
\
free(entry); \
_map_->alloc->free(entry); \
} \
else \
{ \
while (entry != NULL) \
{ \
if (_map_->cmp(entry->key, key) == 0) \
if (_map_->f_key->cmp(entry->key, key) == 0) \
{ \
if (*head == entry) \
*head = entry->next; \
@@ -730,7 +794,7 @@ struct cmc_callbacks_multimap
if (out_values) \
(*out_values)[index++] = entry->value; \
\
free(entry); \
_map_->alloc->free(entry); \
\
entry = temp; \
} \
@@ -763,7 +827,7 @@ struct cmc_callbacks_multimap
*key = result_key; \
*value = result_value; \
} \
else if (_map_->cmp(result_key, *key) > 0) \
else if (_map_->f_key->cmp(result_key, *key) > 0) \
{ \
*key = result_key; \
*value = result_value; \
@@ -792,7 +856,7 @@ struct cmc_callbacks_multimap
*key = result_key; \
*value = result_value; \
} \
else if (_map_->cmp(result_key, *key) < 0) \
else if (_map_->f_key->cmp(result_key, *key) < 0) \
{ \
*key = result_key; \
*value = result_value; \
@@ -834,8 +898,7 @@ struct cmc_callbacks_multimap
\
bool PFX##_full(struct SNAME *_map_) \
{ \
return (double)PFX##_capacity(_map_) * PFX##_load(_map_) <= \
(double)PFX##_count(_map_); \
return (double)_map_->capacity * _map_->load <= (double)_map_->count; \
} \
\
size_t PFX##_count(struct SNAME *_map_) \
@@ -845,7 +908,7 @@ struct cmc_callbacks_multimap
\
size_t PFX##_key_count(struct SNAME *_map_, K key) \
{ \
size_t hash = _map_->hash(key); \
size_t hash = _map_->f_key->hash(key); \
\
struct SNAME##_entry *entry = \
_map_->buffer[hash % _map_->capacity][0]; \
@@ -857,7 +920,7 @@ struct cmc_callbacks_multimap
\
while (entry != NULL) \
{ \
if (_map_->cmp(entry->key, key) == 0) \
if (_map_->f_key->cmp(entry->key, key) == 0) \
total_count++; \
\
entry = entry->next; \
@@ -881,23 +944,23 @@ struct cmc_callbacks_multimap
if (PFX##_capacity(_map_) == capacity) \
return true; \
\
if (PFX##_capacity(_map_) > capacity / PFX##_load(_map_)) \
if (PFX##_capacity(_map_) > capacity / _map_->load) \
return true; \
\
/* Prevent integer overflow */ \
if (capacity >= UINTMAX_MAX * PFX##_load(_map_)) \
if (capacity >= UINTMAX_MAX * _map_->load) \
return false; \
\
/* Calculate required capacity based on the prime numbers */ \
size_t theoretical_size = PFX##_impl_calculate_size(capacity); \
\
/* Not possible to shrink with current available prime numbers */ \
if (theoretical_size < PFX##_count(_map_) / PFX##_load(_map_)) \
if (theoretical_size < PFX##_count(_map_) / _map_->load) \
return false; \
\
struct SNAME *_new_map_ = \
PFX##_new_custom(capacity, PFX##_load(_map_), _map_->cmp, \
_map_->hash, _map_->alloc, _map_->callbacks); \
PFX##_new_custom(capacity, _map_->load, _map_->f_key, \
_map_->f_val, _map_->alloc, _map_->callbacks); \
\
if (!_new_map_) \
return false; \
@@ -915,7 +978,7 @@ struct cmc_callbacks_multimap
\
if (PFX##_count(_map_) != PFX##_count(_new_map_)) \
{ \
PFX##_free(_new_map_, NULL); \
PFX##_free(_new_map_); \
return false; \
} \
\
@@ -927,17 +990,16 @@ struct cmc_callbacks_multimap
_map_->capacity = _new_map_->capacity; \
_new_map_->capacity = tmp_c; \
\
PFX##_free(_new_map_, NULL); \
PFX##_free(_new_map_); \
\
return true; \
} \
\
struct SNAME *PFX##_copy_of(struct SNAME *_map_, K (*key_copy_func)(K), \
V (*value_copy_func)(V)) \
struct SNAME *PFX##_copy_of(struct SNAME *_map_) \
{ \
struct SNAME *result = \
PFX##_new_custom(_map_->capacity, _map_->load, _map_->cmp, \
_map_->hash, _map_->alloc, _map_->callbacks); \
PFX##_new_custom(_map_->capacity, _map_->load, _map_->f_key, \
_map_->f_val, _map_->alloc, _map_->callbacks); \
\
if (!result) \
return NULL; \
@@ -953,10 +1015,10 @@ struct cmc_callbacks_multimap
K key = PFX##_iter_key(&iter); \
V value = PFX##_iter_value(&iter); \
\
if (key_copy_func) \
key = key_copy_func(key); \
if (value_copy_func) \
value = value_copy_func(value); \
if (_map_->f_key->cpy) \
key = _map_->f_key->cpy(key); \
if (_map_->f_val->cpy) \
value = _map_->f_val->cpy(value); \
\
PFX##_insert(result, key, value); \
} \
@@ -1010,17 +1072,12 @@ struct cmc_callbacks_multimap
struct cmc_string str; \
struct SNAME *m_ = _map_; \
\
int n = \
snprintf(str.s, cmc_string_len, cmc_string_fmt_multimap, #SNAME, \
#K, #V, m_, m_->buffer, m_->capacity, m_->count, \
m_->load, m_->cmp, m_->hash, m_->alloc, m_->callbacks); \
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_multimap, \
#SNAME, #K, #V, m_, m_->buffer, m_->capacity, \
m_->count, m_->load, m_->flag, m_->f_key, m_->f_val, \
m_->alloc, m_->callbacks); \
\
if (n < 0 || n == (int)cmc_string_len) \
return (struct cmc_string){ 0 }; \
\
str.s[n] = '\0'; \
\
return str; \
return n >= 0 ? str : (struct cmc_string){ 0 }; \
} \
\
struct SNAME##_iter *PFX##_iter_new(struct SNAME *target) \
@@ -1038,7 +1095,7 @@ struct cmc_callbacks_multimap
\
void PFX##_iter_free(struct SNAME##_iter *iter) \
{ \
free(iter); \
iter->target->alloc->free(iter); \
} \
\
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
@@ -1279,14 +1336,14 @@ struct cmc_callbacks_multimap
\
struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_map_, K key) \
{ \
size_t hash = _map_->hash(key); \
size_t hash = _map_->f_key->hash(key); \
\
struct SNAME##_entry *entry = \
_map_->buffer[hash % _map_->capacity][0]; \
\
while (entry != NULL) \
{ \
if (_map_->cmp(entry->key, key) == 0) \
if (_map_->f_key->cmp(entry->key, key) == 0) \
return entry; \
\
entry = entry->next; \
+109 -95
View File
@@ -151,8 +151,8 @@ static const char *cmc_string_fmt_multiset = "struct %s<%s> "
"count:%" PRIuMAX ", "
"cardinality:%" PRIuMAX ", "
"load:%lf, "
"cmp:%p, "
"hash:%p, "
"flag:%d, "
"f_val:%p, "
"alloc:%p, "
"callbacks:%p }";
@@ -204,23 +204,23 @@ struct cmc_callbacks_multiset
/* Load factor in range (0.0, 1.0) */ \
double load; \
\
/* Element comparison function */ \
int (*cmp)(V, V); \
/* Flags indicating errors or success */ \
int flag; \
\
/* Element hash function */ \
size_t (*hash)(V); \
\
/* Function that returns an iterator to the start of the hashset */ \
struct SNAME##_iter (*it_start)(struct SNAME *); \
\
/* Function that returns an iterator to the end of the hashset */ \
struct SNAME##_iter (*it_end)(struct SNAME *); \
/* Key function table */ \
struct SNAME##_ftab_val *f_val; \
\
/* Custom allocation functions */ \
struct cmc_alloc_node *alloc; \
\
/* Custom callback functions */ \
struct cmc_callbacks_multiset *callbacks; \
\
/* Function that returns an iterator to the start of the hashset */ \
struct SNAME##_iter (*it_start)(struct SNAME *); \
\
/* Function that returns an iterator to the end of the hashset */ \
struct SNAME##_iter (*it_end)(struct SNAME *); \
}; \
\
struct SNAME##_entry \
@@ -239,6 +239,28 @@ struct cmc_callbacks_multiset
enum cmc_entry_state state; \
}; \
\
/* Value struct function table */ \
struct SNAME##_ftab_val \
{ \
/* Comparator function */ \
int (*cmp)(V, V); \
\
/* Copy function */ \
V (*cpy)(V); \
\
/* To string function */ \
bool (*str)(FILE *, V); \
\
/* Free from memory function */ \
void (*free)(V); \
\
/* Hash function */ \
size_t (*hash)(V); \
\
/* Priority function */ \
int (*pri)(V, V); \
}; \
\
/* Hashset Iterator */ \
struct SNAME##_iter \
{ \
@@ -267,13 +289,13 @@ struct cmc_callbacks_multiset
/* Collection Functions */ \
/* Collection Allocation and Deallocation */ \
struct SNAME *PFX##_new(size_t capacity, double load, \
int (*compare)(V, V), size_t (*hash)(V)); \
struct SNAME##_ftab_val *f_val); \
struct SNAME *PFX##_new_custom(size_t capacity, double load, \
int (*compare)(V, V), size_t (*hash)(V), \
struct SNAME##_ftab_val *f_val, \
struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multiset *callbacks); \
void PFX##_clear(struct SNAME *_set_, void (*deallocator)(V)); \
void PFX##_free(struct SNAME *_set_, void (*deallocator)(V)); \
void PFX##_clear(struct SNAME *_set_); \
void PFX##_free(struct SNAME *_set_); \
/* Customization of Allocation and Callbacks */ \
void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multiset *callbacks); \
@@ -297,9 +319,8 @@ struct cmc_callbacks_multiset
double PFX##_load(struct SNAME *_set_); \
/* Collection Utility */ \
bool PFX##_resize(struct SNAME *_set_, size_t capacity); \
struct SNAME *PFX##_copy_of(struct SNAME *_set_, V (*copy_func)(V)); \
bool PFX##_equals(struct SNAME *_set1_, struct SNAME *_set2_, \
bool ignore_multiplicity); \
struct SNAME *PFX##_copy_of(struct SNAME *_set_); \
bool PFX##_equals(struct SNAME *_set1_, struct SNAME *_set2_); \
struct cmc_string PFX##_to_string(struct SNAME *_set_); \
\
/* Set Operations */ \
@@ -354,7 +375,7 @@ struct cmc_callbacks_multiset
static struct SNAME##_iter PFX##_impl_it_end(struct SNAME *_set_); \
\
struct SNAME *PFX##_new(size_t capacity, double load, \
int (*compare)(V, V), size_t (*hash)(V)) \
struct SNAME##_ftab_val *f_val) \
{ \
struct cmc_alloc_node *alloc = &cmc_alloc_node_default; \
\
@@ -365,6 +386,9 @@ struct cmc_callbacks_multiset
if (capacity >= UINTMAX_MAX * load) \
return NULL; \
\
if (!f_val) \
return NULL; \
\
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
\
struct SNAME *_set_ = alloc->malloc(sizeof(struct SNAME)); \
@@ -385,20 +409,18 @@ struct cmc_callbacks_multiset
_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; \
\
_set_->flag = cmc_flags.OK; \
_set_->f_val = f_val; \
_set_->alloc = alloc; \
_set_->callbacks = NULL; \
_set_->it_start = PFX##_impl_it_start; \
_set_->it_end = PFX##_impl_it_end; \
\
return _set_; \
} \
\
struct SNAME *PFX##_new_custom(size_t capacity, double load, \
int (*compare)(V, V), size_t (*hash)(V), \
struct SNAME##_ftab_val *f_val, \
struct cmc_alloc_node *alloc, \
struct cmc_callbacks_multiset *callbacks) \
{ \
@@ -409,6 +431,9 @@ struct cmc_callbacks_multiset
if (capacity >= UINTMAX_MAX * load) \
return NULL; \
\
if (!f_val) \
return NULL; \
\
size_t real_capacity = PFX##_impl_calculate_size(capacity / load); \
\
if (!alloc) \
@@ -432,21 +457,19 @@ struct cmc_callbacks_multiset
_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; \
\
_set_->flag = cmc_flags.OK; \
_set_->f_val = f_val; \
_set_->alloc = alloc; \
_set_->callbacks = callbacks; \
_set_->it_start = PFX##_impl_it_start; \
_set_->it_end = PFX##_impl_it_end; \
\
return _set_; \
} \
\
void PFX##_clear(struct SNAME *_set_, void (*deallocator)(V)) \
void PFX##_clear(struct SNAME *_set_) \
{ \
if (deallocator) \
if (_set_->f_val->free) \
{ \
for (size_t i = 0; i < _set_->capacity; i++) \
{ \
@@ -454,7 +477,7 @@ struct cmc_callbacks_multiset
\
if (entry->state == CMC_ES_FILLED) \
{ \
deallocator(entry->value); \
_set_->f_val->free(entry->value); \
} \
} \
} \
@@ -465,9 +488,9 @@ struct cmc_callbacks_multiset
_set_->count = 0; \
} \
\
void PFX##_free(struct SNAME *_set_, void (*deallocator)(V)) \
void PFX##_free(struct SNAME *_set_) \
{ \
if (deallocator) \
if (_set_->f_val->free) \
{ \
for (size_t i = 0; i < _set_->capacity; i++) \
{ \
@@ -475,13 +498,13 @@ struct cmc_callbacks_multiset
\
if (entry->state == CMC_ES_FILLED) \
{ \
deallocator(entry->value); \
_set_->f_val->free(entry->value); \
} \
} \
} \
\
free(_set_->buffer); \
free(_set_); \
_set_->alloc->free(_set_->buffer); \
_set_->alloc->free(_set_); \
} \
\
void PFX##_customize(struct SNAME *_set_, struct cmc_alloc_node *alloc, \
@@ -618,7 +641,7 @@ struct cmc_callbacks_multiset
\
if (index == 0) \
*value = result; \
else if (_set_->cmp(result, *value) > 0) \
else if (_set_->f_val->cmp(result, *value) > 0) \
*value = result; \
} \
\
@@ -640,7 +663,7 @@ struct cmc_callbacks_multiset
\
if (index == 0) \
*value = result; \
else if (_set_->cmp(result, *value) < 0) \
else if (_set_->f_val->cmp(result, *value) < 0) \
*value = result; \
} \
\
@@ -669,8 +692,7 @@ struct cmc_callbacks_multiset
\
bool PFX##_full(struct SNAME *_set_) \
{ \
return (double)PFX##_capacity(_set_) * PFX##_load(_set_) <= \
(double)PFX##_count(_set_); \
return (double)_set_->capacity * _set_->load <= (double)_set_->count; \
} \
\
size_t PFX##_count(struct SNAME *_set_) \
@@ -695,26 +717,26 @@ struct cmc_callbacks_multiset
\
bool PFX##_resize(struct SNAME *_set_, size_t capacity) \
{ \
if (PFX##_capacity(_set_) == capacity) \
if (_set_->capacity == capacity) \
return true; \
\
if (PFX##_capacity(_set_) > capacity / PFX##_load(_set_)) \
if (_set_->capacity > capacity / _set_->load) \
return true; \
\
/* Prevent integer overflow */ \
if (capacity >= UINTMAX_MAX * PFX##_load(_set_)) \
if (capacity >= UINTMAX_MAX * _set_->load) \
return false; \
\
/* Calculate required capacity based on the prime numbers */ \
size_t theoretical_size = PFX##_impl_calculate_size(capacity); \
\
/* Not possible to shrink with current available prime numbers */ \
if (theoretical_size < PFX##_count(_set_) / PFX##_load(_set_)) \
if (theoretical_size < _set_->count / _set_->load) \
return false; \
\
struct SNAME *_new_set_ = \
PFX##_new_custom(capacity, PFX##_load(_set_), _set_->cmp, \
_set_->hash, _set_->alloc, _set_->callbacks); \
PFX##_new_custom(capacity, _set_->load, _set_->f_val, \
_set_->alloc, _set_->callbacks); \
\
if (!_new_set_) \
return false; \
@@ -728,9 +750,9 @@ struct cmc_callbacks_multiset
PFX##_iter_multiplicity(&iter)); \
} \
\
if (PFX##_count(_set_) != PFX##_count(_new_set_)) \
if (_set_->count != _new_set_->count) \
{ \
PFX##_free(_new_set_, NULL); \
PFX##_free(_new_set_); \
return false; \
} \
\
@@ -742,21 +764,21 @@ struct cmc_callbacks_multiset
_set_->capacity = _new_set_->capacity; \
_new_set_->capacity = tmp_c; \
\
PFX##_free(_new_set_, NULL); \
PFX##_free(_new_set_); \
\
return true; \
} \
\
struct SNAME *PFX##_copy_of(struct SNAME *_set_, V (*copy_func)(V)) \
struct SNAME *PFX##_copy_of(struct SNAME *_set_) \
{ \
struct SNAME *result = \
PFX##_new_custom(_set_->capacity, _set_->load, _set_->cmp, \
_set_->hash, _set_->alloc, _set_->callbacks); \
PFX##_new_custom(_set_->capacity, _set_->load, _set_->f_val, \
_set_->alloc, _set_->callbacks); \
\
if (!result) \
return NULL; \
\
if (copy_func) \
if (_set_->f_val->cpy) \
{ \
for (size_t i = 0; i < _set_->capacity; i++) \
{ \
@@ -774,7 +796,7 @@ struct cmc_callbacks_multiset
target->dist = scan->dist; \
target->multiplicity = scan->multiplicity; \
\
target->value = copy_func(scan->value); \
target->value = _set_->f_val->cpy(scan->value); \
} \
} \
} \
@@ -789,17 +811,15 @@ struct cmc_callbacks_multiset
return result; \
} \
\
bool PFX##_equals(struct SNAME *_set1_, struct SNAME *_set2_, \
bool ignore_multiplicity) \
bool PFX##_equals(struct SNAME *_set1_, struct SNAME *_set2_) \
{ \
if (PFX##_count(_set1_) != PFX##_count(_set2_)) \
if (_set1_->count != _set2_->count) \
return false; \
\
if (!ignore_multiplicity && \
PFX##_cardinality(_set1_) != PFX##_cardinality(_set2_)) \
if (_set1_->cardinality != _set2_->cardinality) \
return false; \
\
if (PFX##_count(_set1_) == 0) \
if (_set1_->count == 0) \
return true; \
\
struct SNAME##_iter iter; \
@@ -814,8 +834,7 @@ struct cmc_callbacks_multiset
if (entry == NULL) \
return false; \
\
if (!ignore_multiplicity && \
entry->multiplicity != PFX##_iter_multiplicity(&iter)) \
if (entry->multiplicity != PFX##_iter_multiplicity(&iter)) \
return false; \
} \
\
@@ -829,22 +848,17 @@ struct cmc_callbacks_multiset
\
int n = snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, \
#SNAME, #V, s_, s_->buffer, s_->capacity, s_->count, \
s_->cardinality, s_->load, s_->cmp, s_->hash, \
s_->cardinality, s_->load, s_->flag, s_->f_val, \
s_->alloc, s_->callbacks); \
\
if (n < 0 || n == (int)cmc_string_len) \
return (struct cmc_string){ 0 }; \
\
str.s[n] = '\0'; \
\
return str; \
return n >= 0 ? str : (struct cmc_string){ 0 }; \
} \
\
struct SNAME *PFX##_union(struct SNAME *_set1_, struct SNAME *_set2_) \
{ \
struct SNAME *_set_r_ = \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->cmp, \
_set1_->hash, _set1_->alloc, _set1_->callbacks); \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->f_val, \
_set1_->alloc, _set1_->callbacks); \
\
if (!_set_r_) \
return NULL; \
@@ -884,8 +898,8 @@ struct cmc_callbacks_multiset
struct SNAME *_set2_) \
{ \
struct SNAME *_set_r_ = \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->cmp, \
_set1_->hash, _set1_->alloc, _set1_->callbacks); \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->f_val, \
_set1_->alloc, _set1_->callbacks); \
\
if (!_set_r_) \
return NULL; \
@@ -915,8 +929,8 @@ struct cmc_callbacks_multiset
struct SNAME *PFX##_difference(struct SNAME *_set1_, struct SNAME *_set2_) \
{ \
struct SNAME *_set_r_ = \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->cmp, \
_set1_->hash, _set1_->alloc, _set1_->callbacks); \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->f_val, \
_set1_->alloc, _set1_->callbacks); \
\
if (!_set_r_) \
return NULL; \
@@ -942,8 +956,8 @@ struct cmc_callbacks_multiset
struct SNAME *PFX##_summation(struct SNAME *_set1_, struct SNAME *_set2_) \
{ \
struct SNAME *_set_r_ = \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->cmp, \
_set1_->hash, _set1_->alloc, _set1_->callbacks); \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->f_val, \
_set1_->alloc, _set1_->callbacks); \
\
if (!_set_r_) \
return NULL; \
@@ -975,8 +989,8 @@ struct cmc_callbacks_multiset
struct SNAME##_iter iter1, iter2; \
\
struct SNAME *_set_r_ = \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->cmp, \
_set1_->hash, _set1_->alloc, _set1_->callbacks); \
PFX##_new_custom(_set1_->capacity, _set1_->load, _set1_->f_val, \
_set1_->alloc, _set1_->callbacks); \
\
if (!_set_r_) \
return NULL; \
@@ -1023,7 +1037,7 @@ struct cmc_callbacks_multiset
\
bool PFX##_is_subset(struct SNAME *_set1_, struct SNAME *_set2_) \
{ \
if (PFX##_count(_set1_) > PFX##_count(_set2_)) \
if (_set1_->count > _set2_->count) \
return false; \
\
if (PFX##_empty(_set1_)) \
@@ -1055,7 +1069,7 @@ struct cmc_callbacks_multiset
\
bool PFX##_is_proper_subset(struct SNAME *_set1_, struct SNAME *_set2_) \
{ \
if (PFX##_count(_set1_) >= PFX##_count(_set2_)) \
if (_set1_->count >= _set2_->count) \
return false; \
\
if (PFX##_empty(_set1_)) \
@@ -1126,7 +1140,7 @@ struct cmc_callbacks_multiset
\
void PFX##_iter_free(struct SNAME##_iter *iter) \
{ \
free(iter); \
iter->target->alloc->free(iter); \
} \
\
void PFX##_iter_init(struct SNAME##_iter *iter, struct SNAME *target) \
@@ -1198,7 +1212,7 @@ struct cmc_callbacks_multiset
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
if (iter->index + 1 == iter->target->count) \
{ \
iter->end = true; \
return false; \
@@ -1257,13 +1271,13 @@ struct cmc_callbacks_multiset
if (iter->end) \
return false; \
\
if (iter->index + 1 == PFX##_count(iter->target)) \
if (iter->index + 1 == iter->target->count) \
{ \
iter->end = true; \
return false; \
} \
\
if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \
if (steps == 0 || iter->index + steps >= iter->target->count) \
return false; \
\
for (size_t i = 0; i < steps; i++) \
@@ -1297,7 +1311,7 @@ struct cmc_callbacks_multiset
/* given index */ \
bool PFX##_iter_go_to(struct SNAME##_iter *iter, size_t index) \
{ \
if (index >= PFX##_count(iter->target)) \
if (index >= iter->target->count) \
return false; \
\
if (iter->index > index) \
@@ -1347,11 +1361,11 @@ struct cmc_callbacks_multiset
\
if (PFX##_full(_set_)) \
{ \
if (!PFX##_resize(_set_, PFX##_capacity(_set_) + 1)) \
if (!PFX##_resize(_set_, _set_->capacity + 1)) \
return NULL; \
} \
\
size_t hash = _set_->hash(element); \
size_t hash = _set_->f_val->hash(element); \
size_t original_pos = hash % _set_->capacity; \
size_t pos = original_pos; \
/* Current multiplicity. Might change due to robin hood hashing */ \
@@ -1409,7 +1423,7 @@ struct cmc_callbacks_multiset
static struct SNAME##_entry *PFX##_impl_get_entry(struct SNAME *_set_, \
V element) \
{ \
size_t hash = _set_->hash(element); \
size_t hash = _set_->f_val->hash(element); \
size_t pos = hash % _set_->capacity; \
\
struct SNAME##_entry *target = &(_set_->buffer[pos]); \
@@ -1417,7 +1431,7 @@ struct cmc_callbacks_multiset
while (target->state == CMC_ES_FILLED || \
target->state == CMC_ES_DELETED) \
{ \
if (_set_->cmp(target->value, element) == 0) \
if (_set_->f_val->cmp(target->value, element) == 0) \
return target; \
\
pos++; \
+37 -21
View File
@@ -7,32 +7,48 @@
CMC_GENERATE_MULTIMAP(mm, multimap, size_t, size_t)
struct multimap_ftab_key *mm_ftab_key =
&(struct multimap_ftab_key){ .cmp = cmp,
.cpy = copy,
.str = str,
.free = custom_free,
.hash = hash,
.pri = pri };
struct multimap_ftab_val *mm_ftab_val =
&(struct multimap_ftab_val){ .cmp = cmp,
.cpy = copy,
.str = str,
.free = custom_free,
.hash = hash,
.pri = pri };
CMC_CREATE_UNIT(multimap_test, true, {
CMC_CREATE_TEST(new, {
struct multimap *map = mm_new(943722, 0.8, cmp, hash);
struct multimap *map = mm_new(943722, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
cmc_assert_not_equals(ptr, NULL, map->buffer);
cmc_assert_equals(size_t, 0, mm_count(map));
cmc_assert_greater_equals(size_t, (943722 / 0.8), mm_capacity(map));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(new[capacity = 0], {
struct multimap *map = mm_new(0, 0.8, cmp, hash);
struct multimap *map = mm_new(0, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_equals(ptr, NULL, map);
});
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
struct multimap *map = mm_new(UINT64_MAX, 0.99, cmp, hash);
struct multimap *map = mm_new(UINT64_MAX, 0.99, mm_ftab_key, mm_ftab_val);
cmc_assert_equals(ptr, NULL, map);
});
CMC_CREATE_TEST(clear[count capacity], {
struct multimap *map = mm_new(100, 0.8, cmp, hash);
struct multimap *map = mm_new(100, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
@@ -41,15 +57,15 @@ CMC_CREATE_UNIT(multimap_test, true, {
cmc_assert_equals(size_t, 50, mm_count(map));
mm_clear(map, NULL);
mm_clear(map);
cmc_assert_equals(size_t, 0, mm_count(map));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(insert[count], {
struct multimap *map = mm_new(100, 0.8, cmp, hash);
struct multimap *map = mm_new(100, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
@@ -58,11 +74,11 @@ CMC_CREATE_UNIT(multimap_test, true, {
cmc_assert_equals(size_t, 100, mm_count(map));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(remove[count], {
struct multimap *map = mm_new(100, 0.8, cmp, hash);
struct multimap *map = mm_new(100, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
@@ -76,11 +92,11 @@ CMC_CREATE_UNIT(multimap_test, true, {
cmc_assert_equals(size_t, 140, mm_count(map));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(remove[count = 0], {
struct multimap *map = mm_new(100, 0.8, cmp, hash);
struct multimap *map = mm_new(100, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
@@ -88,11 +104,11 @@ CMC_CREATE_UNIT(multimap_test, true, {
cmc_assert(!mm_remove(map, 10, &r));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(remove[count = 1], {
struct multimap *map = mm_new(100, 0.8, cmp, hash);
struct multimap *map = mm_new(100, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
@@ -101,27 +117,27 @@ CMC_CREATE_UNIT(multimap_test, true, {
cmc_assert(mm_insert(map, 10, 11));
cmc_assert(mm_remove(map, 10, &r));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(get[key ordering], {
struct multimap *map = mm_new(100, 0.8, cmp, hash);
struct multimap *map = mm_new(100, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
/* Assert that the value 100 is accessed before the value 101 for the
* same key */
/* Assert that the value 100 is accessed before the value 101 for */
/* the same key */
cmc_assert(mm_insert(map, 10, 100));
cmc_assert(mm_insert(map, 20, 102));
cmc_assert(mm_insert(map, 10, 101));
cmc_assert_equals(size_t, 100, mm_get(map, 10));
mm_free(map, NULL);
mm_free(map);
});
CMC_CREATE_TEST(key_count, {
struct multimap *map = mm_new(50, 0.8, cmp, hash);
struct multimap *map = mm_new(50, 0.8, mm_ftab_key, mm_ftab_val);
cmc_assert_not_equals(ptr, NULL, map);
@@ -133,6 +149,6 @@ CMC_CREATE_UNIT(multimap_test, true, {
for (size_t i = 0; i < 20; i++)
cmc_assert_equals(size_t, 50, mm_key_count(map, i));
mm_free(map, NULL);
mm_free(map);
});
});
+23 -15
View File
@@ -7,9 +7,17 @@
CMC_GENERATE_MULTISET(ms, multiset, size_t)
struct multiset_ftab_val *ms_ftab_val =
&(struct multiset_ftab_val){ .cmp = cmp,
.cpy = copy,
.str = str,
.free = custom_free,
.hash = hash,
.pri = pri };
CMC_CREATE_UNIT(multiset_test, true, {
CMC_CREATE_TEST(new, {
struct multiset *set = ms_new(943722, 0.6, cmp, hash);
struct multiset *set = ms_new(943722, 0.6, ms_ftab_val);
cmc_assert_not_equals(ptr, NULL, set);
cmc_assert_not_equals(ptr, NULL, set->buffer);
@@ -17,23 +25,23 @@ CMC_CREATE_UNIT(multiset_test, true, {
cmc_assert_greater_equals(size_t, ((size_t)(943722 / 0.6)),
ms_capacity(set));
ms_free(set, NULL);
ms_free(set);
});
CMC_CREATE_TEST(new[capacity = 0], {
struct multiset *set = ms_new(0, 0.6, cmp, hash);
struct multiset *set = ms_new(0, 0.6, ms_ftab_val);
cmc_assert_equals(ptr, NULL, set);
});
CMC_CREATE_TEST(new[capacity = UINT64_MAX], {
struct multiset *set = ms_new(UINT64_MAX, 0.99, cmp, hash);
struct multiset *set = ms_new(UINT64_MAX, 0.99, ms_ftab_val);
cmc_assert_equals(ptr, NULL, set);
});
CMC_CREATE_TEST(clear[count capacity], {
struct multiset *set = ms_new(100, 0.6, cmp, hash);
struct multiset *set = ms_new(100, 0.6, ms_ftab_val);
cmc_assert_not_equals(ptr, NULL, set);
@@ -42,15 +50,15 @@ CMC_CREATE_UNIT(multiset_test, true, {
cmc_assert_equals(size_t, 50, ms_count(set));
ms_clear(set, NULL);
ms_clear(set);
cmc_assert_equals(size_t, 0, ms_count(set));
ms_free(set, NULL);
ms_free(set);
});
CMC_CREATE_TEST(insert[count cardinality multiplicity], {
struct multiset *set = ms_new(100, 0.6, cmp, hash);
struct multiset *set = ms_new(100, 0.6, ms_ftab_val);
cmc_assert_not_equals(ptr, NULL, set);
@@ -67,11 +75,11 @@ CMC_CREATE_UNIT(multiset_test, true, {
for (size_t i = 0; i <= 3; i++)
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
ms_free(set, NULL);
ms_free(set);
});
CMC_CREATE_TEST(remove[count cardinality multiplicity], {
struct multiset *set = ms_new(100, 0.6, cmp, hash);
struct multiset *set = ms_new(100, 0.6, ms_ftab_val);
cmc_assert_not_equals(ptr, NULL, set);
@@ -100,11 +108,11 @@ CMC_CREATE_UNIT(multiset_test, true, {
cmc_assert_equals(size_t, 1, ms_multiplicity_of(set, 2));
cmc_assert_equals(size_t, 2, ms_multiplicity_of(set, 3));
ms_free(set, NULL);
ms_free(set);
});
CMC_CREATE_TEST(remove_all[count cardinality multiplicity], {
struct multiset *set = ms_new(100, 0.6, cmp, hash);
struct multiset *set = ms_new(100, 0.6, ms_ftab_val);
cmc_assert_not_equals(ptr, NULL, set);
@@ -132,11 +140,11 @@ CMC_CREATE_UNIT(multiset_test, true, {
cmc_assert_equals(size_t, 2, ms_multiplicity_of(set, 2));
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 3));
ms_free(set, NULL);
ms_free(set);
});
CMC_CREATE_TEST(multiplicity, {
struct multiset *set = ms_new(50, 0.6, cmp, hash);
struct multiset *set = ms_new(50, 0.6, ms_ftab_val);
cmc_assert_not_equals(ptr, NULL, set);
@@ -149,6 +157,6 @@ CMC_CREATE_UNIT(multiset_test, true, {
for (size_t i = 0; i < 20; i++)
cmc_assert_equals(size_t, 50, ms_multiplicity_of(set, i));
ms_free(set, NULL);
ms_free(set);
});
});