Added deque.h resize and added more deque and hashmap tests

This commit is contained in:
Leonardo committed 2019-10-05 00:31:29 -03:00
1 parent 8483eda701
commit f0b7b125b9
4 files changed
+1005 -468

No files matched your search

+497 -461
View File
@@ -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 */
+174 -7
View File
@@ -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);
});
});
+313
View File
@@ -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);
});
});
+21
View File
@@ -3,6 +3,7 @@
#define CMC_UNIT_TEST_UTL__
#include <stdlib.h>
#include <cmc/hashmap.h>
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__ */