Complete remake of multiset

This commit is contained in:
Leonardo committed 2019-08-01 23:52:50 -03:00
1 parent 90ee6a424d
commit 1254e657c5
7 files changed
+1895 -859

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
/**
* multiset_operations.c
*
* Creation Date: 01/08/2019
*
* Authors:
* Leonardo Vencovsky (https://github.com/LeoVen)
*
*/
#include <ext/multiset.h>
#include <utl/assert.h>
#include <inttypes.h>
#include <stdio.h>
MULTISET_GENERATE(ms, multiset, , char)
struct pair
{
char value;
size_t mul;
};
int charcmp(char a, char b)
{
return (a > b) - (a < b);
}
size_t charhash(char a)
{
return a;
}
void print_set(multiset *M)
{
cmc_assert_not_equals(ptr, NULL, M);
size_t S = ms_count(M);
printf("%s : ", ms_to_string(M).s);
if (S == 0)
{
printf("{ EMPTY SET }\n");
return;
}
for (multiset_iter it = M->it_start(M); !ms_iter_end(&it); ms_iter_next(&it))
{
size_t index = ms_iter_index(&it);
char value = ms_iter_value(&it);
size_t mul = ms_iter_multiplicity(&it);
if (index == 0)
printf("{ %c:%" PRIuMAX ", ", value, mul);
else if (index == S - 1)
printf("%c:%" PRIuMAX " }\n", value, mul);
else
printf("%c:%" PRIuMAX ", ", value, mul);
}
}
int main(int argc, char const *argv[])
{
struct pair mset1[4] = {{'a', 2}, {'b', 1}, {'c', 3}, {'d', 1}};
struct pair mset2[4] = {{'c', 1}, {'d', 3}, {'e', 1}, {'f', 2}};
multiset *A = ms_new(20, 0.6, charcmp, charhash);
multiset *B = ms_new(20, 0.6, charcmp, charhash);
for (int i = 0; i < 4; i++)
{
cmc_assert(ms_insert_many(A, mset1[i].value, mset1[i].mul));
cmc_assert(ms_insert_many(B, mset2[i].value, mset2[i].mul));
}
printf("Given two sets A and B:\n");
print_set(A);
print_set(B);
multiset *U = ms_union(A, B);
printf("\nA UNION B:\n");
print_set(U);
multiset *I = ms_intersection(A, B);
printf("\nA INTERSECTION B:\n");
print_set(I);
multiset *DA = ms_difference(A, B);
multiset *DB = ms_difference(B, A);
printf("\nA - B:\n");
print_set(DA);
printf("\nB - A:\n");
print_set(DB);
multiset *AB = ms_summation(A, B);
printf("\nA + B:\n");
print_set(AB);
multiset *BA = ms_summation(B, A);
printf("\nB + A:\n");
print_set(BA);
multiset *SD = ms_symmetric_difference(A, B);
printf("\nA SYM DIFF B:\n");
print_set(SD);
ms_free(A);
ms_free(B);
ms_free(U);
ms_free(I);
ms_free(DA);
ms_free(DB);
ms_free(AB);
ms_free(BA);
ms_free(SD);
return 0;
}
-67
View File
@@ -1,67 +0,0 @@
#include <stdio.h>
#include "multiset.h"
MULTISET_GENERATE(ms, multi_set, /* FMOD */, size_t)
int cmp(size_t a, size_t b)
{
if (a > b)
return 1;
else if (a < b)
return -1;
return 0;
}
void prime_cof(const size_t number)
{
multi_set *mset = ms_new(cmp);
size_t num = number;
for (size_t i = 2; num != 1; i++)
{
while (num % i == 0)
{
ms_insert(mset, i);
num /= i;
}
}
printf("The factorization of %llu is given by:\n", number);
multi_set_iter iter;
size_t result, mul, index;
for (ms_iter_new(&iter, mset); !ms_iter_end(&iter);)
{
if (!ms_iter_next(&iter, &result, &mul, &index))
{
printf("ERROR\n");
break;
}
if (ms_count(mset) == 1)
printf("(%llu^%llu)\n", result, mul);
else if (index == 0)
printf("(%llu^%llu ", result, mul);
else if (index == ms_count(mset) - 1)
printf("* %llu^%llu)\n", result, mul);
else
printf("* %llu^%llu ", result, mul);
}
printf("Set Cardinality: %llu\n\n", ms_cardinality(mset));
ms_free(mset);
}
int main(int argc, char const *argv[])
{
prime_cof(360);
prime_cof(55777680);
prime_cof(4294967296);
prime_cof(31415926535);
prime_cof(27182818284);
prime_cof(16180339887);
return 0;
}
+1012 -789
View File
File diff suppressed because it is too large. Load diff
+5 -3
View File
@@ -23,7 +23,7 @@ typedef struct cmc_string_s
char s[200];
} cmc_string;
/* To string formatting */
/* to_string formats */
static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
static const char *cmc_string_fmt_hashmap = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
static const char *cmc_string_fmt_hashset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";
@@ -32,7 +32,9 @@ static const char *cmc_string_fmt_linkedlist = "%s at %p { count:%" PRIuMAX ", h
static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", front:%" PRIuMAX ", back:%" PRIuMAX " }";
static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX " }";
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p, }";
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p, }";
static const char *cmc_string_fmt_treemap = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
static const char *cmc_string_fmt_treeset = "%s at %p { root:%p, count:%" PRIuMAX ", cmp:%p }";
static const char *cmc_string_fmt_multiset = "%s at %p { buffer:%p, capacity:%" PRIuMAX ", count:%" PRIuMAX ", cardinality:%" PRIuMAX ", load:%lf, cmp:%p, hash:%p }";;
#endif /* CMC_STRING_H */
+2
View File
@@ -11,6 +11,7 @@
#include "unt/linkedqueue.c"
#include "unt/multimap.c"
#include "unt/multiset.c"
int main(void)
{
@@ -28,6 +29,7 @@ int main(void)
/* ext */
linkedqueue_test();
multimap_test();
multiset_test();
return 0;
}
+655
View File
@@ -0,0 +1,655 @@
#include "ext/multiset.h"
//MULTISET_GENERATE(ms, multiset, , size_t)
typedef struct multiset_s
{
struct multiset_entry_s *buffer;
size_t capacity;
size_t count;
size_t cardinality;
double load;
int (*cmp)(size_t, size_t);
size_t (*hash)(size_t);
struct multiset_iter_s (*it_start)(struct multiset_s *);
struct multiset_iter_s (*it_end)(struct multiset_s *);
} multiset, *multiset_ptr;
typedef struct multiset_entry_s
{
size_t value;
size_t multiplicity;
size_t dist;
enum cmc_entry_state_e state;
} multiset_entry, *multiset_entry_ptr;
typedef struct multiset_iter_s
{
struct multiset_s *target;
size_t cursor;
size_t index;
size_t first;
size_t last;
bool start;
bool end;
} multiset_iter, *multiset_iter_ptr;
multiset *ms_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t));
void ms_clear(multiset *_set_);
void ms_free(multiset *_set_);
bool ms_insert(multiset *_set_, size_t element);
bool ms_insert_many(multiset *_set_, size_t element, size_t count);
bool ms_update(multiset *_set_, size_t element, size_t multiplicity);
bool ms_remove(multiset *_set_, size_t element);
size_t ms_remove_all(multiset *_set_, size_t element);
bool ms_insert_if(multiset *_set_, size_t element, bool condition);
bool ms_remove_if(multiset *_set_, size_t element, bool condition);
bool ms_max(multiset *_set_, size_t *value);
bool ms_min(multiset *_set_, size_t *value);
size_t ms_multiplicity_of(multiset *_set_, size_t element);
bool ms_contains(multiset *_set_, size_t element);
bool ms_empty(multiset *_set_);
size_t ms_count(multiset *_set_);
size_t ms_cardinality(multiset *_set_);
size_t ms_capacity(multiset *_set_);
cmc_string ms_to_string(multiset *_set_);
multiset *ms_union(multiset *_set1_, multiset *_set2_);
multiset *ms_intersection(multiset *_set1_, multiset *_set2_);
multiset *ms_difference(multiset *_set1_, multiset *_set2_);
multiset *ms_summation(multiset *_set1_, multiset *_set2_);
multiset *ms_symmetric_difference(multiset *_set1_, multiset *_set2_);
bool ms_is_subset(multiset *_set1_, multiset *_set2_);
bool ms_is_superset(multiset *_set1_, multiset *_set2_);
bool ms_is_proper_subset(multiset *_set1_, multiset *_set2_);
bool ms_is_proper_superset(multiset *_set1_, multiset *_set2_);
bool ms_is_disjointset(multiset *_set1_, multiset *_set2_);
multiset_iter *ms_iter_new(multiset *target);
void ms_iter_free(multiset_iter *iter);
void ms_iter_init(multiset_iter *iter, multiset *target);
bool ms_iter_start(multiset_iter *iter);
bool ms_iter_end(multiset_iter *iter);
void ms_iter_to_start(multiset_iter *iter);
void ms_iter_to_end(multiset_iter *iter);
bool ms_iter_next(multiset_iter *iter);
bool ms_iter_prev(multiset_iter *iter);
size_t ms_iter_value(multiset_iter *iter);
size_t ms_iter_multiplicity(multiset_iter *iter);
size_t ms_iter_index(multiset_iter *iter);
static inline size_t ms_impl_default_value(void)
{
size_t _empty_value_;
memset(&_empty_value_, 0, sizeof(size_t));
return _empty_value_;
}
static multiset_entry *ms_impl_insert_and_return(multiset *_set_, size_t element, bool *new_node);
static bool ms_impl_grow(multiset *_set_);
static multiset_entry *ms_impl_get_entry(multiset *_set_, size_t element);
static size_t ms_impl_calculate_size(size_t required);
static multiset_iter ms_impl_it_start(multiset *_set_);
static multiset_iter ms_impl_it_end(multiset *_set_);
multiset *ms_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t))
{
if (capacity == 0 || load <= 0 || load >= 1)
return NULL;
if (capacity >= UINTMAX_MAX * load)
return NULL;
size_t real_capacity = ms_impl_calculate_size(capacity / load);
multiset *_set_ = malloc(sizeof(multiset));
if (!_set_)
return NULL;
_set_->buffer = malloc(sizeof(multiset_entry) * real_capacity);
if (!_set_->buffer)
{
free(_set_);
return NULL;
}
memset(_set_->buffer, 0, sizeof(multiset_entry) * real_capacity);
_set_->count = 0;
_set_->cardinality = 0;
_set_->capacity = real_capacity;
_set_->load = load;
_set_->cmp = compare;
_set_->hash = hash;
_set_->it_start = ms_impl_it_start;
_set_->it_end = ms_impl_it_end;
return _set_;
}
void ms_clear(multiset *_set_)
{
memset(_set_->buffer, 0, sizeof(multiset_entry) * _set_->capacity);
_set_->count = 0;
}
void ms_free(multiset *_set_)
{
free(_set_->buffer);
free(_set_);
}
bool ms_insert(multiset *_set_, size_t element)
{
bool new_node;
multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node);
if (!entry)
return false;
if (!new_node)
entry->multiplicity++;
_set_->cardinality++;
return true;
}
bool ms_insert_many(multiset *_set_, size_t element, size_t count)
{
if (count == 0)
return true;
bool new_node;
multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node);
if (!entry)
return false;
if (new_node)
entry->multiplicity = count;
else
entry->multiplicity += count;
_set_->cardinality += count;
return true;
}
bool ms_update(multiset *_set_, size_t element, size_t multiplicity)
{
if (multiplicity == 0)
return ms_remove_all(_set_, element);
bool new_node;
multiset_entry *entry = ms_impl_insert_and_return(_set_, element, &new_node);
if (!entry)
return false;
if (new_node)
_set_->cardinality++;
_set_->cardinality = (_set_->cardinality - entry->multiplicity) + multiplicity;
entry->multiplicity = multiplicity;
return true;
}
bool ms_remove(multiset *_set_, size_t element)
{
multiset_entry *result = ms_impl_get_entry(_set_, element);
if (result == NULL)
return false;
if (result->multiplicity > 1)
result->multiplicity--;
else
{
result->value = ms_impl_default_value();
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
}
_set_->cardinality--;
return true;
}
size_t ms_remove_all(multiset *_set_, size_t element)
{
multiset_entry *result = ms_impl_get_entry(_set_, element);
if (result == NULL)
return 0;
size_t removed = result->multiplicity;
result->value = ms_impl_default_value();
result->multiplicity = 0;
result->dist = 0;
result->state = CMC_ES_DELETED;
_set_->count--;
_set_->cardinality -= removed;
return removed;
}
bool ms_insert_if(multiset *_set_, size_t element, bool condition)
{
if (condition)
return ms_insert(_set_, element);
return false;
}
bool ms_remove_if(multiset *_set_, size_t element, bool condition)
{
if (condition)
return ms_remove(_set_, element);
return false;
}
bool ms_max(multiset *_set_, size_t *value)
{
if (ms_empty(_set_))
return false;
multiset_iter iter;
for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t result = ms_iter_value(&iter);
size_t index = ms_iter_index(&iter);
if (index == 0)
*value = result;
else if (_set_->cmp(result, *value) > 0)
*value = result;
}
return true;
}
bool ms_min(multiset *_set_, size_t *value)
{
if (ms_empty(_set_))
return false;
multiset_iter iter;
for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t result = ms_iter_value(&iter);
size_t index = ms_iter_index(&iter);
if (index == 0)
*value = result;
else if (_set_->cmp(result, *value) < 0)
*value = result;
}
return true;
}
size_t ms_multiplicity_of(multiset *_set_, size_t element)
{
multiset_entry *entry = ms_impl_get_entry(_set_, element);
if (!entry)
return 0;
return entry->multiplicity;
}
bool ms_contains(multiset *_set_, size_t element) { return ms_impl_get_entry(_set_, element) != NULL; }
bool ms_empty(multiset *_set_) { return _set_->count == 0; }
size_t ms_count(multiset *_set_) { return _set_->count; }
size_t ms_cardinality(multiset *_set_) { return _set_->cardinality; }
size_t ms_capacity(multiset *_set_) { return _set_->capacity; }
cmc_string ms_to_string(multiset *_set_)
{
cmc_string str;
multiset *s_ = _set_;
const char *name = "multiset";
snprintf(str.s, cmc_string_len, cmc_string_fmt_multiset, name, s_, s_->buffer, s_->capacity, s_->count, s_->cardinality, s_->load, s_->cmp, s_->hash);
return str;
}
multiset *ms_union(multiset *_set1_, multiset *_set2_)
{
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return NULL;
multiset_iter iter1, iter2;
ms_iter_init(&iter1, _set1_);
ms_iter_init(&iter2, _set2_);
for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1))
{
size_t value = ms_iter_value(&iter1);
size_t m1 = ms_iter_multiplicity(&iter1);
size_t m2 = ms_multiplicity_of(_set2_, value);
size_t max_ = m1 > m2 ? m1 : m2;
ms_update(_set_r_, value, max_);
}
for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2))
{
size_t value = ms_iter_value(&iter2);
size_t m1 = ms_multiplicity_of(_set1_, value);
size_t m2 = ms_iter_multiplicity(&iter2);
size_t max_ = m1 > m2 ? m1 : m2;
ms_update(_set_r_, value, max_);
}
return _set_r_;
}
multiset *ms_intersection(multiset *_set1_, multiset *_set2_)
{
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return NULL;
multiset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
multiset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
multiset_iter iter;
ms_iter_init(&iter, _set_A_);
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t value = ms_iter_value(&iter);
size_t m1 = ms_iter_multiplicity(&iter);
size_t m2 = ms_multiplicity_of(_set_B_, value);
size_t max_ = m1 < m2 ? m1 : m2;
ms_update(_set_r_, value, max_);
}
return _set_r_;
}
multiset *ms_difference(multiset *_set1_, multiset *_set2_)
{
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return NULL;
multiset_iter iter;
ms_iter_init(&iter, _set1_);
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t value = ms_iter_value(&iter);
size_t m1 = ms_iter_multiplicity(&iter);
size_t m2 = ms_multiplicity_of(_set2_, value);
if (m1 > m2)
ms_update(_set_r_, value, m1 - m2);
}
return _set_r_;
}
multiset *ms_summation(multiset *_set1_, multiset *_set2_)
{
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return NULL;
multiset_iter iter1, iter2;
ms_iter_init(&iter1, _set1_);
ms_iter_init(&iter2, _set2_);
for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1))
{
ms_insert_many(_set_r_, ms_iter_value(&iter1), ms_iter_multiplicity(&iter1));
}
for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2))
{
ms_insert_many(_set_r_, ms_iter_value(&iter2), ms_iter_multiplicity(&iter2));
}
return _set_r_;
}
multiset *ms_symmetric_difference(multiset *_set1_, multiset *_set2_)
{
multiset_iter iter1, iter2;
multiset *_set_r_ = ms_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return NULL;
ms_iter_init(&iter1, _set1_);
ms_iter_init(&iter2, _set2_);
for (ms_iter_to_start(&iter1); !ms_iter_end(&iter1); ms_iter_next(&iter1))
{
size_t value = ms_iter_value(&iter1);
size_t m1 = ms_iter_multiplicity(&iter1);
size_t m2 = ms_multiplicity_of(_set2_, value);
if (m1 != m2)
{
if (m1 > m2)
ms_update(_set_r_, value, m1 - m2);
else
ms_update(_set_r_, value, m2 - m1);
}
}
for (ms_iter_to_start(&iter2); !ms_iter_end(&iter2); ms_iter_next(&iter2))
{
size_t value = ms_iter_value(&iter2);
size_t m1 = ms_multiplicity_of(_set1_, value);
size_t m2 = ms_iter_multiplicity(&iter2);
if (m1 != m2)
{
if (m1 > m2)
ms_update(_set_r_, value, m1 - m2);
else
ms_update(_set_r_, value, m2 - m1);
}
}
return _set_r_;
}
bool ms_is_subset(multiset *_set1_, multiset *_set2_)
{
if (ms_count(_set1_) > ms_count(_set2_))
return false;
if (ms_empty(_set1_))
return true;
multiset_iter iter;
ms_iter_init(&iter, _set1_);
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t value = ms_iter_value(&iter);
size_t m1 = ms_iter_multiplicity(&iter);
size_t m2 = ms_multiplicity_of(_set2_, value);
if (m1 > m2)
return false;
}
return true;
}
bool ms_is_superset(multiset *_set1_, multiset *_set2_) { return ms_is_subset(_set2_, _set1_); }
bool ms_is_proper_subset(multiset *_set1_, multiset *_set2_)
{
if (ms_count(_set1_) >= ms_count(_set2_))
return false;
if (ms_empty(_set1_))
{
if (!ms_empty(_set2_))
return true;
else
return false;
}
multiset_iter iter;
ms_iter_init(&iter, _set1_);
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t value = ms_iter_value(&iter);
size_t m1 = ms_iter_multiplicity(&iter);
size_t m2 = ms_multiplicity_of(_set2_, value);
if (m1 >= m2)
return false;
}
return true;
}
bool ms_is_proper_superset(multiset *_set1_, multiset *_set2_) { return ms_is_proper_subset(_set2_, _set1_); }
bool ms_is_disjointset(multiset *_set1_, multiset *_set2_)
{
if (ms_empty(_set1_))
return true;
multiset_iter iter;
ms_iter_init(&iter, _set1_);
for (ms_iter_to_start(&iter); !ms_iter_end(&iter); ms_iter_next(&iter))
{
size_t value = ms_iter_value(&iter);
if (ms_contains(_set2_, value))
return false;
}
return true;
}
multiset_iter *ms_iter_new(multiset *target)
{
multiset_iter *iter = malloc(sizeof(multiset_iter));
if (!iter)
return NULL;
ms_iter_init(iter, target);
return iter;
}
void ms_iter_free(multiset_iter *iter) { free(iter); }
void ms_iter_init(multiset_iter *iter, multiset *target)
{
iter->target = target;
iter->cursor = 0;
iter->index = 0;
iter->start = true;
iter->end = ms_empty(target);
if (!ms_empty(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == CMC_ES_FILLED)
{
iter->first = i;
break;
}
}
iter->cursor = iter->first;
for (size_t i = target->capacity; i > 0; i--)
{
if (target->buffer[i - 1].state == CMC_ES_FILLED)
{
iter->last = i - 1;
break;
}
}
}
}
bool ms_iter_start(multiset_iter *iter) { return ms_empty(iter->target) || iter->start; }
bool ms_iter_end(multiset_iter *iter) { return ms_empty(iter->target) || iter->end; }
void ms_iter_to_start(multiset_iter *iter)
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = ms_empty(iter->target);
}
void ms_iter_to_end(multiset_iter *iter)
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = ms_empty(iter->target);
iter->end = true;
}
bool ms_iter_next(multiset_iter *iter)
{
if (iter->end)
return false;
multiset_entry *scan = &(iter->target->buffer[iter->cursor]);
if (iter->cursor == iter->last)
iter->end = true;
else
{
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
}
iter->start = ms_empty(iter->target);
return true;
}
bool ms_iter_prev(multiset_iter *iter)
{
if (iter->start)
return false;
multiset_entry *scan = &(iter->target->buffer[iter->cursor]);
if (iter->cursor == iter->first)
iter->start = true;
else
{
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == CMC_ES_FILLED)
break;
}
}
iter->end = ms_empty(iter->target);
return true;
}
size_t ms_iter_value(multiset_iter *iter)
{
if (ms_empty(iter->target))
return ms_impl_default_value();
return iter->target->buffer[iter->cursor].value;
}
size_t ms_iter_multiplicity(multiset_iter *iter)
{
if (ms_empty(iter->target))
return 0;
return iter->target->buffer[iter->cursor].multiplicity;
}
size_t ms_iter_index(multiset_iter *iter) { return iter->index; }
static multiset_entry *ms_impl_insert_and_return(multiset *_set_, size_t element, bool *new_node)
{
*new_node = false;
multiset_entry *entry = ms_impl_get_entry(_set_, element);
if (entry != NULL)
return entry;
*new_node = true;
if ((double)_set_->capacity * _set_->load <= (double)_set_->count)
{
if (!ms_impl_grow(_set_))
return NULL;
}
size_t hash = _set_->hash(element);
size_t original_pos = hash % _set_->capacity;
size_t pos = original_pos;
size_t curr_mul = 1;
multiset_entry *target = &(_set_->buffer[pos]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = element;
target->multiplicity = curr_mul;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
if (target->state == CMC_ES_EMPTY || target->state == CMC_ES_DELETED)
{
target->value = element;
target->multiplicity = curr_mul;
target->dist = pos - original_pos;
target->state = CMC_ES_FILLED;
break;
}
else if (target->dist < pos - original_pos)
{
size_t tmp = target->value;
size_t tmp_dist = target->dist;
size_t tmp_mul = target->multiplicity;
target->value = element;
target->dist = pos - original_pos;
target->multiplicity = curr_mul;
element = tmp;
original_pos = pos - tmp_dist;
curr_mul = tmp_mul;
}
}
}
_set_->count++;
return target;
}
static bool ms_impl_grow(multiset *_set_)
{
size_t new_size = ms_impl_calculate_size(_set_->capacity + _set_->capacity / 2);
multiset *_new_set_ = ms_new(new_size, _set_->load, _set_->cmp, _set_->hash);
if (!_new_set_)
return false;
multiset_iter iter;
for (ms_iter_init(&iter, _set_); !ms_iter_end(&iter); ms_iter_next(&iter))
{
ms_insert_many(_new_set_, ms_iter_value(&iter), ms_iter_multiplicity(&iter));
}
if (_set_->count != _new_set_->count)
{
ms_free(_new_set_);
return false;
}
multiset_entry *tmp = _set_->buffer;
_set_->buffer = _new_set_->buffer;
_new_set_->buffer = tmp;
_set_->capacity = _new_set_->capacity;
ms_free(_new_set_);
return true;
}
static multiset_entry *ms_impl_get_entry(multiset *_set_, size_t element)
{
size_t hash = _set_->hash(element);
size_t pos = hash % _set_->capacity;
multiset_entry *target = &(_set_->buffer[pos]);
while (target->state == CMC_ES_FILLED || target->state == CMC_ES_DELETED)
{
if (_set_->cmp(target->value, element) == 0)
return target;
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
}
return NULL;
}
static size_t ms_impl_calculate_size(size_t required)
{
const size_t count = sizeof(cmc_hashtable_primes) / sizeof(cmc_hashtable_primes[0]);
if (cmc_hashtable_primes[count - 1] < required)
return required;
size_t i = 0;
while (cmc_hashtable_primes[i] < required)
i++;
return cmc_hashtable_primes[i];
}
static multiset_iter ms_impl_it_start(multiset *_set_)
{
multiset_iter iter;
ms_iter_init(&iter, _set_);
return iter;
}
static multiset_iter ms_impl_it_end(multiset *_set_)
{
multiset_iter iter;
ms_iter_init(&iter, _set_);
ms_iter_to_end(&iter);
return iter;
}
+102
View File
@@ -0,0 +1,102 @@
#include "utl/assert.h"
#include "utl/test.h"
#include "../src/multiset.c"
#include "utl.c"
CMC_CREATE_UNIT(multiset_test, true, {
CMC_CREATE_TEST(new, {
multiset *set = ms_new(943722, 0.6, cmp, hash);
bool passed = (set->capacity >= (943722 / 0.6)) && set->count == 0 && set->buffer;
cmc_assert_not_equals(ptr, NULL, set);
cmc_assert(ms_capacity(set) > (943722 / 0.6));
CMC_TEST_PASS_ELSE_FAIL(passed);
ms_free(set);
});
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
multiset *set = ms_new(0, 0.6, cmp, hash);
cmc_assert_equals(ptr, NULL, set);
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
});
CMC_CREATE_TEST(new[edge_case:capacity = UINTMAX_MAX], {
multiset *set = ms_new(UINTMAX_MAX, 0.99, cmp, hash);
cmc_assert_equals(ptr, NULL, set);
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
});
CMC_CREATE_TEST(clear[count capacity], {
multiset *set = ms_new(100, 0.6, cmp, hash);
cmc_assert_not_equals(ptr, NULL, set);
for (size_t i = 0; i < 50; i++)
cmc_assert(ms_insert(set, i));
cmc_assert_equals(size_t, 50, ms_count(set));
ms_clear(set);
cmc_assert_equals(size_t, 0, ms_count(set));
CMC_TEST_PASS_ELSE_FAIL(ms_count(set) == 0);
ms_free(set);
});
CMC_CREATE_TEST(insert[count cardinality multiplicity], {
multiset *set = ms_new(100, 0.6, cmp, hash);
cmc_assert_not_equals(ptr, NULL, set);
cmc_assert(ms_insert(set, 1));
cmc_assert(ms_insert(set, 2));
cmc_assert(ms_insert(set, 2));
cmc_assert(ms_insert(set, 3));
cmc_assert(ms_insert(set, 3));
cmc_assert(ms_insert(set, 3));
cmc_assert_equals(size_t, 3, ms_count(set));
cmc_assert_equals(size_t, 6, ms_cardinality(set));
bool passed = ms_count(set) == 3 && ms_cardinality(set) == 6;
for (size_t i = 0; i <= 3; i++)
passed = passed && ms_multiplicity_of(set, i) == i;
CMC_TEST_PASS_ELSE_FAIL(passed);
ms_free(set);
});
CMC_CREATE_TEST(multiplicity, {
multiset *set = ms_new(100, 0.6, cmp, hash);
cmc_assert_not_equals(ptr, NULL, set);
for (size_t i = 0; i < 100; i++)
cmc_assert(ms_insert(set, i % 20));
cmc_assert_equals(size_t, 20, ms_count(set));
cmc_assert_equals(size_t, 100, ms_cardinality(set));
bool passed = ms_count(set) == 20 && ms_cardinality(set) == 100;
for (size_t i = 0; i < 20; i++)
passed = passed && ms_multiplicity_of(set, i) == 5;
CMC_TEST_PASS_ELSE_FAIL(passed);
ms_free(set);
});
});