diff --git a/src/cmc/heap.h b/src/cmc/heap.h index 59de0da..611b35e 100644 --- a/src/cmc/heap.h +++ b/src/cmc/heap.h @@ -307,6 +307,9 @@ typedef enum cmc_heap_order_e \ bool PFX##_resize(SNAME *_heap_, size_t capacity) \ { \ + if (PFX##_capacity(_heap_) == capacity) \ + return true; \ + \ if (capacity < PFX##_count(_heap_)) \ return false; \ \ diff --git a/src/cmc/list.h b/src/cmc/list.h index 7903e0f..0c01f8a 100644 --- a/src/cmc/list.h +++ b/src/cmc/list.h @@ -542,6 +542,9 @@ static const char *cmc_string_fmt_list = "%s at %p { buffer:%p, capacity:%" PRIu \ bool PFX##_resize(SNAME *_list_, size_t capacity) \ { \ + if (PFX##_capacity(_list_) == capacity) \ + return true; \ + \ if (capacity < PFX##_count(_list_)) \ return false; \ \ diff --git a/src/cmc/queue.h b/src/cmc/queue.h index 9486741..a43feba 100644 --- a/src/cmc/queue.h +++ b/src/cmc/queue.h @@ -129,6 +129,7 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI size_t PFX##_count(SNAME *_queue_); \ size_t PFX##_capacity(SNAME *_queue_); \ /* Collection Utility */ \ + bool PFX##_resize(SNAME *_queue_, size_t capacity); \ SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)); \ bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)); \ cmc_string PFX##_to_string(SNAME *_queue_); \ @@ -166,423 +167,442 @@ static const char *cmc_string_fmt_queue = "%s at %p { buffer:%p, capacity:%" PRI } \ \ /* SOURCE ********************************************************************/ -#define CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) \ - \ - /* Implementation Detail Functions */ \ - static bool PFX##_impl_grow(SNAME *_queue_); \ - static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \ - static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \ - \ - SNAME *PFX##_new(size_t capacity) \ - { \ - if (capacity < 1) \ - return NULL; \ - \ - SNAME *_queue_ = malloc(sizeof(SNAME)); \ - \ - if (!_queue_) \ - return NULL; \ - \ - _queue_->buffer = malloc(sizeof(V) * capacity); \ - \ - if (!_queue_->buffer) \ - { \ - free(_queue_); \ - return NULL; \ - } \ - \ - memset(_queue_->buffer, 0, sizeof(V) * capacity); \ - \ - _queue_->capacity = capacity; \ - _queue_->count = 0; \ - _queue_->front = 0; \ - _queue_->back = 0; \ - \ - _queue_->it_start = PFX##_impl_it_start; \ - _queue_->it_end = PFX##_impl_it_end; \ - \ - return _queue_; \ - } \ - \ - void PFX##_clear(SNAME *_queue_, void (*deallocator)(V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \ - { \ - deallocator(_queue_->buffer[i]); \ - } \ - } \ - \ - memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \ - \ - _queue_->count = 0; \ - _queue_->front = 0; \ - _queue_->back = 0; \ - } \ - \ - void PFX##_free(SNAME *_queue_, void (*deallocator)(V)) \ - { \ - if (deallocator) \ - { \ - for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \ - { \ - deallocator(_queue_->buffer[i]); \ - } \ - } \ - \ - free(_queue_->buffer); \ - free(_queue_); \ - } \ - \ - bool PFX##_enqueue(SNAME *_queue_, V element) \ - { \ - if (PFX##_full(_queue_)) \ - { \ - if (!PFX##_impl_grow(_queue_)) \ - return false; \ - } \ - \ - _queue_->buffer[_queue_->back] = element; \ - \ - _queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1; \ - _queue_->count++; \ - \ - return true; \ - } \ - \ - bool PFX##_dequeue(SNAME *_queue_) \ - { \ - if (PFX##_empty(_queue_)) \ - return false; \ - \ - _queue_->buffer[_queue_->front] = PFX##_impl_default_value(); \ - \ - _queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; \ - _queue_->count--; \ - \ - return true; \ - } \ - \ - V PFX##_peek(SNAME *_queue_) \ - { \ - if (PFX##_empty(_queue_)) \ - return PFX##_impl_default_value(); \ - \ - return _queue_->buffer[_queue_->front]; \ - } \ - \ - bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \ - { \ - for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \ - { \ - if (comparator(_queue_->buffer[i], element) == 0) \ - return true; \ - } \ - \ - return false; \ - } \ - \ - bool PFX##_empty(SNAME *_queue_) \ - { \ - return _queue_->count == 0; \ - } \ - \ - bool PFX##_full(SNAME *_queue_) \ - { \ - return _queue_->count >= _queue_->capacity; \ - } \ - \ - size_t PFX##_count(SNAME *_queue_) \ - { \ - return _queue_->count; \ - } \ - \ - size_t PFX##_capacity(SNAME *_queue_) \ - { \ - return _queue_->capacity; \ - } \ - \ - SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)) \ - { \ - SNAME *result = PFX##_new(_queue_->capacity); \ - \ - if (!result) \ - return NULL; \ - \ - if (copy_func) \ - { \ - for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \ - { \ - result->buffer[j] = copy_func(_queue_->buffer[i]); \ - } \ - } \ - else \ - { \ - for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \ - { \ - result->buffer[j] = _queue_->buffer[i]; \ - } \ - } \ - \ - result->count = _queue_->count; \ - \ - return result; \ - } \ - \ - bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)) \ - { \ - if (PFX##_count(_queue1_) != PFX##_count(_queue2_)) \ - return false; \ - \ - size_t i, j, k; \ - for (i = _queue1_->front, j = _queue2_->front, k = 0; k < PFX##_count(_queue1_); k++) \ - { \ - if (comparator(_queue1_->buffer[i], _queue2_->buffer[j]) == 0) \ - return false; \ - \ - i = (i + 1) % _queue1_->capacity; \ - j = (j + 1) % _queue2_->capacity; \ - } \ - \ - return true; \ - } \ - \ - cmc_string PFX##_to_string(SNAME *_queue_) \ - { \ - cmc_string str; \ - SNAME *q_ = _queue_; \ - const char *name = #SNAME; \ - \ - snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \ - name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->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; \ - else \ - iter->cursor = (iter->target->back == 0) ? iter->target->capacity - 1 : iter->target->back - 1; \ - \ - iter->index = iter->target->count - 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 *_queue_) \ - { \ - \ - size_t new_capacity = _queue_->capacity * 2; \ - \ - V *new_buffer = malloc(sizeof(V) * new_capacity); \ - \ - if (!new_buffer) \ - return false; \ - \ - for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->capacity, j++) \ - { \ - new_buffer[j] = _queue_->buffer[i]; \ - } \ - \ - free(_queue_->buffer); \ - \ - _queue_->buffer = new_buffer; \ - _queue_->capacity = new_capacity; \ - _queue_->front = 0; \ - _queue_->back = _queue_->count; \ - \ - return true; \ - } \ - \ - static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \ - { \ - SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _queue_); \ - PFX##_iter_to_start(&iter); \ - \ - return iter; \ - } \ - \ - static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \ - { \ - SNAME##_iter iter; \ - \ - PFX##_iter_init(&iter, _queue_); \ - PFX##_iter_to_end(&iter); \ - \ - return iter; \ +#define CMC_GENERATE_QUEUE_SOURCE(PFX, SNAME, V) \ + \ + /* Implementation Detail Functions */ \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \ + \ + SNAME *PFX##_new(size_t capacity) \ + { \ + if (capacity < 1) \ + return NULL; \ + \ + SNAME *_queue_ = malloc(sizeof(SNAME)); \ + \ + if (!_queue_) \ + return NULL; \ + \ + _queue_->buffer = malloc(sizeof(V) * capacity); \ + \ + if (!_queue_->buffer) \ + { \ + free(_queue_); \ + return NULL; \ + } \ + \ + memset(_queue_->buffer, 0, sizeof(V) * capacity); \ + \ + _queue_->capacity = capacity; \ + _queue_->count = 0; \ + _queue_->front = 0; \ + _queue_->back = 0; \ + \ + _queue_->it_start = PFX##_impl_it_start; \ + _queue_->it_end = PFX##_impl_it_end; \ + \ + return _queue_; \ + } \ + \ + void PFX##_clear(SNAME *_queue_, void (*deallocator)(V)) \ + { \ + if (deallocator) \ + { \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \ + { \ + deallocator(_queue_->buffer[i]); \ + \ + i = (i + 1) % _queue_->capacity; \ + } \ + } \ + \ + memset(_queue_->buffer, 0, sizeof(V) * _queue_->capacity); \ + \ + _queue_->count = 0; \ + _queue_->front = 0; \ + _queue_->back = 0; \ + } \ + \ + void PFX##_free(SNAME *_queue_, void (*deallocator)(V)) \ + { \ + if (deallocator) \ + { \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \ + { \ + deallocator(_queue_->buffer[i]); \ + \ + i = (i + 1) % _queue_->capacity; \ + } \ + } \ + \ + free(_queue_->buffer); \ + free(_queue_); \ + } \ + \ + bool PFX##_enqueue(SNAME *_queue_, V element) \ + { \ + if (PFX##_full(_queue_)) \ + { \ + if (!PFX##_resize(_queue_, PFX##_capacity(_queue_) * 2)) \ + return false; \ + } \ + \ + _queue_->buffer[_queue_->back] = element; \ + \ + _queue_->back = (_queue_->back == _queue_->capacity - 1) ? 0 : _queue_->back + 1; \ + _queue_->count++; \ + \ + return true; \ + } \ + \ + bool PFX##_dequeue(SNAME *_queue_) \ + { \ + if (PFX##_empty(_queue_)) \ + return false; \ + \ + _queue_->buffer[_queue_->front] = PFX##_impl_default_value(); \ + \ + _queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; \ + _queue_->count--; \ + \ + return true; \ + } \ + \ + V PFX##_peek(SNAME *_queue_) \ + { \ + if (PFX##_empty(_queue_)) \ + return PFX##_impl_default_value(); \ + \ + return _queue_->buffer[_queue_->front]; \ + } \ + \ + bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \ + { \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \ + { \ + if (comparator(_queue_->buffer[i], element) == 0) \ + return true; \ + \ + i = (i + 1) % _queue_->capacity; \ + } \ + \ + return false; \ + } \ + \ + bool PFX##_empty(SNAME *_queue_) \ + { \ + return _queue_->count == 0; \ + } \ + \ + bool PFX##_full(SNAME *_queue_) \ + { \ + return _queue_->count >= _queue_->capacity; \ + } \ + \ + size_t PFX##_count(SNAME *_queue_) \ + { \ + return _queue_->count; \ + } \ + \ + size_t PFX##_capacity(SNAME *_queue_) \ + { \ + return _queue_->capacity; \ + } \ + \ + bool PFX##_resize(SNAME *_queue_, size_t capacity) \ + { \ + if (PFX##_capacity(_queue_) == capacity) \ + return true; \ + \ + if (capacity < PFX##_count(_queue_)) \ + return false; \ + \ + V *new_buffer = malloc(sizeof(V) * capacity); \ + \ + if (!new_buffer) \ + return false; \ + \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \ + { \ + new_buffer[j] = _queue_->buffer[i]; \ + \ + i = (i + 1) % PFX##_capacity(_queue_); \ + } \ + \ + free(_queue_->buffer); \ + \ + _queue_->buffer = new_buffer; \ + _queue_->capacity = capacity; \ + _queue_->front = 0; \ + _queue_->back = _queue_->count; \ + \ + return true; \ + } \ + \ + SNAME *PFX##_copy_of(SNAME *_queue_, V (*copy_func)(V)) \ + { \ + SNAME *result = PFX##_new(_queue_->capacity); \ + \ + if (!result) \ + return NULL; \ + \ + if (copy_func) \ + { \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \ + { \ + result->buffer[j] = copy_func(_queue_->buffer[i]); \ + \ + i = (i + 1) % _queue_->capacity; \ + } \ + } \ + else \ + { \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; j++) \ + { \ + result->buffer[j] = _queue_->buffer[i]; \ + \ + i = (i + 1) % _queue_->capacity; \ + } \ + } \ + \ + result->count = _queue_->count; \ + \ + return result; \ + } \ + \ + bool PFX##_equals(SNAME *_queue1_, SNAME *_queue2_, int (*comparator)(V, V)) \ + { \ + if (PFX##_count(_queue1_) != PFX##_count(_queue2_)) \ + return false; \ + \ + size_t i, j, k; \ + for (i = _queue1_->front, j = _queue2_->front, k = 0; k < PFX##_count(_queue1_); k++) \ + { \ + if (comparator(_queue1_->buffer[i], _queue2_->buffer[j]) != 0) \ + return false; \ + \ + i = (i + 1) % _queue1_->capacity; \ + j = (j + 1) % _queue2_->capacity; \ + } \ + \ + return true; \ + } \ + \ + cmc_string PFX##_to_string(SNAME *_queue_) \ + { \ + cmc_string str; \ + SNAME *q_ = _queue_; \ + const char *name = #SNAME; \ + \ + snprintf(str.s, cmc_string_len, cmc_string_fmt_queue, \ + name, q_, q_->buffer, q_->capacity, q_->count, q_->front, q_->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; \ + else \ + { \ + if (iter->target->back == 0) \ + iter->cursor = iter->target->capacity - 1; \ + else \ + iter->cursor = iter->target->back - 1; \ + } \ + \ + iter->index = iter->target->count - 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 *_queue_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _queue_); \ + PFX##_iter_to_start(&iter); \ + \ + return iter; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _queue_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_QUEUE_H */ diff --git a/src/cmc/stack.h b/src/cmc/stack.h index 829a76f..caa3f76 100644 --- a/src/cmc/stack.h +++ b/src/cmc/stack.h @@ -105,6 +105,7 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI size_t PFX##_count(SNAME *_stack_); \ size_t PFX##_capacity(SNAME *_stack_); \ /* Collection Utility */ \ + bool PFX##_resize(SNAME *_stack_, size_t capacity); \ SNAME *PFX##_copy_of(SNAME *_stack_, V (*copy_func)(V)); \ bool PFX##_equals(SNAME *_stack1_, SNAME *_stack2_, int (*comparator)(V, V)); \ cmc_string PFX##_to_string(SNAME *_stack_); \ @@ -145,7 +146,6 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI #define CMC_GENERATE_STACK_SOURCE(PFX, SNAME, V) \ \ /* Implementation Detail Functions */ \ - static bool PFX##_impl_grow(SNAME *_stack_); \ static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_); \ static SNAME##_iter PFX##_impl_it_end(SNAME *_stack_); \ \ @@ -207,7 +207,7 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI { \ if (PFX##_full(_stack_)) \ { \ - if (!PFX##_impl_grow(_stack_)) \ + if (!PFX##_resize(_stack_, PFX##_capacity(_stack_) * 2)) \ return false; \ } \ \ @@ -265,6 +265,25 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI return _stack_->capacity; \ } \ \ + bool PFX##_resize(SNAME *_stack_, size_t capacity) \ + { \ + if (PFX##_capacity(_stack_) == capacity) \ + return true; \ + \ + if (capacity < PFX##_count(_stack_)) \ + return false; \ + \ + V *new_buffer = realloc(_stack_->buffer, sizeof(V) * capacity); \ + \ + if (!new_buffer) \ + return false; \ + \ + _stack_->buffer = new_buffer; \ + _stack_->capacity = capacity; \ + \ + return true; \ + } \ + \ SNAME *PFX##_copy_of(SNAME *_stack_, V (*copy_func)(V)) \ { \ SNAME *result = PFX##_new(_stack_->capacity); \ @@ -485,21 +504,6 @@ static const char *cmc_string_fmt_stack = "%s at %p { buffer:%p, capacity:%" PRI return iter->target->count - 1 - iter->cursor; \ } \ \ - static bool PFX##_impl_grow(SNAME *_stack_) \ - { \ - size_t new_capacity = _stack_->capacity * 2; \ - \ - V *new_buffer = realloc(_stack_->buffer, sizeof(V) * new_capacity); \ - \ - if (!new_buffer) \ - return false; \ - \ - _stack_->buffer = new_buffer; \ - _stack_->capacity = new_capacity; \ - \ - return true; \ - } \ - \ static SNAME##_iter PFX##_impl_it_start(SNAME *_stack_) \ { \ SNAME##_iter iter; \ diff --git a/tests/main/unt/queue.c b/tests/main/unt/queue.c index 165482e..5d6c296 100644 --- a/tests/main/unt/queue.c +++ b/tests/main/unt/queue.c @@ -62,4 +62,349 @@ CMC_CREATE_UNIT(queue_test, true, { q_free(q, NULL); }); + + CMC_CREATE_TEST(buffer_growth[item preservation], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 1; i <= 1200; i++) + { + q_enqueue(q, i); + } + + size_t sum = 0; + for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++) + sum += q->buffer[i]; + + cmc_assert_equals(size_t, 1200, q_count(q)); + cmc_assert_equals(size_t, 720600, sum); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(enqueue[count capacity], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 0; i < 150; i++) + cmc_assert(q_enqueue(q, i)); + + cmc_assert_equals(size_t, 150, q_count(q)); + cmc_assert_greater(size_t, 100, q_capacity(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(enqueue[item preservation], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 1; i <= 100; i++) + cmc_assert(q_enqueue(q, i)); + + size_t sum = 0; + + for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++) + { + sum += q->buffer[i]; + } + + cmc_assert_equals(size_t, 5050, sum); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(dequeue[count capacity], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert(q_enqueue(q, 10)); + cmc_assert(q_dequeue(q)); + + cmc_assert_equals(size_t, 0, q_count(q)); + + cmc_assert(q_enqueue(q, 10)); + cmc_assert(q_dequeue(q)); + + cmc_assert_equals(size_t, 0, q_count(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(dequeue[item preservation], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 200; i > 0; i--) + cmc_assert(q_enqueue(q, i)); + + for (size_t i = 0; i < 100; i++) + cmc_assert(q_dequeue(q)); + + size_t sum = 0; + + for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++) + { + sum += q->buffer[i]; + } + + cmc_assert_equals(size_t, 5050, sum); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(peek[count = 0], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + size_t r = q_peek(q); + + cmc_assert_equals(size_t, q_impl_default_value(), r); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(peek[sum], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + size_t sum = 0; + + for (size_t i = 0; i <= 100; i++) + cmc_assert(q_enqueue(q, i)); + + while (!q_empty(q)) + { + size_t r = q_peek(q); + + sum += r; + + cmc_assert(q_dequeue(q)); + } + + cmc_assert_equals(size_t, 5050, sum); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(contains, { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 1; i <= 20; i++) + cmc_assert(q_enqueue(q, i)); + + for (size_t i = 1; i <= 20; i++) + cmc_assert(q_contains(q, i, cmp)); + + q_clear(q, NULL); + + for (size_t i = 1; i <= 20; i++) + cmc_assert(!q_contains(q, i, cmp)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(contains[count = 0], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert(!q_contains(q, 10, cmp)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(contains[count = 1], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert(!q_contains(q, 10, cmp)); + + cmc_assert(q_enqueue(q, 100)); + + cmc_assert(q_contains(q, 100, cmp)); + cmc_assert(!q_contains(q, 101, cmp)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(empty, { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert(q_empty(q)); + + cmc_assert(q_enqueue(q, 1)); + + cmc_assert(!q_empty(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(full, { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert(!q_full(q)); + + for (size_t i = 0; i != q_capacity(q); i++) + cmc_assert(q_enqueue(q, i)); + + cmc_assert(q_full(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(count, { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert_equals(size_t, 0, q_count(q)); + + for (size_t i = 0; i < 100; i++) + cmc_assert(q_enqueue(q, i)); + + cmc_assert_equals(size_t, 100, q_count(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(capacity, { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + cmc_assert_equals(size_t, 100, q_capacity(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(resize, { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 0; i < 150; i++) + cmc_assert(q_enqueue(q, i)); + + cmc_assert_equals(size_t, 150, q_count(q)); + cmc_assert(q_resize(q, q_count(q))); + cmc_assert_equals(size_t, 150, q_capacity(q)); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(resize[item preservation], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 1; i <= 150; i++) + cmc_assert(q_enqueue(q, i)); + + cmc_assert(q_resize(q, q_count(q))); + + size_t sum = 0; + + for (size_t i = q->front, j = 0; j < q->count; i = (i + 1) % q->capacity, j++) + { + sum += q->buffer[i]; + } + + cmc_assert_equals(size_t, 11325, sum); + + q_free(q, NULL); + }); + + CMC_CREATE_TEST(copy_of, { + queue *d1 = q_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + + for (size_t i = 1; i <= 150; i++) + cmc_assert(q_enqueue(d1, i)); + + queue *d2 = q_copy_of(d1, NULL); + + cmc_assert_not_equals(ptr, NULL, d2); + cmc_assert_equals(size_t, q_count(d1), q_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; + } + + q_free(d1, NULL); + q_free(d2, NULL); + }); + + CMC_CREATE_TEST(equals, { + queue *d1 = q_new(100); + queue *d2 = q_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + cmc_assert_not_equals(ptr, NULL, d2); + + for (size_t i = 1; i <= 150; i++) + { + cmc_assert(q_enqueue(d1, i)); + cmc_assert(q_enqueue(d2, i)); + } + + cmc_assert(q_equals(d1, d2, cmp)); + + q_free(d1, NULL); + q_free(d2, NULL); + }); + + CMC_CREATE_TEST(equals[from copy], { + queue *d1 = q_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + + for (size_t i = 1; i <= 150; i++) + { + cmc_assert(q_enqueue(d1, i)); + } + + queue *d2 = q_copy_of(d1, NULL); + + cmc_assert_not_equals(ptr, NULL, d2); + + cmc_assert(q_equals(d1, d2, cmp)); + + q_free(d1, NULL); + q_free(d2, NULL); + }); + + CMC_CREATE_TEST(equals[count = 0], { + queue *d1 = q_new(100); + + cmc_assert_not_equals(ptr, NULL, d1); + + queue *d2 = q_copy_of(d1, NULL); + + cmc_assert_not_equals(ptr, NULL, d2); + + cmc_assert(q_equals(d1, d2, cmp)); + + q_free(d1, NULL); + q_free(d2, NULL); + }); }); diff --git a/tests/main/unt/utl.c b/tests/main/unt/utl.c index 5586ee4..5844154 100644 --- a/tests/main/unt/utl.c +++ b/tests/main/unt/utl.c @@ -31,14 +31,14 @@ size_t hashcapminus1(size_t a) return cmc_hashtable_primes[0] - 1; } +size_t hashcapminus4(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__ */