From f0b7b125b91f2c518833cbcad5044228cec0436b Mon Sep 17 00:00:00 2001 From: Leonardo Date: Sat, 5 Oct 2019 00:31:29 -0300 Subject: [PATCH] Added deque.h resize and added more deque and hashmap tests --- src/cmc/deque.h | 958 ++++++++++++++++++++------------------- tests/main/unt/deque.c | 181 +++++++- tests/main/unt/hashmap.c | 313 +++++++++++++ tests/main/unt/utl.c | 21 + 4 files changed, 1005 insertions(+), 468 deletions(-) diff --git a/src/cmc/deque.h b/src/cmc/deque.h index 048a74c..5bb3b3d 100644 --- a/src/cmc/deque.h +++ b/src/cmc/deque.h @@ -120,6 +120,7 @@ static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRI size_t PFX##_count(SNAME *_deque_); \ size_t PFX##_capacity(SNAME *_deque_); \ /* Collection Utility */ \ + bool PFX##_resize(SNAME *_deque_, size_t capacity); \ SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)); \ bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)); \ cmc_string PFX##_to_string(SNAME *_deque_); \ @@ -157,467 +158,502 @@ static const char *cmc_string_fmt_deque = "%s at %p { buffer:%p, capacity:%" PRI } \ \ /* SOURCE ********************************************************************/ -#define CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V) \ - \ - /* Implementation Detail Functions */ \ - static bool PFX##_impl_grow(SNAME *_deque_); \ - static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \ - static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \ - \ - SNAME *PFX##_new(size_t capacity) \ - { \ - if (capacity < 1) \ - return NULL; \ - \ - SNAME *_deque_ = malloc(sizeof(SNAME)); \ - \ - if (!_deque_) \ - return NULL; \ - \ - _deque_->buffer = malloc(sizeof(V) * capacity); \ - \ - if (!_deque_->buffer) \ - { \ - free(_deque_); \ - return NULL; \ - } \ - \ - memset(_deque_->buffer, 0, sizeof(V) * capacity); \ - \ - _deque_->capacity = capacity; \ - _deque_->count = 0; \ - _deque_->front = 0; \ - _deque_->back = 0; \ - \ - _deque_->it_start = PFX##_impl_it_start; \ - _deque_->it_end = PFX##_impl_it_end; \ - \ - return _deque_; \ - } \ - \ - void PFX##_clear(SNAME *_deque_, void (*deallocator)(V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \ - { \ - deallocator(_deque_->buffer[i]); \ - } \ - } \ - \ - memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \ - \ - _deque_->count = 0; \ - _deque_->front = 0; \ - _deque_->back = 0; \ - } \ - \ - void PFX##_free(SNAME *_deque_, void (*deallocator)(V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \ - { \ - deallocator(_deque_->buffer[i]); \ - } \ - } \ - \ - free(_deque_->buffer); \ - free(_deque_); \ - } \ - \ - bool PFX##_push_front(SNAME *_deque_, V element) \ - { \ - if (PFX##_full(_deque_)) \ - { \ - if (!PFX##_impl_grow(_deque_)) \ - return false; \ - } \ - \ - _deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \ - \ - _deque_->buffer[_deque_->front] = element; \ - \ - _deque_->count++; \ - \ - return true; \ - } \ - \ - bool PFX##_push_back(SNAME *_deque_, V element) \ - { \ - if (PFX##_full(_deque_)) \ - { \ - if (!PFX##_impl_grow(_deque_)) \ - return false; \ - } \ - \ - _deque_->buffer[_deque_->back] = element; \ - \ - _deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1; \ - \ - _deque_->count++; \ - \ - return true; \ - } \ - \ - bool PFX##_pop_front(SNAME *_deque_) \ - { \ - if (PFX##_empty(_deque_)) \ - return false; \ - \ - _deque_->buffer[_deque_->front] = PFX##_impl_default_value(); \ - \ - _deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \ - \ - _deque_->count--; \ - \ - return true; \ - } \ - \ - bool PFX##_pop_back(SNAME *_deque_) \ - { \ - if (PFX##_empty(_deque_)) \ - return false; \ - \ - _deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \ - \ - _deque_->buffer[_deque_->back] = PFX##_impl_default_value(); \ - \ - _deque_->count--; \ - \ - return true; \ - } \ - \ - V PFX##_front(SNAME *_deque_) \ - { \ - if (PFX##_empty(_deque_)) \ - return PFX##_impl_default_value(); \ - \ - return _deque_->buffer[_deque_->front]; \ - } \ - \ - V PFX##_back(SNAME *_deque_) \ - { \ - if (PFX##_empty(_deque_)) \ - return PFX##_impl_default_value(); \ - \ - return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; \ - } \ - \ - bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)) \ - { \ - for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \ - { \ - if (comparator(_deque_->buffer[i], element) == 0) \ - return true; \ - } \ - \ - return false; \ - } \ - \ - bool PFX##_empty(SNAME *_deque_) \ - { \ - return _deque_->count == 0; \ - } \ - \ - bool PFX##_full(SNAME *_deque_) \ - { \ - return _deque_->count >= _deque_->capacity; \ - } \ - \ - size_t PFX##_count(SNAME *_deque_) \ - { \ - return _deque_->count; \ - } \ - \ - size_t PFX##_capacity(SNAME *_deque_) \ - { \ - return _deque_->capacity; \ - } \ - \ - SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)) \ - { \ - SNAME *result = PFX##_new(_deque_->capacity); \ - \ - if (!result) \ - return NULL; \ - \ - if (copy_func) \ - { \ - for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \ - { \ - result->buffer[j] = copy_func(_deque_->buffer[i]); \ - } \ - } \ - else \ - { \ - for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \ - { \ - result->buffer[j] = _deque_->buffer[i]; \ - } \ - } \ - \ - result->count = _deque_->count; \ - \ - return result; \ - } \ - \ - bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)) \ - { \ - if (PFX##_count(_deque1_) != PFX##_count(_deque2_)) \ - return false; \ - \ - size_t i, j, k; \ - for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \ - { \ - if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) != 0) \ - return false; \ - \ - i = (i + 1) % _deque1_->capacity; \ - j = (j + 1) % _deque2_->capacity; \ - } \ - \ - return true; \ - } \ - \ - cmc_string PFX##_to_string(SNAME *_deque_) \ - { \ - cmc_string str; \ - SNAME *d_ = _deque_; \ - const char *name = #SNAME; \ - \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \ - name, d_, d_->buffer, d_->capacity, d_->count, d_->front, d_->back); \ - \ - return str; \ - } \ - \ - SNAME##_iter *PFX##_iter_new(SNAME *target) \ - { \ - SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ - \ - if (!iter) \ - return NULL; \ - \ - PFX##_iter_init(iter, target); \ - \ - return iter; \ - } \ - \ - void PFX##_iter_free(SNAME##_iter *iter) \ - { \ - free(iter); \ - } \ - \ - void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \ - { \ - iter->target = target; \ - iter->cursor = target->front; \ - iter->index = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(target); \ - } \ - \ - bool PFX##_iter_start(SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->start; \ - } \ - \ - bool PFX##_iter_end(SNAME##_iter *iter) \ - { \ - return PFX##_empty(iter->target) || iter->end; \ - } \ - \ - void PFX##_iter_to_start(SNAME##_iter *iter) \ - { \ - iter->cursor = iter->target->front; \ - iter->index = 0; \ - iter->start = true; \ - iter->end = PFX##_empty(iter->target); \ - } \ - \ - void PFX##_iter_to_end(SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - { \ - iter->cursor = 0; \ - iter->index = 0; \ - } \ - else \ - { \ - iter->cursor = (iter->target->back == 0) ? iter->target->capacity - 1 : iter->target->back - 1; \ - iter->index = PFX##_count(iter->target) - 1; \ - } \ - \ - iter->start = PFX##_empty(iter->target); \ - iter->end = true; \ - } \ - \ - bool PFX##_iter_next(SNAME##_iter *iter) \ - { \ - if (iter->end) \ - return false; \ - \ - if (iter->index + 1 == PFX##_count(iter->target)) \ - { \ - iter->end = true; \ - return false; \ - } \ - \ - iter->start = PFX##_empty(iter->target); \ - \ - iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \ - iter->index++; \ - \ - return true; \ - } \ - \ - bool PFX##_iter_prev(SNAME##_iter *iter) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->index == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - iter->end = PFX##_empty(iter->target); \ - \ - iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \ - iter->index--; \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator moved */ \ - bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \ - { \ - if (iter->end) \ - return false; \ - \ - if (iter->index + 1 == PFX##_count(iter->target)) \ - { \ - iter->end = true; \ - return false; \ - } \ - \ - if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \ - return false; \ - \ - iter->start = PFX##_empty(iter->target); \ - \ - iter->index += steps; \ - iter->cursor = (iter->cursor + steps) % iter->target->capacity; \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator moved */ \ - bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \ - { \ - if (iter->start) \ - return false; \ - \ - if (iter->index == 0) \ - { \ - iter->start = true; \ - return false; \ - } \ - \ - if (steps == 0 || iter->index < steps) \ - return false; \ - \ - iter->end = PFX##_empty(iter->target); \ - \ - iter->index -= steps; \ - \ - /* Prevent underflow */ \ - if (iter->cursor < steps) \ - iter->cursor += PFX##_capacity(iter->target); \ - \ - iter->cursor -= steps; \ - \ - return true; \ - } \ - \ - /* Returns true only if the iterator was able to be positioned at the given index */ \ - bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \ - { \ - if (index >= PFX##_count(iter->target)) \ - return false; \ - \ - if (iter->index > index) \ - return PFX##_iter_rewind(iter, iter->index - index); \ - else if (iter->index < index) \ - return PFX##_iter_advance(iter, index - iter->index); \ - \ - return true; \ - } \ - \ - V PFX##_iter_value(SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return PFX##_impl_default_value(); \ - \ - return iter->target->buffer[iter->cursor]; \ - } \ - \ - V *PFX##_iter_rvalue(SNAME##_iter *iter) \ - { \ - if (PFX##_empty(iter->target)) \ - return NULL; \ - \ - return &(iter->target->buffer[iter->cursor]); \ - } \ - \ - size_t PFX##_iter_index(SNAME##_iter *iter) \ - { \ - return iter->index; \ - } \ - \ - static bool PFX##_impl_grow(SNAME *_deque_) \ - { \ - size_t new_capacity = _deque_->capacity * 2; \ - \ - V *new_buffer = malloc(sizeof(V) * new_capacity); \ - \ - if (!new_buffer) \ - return false; \ - \ - for (size_t i = _deque_->front, j = 0; j < _deque_->count; i = (i + 1) % _deque_->capacity, j++) \ - { \ - new_buffer[j] = _deque_->buffer[i]; \ - } \ - \ - free(_deque_->buffer); \ - \ - _deque_->buffer = new_buffer; \ - _deque_->capacity = new_capacity; \ - _deque_->front = 0; \ - _deque_->back = _deque_->count; \ - \ - return true; \ - } \ - \ - static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \ - { \ - SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _deque_); \ - \ - return iter; \ - } \ - \ - static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \ - { \ - SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _deque_); \ - PFX##_iter_to_end(&iter); \ - \ - return iter; \ +#define CMC_GENERATE_DEQUE_SOURCE(PFX, SNAME, V) \ + \ + /* Implementation Detail Functions */ \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \ + \ + SNAME *PFX##_new(size_t capacity) \ + { \ + if (capacity < 1) \ + return NULL; \ + \ + SNAME *_deque_ = malloc(sizeof(SNAME)); \ + \ + if (!_deque_) \ + return NULL; \ + \ + _deque_->buffer = malloc(sizeof(V) * capacity); \ + \ + if (!_deque_->buffer) \ + { \ + free(_deque_); \ + return NULL; \ + } \ + \ + memset(_deque_->buffer, 0, sizeof(V) * capacity); \ + \ + _deque_->capacity = capacity; \ + _deque_->count = 0; \ + _deque_->front = 0; \ + _deque_->back = 0; \ + \ + _deque_->it_start = PFX##_impl_it_start; \ + _deque_->it_end = PFX##_impl_it_end; \ + \ + return _deque_; \ + } \ + \ + void PFX##_clear(SNAME *_deque_, void (*deallocator)(V)) \ + { \ + if (deallocator) \ + { \ + for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \ + { \ + deallocator(_deque_->buffer[i]); \ + \ + i = (i + 1) % _deque_->capacity; \ + } \ + } \ + \ + memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity); \ + \ + _deque_->count = 0; \ + _deque_->front = 0; \ + _deque_->back = 0; \ + } \ + \ + void PFX##_free(SNAME *_deque_, void (*deallocator)(V)) \ + { \ + if (deallocator) \ + { \ + for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \ + { \ + deallocator(_deque_->buffer[i]); \ + \ + i = (i + 1) % _deque_->capacity; \ + } \ + } \ + \ + free(_deque_->buffer); \ + free(_deque_); \ + } \ + \ + bool PFX##_push_front(SNAME *_deque_, V element) \ + { \ + if (PFX##_full(_deque_)) \ + { \ + if (!PFX##_resize(_deque_, PFX##_capacity(_deque_) * 2)) \ + return false; \ + } \ + \ + _deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1; \ + \ + _deque_->buffer[_deque_->front] = element; \ + \ + _deque_->count++; \ + \ + return true; \ + } \ + \ + bool PFX##_push_back(SNAME *_deque_, V element) \ + { \ + if (PFX##_full(_deque_)) \ + { \ + if (!PFX##_resize(_deque_, PFX##_capacity(_deque_) * 2)) \ + return false; \ + } \ + \ + _deque_->buffer[_deque_->back] = element; \ + \ + _deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1; \ + \ + _deque_->count++; \ + \ + return true; \ + } \ + \ + bool PFX##_pop_front(SNAME *_deque_) \ + { \ + if (PFX##_empty(_deque_)) \ + return false; \ + \ + _deque_->buffer[_deque_->front] = PFX##_impl_default_value(); \ + \ + _deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1; \ + \ + _deque_->count--; \ + \ + return true; \ + } \ + \ + bool PFX##_pop_back(SNAME *_deque_) \ + { \ + if (PFX##_empty(_deque_)) \ + return false; \ + \ + _deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1; \ + \ + _deque_->buffer[_deque_->back] = PFX##_impl_default_value(); \ + \ + _deque_->count--; \ + \ + return true; \ + } \ + \ + V PFX##_front(SNAME *_deque_) \ + { \ + if (PFX##_empty(_deque_)) \ + return PFX##_impl_default_value(); \ + \ + return _deque_->buffer[_deque_->front]; \ + } \ + \ + V PFX##_back(SNAME *_deque_) \ + { \ + if (PFX##_empty(_deque_)) \ + return PFX##_impl_default_value(); \ + \ + return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; \ + } \ + \ + bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)) \ + { \ + for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \ + { \ + if (comparator(_deque_->buffer[i], element) == 0) \ + return true; \ + \ + i = (i + 1) % _deque_->capacity; \ + } \ + \ + return false; \ + } \ + \ + bool PFX##_empty(SNAME *_deque_) \ + { \ + return _deque_->count == 0; \ + } \ + \ + bool PFX##_full(SNAME *_deque_) \ + { \ + return _deque_->count >= _deque_->capacity; \ + } \ + \ + size_t PFX##_count(SNAME *_deque_) \ + { \ + return _deque_->count; \ + } \ + \ + size_t PFX##_capacity(SNAME *_deque_) \ + { \ + return _deque_->capacity; \ + } \ + \ + bool PFX##_resize(SNAME *_deque_, size_t capacity) \ + { \ + if (PFX##_capacity(_deque_) == capacity) \ + return true; \ + \ + size_t new_capacity = 0; \ + \ + if (capacity < PFX##_capacity(_deque_)) \ + { \ + /* Shrink */ \ + if (capacity < PFX##_count(_deque_)) \ + return false; \ + \ + new_capacity = capacity; \ + } \ + else \ + { \ + /* Grow */ \ + if (PFX##_capacity(_deque_) * 2 < capacity) \ + new_capacity = capacity; \ + else \ + new_capacity = PFX##_capacity(_deque_) * 2; \ + } \ + \ + V *new_buffer = malloc(sizeof(V) * new_capacity); \ + \ + if (!new_buffer) \ + return false; \ + \ + for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \ + { \ + new_buffer[j] = _deque_->buffer[i]; \ + \ + i = (i + 1) % PFX##_capacity(_deque_); \ + } \ + \ + free(_deque_->buffer); \ + \ + _deque_->buffer = new_buffer; \ + _deque_->capacity = new_capacity; \ + _deque_->front = 0; \ + _deque_->back = _deque_->count; \ + \ + return true; \ + } \ + \ + SNAME *PFX##_copy_of(SNAME *_deque_, V (*copy_func)(V)) \ + { \ + SNAME *result = PFX##_new(_deque_->capacity); \ + \ + if (!result) \ + return NULL; \ + \ + if (copy_func) \ + { \ + for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \ + { \ + result->buffer[j] = copy_func(_deque_->buffer[i]); \ + \ + i = (i + 1) % _deque_->capacity; \ + } \ + } \ + else \ + { \ + for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++) \ + { \ + result->buffer[j] = _deque_->buffer[i]; \ + \ + i = (i + 1) % _deque_->capacity; \ + } \ + } \ + \ + result->count = _deque_->count; \ + \ + return result; \ + } \ + \ + bool PFX##_equals(SNAME *_deque1_, SNAME *_deque2_, int (*comparator)(V, V)) \ + { \ + if (PFX##_count(_deque1_) != PFX##_count(_deque2_)) \ + return false; \ + \ + size_t i, j, k; \ + for (i = _deque1_->front, j = _deque2_->front, k = 0; k < PFX##_count(_deque1_); k++) \ + { \ + if (comparator(_deque1_->buffer[i], _deque2_->buffer[j]) != 0) \ + return false; \ + \ + i = (i + 1) % _deque1_->capacity; \ + j = (j + 1) % _deque2_->capacity; \ + } \ + \ + return true; \ + } \ + \ + cmc_string PFX##_to_string(SNAME *_deque_) \ + { \ + cmc_string str; \ + SNAME *d_ = _deque_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_deque, \ + name, d_, d_->buffer, d_->capacity, d_->count, d_->front, d_->back); \ + \ + return str; \ + } \ + \ + SNAME##_iter *PFX##_iter_new(SNAME *target) \ + { \ + SNAME##_iter *iter = malloc(sizeof(SNAME##_iter)); \ + \ + if (!iter) \ + return NULL; \ + \ + PFX##_iter_init(iter, target); \ + \ + return iter; \ + } \ + \ + void PFX##_iter_free(SNAME##_iter *iter) \ + { \ + free(iter); \ + } \ + \ + void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \ + { \ + iter->target = target; \ + iter->cursor = target->front; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(target); \ + } \ + \ + bool PFX##_iter_start(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->start; \ + } \ + \ + bool PFX##_iter_end(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->end; \ + } \ + \ + void PFX##_iter_to_start(SNAME##_iter *iter) \ + { \ + iter->cursor = iter->target->front; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(iter->target); \ + } \ + \ + void PFX##_iter_to_end(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + { \ + iter->cursor = 0; \ + iter->index = 0; \ + } \ + else \ + { \ + if (iter->target->back == 0) \ + iter->cursor = iter->target->capacity - 1; \ + else \ + iter->cursor = iter->target->back - 1; \ + \ + iter->index = PFX##_count(iter->target) - 1; \ + } \ + \ + iter->start = PFX##_empty(iter->target); \ + iter->end = true; \ + } \ + \ + bool PFX##_iter_next(SNAME##_iter *iter) \ + { \ + if (iter->end) \ + return false; \ + \ + if (iter->index + 1 == PFX##_count(iter->target)) \ + { \ + iter->end = true; \ + return false; \ + } \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + iter->cursor = (iter->cursor + 1) % (iter->target->capacity); \ + iter->index++; \ + \ + return true; \ + } \ + \ + bool PFX##_iter_prev(SNAME##_iter *iter) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->index == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; \ + iter->index--; \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator moved */ \ + bool PFX##_iter_advance(SNAME##_iter *iter, size_t steps) \ + { \ + if (iter->end) \ + return false; \ + \ + if (iter->index + 1 == PFX##_count(iter->target)) \ + { \ + iter->end = true; \ + return false; \ + } \ + \ + if (steps == 0 || iter->index + steps >= PFX##_count(iter->target)) \ + return false; \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + iter->index += steps; \ + iter->cursor = (iter->cursor + steps) % iter->target->capacity; \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator moved */ \ + bool PFX##_iter_rewind(SNAME##_iter *iter, size_t steps) \ + { \ + if (iter->start) \ + return false; \ + \ + if (iter->index == 0) \ + { \ + iter->start = true; \ + return false; \ + } \ + \ + if (steps == 0 || iter->index < steps) \ + return false; \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + iter->index -= steps; \ + \ + /* Prevent underflow */ \ + if (iter->cursor < steps) \ + iter->cursor += PFX##_capacity(iter->target); \ + \ + iter->cursor -= steps; \ + \ + return true; \ + } \ + \ + /* Returns true only if the iterator was able to be positioned at the given index */ \ + bool PFX##_iter_go_to(SNAME##_iter *iter, size_t index) \ + { \ + if (index >= PFX##_count(iter->target)) \ + return false; \ + \ + if (iter->index > index) \ + return PFX##_iter_rewind(iter, iter->index - index); \ + else if (iter->index < index) \ + return PFX##_iter_advance(iter, index - iter->index); \ + \ + return true; \ + } \ + \ + V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return PFX##_impl_default_value(); \ + \ + return iter->target->buffer[iter->cursor]; \ + } \ + \ + V *PFX##_iter_rvalue(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ + return &(iter->target->buffer[iter->cursor]); \ + } \ + \ + size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _deque_); \ + \ + return iter; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _deque_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_DEQUE_H */ diff --git a/tests/main/unt/deque.c b/tests/main/unt/deque.c index 40120c1..b1bb3c5 100644 --- a/tests/main/unt/deque.c +++ b/tests/main/unt/deque.c @@ -19,13 +19,13 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); - CMC_CREATE_TEST(new [edge_case:capacity = 0], { + CMC_CREATE_TEST(new[edge_case capacity = 0], { deque *d = d_new(0); cmc_assert_equals(ptr, NULL, d); }); - CMC_CREATE_TEST(new [edge_case:capacity = UINT64_MAX], { + CMC_CREATE_TEST(new[edge_case capacity = UINT64_MAX], { deque *d = d_new(UINT64_MAX); cmc_assert_equals(ptr, NULL, d); @@ -49,7 +49,7 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); - CMC_CREATE_TEST(buffer_growth [edge_case:capacity = 1], { + CMC_CREATE_TEST(buffer_growth[edge_case capacity = 1], { deque *d = d_new(1); cmc_assert_not_equals(ptr, NULL, d); @@ -63,6 +63,29 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); + CMC_CREATE_TEST(buffer_growth[item_preservation], { + deque *d = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d); + + for (size_t i = 1; i <= 1200; i++) + { + if (i % 2 == 0) + d_push_front(d, i); + else + d_push_back(d, i); + } + + size_t sum = 0; + for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++) + sum += d->buffer[i]; + + cmc_assert_equals(size_t, 1200, d_count(d)); + cmc_assert_equals(size_t, 720600, sum); + + d_free(d, NULL); + }); + CMC_CREATE_TEST(push_front[count capacity], { deque *d = d_new(100); @@ -277,7 +300,7 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); - CMC_CREATE_TEST(front [edge_case:count = 0], { + CMC_CREATE_TEST(front[edge_case count = 0], { deque *d = d_new(100); cmc_assert_not_equals(ptr, NULL, d); @@ -318,7 +341,7 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); - CMC_CREATE_TEST(back [edge_case:count = 0], { + CMC_CREATE_TEST(back[edge_case count = 0], { deque *d = d_new(100); cmc_assert_not_equals(ptr, NULL, d); @@ -381,7 +404,7 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); - CMC_CREATE_TEST(contains [edge_case:count = 0], { + CMC_CREATE_TEST(contains[edge_case count = 0], { deque *d = d_new(100); cmc_assert_not_equals(ptr, NULL, d); @@ -391,7 +414,7 @@ CMC_CREATE_UNIT(deque_test, true, { d_free(d, NULL); }); - CMC_CREATE_TEST(contains [edge_case:count = 1], { + CMC_CREATE_TEST(contains[edge_case count = 1], { deque *d = d_new(100); cmc_assert_not_equals(ptr, NULL, d); @@ -459,8 +482,152 @@ CMC_CREATE_UNIT(deque_test, true, { CMC_CREATE_TEST(capacity, { deque *d = d_new(100); + cmc_assert_not_equals(ptr, NULL, d); + cmc_assert_equals(size_t, 100, d_capacity(d)); d_free(d, NULL); }); + + CMC_CREATE_TEST(resize, { + deque *d = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d); + + for (size_t i = 0; i < 150; i++) + { + if (i % 2 == 0) + cmc_assert(d_push_back(d, i)); + else + cmc_assert(d_push_front(d, i)); + } + + cmc_assert_equals(size_t, 150, d_count(d)); + cmc_assert(d_resize(d, d_count(d))); + cmc_assert_equals(size_t, 150, d_capacity(d)); + + d_free(d, NULL); + }); + + CMC_CREATE_TEST(resize[item_preservation], { + deque *d = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d); + + for (size_t i = 1; i <= 150; i++) + { + if (i % 2 != 0) + cmc_assert(d_push_back(d, i)); + else + cmc_assert(d_push_front(d, i)); + } + + cmc_assert(d_resize(d, d_count(d))); + + size_t sum = 0; + + for (size_t i = d->front, j = 0; j < d->count; i = (i + 1) % d->capacity, j++) + { + sum += d->buffer[i]; + } + + cmc_assert_equals(size_t, 11325, sum); + + d_free(d, NULL); + }); + + CMC_CREATE_TEST(copy_of, { + deque *d1 = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + + for (size_t i = 1; i <= 150; i++) + { + if (i % 2 != 0) + cmc_assert(d_push_back(d1, i)); + else + cmc_assert(d_push_front(d1, i)); + } + + deque *d2 = d_copy_of(d1, NULL); + + cmc_assert_not_equals(ptr, NULL, d2); + cmc_assert_equals(size_t, d_count(d1), d_count(d2)); + + for (size_t i1 = d1->front, i2 = d2->front, j = 0; j < d1->count; j++) + { + cmc_assert_equals(size_t, d1->buffer[i1], d2->buffer[i2]); + + i1 = (i1 + 1) % d1->capacity; + i2 = (i2 + 1) % d2->capacity; + } + + d_free(d1, NULL); + d_free(d2, NULL); + }); + + CMC_CREATE_TEST(equals, { + deque *d1 = d_new(100); + deque *d2 = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + cmc_assert_not_equals(ptr, NULL, d2); + + for (size_t i = 1; i <= 150; i++) + { + if (i % 2 != 0) + { + cmc_assert(d_push_back(d1, i)); + cmc_assert(d_push_back(d2, i)); + } + else + { + cmc_assert(d_push_front(d1, i)); + cmc_assert(d_push_front(d2, i)); + } + } + + cmc_assert(d_equals(d1, d2, cmp)); + + d_free(d1, NULL); + d_free(d2, NULL); + }); + + CMC_CREATE_TEST(equals[from copy], { + deque *d1 = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + + for (size_t i = 1; i <= 150; i++) + { + if (i % 2 != 0) + cmc_assert(d_push_back(d1, i)); + else + cmc_assert(d_push_front(d1, i)); + } + + deque *d2 = d_copy_of(d1, NULL); + + cmc_assert_not_equals(ptr, NULL, d2); + + cmc_assert(d_equals(d1, d2, cmp)); + + d_free(d1, NULL); + d_free(d2, NULL); + }); + + CMC_CREATE_TEST(equals[edge_case count = 0], { + deque *d1 = d_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + + deque *d2 = d_copy_of(d1, NULL); + + cmc_assert_not_equals(ptr, NULL, d2); + + cmc_assert(d_equals(d1, d2, cmp)); + + d_free(d1, NULL); + d_free(d2, NULL); + }); }); diff --git a/tests/main/unt/hashmap.c b/tests/main/unt/hashmap.c index 77acdcf..beeadb6 100644 --- a/tests/main/unt/hashmap.c +++ b/tests/main/unt/hashmap.c @@ -47,4 +47,317 @@ CMC_CREATE_UNIT(hashmap_test, true, { hm_free(map, NULL); }); + + CMC_CREATE_TEST(insert, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(hm_insert(map, 1, 1)); + cmc_assert_equals(size_t, 1, hm_count(map)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(insert[edge_case smallest capacity], { + hashmap *map = hm_new(1, 0.99, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map)); + cmc_assert(hm_insert(map, 1, 1)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(insert[element position], { + // Using the numhash the key is the hash itself + hashmap *map = hm_new(1, 0.99, cmp, numhash); + + cmc_assert_not_equals(ptr, NULL, map); + + size_t capacity = hm_capacity(map); + + cmc_assert_greater(size_t, 0, capacity); + + cmc_assert(hm_insert(map, capacity - 1, capacity - 1)); + cmc_assert(hm_insert(map, capacity, capacity)); + + cmc_assert_equals(size_t, capacity - 1, map->buffer[capacity - 1].key); + cmc_assert_equals(size_t, capacity, map->buffer[0].key); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(insert[distance], { + hashmap *map = hm_new(500, 0.6, cmp, hash0); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i < 200; i++) + cmc_assert(hm_insert(map, i, i)); + + // Everything is hashed to 0 so key 0 should have dist 0, key 1 dist 1, etc + for (size_t i = 0; i < 200; i++) + cmc_assert_equals(size_t, i, map->buffer[i].dist); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(insert[distance wrap], { + hashmap *map = hm_new(1, 0.99, cmp, hashcapminus1); + + cmc_assert_not_equals(ptr, NULL, map); + + size_t capacity = hm_capacity(map); + + // Just to be sure, not part of the test + cmc_assert_equals(size_t, cmc_hashtable_primes[0] - 1, hashcapminus1(0)); + cmc_assert_equals(size_t, capacity - 1, hashcapminus1(0)); + + cmc_assert(hm_insert(map, 0, 0)); + cmc_assert(hm_insert(map, 1, 1)); + + cmc_assert_equals(size_t, 0, map->buffer[capacity - 1].dist); + cmc_assert_equals(size_t, 1, map->buffer[0].dist); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(update, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(hm_insert(map, 1, 1)); + + size_t old; + cmc_assert(hm_update(map, 1, 2, &old)); + + cmc_assert_equals(size_t, 1, old); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(update[key not found], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hm_insert(map, i, i)); + + cmc_assert(!hm_update(map, 120, 120, NULL)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(remove, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hm_insert(map, i, i)); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hm_remove(map, i, NULL)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(remove[key not found], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i < 100; i++) + cmc_assert(hm_insert(map, i, i)); + + for (size_t i = 100; i < 200; i++) + cmc_assert(!hm_remove(map, i, NULL)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(max, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(hm_insert(map, i, i)); + + size_t key; + size_t val; + cmc_assert(hm_max(map, &key, &val)); + + cmc_assert_equals(size_t, 100, key); + cmc_assert_equals(size_t, 100, val); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(max[edge_case count = 0], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(!hm_min(map, NULL, NULL)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(min, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(hm_insert(map, i, i)); + + size_t key; + size_t val; + cmc_assert(hm_min(map, &key, &val)); + + cmc_assert_equals(size_t, 1, key); + cmc_assert_equals(size_t, 1, val); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(min[edge_case count = 0], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(!hm_min(map, NULL, NULL)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(get, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(hm_insert(map, 4321, 1234)); + + cmc_assert_equals(size_t, 1234, hm_get(map, 4321)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(get[edge_case count = 0], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert_equals(size_t, hm_impl_default_value(), hm_get(map, 4321)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(get_ref, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(hm_insert(map, 4321, 1234)); + + size_t *result = hm_get_ref(map, 4321); + + cmc_assert_not_equals(ptr, NULL, result); + cmc_assert_equals(size_t, 1234, *result); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(get_ref[edge_case count = 0], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert_equals(ptr, NULL, hm_get_ref(map, 4321)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(contains, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(hm_insert(map, 987654321, 1)); + + cmc_assert(hm_contains(map, 987654321)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(contains[sum], { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 101; i <= 200; i++) + cmc_assert(hm_insert(map, i, i)); + + size_t sum = 0; + for (size_t i = 1; i <= 300; i++) + if (hm_contains(map, i)) + sum += i; + + cmc_assert_equals(size_t, 15050, sum); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(empty, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert(hm_empty(map)); + + cmc_assert(hm_insert(map, 1, 1)); + + cmc_assert(!hm_empty(map)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(count, { + hashmap *map = hm_new(100, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 1; i < 100; i++) + { + cmc_assert(hm_insert(map, i, i)); + cmc_assert_equals(size_t, i, hm_count(map)); + } + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(capacity, { + hashmap *map = hm_new(2500, 0.6, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert_greater_equals(size_t, (size_t)(2500 / 0.6), hm_capacity(map)); + + hm_free(map, NULL); + }); + + CMC_CREATE_TEST(capacity[small], { + hashmap *map = hm_new(1, 0.99, cmp, hash); + + cmc_assert_not_equals(ptr, NULL, map); + + cmc_assert_equals(size_t, cmc_hashtable_primes[0], hm_capacity(map)); + + hm_free(map, NULL); + }); }); diff --git a/tests/main/unt/utl.c b/tests/main/unt/utl.c index b42a9e4..5586ee4 100644 --- a/tests/main/unt/utl.c +++ b/tests/main/unt/utl.c @@ -3,6 +3,7 @@ #define CMC_UNIT_TEST_UTL__ #include +#include int cmp(size_t a, size_t b) { @@ -20,4 +21,24 @@ size_t hash(size_t a) return a; } +size_t numhash(size_t a) +{ + return a; +} + +size_t hashcapminus1(size_t a) +{ + return cmc_hashtable_primes[0] - 1; +} + +size_t hash0(size_t a) +{ + return 0; +} + +size_t hashmod40(size_t a) +{ + return a % 40; +} + #endif /* CMC_UNIT_TEST_UTL__ */