Adding functions table to multimap and multiset
This commit is contained in:
1 parent
683decfa64
commit
147e622580
4 files changed
+326
-231
No files matched your search
+157
-100
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user