Added resize to multimap, multiset and sortedlist
This commit is contained in:
1 parent
99cd01ba1e
commit
2d3b441d74
6 files changed
+1067
-937
No files matched your search
+893
-873
File diff suppressed because it is too large.
Load diff
+65
-37
@@ -185,10 +185,13 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
/* Collection State */ \
|
||||
bool PFX##_contains(SNAME *_set_, V element); \
|
||||
bool PFX##_empty(SNAME *_set_); \
|
||||
bool PFX##_full(SNAME *_set_); \
|
||||
size_t PFX##_count(SNAME *_set_); \
|
||||
size_t PFX##_cardinality(SNAME *_set_); \
|
||||
size_t PFX##_capacity(SNAME *_set_); \
|
||||
double PFX##_load(SNAME *_set_); \
|
||||
/* Collection Utility */ \
|
||||
bool PFX##_resize(SNAME *_set_, size_t capacity); \
|
||||
SNAME *PFX##_copy_of(SNAME *_set_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_set1_, SNAME *_set2_, bool ignore_multiplicity); \
|
||||
cmc_string PFX##_to_string(SNAME *_set_); \
|
||||
@@ -242,7 +245,6 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
\
|
||||
/* 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_); \
|
||||
@@ -493,6 +495,11 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
return _set_->count == 0; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_full(SNAME *_set_) \
|
||||
{ \
|
||||
return (double)PFX##_capacity(_set_) * PFX##_load(_set_) <= (double)PFX##_count(_set_); \
|
||||
} \
|
||||
\
|
||||
size_t PFX##_count(SNAME *_set_) \
|
||||
{ \
|
||||
return _set_->count; \
|
||||
@@ -508,6 +515,61 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
return _set_->capacity; \
|
||||
} \
|
||||
\
|
||||
double PFX##_load(SNAME *_set_) \
|
||||
{ \
|
||||
return _set_->load; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_resize(SNAME *_set_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_set_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (PFX##_capacity(_set_) > capacity / PFX##_load(_set_)) \
|
||||
return true; \
|
||||
\
|
||||
/* Prevent integer overflow */ \
|
||||
if (capacity >= UINTMAX_MAX * PFX##_load(_set_)) \
|
||||
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_)) \
|
||||
return false; \
|
||||
\
|
||||
SNAME *_new_set_ = PFX##_new(capacity, PFX##_load(_set_), _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 (PFX##_count(_set_) != PFX##_count(_new_set_)) \
|
||||
{ \
|
||||
PFX##_free(_new_set_, NULL); \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
SNAME##_entry *tmp_b = _set_->buffer; \
|
||||
_set_->buffer = _new_set_->buffer; \
|
||||
_new_set_->buffer = tmp_b; \
|
||||
\
|
||||
size_t tmp_c = _set_->capacity; \
|
||||
_set_->capacity = _new_set_->capacity; \
|
||||
_new_set_->capacity = tmp_c; \
|
||||
\
|
||||
PFX##_free(_new_set_, NULL); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
SNAME *PFX##_copy_of(SNAME *_set_, V (*copy_func)(V)) \
|
||||
{ \
|
||||
SNAME *result = PFX##_new(_set_->capacity, _set_->load, _set_->cmp, _set_->hash); \
|
||||
@@ -1063,9 +1125,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
\
|
||||
*new_node = true; \
|
||||
\
|
||||
if ((double)_set_->capacity * _set_->load <= (double)_set_->count) \
|
||||
if (PFX##_full(_set_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_set_)) \
|
||||
if (!PFX##_resize(_set_, PFX##_capacity(_set_) + 1)) \
|
||||
return NULL; \
|
||||
} \
|
||||
\
|
||||
@@ -1123,40 +1185,6 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531,
|
||||
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_, NULL); \
|
||||
\
|
||||
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_, NULL); \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static SNAME##_entry *PFX##_impl_get_entry(SNAME *_set_, V element) \
|
||||
{ \
|
||||
size_t hash = _set_->hash(element); \
|
||||
|
||||
+21
-20
@@ -109,6 +109,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
size_t PFX##_count(SNAME *_list_); \
|
||||
size_t PFX##_capacity(SNAME *_list_); \
|
||||
/* Collection Utility */ \
|
||||
bool PFX##_resize(SNAME *_list_, size_t capacity); \
|
||||
void PFX##_sort(SNAME *_list_); \
|
||||
SNAME *PFX##_copy_of(SNAME *_list_, V (*copy_func)(V)); \
|
||||
bool PFX##_equals(SNAME *_list1_, SNAME *_list2_); \
|
||||
@@ -149,7 +150,6 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
#define CMC_GENERATE_SORTEDLIST_SOURCE(PFX, SNAME, V) \
|
||||
\
|
||||
/* Implementation Detail Functions */ \
|
||||
static bool PFX##_impl_grow(SNAME *_list_, size_t required); \
|
||||
static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value); \
|
||||
static size_t PFX##_impl_binary_search_last(SNAME *_list_, V value); \
|
||||
void PFX##_impl_sort_quicksort(V *array, int (*cmp)(V, V), size_t low, size_t high); \
|
||||
@@ -215,7 +215,7 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
{ \
|
||||
if (PFX##_full(_list_)) \
|
||||
{ \
|
||||
if (!PFX##_impl_grow(_list_, _list_->count + 1)) \
|
||||
if (!PFX##_resize(_list_, PFX##_capacity(_list_) * 2)) \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
@@ -315,6 +315,25 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
return _list_->capacity; \
|
||||
} \
|
||||
\
|
||||
bool PFX##_resize(SNAME *_list_, size_t capacity) \
|
||||
{ \
|
||||
if (PFX##_capacity(_list_) == capacity) \
|
||||
return true; \
|
||||
\
|
||||
if (capacity < PFX##_count(_list_)) \
|
||||
return false; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer = new_buffer; \
|
||||
_list_->capacity = capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
void PFX##_sort(SNAME *_list_) \
|
||||
{ \
|
||||
if (!_list_->is_sorted && _list_->count > 1) \
|
||||
@@ -536,24 +555,6 @@ static const char *cmc_string_fmt_sortedlist = "%s at %p { buffer:%p, capacity:%
|
||||
return iter->cursor; \
|
||||
} \
|
||||
\
|
||||
static bool PFX##_impl_grow(SNAME *_list_, size_t required) \
|
||||
{ \
|
||||
size_t new_capacity = _list_->capacity * 2; \
|
||||
\
|
||||
if (new_capacity < required) \
|
||||
new_capacity = required; \
|
||||
\
|
||||
V *new_buffer = realloc(_list_->buffer, sizeof(V) * new_capacity); \
|
||||
\
|
||||
if (!new_buffer) \
|
||||
return false; \
|
||||
\
|
||||
_list_->buffer = new_buffer; \
|
||||
_list_->capacity = new_capacity; \
|
||||
\
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static size_t PFX##_impl_binary_search_first(SNAME *_list_, V value) \
|
||||
{ \
|
||||
if (PFX##_empty(_list_)) \
|
||||
|
||||
@@ -53,10 +53,10 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 200; i++)
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 200, mm_count(map));
|
||||
cmc_assert_equals(size_t, 100, mm_count(map));
|
||||
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
@@ -119,4 +119,20 @@ CMC_CREATE_UNIT(multimap_test, true, {
|
||||
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(key_count, {
|
||||
multimap *map = mm_new(50, 0.8, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, map);
|
||||
|
||||
for (size_t i = 0; i < 1000; i++)
|
||||
cmc_assert(mm_insert(map, i % 20, i % 20));
|
||||
|
||||
cmc_assert_equals(size_t, 1000, mm_count(map));
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
cmc_assert_equals(size_t, 50, mm_key_count(map, i));
|
||||
|
||||
mm_free(map, NULL);
|
||||
});
|
||||
});
|
||||
@@ -69,19 +69,84 @@ CMC_CREATE_UNIT(multiset_test, true, {
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(multiplicity, {
|
||||
CMC_CREATE_TEST(remove[count cardinality 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, 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));
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
cmc_assert(ms_remove(set, 1));
|
||||
cmc_assert(ms_remove(set, 2));
|
||||
cmc_assert(ms_remove(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 2, ms_count(set));
|
||||
cmc_assert_equals(size_t, 3, ms_cardinality(set));
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 0));
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 1));
|
||||
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);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(remove_all[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));
|
||||
|
||||
for (size_t i = 0; i <= 3; i++)
|
||||
cmc_assert_equals(size_t, i, ms_multiplicity_of(set, i));
|
||||
|
||||
cmc_assert(ms_remove_all(set, 1));
|
||||
cmc_assert(ms_remove_all(set, 3));
|
||||
|
||||
cmc_assert_equals(size_t, 1, ms_count(set));
|
||||
cmc_assert_equals(size_t, 2, ms_cardinality(set));
|
||||
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 0));
|
||||
cmc_assert_equals(size_t, 0, ms_multiplicity_of(set, 1));
|
||||
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);
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(multiplicity, {
|
||||
multiset *set = ms_new(50, 0.6, cmp, hash);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, set);
|
||||
|
||||
for (size_t i = 0; i < 1000; 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));
|
||||
cmc_assert_equals(size_t, 1000, ms_cardinality(set));
|
||||
|
||||
for (size_t i = 0; i < 20; i++)
|
||||
cmc_assert_equals(size_t, 5, ms_multiplicity_of(set, i));
|
||||
cmc_assert_equals(size_t, 50, ms_multiplicity_of(set, i));
|
||||
|
||||
ms_free(set, NULL);
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ CMC_CREATE_UNIT(sortedlist_test, true, {
|
||||
});
|
||||
|
||||
CMC_CREATE_TEST(buffer_growth[capacity = 1], {
|
||||
sortedlist *sl = sl_new(100, cmp);
|
||||
sortedlist *sl = sl_new(1, cmp);
|
||||
|
||||
cmc_assert_not_equals(ptr, NULL, sl);
|
||||
|
||||
|
||||
Reference in new issue
Block a user