Tests update
This commit is contained in:
1 parent
78cfc0c335
commit
6a2cb70fb5
11 files changed
+1157
-8
No files matched your search
@@ -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
@@ -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,4 +1,4 @@
|
||||
#include "macro_collections.h"
|
||||
#include "cmc/deque.h"
|
||||
|
||||
typedef struct deque_s
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,4 +1,4 @@
|
||||
#include "macro_collections.h"
|
||||
#include "cmc/list.h"
|
||||
|
||||
typedef struct list_s
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in new issue
Block a user