Tests update

This commit is contained in:
Leonardo committed 2019-07-02 01:05:16 -03:00
1 parent 78cfc0c335
commit 6a2cb70fb5
11 files changed
+1157 -8

No files matched your search

+6
View File
@@ -8,3 +8,9 @@ main:
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
./main
gcov ./main.c
dev:
$(CC) main.c -o main $(CFLAGS) $(CVFLAGS) -I $(INCLUDE)
./main
gcov ./main.c -n
rm *.gcda *.gcno *.exe
+5 -1
View File
@@ -1,9 +1,13 @@
#include "unt/list.c"
#include "unt/deque.c"
#include "unt/hashmap.c"
#include "unt/hashset.c"
#include "unt/list.c"
int main(void)
{
deque_test();
hashmap_test();
hashset_test();
list_test();
return 0;
+1 -1
View File
@@ -1,4 +1,4 @@
#include "macro_collections.h"
#include "cmc/deque.h"
typedef struct deque_s
{
+425
View File
@@ -0,0 +1,425 @@
#include "cmc/hashmap.h"
typedef struct hashmap_s
{
struct hashmap_entry_s *buffer;
size_t capacity;
size_t count;
double load;
int (*cmp)(size_t, size_t);
size_t (*hash)(size_t);
struct hashmap_iter_s (*it_start)(struct hashmap_s *);
struct hashmap_iter_s (*it_end)(struct hashmap_s *);
} hashmap, *hashmap_ptr;
typedef struct hashmap_entry_s
{
size_t key;
size_t value;
size_t dist;
enum EntryState_e state;
} hashmap_entry, *hashmap_entry_ptr;
typedef struct hashmap_iter_s
{
struct hashmap_s *target;
size_t cursor;
size_t index;
size_t first;
size_t last;
bool start;
bool end;
} hashmap_iter, *hashmap_iter_ptr;
hashmap *hm_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t));
void hm_clear(hashmap *_map_);
void hm_free(hashmap *_map_);
bool hm_insert(hashmap *_map_, size_t key, size_t value);
bool hm_remove(hashmap *_map_, size_t key, size_t *value);
bool hm_insert_if(hashmap *_map_, size_t key, size_t value, bool condition);
bool hm_remove_if(hashmap *_map_, size_t key, size_t *value, bool condition);
bool hm_max(hashmap *_map_, size_t *key, size_t *value);
bool hm_min(hashmap *_map_, size_t *key, size_t *value);
size_t hm_get(hashmap *_map_, size_t key);
size_t *hm_get_ref(hashmap *_map_, size_t key);
bool hm_contains(hashmap *_map_, size_t key);
bool hm_empty(hashmap *_map_);
size_t hm_count(hashmap *_map_);
size_t hm_capacity(hashmap *_map_);
hashmap_iter *hm_iter_new(hashmap *target);
void hm_iter_free(hashmap_iter *iter);
void hm_iter_init(hashmap_iter *iter, hashmap *target);
bool hm_iter_start(hashmap_iter *iter);
bool hm_iter_end(hashmap_iter *iter);
void hm_iter_to_start(hashmap_iter *iter);
void hm_iter_to_end(hashmap_iter *iter);
bool hm_iter_next(hashmap_iter *iter);
bool hm_iter_prev(hashmap_iter *iter);
size_t hm_iter_key(hashmap_iter *iter);
size_t hm_iter_value(hashmap_iter *iter);
size_t *hm_iter_rvalue(hashmap_iter *iter);
size_t hm_iter_index(hashmap_iter *iter);
static inline size_t hm_impl_default_key(void)
{
size_t _empty_key_;
memset(&_empty_key_, 0, sizeof(size_t));
return _empty_key_;
}
static inline size_t hm_impl_default_value(void)
{
size_t _empty_value_;
memset(&_empty_value_, 0, sizeof(size_t));
return _empty_value_;
}
static bool hm_impl_grow(hashmap *_map_);
static hashmap_entry *hm_impl_get_entry(hashmap *_map_, size_t key);
static size_t hm_impl_calculate_size(size_t required);
static hashmap_iter hm_impl_it_start(hashmap *_map_);
static hashmap_iter hm_impl_it_end(hashmap *_map_);
hashmap *hm_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 0;
size_t real_capacity = hm_impl_calculate_size(capacity / load);
hashmap *_map_ = malloc(sizeof(hashmap));
if (!_map_)
return 0;
_map_->buffer = malloc(sizeof(hashmap_entry) * real_capacity);
if (!_map_->buffer)
{
free(_map_);
return 0;
}
memset(_map_->buffer, 0, sizeof(hashmap_entry) * real_capacity);
_map_->count = 0;
_map_->capacity = real_capacity;
_map_->load = load;
_map_->cmp = compare;
_map_->hash = hash;
_map_->it_start = hm_impl_it_start;
_map_->it_end = hm_impl_it_end;
return _map_;
}
void hm_clear(hashmap *_map_)
{
memset(_map_->buffer, 0, sizeof(hashmap_entry) * _map_->capacity);
_map_->count = 0;
}
void hm_free(hashmap *_map_)
{
free(_map_->buffer);
free(_map_);
}
bool hm_insert(hashmap *_map_, size_t key, size_t value)
{
if ((double)_map_->capacity * _map_->load <= (double)_map_->count)
{
if (!hm_impl_grow(_map_))
return false;
}
size_t hash = _map_->hash(key);
size_t original_pos = hash % _map_->capacity;
size_t pos = original_pos;
hashmap_entry *target = &(_map_->buffer[pos]);
if (hm_impl_get_entry(_map_, key) != 0)
return false;
if (target->state == ES_EMPTY || target->state == ES_DELETED)
{
target->key = key;
target->value = value;
target->dist = original_pos - pos;
target->state = ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_map_->buffer[pos % _map_->capacity]);
if (target->state == ES_EMPTY || target->state == ES_DELETED)
{
target->key = key;
target->value = value;
target->dist = pos - original_pos;
target->state = ES_FILLED;
break;
}
else if (target->dist < original_pos - pos)
{
size_t tmp_k = target->key;
size_t tmp_v = target->value;
size_t tmp_dist = target->dist;
target->key = key;
target->value = value;
target->dist = pos - original_pos;
key = tmp_k;
value = tmp_v;
original_pos = pos - tmp_dist;
}
}
}
_map_->count++;
return true;
}
bool hm_remove(hashmap *_map_, size_t key, size_t *value)
{
hashmap_entry *result = hm_impl_get_entry(_map_, key);
if (result == 0)
return false;
*value = result->value;
result->key = hm_impl_default_key();
result->value = hm_impl_default_value();
result->dist = 0;
result->state = ES_DELETED;
_map_->count--;
return true;
}
bool hm_insert_if(hashmap *_map_, size_t key, size_t value, bool condition)
{
if (condition)
return hm_insert(_map_, key, value);
return false;
}
bool hm_remove_if(hashmap *_map_, size_t key, size_t *value, bool condition)
{
if (condition)
return hm_remove(_map_, key, value);
return false;
}
bool hm_max(hashmap *_map_, size_t *key, size_t *value)
{
if (hm_empty(_map_))
return false;
hashmap_iter iter;
for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter))
{
size_t result_key = hm_iter_key(&iter);
size_t result_value = hm_iter_value(&iter);
size_t index = hm_iter_index(&iter);
if (index == 0)
{
*key = result_key;
*value = result_value;
}
else if (_map_->cmp(result_key, *key) > 0)
{
*key = result_key;
*value = result_value;
}
}
return true;
}
bool hm_min(hashmap *_map_, size_t *key, size_t *value)
{
if (hm_empty(_map_))
return false;
hashmap_iter iter;
for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter))
{
size_t result_key = hm_iter_key(&iter);
size_t result_value = hm_iter_value(&iter);
size_t index = hm_iter_index(&iter);
if (index == 0)
{
*key = result_key;
*value = result_value;
}
else if (_map_->cmp(result_key, *key) < 0)
{
*key = result_key;
*value = result_value;
}
}
return true;
}
size_t hm_get(hashmap *_map_, size_t key)
{
hashmap_entry *entry = hm_impl_get_entry(_map_, key);
if (!entry)
hm_impl_default_value();
return entry->value;
}
size_t *hm_get_ref(hashmap *_map_, size_t key)
{
hashmap_entry *entry = hm_impl_get_entry(_map_, key);
if (!entry)
return 0;
return &(entry->value);
}
bool hm_contains(hashmap *_map_, size_t key) { return hm_impl_get_entry(_map_, key) != 0; }
bool hm_empty(hashmap *_map_) { return _map_->count == 0; }
size_t hm_count(hashmap *_map_) { return _map_->count; }
size_t hm_capacity(hashmap *_map_) { return _map_->capacity; }
hashmap_iter *hm_iter_new(hashmap *target)
{
hashmap_iter *iter = malloc(sizeof(hashmap_iter));
if (!iter)
return 0;
hm_iter_init(iter, target);
return iter;
}
void hm_iter_free(hashmap_iter *iter) { free(iter); }
void hm_iter_init(hashmap_iter *iter, hashmap *target)
{
iter->target = target;
iter->cursor = 0;
iter->index = 0;
iter->start = true;
iter->end = hm_empty(target);
if (!hm_empty(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == 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 == ES_FILLED)
{
iter->last = i - 1;
break;
}
}
}
}
bool hm_iter_start(hashmap_iter *iter) { return hm_empty(iter->target) || iter->start; }
bool hm_iter_end(hashmap_iter *iter) { return hm_empty(iter->target) || iter->end; }
void hm_iter_to_start(hashmap_iter *iter)
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = hm_empty(iter->target);
}
void hm_iter_to_end(hashmap_iter *iter)
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = hm_empty(iter->target);
iter->end = true;
}
bool hm_iter_next(hashmap_iter *iter)
{
if (iter->end)
return false;
hashmap_entry *scan = &(iter->target->buffer[iter->cursor]);
if (iter->cursor == iter->last)
{
iter->end = true;
return false;
}
iter->index++;
while (1)
{
iter->cursor++;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == ES_FILLED)
break;
}
iter->start = hm_empty(iter->target);
return true;
}
bool hm_iter_prev(hashmap_iter *iter)
{
if (iter->start)
return false;
hashmap_entry *scan = &(iter->target->buffer[iter->cursor]);
if (iter->cursor == iter->first)
{
iter->start = true;
return false;
}
iter->index--;
while (1)
{
iter->cursor--;
scan = &(iter->target->buffer[iter->cursor]);
if (scan->state == ES_FILLED)
break;
}
iter->end = hm_empty(iter->target);
return true;
}
size_t hm_iter_key(hashmap_iter *iter)
{
if (hm_empty(iter->target))
hm_impl_default_key();
return iter->target->buffer[iter->cursor].key;
}
size_t hm_iter_value(hashmap_iter *iter)
{
if (hm_empty(iter->target))
hm_impl_default_value();
return iter->target->buffer[iter->cursor].value;
}
size_t *hm_iter_rvalue(hashmap_iter *iter)
{
if (hm_empty(iter->target))
return 0;
return &(iter->target->buffer[iter->cursor].value);
}
size_t hm_iter_index(hashmap_iter *iter) { return iter->index; }
static bool hm_impl_grow(hashmap *_map_)
{
size_t new_size = hm_impl_calculate_size(_map_->capacity + _map_->capacity / 2);
hashmap *_new_map_ = hm_new(new_size, _map_->load, _map_->cmp, _map_->hash);
if (!_new_map_)
return false;
hashmap_iter iter;
for (hm_iter_init(&iter, _map_); !hm_iter_end(&iter); hm_iter_next(&iter))
{
size_t key = hm_iter_key(&iter);
size_t value = hm_iter_value(&iter);
hm_insert(_new_map_, key, value);
}
if (_map_->count != _new_map_->count)
{
hm_free(_new_map_);
return false;
}
hashmap_entry *tmp = _map_->buffer;
_map_->buffer = _new_map_->buffer;
_new_map_->buffer = tmp;
_map_->capacity = _new_map_->capacity;
hm_free(_new_map_);
return true;
}
static hashmap_entry *hm_impl_get_entry(hashmap *_map_, size_t key)
{
size_t hash = _map_->hash(key);
size_t pos = hash % _map_->capacity;
hashmap_entry *target = &(_map_->buffer[pos]);
while (target->state == ES_FILLED || target->state == ES_DELETED)
{
if (_map_->cmp(target->key, key) == 0)
return target;
pos++;
target = &(_map_->buffer[pos % _map_->capacity]);
}
return 0;
}
static size_t hm_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 hashmap_iter hm_impl_it_start(hashmap *_map_)
{
hashmap_iter iter;
hm_iter_init(&iter, _map_);
return iter;
}
static hashmap_iter hm_impl_it_end(hashmap *_map_)
{
hashmap_iter iter;
hm_iter_init(&iter, _map_);
hm_iter_to_end(&iter);
return iter;
}
+499
View File
@@ -0,0 +1,499 @@
#include "cmc/hashset.h"
typedef struct hashset_s
{
struct hashset_entry_s *buffer;
size_t capacity;
size_t count;
double load;
int (*cmp)(size_t, size_t);
size_t (*hash)(size_t);
struct hashset_iter_s (*it_start)(struct hashset_s *);
struct hashset_iter_s (*it_end)(struct hashset_s *);
} hashset, *hashset_ptr;
typedef struct hashset_entry_s
{
size_t value;
size_t dist;
enum EntryState_e state;
} hashset_entry, *hashset_entry_ptr;
typedef struct hashset_iter_s
{
struct hashset_s *target;
size_t cursor;
size_t index;
size_t first;
size_t last;
bool start;
bool end;
} hashset_iter, *hashset_iter_ptr;
hashset *hs_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t));
void hs_clear(hashset *_set_);
void hs_free(hashset *_set_);
bool hs_insert(hashset *_set_, size_t element);
bool hs_remove(hashset *_set_, size_t element);
bool hs_insert_if(hashset *_set_, size_t element, bool condition);
bool hs_remove_if(hashset *_set_, size_t element, bool condition);
bool hs_max(hashset *_set_, size_t *value);
bool hs_min(hashset *_set_, size_t *value);
bool hs_contains(hashset *_set_, size_t element);
bool hs_empty(hashset *_set_);
size_t hs_count(hashset *_set_);
size_t hs_capacity(hashset *_set_);
hashset *hs_union(hashset *_set1_, hashset *_set2_);
hashset *hs_intersection(hashset *_set1_, hashset *_set2_);
hashset *hs_difference(hashset *_set1_, hashset *_set2_);
hashset *hs_symmetric_difference(hashset *_set1_, hashset *_set2_);
bool hs_is_subset(hashset *_set1_, hashset *_set2_);
bool hs_is_superset(hashset *_set1_, hashset *_set2_);
bool hs_is_proper_subset(hashset *_set1_, hashset *_set2_);
bool hs_is_proper_superset(hashset *_set1_, hashset *_set2_);
bool hs_is_disjointset(hashset *_set1_, hashset *_set2_);
hashset_iter *hs_iter_new(hashset *target);
void hs_iter_free(hashset_iter *iter);
void hs_iter_init(hashset_iter *iter, hashset *target);
bool hs_iter_start(hashset_iter *iter);
bool hs_iter_end(hashset_iter *iter);
void hs_iter_to_start(hashset_iter *iter);
void hs_iter_to_end(hashset_iter *iter);
bool hs_iter_next(hashset_iter *iter);
bool hs_iter_prev(hashset_iter *iter);
size_t hs_iter_value(hashset_iter *iter);
size_t hs_iter_index(hashset_iter *iter);
static inline size_t hs_impl_default_value(void)
{
size_t _empty_value_;
memset(&_empty_value_, 0, sizeof(size_t));
return _empty_value_;
}
static bool hs_impl_grow(hashset *_set_);
static hashset_entry *hs_impl_get_entry(hashset *_set_, size_t element);
static size_t hs_impl_calculate_size(size_t required);
static hashset_iter hs_impl_it_start(hashset *_set_);
static hashset_iter hs_impl_it_end(hashset *_set_);
hashset *hs_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;
size_t real_capacity = hs_impl_calculate_size(capacity / load);
hashset *_set_ = malloc(sizeof(hashset));
if (!_set_)
return NULL;
_set_->buffer = malloc(sizeof(hashset_entry) * real_capacity);
if (!_set_->buffer)
{
free(_set_);
return NULL;
}
memset(_set_->buffer, 0, sizeof(hashset_entry) * real_capacity);
_set_->count = 0;
_set_->capacity = real_capacity;
_set_->load = load;
_set_->cmp = compare;
_set_->hash = hash;
_set_->it_start = hs_impl_it_start;
_set_->it_end = hs_impl_it_end;
return _set_;
}
void hs_clear(hashset *_set_)
{
memset(_set_->buffer, 0, sizeof(hashset_entry) * _set_->capacity);
_set_->count = 0;
}
void hs_free(hashset *_set_)
{
free(_set_->buffer);
free(_set_);
}
bool hs_insert(hashset *_set_, size_t element)
{
if ((double)_set_->capacity * _set_->load <= (double)_set_->count)
{
if (!hs_impl_grow(_set_))
return false;
}
size_t hash = _set_->hash(element);
size_t original_pos = hash % _set_->capacity;
size_t pos = original_pos;
hashset_entry *target = &(_set_->buffer[pos]);
if (hs_impl_get_entry(_set_, element) != NULL)
return false;
if (target->state == ES_EMPTY || target->state == ES_DELETED)
{
target->value = element;
target->dist = pos - original_pos;
target->state = ES_FILLED;
}
else
{
while (true)
{
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
if (target->state == ES_EMPTY || target->state == ES_DELETED)
{
target->value = element;
target->dist = pos - original_pos;
target->state = ES_FILLED;
break;
}
else if (target->dist < pos - original_pos)
{
size_t tmp = target->value;
size_t tmp_dist = target->dist;
target->value = element;
target->dist = pos - original_pos;
element = tmp;
original_pos = pos - tmp_dist;
}
}
}
_set_->count++;
return true;
}
bool hs_remove(hashset *_set_, size_t element)
{
hashset_entry *result = hs_impl_get_entry(_set_, element);
if (result == NULL)
return false;
result->value = hs_impl_default_value();
result->dist = 0;
result->state = ES_DELETED;
_set_->count--;
return true;
}
bool hs_insert_if(hashset *_set_, size_t element, bool condition)
{
if (condition)
return hs_insert(_set_, element);
return false;
}
bool hs_remove_if(hashset *_set_, size_t element, bool condition)
{
if (condition)
return hs_remove(_set_, element);
return false;
}
bool hs_max(hashset *_set_, size_t *value)
{
if (hs_empty(_set_))
return false;
hashset_iter iter;
for (hs_iter_init(&iter, _set_); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t result = hs_iter_value(&iter);
size_t index = hs_iter_index(&iter);
if (index == 0)
*value = result;
else if (_set_->cmp(result, *value) > 0)
*value = result;
}
return true;
}
bool hs_min(hashset *_set_, size_t *value)
{
if (hs_empty(_set_))
return false;
hashset_iter iter;
for (hs_iter_init(&iter, _set_); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t result = hs_iter_value(&iter);
size_t index = hs_iter_index(&iter);
if (index == 0)
*value = result;
else if (_set_->cmp(result, *value) < 0)
*value = result;
}
return true;
}
bool hs_contains(hashset *_set_, size_t element) { return hs_impl_get_entry(_set_, element) != NULL; }
bool hs_empty(hashset *_set_) { return _set_->count == 0; }
size_t hs_count(hashset *_set_) { return _set_->count; }
size_t hs_capacity(hashset *_set_) { return _set_->capacity; }
hashset *hs_union(hashset *_set1_, hashset *_set2_)
{
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return false;
hashset_iter iter1, iter2;
hs_iter_init(&iter1, _set1_);
hs_iter_init(&iter2, _set2_);
for (hs_iter_to_start(&iter1); !hs_iter_end(&iter1); hs_iter_next(&iter1))
{
hs_insert(_set_r_, hs_iter_value(&iter1));
}
for (hs_iter_to_start(&iter2); !hs_iter_end(&iter2); hs_iter_next(&iter2))
{
hs_insert(_set_r_, hs_iter_value(&iter2));
}
return _set_r_;
}
hashset *hs_intersection(hashset *_set1_, hashset *_set2_)
{
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return false;
hashset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_;
hashset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_;
hashset_iter iter;
hs_iter_init(&iter, _set_A_);
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t value = hs_iter_value(&iter);
if (hs_impl_get_entry(_set_B_, value) != NULL)
hs_insert(_set_r_, value);
}
return _set_r_;
}
hashset *hs_difference(hashset *_set1_, hashset *_set2_)
{
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return false;
hashset_iter iter;
hs_iter_init(&iter, _set1_);
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t value = hs_iter_value(&iter);
if (hs_impl_get_entry(_set2_, value) == NULL)
hs_insert(_set_r_, value);
}
return _set_r_;
}
hashset *hs_symmetric_difference(hashset *_set1_, hashset *_set2_)
{
hashset_iter iter1, iter2;
hashset *_set_r_ = hs_new(_set1_->capacity, _set1_->load, _set1_->cmp, _set1_->hash);
if (!_set_r_)
return false;
hs_iter_init(&iter1, _set1_);
hs_iter_init(&iter2, _set2_);
for (hs_iter_to_start(&iter1); !hs_iter_end(&iter1); hs_iter_next(&iter1))
{
size_t value = hs_iter_value(&iter1);
if (hs_impl_get_entry(_set2_, value) == NULL)
hs_insert(_set_r_, value);
}
for (hs_iter_to_start(&iter2); !hs_iter_end(&iter2); hs_iter_next(&iter2))
{
size_t value = hs_iter_value(&iter2);
if (hs_impl_get_entry(_set1_, value) == NULL)
hs_insert(_set_r_, value);
}
return _set_r_;
}
bool hs_is_subset(hashset *_set1_, hashset *_set2_)
{
if (hs_count(_set1_) > hs_count(_set2_))
return false;
if (hs_empty(_set1_))
return true;
hashset_iter iter;
hs_iter_init(&iter, _set1_);
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t value = hs_iter_value(&iter);
if (!hs_contains(_set2_, value))
return false;
}
return true;
}
bool hs_is_superset(hashset *_set1_, hashset *_set2_) { return hs_is_subset(_set2_, _set1_); }
bool hs_is_proper_subset(hashset *_set1_, hashset *_set2_)
{
if (hs_count(_set1_) >= hs_count(_set2_))
return false;
if (hs_empty(_set1_))
{
if (!hs_empty(_set2_))
return true;
else
return false;
}
hashset_iter iter;
hs_iter_init(&iter, _set1_);
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t value = hs_iter_value(&iter);
if (!hs_contains(_set2_, value))
return false;
}
return true;
}
bool hs_is_proper_superset(hashset *_set1_, hashset *_set2_) { return hs_is_proper_subset(_set2_, _set1_); }
bool hs_is_disjointset(hashset *_set1_, hashset *_set2_)
{
if (hs_empty(_set1_))
return true;
hashset_iter iter;
hs_iter_init(&iter, _set1_);
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
{
size_t value = hs_iter_value(&iter);
if (hs_contains(_set2_, value))
return false;
}
return true;
}
hashset_iter *hs_iter_new(hashset *target)
{
hashset_iter *iter = malloc(sizeof(hashset_iter));
if (!iter)
return NULL;
hs_iter_init(iter, target);
return iter;
}
void hs_iter_free(hashset_iter *iter) { free(iter); }
void hs_iter_init(hashset_iter *iter, hashset *target)
{
iter->target = target;
iter->cursor = 0;
iter->index = 0;
iter->start = true;
iter->end = hs_empty(target);
if (!hs_empty(target))
{
for (size_t i = 0; i < target->capacity; i++)
{
if (target->buffer[i].state == 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 == ES_FILLED)
{
iter->last = i - 1;
break;
}
}
}
}
bool hs_iter_start(hashset_iter *iter) { return hs_empty(iter->target) || iter->start; }
bool hs_iter_end(hashset_iter *iter) { return hs_empty(iter->target) || iter->end; }
void hs_iter_to_start(hashset_iter *iter)
{
iter->cursor = iter->first;
iter->index = 0;
iter->start = true;
iter->end = hs_empty(iter->target);
}
void hs_iter_to_end(hashset_iter *iter)
{
iter->cursor = iter->last;
iter->index = iter->target->count - 1;
iter->start = hs_empty(iter->target);
iter->end = true;
}
bool hs_iter_next(hashset_iter *iter)
{
if (iter->end)
return false;
hashset_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 == ES_FILLED)
break;
}
}
iter->start = hs_empty(iter->target);
return true;
}
bool hs_iter_prev(hashset_iter *iter)
{
if (iter->start)
return false;
hashset_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 == ES_FILLED)
break;
}
}
iter->end = hs_empty(iter->target);
return true;
}
size_t hs_iter_value(hashset_iter *iter)
{
if (hs_empty(iter->target))
return hs_impl_default_value();
return iter->target->buffer[iter->cursor].value;
}
size_t hs_iter_index(hashset_iter *iter) { return iter->index; }
static bool hs_impl_grow(hashset *_set_)
{
size_t new_size = hs_impl_calculate_size(_set_->capacity + _set_->capacity / 2);
hashset *_new_set_ = hs_new(new_size, _set_->load, _set_->cmp, _set_->hash);
if (!_new_set_)
return false;
hashset_iter iter;
for (hs_iter_init(&iter, _set_); !hs_iter_end(&iter); hs_iter_next(&iter))
{
hs_insert(_new_set_, hs_iter_value(&iter));
}
if (_set_->count != _new_set_->count)
{
hs_free(_new_set_);
return false;
}
hashset_entry *tmp = _set_->buffer;
_set_->buffer = _new_set_->buffer;
_new_set_->buffer = tmp;
_set_->capacity = _new_set_->capacity;
hs_free(_new_set_);
return true;
}
static hashset_entry *hs_impl_get_entry(hashset *_set_, size_t element)
{
size_t hash = _set_->hash(element);
size_t pos = hash % _set_->capacity;
hashset_entry *target = &(_set_->buffer[pos]);
while (target->state == ES_FILLED || target->state == ES_DELETED)
{
if (_set_->cmp(target->value, element) == 0)
return target;
pos++;
target = &(_set_->buffer[pos % _set_->capacity]);
}
return NULL;
}
static size_t hs_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 hashset_iter hs_impl_it_start(hashset *_set_)
{
hashset_iter iter;
hs_iter_init(&iter, _set_);
return iter;
}
static hashset_iter hs_impl_it_end(hashset *_set_)
{
hashset_iter iter;
hs_iter_init(&iter, _set_);
hs_iter_to_end(&iter);
return iter;
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "macro_collections.h"
#include "cmc/list.h"
typedef struct list_s
{
+23
View File
@@ -0,0 +1,23 @@
/* Utility folder to be included in the unit tests */
#ifndef CMC_UNIT_TEST_UTL__
#define CMC_UNIT_TEST_UTL__
#include <stdlib.h>
int cmp(size_t a, size_t b)
{
return (a > b) - (a < b);
}
size_t hash(size_t a)
{
a += ~(a << 15);
a ^= (a >> 10);
a += (a << 3);
a ^= (a >> 6);
a += ~(a << 11);
a ^= (a >> 16);
return a;
}
#endif /* CMC_UNIT_TEST_UTL__ */
+46 -1
View File
@@ -1,3 +1,5 @@
#include "utl/assert.h"
#include "utl/test.h"
#include "../src/deque.c"
CMC_CREATE_UNIT(deque_test, true, {
@@ -16,7 +18,7 @@ CMC_CREATE_UNIT(deque_test, true, {
d_free(d);
});
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
deque *d = d_new(0);
@@ -25,4 +27,47 @@ CMC_CREATE_UNIT(deque_test, true, {
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
});
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
deque *d = d_new(UINT64_MAX);
cmc_assert_equals(ptr, NULL, d);
CMC_TEST_PASS_ELSE_FAIL(d == NULL);
});
CMC_CREATE_TEST(clear[count capacity], {
deque *d = d_new(100);
cmc_assert_not_equals(ptr, NULL, d);
for (size_t i = 0; i < 50; i++)
d_push_back(d, i);
cmc_assert_equals(size_t, 50, d_count(d));
d_clear(d);
cmc_assert_equals(size_t, 0, d_count(d));
cmc_assert_equals(size_t, 100, d_capacity(d));
CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 0 && d_capacity(d) == 100);
d_free(d);
});
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
deque *d = d_new(1);
cmc_assert_not_equals(ptr, NULL, d);
for (size_t i = 0; i < 50; i++)
d_push_back(d, i);
cmc_assert_equals(size_t, 50, d_count(d));
CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 50);
d_free(d);
});
});
+56
View File
@@ -0,0 +1,56 @@
#include "utl/assert.h"
#include "utl/test.h"
#include "../src/hashmap.c"
#include "../src/utl.c"
CMC_CREATE_UNIT(hashmap_test, true, {
CMC_CREATE_TEST(new, {
hashmap *map = hm_new(943722, 0.6, cmp, hash);
bool passed = (map->capacity >= (943722 / 0.6)) && map->count == 0 && map->buffer;
cmc_assert_not_equals(ptr, NULL, map);
cmc_assert(hm_capacity(map) > (943722 / 0.6));
CMC_TEST_PASS_ELSE_FAIL(passed);
hm_free(map);
});
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
hashmap *map = hm_new(0, 0.6, cmp, hash);
cmc_assert_equals(ptr, NULL, map);
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
});
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
hashmap *map = hm_new(UINT64_MAX, 0.6, cmp, hash);
cmc_assert_equals(ptr, NULL, map);
CMC_TEST_PASS_ELSE_FAIL(map == NULL);
});
CMC_CREATE_TEST(clear[count capacity], {
hashmap *map = hm_new(100, 0.6, cmp, hash);
cmc_assert_not_equals(ptr, NULL, map);
for (size_t i = 0; i < 50; i++)
hm_insert(map, i, i);
cmc_assert_equals(size_t, 50, hm_count(map));
hm_clear(map);
cmc_assert_equals(size_t, 0, hm_count(map));
CMC_TEST_PASS_ELSE_FAIL(hm_count(map) == 0);
hm_free(map);
});
});
+56
View File
@@ -0,0 +1,56 @@
#include "utl/assert.h"
#include "utl/test.h"
#include "../src/hashset.c"
#include "../src/utl.c"
CMC_CREATE_UNIT(hashset_test, true, {
CMC_CREATE_TEST(new, {
hashset *set = hs_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(hs_capacity(set) > (943722 / 0.6));
CMC_TEST_PASS_ELSE_FAIL(passed);
hs_free(set);
});
CMC_CREATE_TEST(new[edge_case:capacity = 0], {
hashset *set = hs_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 = UINT64_MAX], {
hashset *set = hs_new(UINT64_MAX, 0.6, cmp, hash);
cmc_assert_equals(ptr, NULL, set);
CMC_TEST_PASS_ELSE_FAIL(set == NULL);
});
CMC_CREATE_TEST(clear[count capacity], {
hashset *set = hs_new(100, 0.6, cmp, hash);
cmc_assert_not_equals(ptr, NULL, set);
for (size_t i = 0; i < 50; i++)
hs_insert(set, i);
cmc_assert_equals(size_t, 50, hs_count(set));
hs_clear(set);
cmc_assert_equals(size_t, 0, hs_count(set));
CMC_TEST_PASS_ELSE_FAIL(hs_count(set) == 0);
hs_free(set);
});
});
+39 -4
View File
@@ -1,3 +1,5 @@
#include "utl/assert.h"
#include "utl/test.h"
#include "../src/list.c"
CMC_CREATE_UNIT(list_test, true, {
@@ -12,10 +14,7 @@ CMC_CREATE_UNIT(list_test, true, {
cmc_assert_equals(size_t, 0, l_count(l));
cmc_assert_not_equals(ptr, NULL, l->buffer);
if (passed)
CMC_TEST_PASS();
else
CMC_TEST_FAIL();
CMC_TEST_PASS_ELSE_FAIL(passed);
l_free(l);
});
@@ -28,6 +27,14 @@ CMC_CREATE_UNIT(list_test, true, {
CMC_TEST_PASS_ELSE_FAIL(l == NULL);
});
CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], {
list *l = l_new(UINT64_MAX);
cmc_assert_equals(ptr, NULL, l);
CMC_TEST_PASS_ELSE_FAIL(l == NULL);
});
CMC_CREATE_TEST(new_from[count item_preservation], {
size_t v[5];
@@ -76,13 +83,41 @@ CMC_CREATE_UNIT(list_test, true, {
for (size_t i = 0; i < 50; i++)
l_push_back(l, i);
cmc_assert_equals(size_t, 50, l_count(l));
l_clear(l);
cmc_assert_equals(size_t, 0, l_count(l));
cmc_assert_equals(size_t, 100, l_capacity(l));
CMC_TEST_PASS_ELSE_FAIL(l_count(l) == 0 && l_capacity(l) == 100);
l_free(l);
});
CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], {
list *l = l_new(1);
cmc_assert_not_equals(ptr, NULL, l);
for (size_t i = 0; i < 100; i++)
l_push_back(l, i);
cmc_assert_equals(size_t, 100, l_count(l));
bool passed = true;
for (size_t i = 0; i < 100; i++)
{
passed = passed && l_get(l, i) == i;
cmc_assert_equals(size_t, i, l_get(l, i));
}
CMC_TEST_PASS_ELSE_FAIL(passed);
l_free(l);
});
CMC_CREATE_TEST(push_front[count capacity item_preservation grow], {
list *l = l_new(100);