diff --git a/tests/main/main.c b/tests/main/main.c index 9053716..1ddcfd3 100644 --- a/tests/main/main.c +++ b/tests/main/main.c @@ -4,6 +4,10 @@ #include "unt/heap.c" #include "unt/linkedlist.c" #include "unt/list.c" +#include "unt/queue.c" +#include "unt/stack.c" +#include "unt/treemap.c" +#include "unt/treeset.c" int main(void) { @@ -13,6 +17,10 @@ int main(void) heap_test(); linkedlist_test(); list_test(); + queue_test(); + stack_test(); + treemap_test(); + treeset_test(); return 0; } diff --git a/tests/main/src/deque.c b/tests/main/src/deque.c index 0cf3cf9..13ff3c0 100644 --- a/tests/main/src/deque.c +++ b/tests/main/src/deque.c @@ -160,13 +160,13 @@ bool d_pop_back_if(deque *_deque_, bool condition) size_t d_front(deque *_deque_) { if (d_empty(_deque_)) - d_impl_default_value(); + return d_impl_default_value(); return _deque_->buffer[_deque_->front]; } size_t d_back(deque *_deque_) { if (d_empty(_deque_)) - d_impl_default_value(); + return d_impl_default_value(); return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1]; } bool d_contains(deque *_deque_, size_t element, int (*comparator)(size_t, size_t)) @@ -249,7 +249,7 @@ bool d_iter_prev(deque_iter *iter) size_t d_iter_value(deque_iter *iter) { if (d_empty(iter->target)) - d_impl_default_value(); + return d_impl_default_value(); return iter->target->buffer[iter->cursor]; } size_t *d_iter_rvalue(deque_iter *iter) diff --git a/tests/main/src/hashmap.c b/tests/main/src/hashmap.c index 5b30ab1..9dba819 100644 --- a/tests/main/src/hashmap.c +++ b/tests/main/src/hashmap.c @@ -76,16 +76,16 @@ static hashmap_iter hm_impl_it_end(hashmap *_map_); hashmap *hm_new(size_t capacity, double load, int (*compare)(size_t, size_t), size_t (*hash)(size_t)) { if (capacity == 0 || load <= 0 || load >= 1) - return 0; + return NULL; size_t real_capacity = hm_impl_calculate_size(capacity / load); hashmap *_map_ = malloc(sizeof(hashmap)); if (!_map_) - return 0; + return NULL; _map_->buffer = malloc(sizeof(hashmap_entry) * real_capacity); if (!_map_->buffer) { free(_map_); - return 0; + return NULL; } memset(_map_->buffer, 0, sizeof(hashmap_entry) * real_capacity); _map_->count = 0; @@ -118,7 +118,7 @@ bool hm_insert(hashmap *_map_, size_t key, size_t value) size_t original_pos = hash % _map_->capacity; size_t pos = original_pos; hashmap_entry *target = &(_map_->buffer[pos]); - if (hm_impl_get_entry(_map_, key) != 0) + if (hm_impl_get_entry(_map_, key) != NULL) return false; if (target->state == ES_EMPTY || target->state == ES_DELETED) { @@ -161,7 +161,7 @@ bool hm_insert(hashmap *_map_, size_t key, size_t value) bool hm_remove(hashmap *_map_, size_t key, size_t *value) { hashmap_entry *result = hm_impl_get_entry(_map_, key); - if (result == 0) + if (result == NULL) return false; *value = result->value; result->key = hm_impl_default_key(); @@ -233,17 +233,17 @@ size_t hm_get(hashmap *_map_, size_t key) { hashmap_entry *entry = hm_impl_get_entry(_map_, key); if (!entry) - hm_impl_default_value(); + return hm_impl_default_value(); return entry->value; } size_t *hm_get_ref(hashmap *_map_, size_t key) { hashmap_entry *entry = hm_impl_get_entry(_map_, key); if (!entry) - return 0; + return NULL; return &(entry->value); } -bool hm_contains(hashmap *_map_, size_t key) { return hm_impl_get_entry(_map_, key) != 0; } +bool hm_contains(hashmap *_map_, size_t key) { return hm_impl_get_entry(_map_, key) != NULL; } bool hm_empty(hashmap *_map_) { return _map_->count == 0; } size_t hm_count(hashmap *_map_) { return _map_->count; } size_t hm_capacity(hashmap *_map_) { return _map_->capacity; } @@ -251,7 +251,7 @@ hashmap_iter *hm_iter_new(hashmap *target) { hashmap_iter *iter = malloc(sizeof(hashmap_iter)); if (!iter) - return 0; + return NULL; hm_iter_init(iter, target); return iter; } @@ -345,19 +345,19 @@ bool hm_iter_prev(hashmap_iter *iter) size_t hm_iter_key(hashmap_iter *iter) { if (hm_empty(iter->target)) - hm_impl_default_key(); + return hm_impl_default_key(); return iter->target->buffer[iter->cursor].key; } size_t hm_iter_value(hashmap_iter *iter) { if (hm_empty(iter->target)) - hm_impl_default_value(); + return hm_impl_default_value(); return iter->target->buffer[iter->cursor].value; } size_t *hm_iter_rvalue(hashmap_iter *iter) { if (hm_empty(iter->target)) - return 0; + return NULL; return &(iter->target->buffer[iter->cursor].value); } size_t hm_iter_index(hashmap_iter *iter) { return iter->index; } @@ -398,7 +398,7 @@ static hashmap_entry *hm_impl_get_entry(hashmap *_map_, size_t key) pos++; target = &(_map_->buffer[pos % _map_->capacity]); } - return 0; + return NULL; } static size_t hm_impl_calculate_size(size_t required) { diff --git a/tests/main/src/linkedlist.c b/tests/main/src/linkedlist.c index 1e6d705..6a7b8bb 100644 --- a/tests/main/src/linkedlist.c +++ b/tests/main/src/linkedlist.c @@ -230,13 +230,13 @@ bool ll_pop_if(linkedlist *_list_, size_t index, bool condition) size_t ll_front(linkedlist *_list_) { if (ll_empty(_list_)) - ll_impl_default_value(); + return ll_impl_default_value(); return _list_->head->data; } size_t ll_get(linkedlist *_list_, size_t index) { if (index >= _list_->count || ll_empty(_list_)) - ll_impl_default_value(); + return ll_impl_default_value(); linkedlist_node *scan = ll_get_node(_list_, index); if (scan == NULL) return ll_impl_default_value(); diff --git a/tests/main/src/queue.c b/tests/main/src/queue.c new file mode 100644 index 0000000..d370310 --- /dev/null +++ b/tests/main/src/queue.c @@ -0,0 +1,248 @@ +#include "cmc/queue.h" + +typedef struct queue_s +{ + size_t *buffer; + size_t capacity; + size_t count; + size_t front; + size_t rear; + struct queue_iter_s (*it_start)(struct queue_s *); + struct queue_iter_s (*it_end)(struct queue_s *); +} queue, *queue_ptr; +typedef struct queue_iter_s +{ + struct queue_s *target; + size_t cursor; + size_t index; + bool start; + bool end; +} queue_iter, *queue_iter_ptr; +queue *q_new(size_t capacity); +void q_clear(queue *_queue_); +void q_free(queue *_queue_); +bool q_enqueue(queue *_queue_, size_t element); +bool q_dequeue(queue *_queue_); +bool q_enqueue_if(queue *_queue_, size_t element, bool condition); +bool q_dequeue_if(queue *_queue_, bool condition); +size_t q_peek(queue *_queue_); +bool q_contains(queue *_queue_, size_t element, int (*comparator)(size_t, size_t)); +bool q_empty(queue *_queue_); +bool q_full(queue *_queue_); +size_t q_count(queue *_queue_); +size_t q_capacity(queue *_queue_); +queue_iter *q_iter_new(queue *target); +void q_iter_free(queue_iter *iter); +void q_iter_init(queue_iter *iter, queue *target); +bool q_iter_start(queue_iter *iter); +bool q_iter_end(queue_iter *iter); +void q_iter_to_start(queue_iter *iter); +void q_iter_to_end(queue_iter *iter); +bool q_iter_next(queue_iter *iter); +bool q_iter_prev(queue_iter *iter); +size_t q_iter_value(queue_iter *iter); +size_t *q_iter_rvalue(queue_iter *iter); +size_t q_iter_index(queue_iter *iter); +static inline size_t q_impl_default_value(void) +{ + size_t _empty_value_; + memset(&_empty_value_, 0, sizeof(size_t)); + return _empty_value_; +} +static bool q_impl_grow(queue *_queue_); +static queue_iter q_impl_it_start(queue *_queue_); +static queue_iter q_impl_it_end(queue *_queue_); +queue *q_new(size_t capacity) +{ + if (capacity < 1) + return NULL; + queue *_queue_ = malloc(sizeof(queue)); + if (!_queue_) + return NULL; + _queue_->buffer = malloc(sizeof(size_t) * capacity); + if (!_queue_->buffer) + { + free(_queue_); + return NULL; + } + memset(_queue_->buffer, 0, sizeof(size_t) * capacity); + _queue_->capacity = capacity; + _queue_->count = 0; + _queue_->front = 0; + _queue_->rear = 0; + _queue_->it_start = q_impl_it_start; + _queue_->it_end = q_impl_it_end; + return _queue_; +} +void q_clear(queue *_queue_) +{ + memset(_queue_->buffer, 0, sizeof(size_t) * _queue_->capacity); + _queue_->count = 0; + _queue_->front = 0; + _queue_->rear = 0; +} +void q_free(queue *_queue_) +{ + free(_queue_->buffer); + free(_queue_); +} +bool q_enqueue(queue *_queue_, size_t element) +{ + if (q_full(_queue_)) + { + if (!q_impl_grow(_queue_)) + return false; + } + _queue_->buffer[_queue_->rear] = element; + _queue_->rear = (_queue_->rear == _queue_->capacity - 1) ? 0 : _queue_->rear + 1; + _queue_->count++; + return true; +} +bool q_dequeue(queue *_queue_) +{ + if (q_empty(_queue_)) + return false; + _queue_->buffer[_queue_->front] = q_impl_default_value(); + _queue_->front = (_queue_->front == _queue_->capacity - 1) ? 0 : _queue_->front + 1; + _queue_->count--; + return true; +} +bool q_enqueue_if(queue *_queue_, size_t element, bool condition) +{ + if (condition) + return q_enqueue(_queue_, element); + return false; +} +bool q_dequeue_if(queue *_queue_, bool condition) +{ + if (condition) + return q_dequeue(_queue_); + return false; +} +size_t q_peek(queue *_queue_) +{ + if (q_empty(_queue_)) + return q_impl_default_value(); + return _queue_->buffer[_queue_->front]; +} +bool q_contains(queue *_queue_, size_t element, int (*comparator)(size_t, size_t)) +{ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->count, j++) + { + if (comparator(_queue_->buffer[i], element) == 0) + return true; + } + return false; +} +bool q_empty(queue *_queue_) { return _queue_->count == 0; } +bool q_full(queue *_queue_) { return _queue_->count >= _queue_->capacity; } +size_t q_count(queue *_queue_) { return _queue_->count; } +size_t q_capacity(queue *_queue_) { return _queue_->capacity; } +queue_iter *q_iter_new(queue *target) +{ + queue_iter *iter = malloc(sizeof(queue_iter)); + if (!iter) + return NULL; + q_iter_init(iter, target); + return iter; +} +void q_iter_free(queue_iter *iter) { free(iter); } +void q_iter_init(queue_iter *iter, queue *target) +{ + iter->target = target; + iter->cursor = target->front; + iter->index = 0; + iter->start = true; + iter->end = q_empty(target); +} +bool q_iter_start(queue_iter *iter) { return q_empty(iter->target) || iter->start; } +bool q_iter_end(queue_iter *iter) { return q_empty(iter->target) || iter->end; } +void q_iter_to_start(queue_iter *iter) +{ + iter->cursor = iter->target->front; + iter->index = 0; + iter->start = true; + iter->end = q_empty(iter->target); +} +void q_iter_to_end(queue_iter *iter) +{ + if (q_empty(iter->target)) + iter->cursor = 0; + else + iter->cursor = (iter->target->rear == 0) ? iter->target->capacity - 1 : iter->target->rear - 1; + iter->index = iter->target->count - 1; + iter->start = q_empty(iter->target); + iter->end = true; +} +bool q_iter_next(queue_iter *iter) +{ + if (iter->end) + return false; + iter->start = q_empty(iter->target); + if (iter->index == iter->target->count - 1) + iter->end = true; + else + { + iter->cursor = (iter->cursor + 1) % (iter->target->capacity); + iter->index++; + } + return true; +} +bool q_iter_prev(queue_iter *iter) +{ + if (iter->start) + return false; + iter->end = q_empty(iter->target); + if (iter->index == 0) + iter->start = true; + else + { + iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1; + iter->index--; + } + return true; +} +size_t q_iter_value(queue_iter *iter) +{ + if (q_empty(iter->target)) + return q_impl_default_value(); + return iter->target->buffer[iter->cursor]; +} +size_t *q_iter_rvalue(queue_iter *iter) +{ + if (q_empty(iter->target)) + return NULL; + return &(iter->target->buffer[iter->cursor]); +} +size_t q_iter_index(queue_iter *iter) { return iter->index; } +static bool q_impl_grow(queue *_queue_) +{ + size_t new_capacity = _queue_->capacity * 2; + size_t *new_buffer = malloc(sizeof(size_t) * 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_->rear = _queue_->count; + return true; +} +static queue_iter q_impl_it_start(queue *_queue_) +{ + queue_iter iter; + q_iter_init(&iter, _queue_); + q_iter_to_start(&iter); + return iter; +} +static queue_iter q_impl_it_end(queue *_queue_) +{ + queue_iter iter; + q_iter_init(&iter, _queue_); + q_iter_to_end(&iter); + return iter; +} diff --git a/tests/main/src/stack.c b/tests/main/src/stack.c new file mode 100644 index 0000000..ebafc7e --- /dev/null +++ b/tests/main/src/stack.c @@ -0,0 +1,218 @@ +#include "cmc/stack.h" + +typedef struct stack_s +{ + size_t *buffer; + size_t capacity; + size_t count; + struct stack_iter_s (*it_start)(struct stack_s *); + struct stack_iter_s (*it_end)(struct stack_s *); +} stack, *stack_ptr; +typedef struct stack_iter_s +{ + struct stack_s *target; + size_t cursor; + bool start; + bool end; +} stack_iter, *stack_iter_ptr; +stack *s_new(size_t capacity); +void s_clear(stack *_stack_); +void s_free(stack *_stack_); +bool s_push(stack *_stack_, size_t element); +bool s_pop(stack *_stack_); +bool s_push_if(stack *_stack_, size_t element, bool condition); +bool s_pop_if(stack *_stack_, bool condition); +size_t s_top(stack *_stack_); +bool s_contains(stack *_stack_, size_t element, int (*comparator)(size_t, size_t)); +bool s_empty(stack *_stack_); +bool s_full(stack *_stack_); +size_t s_count(stack *_stack_); +size_t s_capacity(stack *_stack_); +stack_iter *s_iter_new(stack *target); +void s_iter_free(stack_iter *iter); +void s_iter_init(stack_iter *iter, stack *target); +bool s_iter_start(stack_iter *iter); +bool s_iter_end(stack_iter *iter); +void s_iter_to_start(stack_iter *iter); +void s_iter_to_end(stack_iter *iter); +bool s_iter_next(stack_iter *iter); +bool s_iter_prev(stack_iter *iter); +size_t s_iter_value(stack_iter *iter); +size_t *s_iter_rvalue(stack_iter *iter); +size_t s_iter_index(stack_iter *iter); +static inline size_t s_impl_default_value(void) +{ + size_t _empty_value_; + memset(&_empty_value_, 0, sizeof(size_t)); + return _empty_value_; +} +static bool s_impl_grow(stack *_stack_); +static stack_iter s_impl_it_start(stack *_stack_); +static stack_iter s_impl_it_end(stack *_stack_); +stack *s_new(size_t capacity) +{ + if (capacity < 1) + return NULL; + stack *_stack_ = malloc(sizeof(stack)); + if (!_stack_) + return NULL; + _stack_->buffer = malloc(sizeof(size_t) * capacity); + if (!_stack_->buffer) + { + free(_stack_); + return NULL; + } + memset(_stack_->buffer, 0, sizeof(size_t) * capacity); + _stack_->capacity = capacity; + _stack_->count = 0; + _stack_->it_start = s_impl_it_start; + _stack_->it_end = s_impl_it_end; + return _stack_; +} +void s_clear(stack *_stack_) +{ + memset(_stack_->buffer, 0, sizeof(size_t) * _stack_->capacity); + _stack_->count = 0; +} +void s_free(stack *_stack_) +{ + free(_stack_->buffer); + free(_stack_); +} +bool s_push(stack *_stack_, size_t element) +{ + if (s_full(_stack_)) + { + if (!s_impl_grow(_stack_)) + return false; + } + _stack_->buffer[_stack_->count++] = element; + return true; +} +bool s_pop(stack *_stack_) +{ + if (s_empty(_stack_)) + return false; + _stack_->buffer[--_stack_->count] = s_impl_default_value(); + return true; +} +bool s_push_if(stack *_stack_, size_t element, bool condition) +{ + if (condition) + return s_push(_stack_, element); + return false; +} +bool s_pop_if(stack *_stack_, bool condition) +{ + if (condition) + return s_pop(_stack_); + return false; +} +size_t s_top(stack *_stack_) +{ + if (s_empty(_stack_)) + return s_impl_default_value(); + return _stack_->buffer[_stack_->count - 1]; +} +bool s_contains(stack *_stack_, size_t element, int (*comparator)(size_t, size_t)) +{ + for (size_t i = 0; i < _stack_->count; i++) + { + if (comparator(_stack_->buffer[i], element) == 0) + return true; + } + return false; +} +bool s_empty(stack *_stack_) { return _stack_->count == 0; } +bool s_full(stack *_stack_) { return _stack_->count >= _stack_->capacity; } +size_t s_count(stack *_stack_) { return _stack_->count; } +size_t s_capacity(stack *_stack_) { return _stack_->capacity; } +stack_iter *s_iter_new(stack *target) +{ + stack_iter *iter = malloc(sizeof(stack_iter)); + if (!iter) + return NULL; + s_iter_init(iter, target); + return iter; +} +void s_iter_free(stack_iter *iter) { free(iter); } +void s_iter_init(stack_iter *iter, stack *target) +{ + iter->target = target; + iter->cursor = iter->target->count - 1; + iter->start = true; + iter->end = s_empty(target); +} +bool s_iter_start(stack_iter *iter) { return s_empty(iter->target) || iter->start; } +bool s_iter_end(stack_iter *iter) { return s_empty(iter->target) || iter->end; } +void s_iter_to_start(stack_iter *iter) +{ + iter->cursor = iter->target->count - 1; + iter->start = true; + iter->end = s_empty(iter->target); +} +void s_iter_to_end(stack_iter *iter) +{ + iter->cursor = 0; + iter->start = s_empty(iter->target); + iter->end = true; +} +bool s_iter_next(stack_iter *iter) +{ + if (iter->end) + return false; + iter->start = s_empty(iter->target); + if (iter->cursor == 0) + iter->end = true; + else + iter->cursor--; + return true; +} +bool s_iter_prev(stack_iter *iter) +{ + if (iter->start) + return false; + iter->end = s_empty(iter->target); + if (iter->cursor == iter->target->count - 1) + iter->start = true; + else + iter->cursor++; + return true; +} +size_t s_iter_value(stack_iter *iter) +{ + if (s_empty(iter->target)) + return s_impl_default_value(); + return iter->target->buffer[iter->cursor]; +} +size_t *s_iter_rvalue(stack_iter *iter) +{ + if (s_empty(iter->target)) + return NULL; + return &(iter->target->buffer[iter->cursor]); +} +size_t s_iter_index(stack_iter *iter) { return iter->target->count - 1 - iter->cursor; } +static bool s_impl_grow(stack *_stack_) +{ + size_t new_capacity = _stack_->capacity * 2; + size_t *new_buffer = realloc(_stack_->buffer, sizeof(size_t) * new_capacity); + if (!new_buffer) + return false; + _stack_->buffer = new_buffer; + _stack_->capacity = new_capacity; + return true; +} +static stack_iter s_impl_it_start(stack *_stack_) +{ + stack_iter iter; + s_iter_init(&iter, _stack_); + s_iter_to_start(&iter); + return iter; +} +static stack_iter s_impl_it_end(stack *_stack_) +{ + stack_iter iter; + s_iter_init(&iter, _stack_); + s_iter_to_end(&iter); + return iter; +} diff --git a/tests/main/src/treemap.c b/tests/main/src/treemap.c new file mode 100644 index 0000000..142f50c --- /dev/null +++ b/tests/main/src/treemap.c @@ -0,0 +1,597 @@ +#include "cmc/treemap.h" + +typedef struct treemap_s +{ + struct treemap_node_s *root; + size_t count; + int (*cmp)(size_t, size_t); + struct treemap_iter_s (*it_start)(struct treemap_s *); + struct treemap_iter_s (*it_end)(struct treemap_s *); +} treemap, *treemap_ptr; +typedef struct treemap_node_s +{ + size_t key; + size_t value; + unsigned char height; + struct treemap_node_s *right; + struct treemap_node_s *left; + struct treemap_node_s *parent; +} treemap_node, *treemap_node_ptr; +typedef struct treemap_iter_s +{ + struct treemap_s *target; + struct treemap_node_s *cursor; + struct treemap_node_s *first; + struct treemap_node_s *last; + size_t index; + bool start; + bool end; +} treemap_iter, *treemap_iter_ptr; +treemap *tm_new(int (*compare)(size_t, size_t)); +void tm_clear(treemap *_map_); +void tm_free(treemap *_map_); +bool tm_insert(treemap *_map_, size_t key, size_t value); +bool tm_remove(treemap *_map_, size_t key, size_t *value); +bool tm_insert_if(treemap *_map_, size_t key, size_t value, bool condition); +bool tm_remove_if(treemap *_map_, size_t key, size_t *value, bool condition); +bool tm_max(treemap *_map_, size_t *key, size_t *value); +bool tm_min(treemap *_map_, size_t *key, size_t *value); +size_t tm_get(treemap *_map_, size_t key); +size_t *tm_get_ref(treemap *_map_, size_t key); +bool tm_contains(treemap *_map_, size_t key); +bool tm_empty(treemap *_map_); +size_t tm_count(treemap *_map_); +treemap_iter *tm_iter_new(treemap *target); +void tm_iter_free(treemap_iter *iter); +void tm_iter_init(treemap_iter *iter, treemap *target); +bool tm_iter_start(treemap_iter *iter); +bool tm_iter_end(treemap_iter *iter); +void tm_iter_to_start(treemap_iter *iter); +void tm_iter_to_end(treemap_iter *iter); +bool tm_iter_next(treemap_iter *iter); +bool tm_iter_prev(treemap_iter *iter); +size_t tm_iter_key(treemap_iter *iter); +size_t tm_iter_value(treemap_iter *iter); +size_t *tm_iter_rvalue(treemap_iter *iter); +size_t tm_iter_index(treemap_iter *iter); +static inline size_t tm_impl_default_key(void) +{ + size_t _empty_key_; + memset(&_empty_key_, 0, sizeof(size_t)); + return _empty_key_; +} +static inline size_t tm_impl_default_value(void) +{ + size_t _empty_value_; + memset(&_empty_value_, 0, sizeof(size_t)); + return _empty_value_; +} +static treemap_node *tm_impl_new_node(size_t key, size_t value); +static treemap_node *tm_impl_get_node(treemap *_map_, size_t key); +static unsigned char tm_impl_h(treemap_node *node); +static unsigned char tm_impl_hupdate(treemap_node *node); +static void tm_impl_rotate_right(treemap_node **Z); +static void tm_impl_rotate_left(treemap_node **Z); +static void tm_impl_rebalance(treemap *_map_, treemap_node *node); +static treemap_iter tm_impl_it_start(treemap *_map_); +static treemap_iter tm_impl_it_end(treemap *_map_); +treemap *tm_new(int (*compare)(size_t, size_t)) +{ + treemap *_map_ = malloc(sizeof(treemap)); + if (!_map_) + return NULL; + _map_->count = 0; + _map_->root = NULL; + _map_->cmp = compare; + _map_->it_start = tm_impl_it_start; + _map_->it_end = tm_impl_it_end; + return _map_; +} +void tm_clear(treemap *_map_) +{ + treemap_node *scan = _map_->root; + treemap_node *up = NULL; + while (scan != NULL) + { + if (scan->left != NULL) + { + treemap_node *left = scan->left; + scan->left = up; + up = scan; + scan = left; + } + else if (scan->right != NULL) + { + treemap_node *right = scan->right; + scan->left = up; + scan->right = NULL; + up = scan; + scan = right; + } + else + { + if (up == NULL) + { + free(scan); + scan = NULL; + } + while (up != NULL) + { + free(scan); + if (up->right != NULL) + { + scan = up->right; + up->right = NULL; + break; + } + else + { + scan = up; + up = up->left; + } + } + } + } + _map_->count = 0; + _map_->root = NULL; +} +void tm_free(treemap *_map_) +{ + tm_clear(_map_); + free(_map_); +} +bool tm_insert(treemap *_map_, size_t key, size_t value) +{ + if (tm_empty(_map_)) + { + _map_->root = tm_impl_new_node(key, value); + if (!_map_->root) + return false; + } + else + { + treemap_node *scan = _map_->root; + treemap_node *parent = scan; + while (scan != NULL) + { + parent = scan; + if (_map_->cmp(scan->key, key) > 0) + scan = scan->left; + else if (_map_->cmp(scan->key, key) < 0) + scan = scan->right; + else + return false; + } + treemap_node *node; + if (_map_->cmp(parent->key, key) > 0) + { + parent->left = tm_impl_new_node(key, value); + if (!parent->left) + return false; + parent->left->parent = parent; + node = parent->left; + } + else + { + parent->right = tm_impl_new_node(key, value); + if (!parent->right) + return false; + parent->right->parent = parent; + node = parent->right; + } + tm_impl_rebalance(_map_, node); + } + _map_->count++; + return true; +} +bool tm_remove(treemap *_map_, size_t key, size_t *value) +{ + treemap_node *node = tm_impl_get_node(_map_, key); + if (!node) + return false; + *value = node->value; + treemap_node *temp = NULL, *unbalanced = NULL; + bool is_root = node->parent == NULL; + if (node->left == NULL && node->right == NULL) + { + if (is_root) + _map_->root = NULL; + else + { + unbalanced = node->parent; + if (node->parent->right == node) + node->parent->right = NULL; + else + node->parent->left = NULL; + } + free(node); + } + else if (node->left == NULL) + { + if (is_root) + { + _map_->root = node->right; + _map_->root->parent = NULL; + } + else + { + unbalanced = node->parent; + node->right->parent = node->parent; + if (node->parent->right == node) + node->parent->right = node->right; + else + node->parent->left = node->right; + } + free(node); + } + else if (node->right == NULL) + { + if (is_root) + { + _map_->root = node->left; + _map_->root->parent = NULL; + } + else + { + unbalanced = node->parent; + node->left->parent = node->parent; + if (node->parent->right == node) + node->parent->right = node->left; + else + node->parent->left = node->left; + } + free(node); + } + else + { + temp = node->right; + while (temp->left != NULL) + temp = temp->left; + size_t temp_key = temp->key; + size_t temp_val = temp->value; + unbalanced = temp->parent; + if (temp->left == NULL && temp->right == NULL) + { + if (temp->parent->right == temp) + temp->parent->right = NULL; + else + temp->parent->left = NULL; + } + else if (temp->left == NULL) + { + temp->right->parent = temp->parent; + if (temp->parent->right == temp) + temp->parent->right = temp->right; + else + temp->parent->left = temp->right; + } + else if (temp->right == NULL) + { + temp->left->parent = temp->parent; + if (temp->parent->right == temp) + temp->parent->right = temp->left; + else + temp->parent->left = temp->left; + } + free(temp); + node->key = temp_key; + node->value = temp_val; + } + if (unbalanced != NULL) + tm_impl_rebalance(_map_, unbalanced); + _map_->count--; + if (_map_->count == 0) + _map_->root = NULL; + return true; +} +bool tm_insert_if(treemap *_map_, size_t key, size_t value, bool condition) +{ + if (condition) + return tm_insert(_map_, key, value); + return false; +} +bool tm_remove_if(treemap *_map_, size_t key, size_t *value, bool condition) +{ + if (condition) + return tm_remove(_map_, key, value); + return false; +} +bool tm_max(treemap *_map_, size_t *key, size_t *value) +{ + if (tm_empty(_map_)) + return false; + treemap_node *scan = _map_->root; + while (scan->right != NULL) + scan = scan->right; + *key = scan->key; + *value = scan->value; + return true; +} +bool tm_min(treemap *_map_, size_t *key, size_t *value) +{ + if (tm_empty(_map_)) + return false; + treemap_node *scan = _map_->root; + while (scan->left != NULL) + scan = scan->left; + *key = scan->key; + *value = scan->value; + return true; +} +size_t tm_get(treemap *_map_, size_t key) +{ + treemap_node *node = tm_impl_get_node(_map_, key); + if (!node) + return tm_impl_default_value(); + return node->value; +} +size_t *tm_get_ref(treemap *_map_, size_t key) +{ + treemap_node *node = tm_impl_get_node(_map_, key); + if (!node) + return NULL; + return &(node->value); +} +bool tm_contains(treemap *_map_, size_t key) +{ + treemap_node *scan = _map_->root; + while (scan != NULL) + { + if (_map_->cmp(scan->key, key) > 0) + scan = scan->left; + else if (_map_->cmp(scan->key, key) < 0) + scan = scan->right; + else + return true; + } + return false; +} +bool tm_empty(treemap *_map_) { return _map_->count == 0; } +size_t tm_count(treemap *_map_) { return _map_->count; } +treemap_iter *tm_iter_new(treemap *target) +{ + treemap_iter *iter = malloc(sizeof(treemap_iter)); + if (!iter) + return NULL; + tm_iter_init(iter, target); + return iter; +} +void tm_iter_free(treemap_iter *iter) { free(iter); } +void tm_iter_init(treemap_iter *iter, treemap *target) +{ + iter->target = target; + iter->index = 0; + iter->start = true; + iter->end = tm_empty(target); + iter->cursor = target->root; + while (iter->cursor->left != NULL) + iter->cursor = iter->cursor->left; + iter->first = iter->cursor; + iter->last = target->root; + while (iter->last->right != NULL) + iter->last = iter->last->right; +} +bool tm_iter_start(treemap_iter *iter) { return tm_empty(iter->target) || iter->start; } +bool tm_iter_end(treemap_iter *iter) { return tm_empty(iter->target) || iter->end; } +void tm_iter_to_start(treemap_iter *iter) +{ + iter->index = 0; + iter->start = true; + iter->end = tm_empty(iter->target); + iter->cursor = iter->first; +} +void tm_iter_to_end(treemap_iter *iter) +{ + iter->index = iter->target->count - 1; + iter->start = tm_empty(iter->target); + iter->end = true; + iter->cursor = iter->last; +} +bool tm_iter_next(treemap_iter *iter) +{ + if (iter->end) + return false; + iter->start = false; + if (iter->cursor->right != NULL) + { + iter->cursor = iter->cursor->right; + while (iter->cursor->left != NULL) + iter->cursor = iter->cursor->left; + iter->index++; + return true; + } + while (true) + { + if (iter->cursor == iter->last) + { + iter->end = true; + return true; + } + if (iter->cursor->parent->left == iter->cursor) + { + iter->cursor = iter->cursor->parent; + iter->index++; + return true; + } + iter->cursor = iter->cursor->parent; + } +} +bool tm_iter_prev(treemap_iter *iter) +{ + if (iter->start) + return false; + iter->end = false; + if (iter->cursor->left != NULL) + { + iter->cursor = iter->cursor->left; + while (iter->cursor->right != NULL) + iter->cursor = iter->cursor->right; + iter->index--; + return true; + } + while (true) + { + if (iter->cursor == iter->first) + { + iter->start = true; + return true; + } + if (iter->cursor->parent->right == iter->cursor) + { + iter->cursor = iter->cursor->parent; + iter->index--; + return true; + } + iter->cursor = iter->cursor->parent; + } +} +size_t tm_iter_key(treemap_iter *iter) +{ + if (tm_empty(iter->target)) + return tm_impl_default_key(); + return iter->cursor->key; +} +size_t tm_iter_value(treemap_iter *iter) +{ + if (tm_empty(iter->target)) + return tm_impl_default_value(); + return iter->cursor->value; +} +size_t *tm_iter_rvalue(treemap_iter *iter) +{ + if (tm_empty(iter->target)) + return NULL; + return &(iter->cursor->value); +} +size_t tm_iter_index(treemap_iter *iter) { return iter->index; } +static treemap_node *tm_impl_new_node(size_t key, size_t value) +{ + treemap_node *node = malloc(sizeof(treemap_node)); + if (!node) + return NULL; + node->key = key; + node->value = value; + node->right = NULL; + node->left = NULL; + node->parent = NULL; + node->height = 0; + return node; +} +static treemap_node *tm_impl_get_node(treemap *_map_, size_t key) +{ + if (tm_empty(_map_)) + return NULL; + treemap_node *scan = _map_->root; + while (scan != NULL) + { + if (_map_->cmp(scan->key, key) > 0) + scan = scan->left; + else if (_map_->cmp(scan->key, key) < 0) + scan = scan->right; + else + return scan; + } + return NULL; +} +static unsigned char tm_impl_h(treemap_node *node) +{ + if (node == NULL) + return 0; + return node->height; +} +static unsigned char tm_impl_hupdate(treemap_node *node) +{ + if (node == NULL) + return 0; + unsigned char h_l = tm_impl_h(node->left); + unsigned char h_r = tm_impl_h(node->right); + return 1 + (h_l > h_r ? h_l : h_r); +} +static void tm_impl_rotate_right(treemap_node **Z) +{ + treemap_node *root = *Z; + treemap_node *new_root = root->left; + if (root->parent != NULL) + { + if (root->parent->left == root) + root->parent->left = new_root; + else + root->parent->right = new_root; + } + new_root->parent = root->parent; + root->parent = new_root; + root->left = new_root->right; + if (root->left) + root->left->parent = root; + new_root->right = root; + root->height = tm_impl_hupdate(root); + new_root->height = tm_impl_hupdate(new_root); + *Z = new_root; +} +static void tm_impl_rotate_left(treemap_node **Z) +{ + treemap_node *root = *Z; + treemap_node *new_root = root->right; + if (root->parent != NULL) + { + if (root->parent->right == root) + root->parent->right = new_root; + else + root->parent->left = new_root; + } + new_root->parent = root->parent; + root->parent = new_root; + root->right = new_root->left; + if (root->right) + root->right->parent = root; + new_root->left = root; + root->height = tm_impl_hupdate(root); + new_root->height = tm_impl_hupdate(new_root); + *Z = new_root; +} +static void tm_impl_rebalance(treemap *_map_, treemap_node *node) +{ + treemap_node *scan = node, *child = NULL; + int balance; + bool is_root = false; + while (scan != NULL) + { + if (scan->parent == NULL) + is_root = true; + scan->height = tm_impl_hupdate(scan); + balance = tm_impl_h(scan->right) - tm_impl_h(scan->left); + if (balance >= 2) + { + child = scan->right; + if (tm_impl_h(child->right) < tm_impl_h(child->left)) + tm_impl_rotate_right(&(scan->right)); + tm_impl_rotate_left(&scan); + } + else if (balance <= -2) + { + child = scan->left; + if (tm_impl_h(child->left) < tm_impl_h(child->right)) + tm_impl_rotate_left(&(scan->left)); + tm_impl_rotate_right(&scan); + } + if (is_root) + { + _map_->root = scan; + is_root = false; + } + scan = scan->parent; + } +} +static treemap_iter tm_impl_it_start(treemap *_map_) +{ + treemap_iter iter; + tm_iter_init(&iter, _map_); + return iter; +} +static treemap_iter tm_impl_it_end(treemap *_map_) +{ + treemap_iter iter; + tm_iter_init(&iter, _map_); + tm_iter_to_end(&iter); + return iter; +} diff --git a/tests/main/src/treeset.c b/tests/main/src/treeset.c new file mode 100644 index 0000000..c6c3cbd --- /dev/null +++ b/tests/main/src/treeset.c @@ -0,0 +1,688 @@ +#include "cmc/treeset.h" + +typedef struct treeset_s +{ + struct treeset_node_s *root; + size_t count; + int (*cmp)(size_t, size_t); + struct treeset_iter_s (*it_start)(struct treeset_s *); + struct treeset_iter_s (*it_end)(struct treeset_s *); +} treeset, *treeset_ptr; +typedef struct treeset_node_s +{ + size_t value; + unsigned char height; + struct treeset_node_s *right; + struct treeset_node_s *left; + struct treeset_node_s *parent; +} treeset_node, *treeset_node_ptr; +typedef struct treeset_iter_s +{ + struct treeset_s *target; + struct treeset_node_s *cursor; + struct treeset_node_s *first; + struct treeset_node_s *last; + size_t index; + bool start; + bool end; +} treeset_iter, *treeset_iter_ptr; +treeset *ts_new(int (*compare)(size_t, size_t)); +void ts_clear(treeset *_set_); +void ts_free(treeset *_set_); +bool ts_insert(treeset *_set_, size_t element); +bool ts_remove(treeset *_set_, size_t element); +bool ts_insert_if(treeset *_set_, size_t element, bool condition); +bool ts_remove_if(treeset *_set_, size_t element, bool condition); +bool ts_max(treeset *_set_, size_t *value); +bool ts_min(treeset *_set_, size_t *value); +bool ts_contains(treeset *_set_, size_t element); +bool ts_empty(treeset *_set_); +size_t ts_count(treeset *_set_); +treeset *ts_union(treeset *_set1_, treeset *_set2_); +treeset *ts_intersection(treeset *_set1_, treeset *_set2_); +treeset *ts_difference(treeset *_set1_, treeset *_set2_); +treeset *ts_symmetric_difference(treeset *_set1_, treeset *_set2_); +bool ts_is_subset(treeset *_set1_, treeset *_set2_); +bool ts_is_superset(treeset *_set1_, treeset *_set2_); +bool ts_is_proper_subset(treeset *_set1_, treeset *_set2_); +bool ts_is_proper_superset(treeset *_set1_, treeset *_set2_); +bool ts_is_disjointset(treeset *_set1_, treeset *_set2_); +treeset_iter *ts_iter_new(treeset *target); +void ts_iter_free(treeset_iter *iter); +void ts_iter_init(treeset_iter *iter, treeset *target); +bool ts_iter_start(treeset_iter *iter); +bool ts_iter_end(treeset_iter *iter); +void ts_iter_to_start(treeset_iter *iter); +void ts_iter_to_end(treeset_iter *iter); +bool ts_iter_next(treeset_iter *iter); +bool ts_iter_prev(treeset_iter *iter); +size_t ts_iter_value(treeset_iter *iter); +size_t ts_iter_index(treeset_iter *iter); +static inline size_t ts_impl_default_value(void) +{ + size_t _empty_value_; + memset(&_empty_value_, 0, sizeof(size_t)); + return _empty_value_; +} +static treeset_node *ts_impl_new_node(size_t element); +static treeset_node *ts_impl_get_node(treeset *_set_, size_t element); +static unsigned char ts_impl_h(treeset_node *node); +static unsigned char ts_impl_hupdate(treeset_node *node); +static void ts_impl_rotate_right(treeset_node **Z); +static void ts_impl_rotate_left(treeset_node **Z); +static void ts_impl_rebalance(treeset *_set_, treeset_node *node); +static treeset_iter ts_impl_it_start(treeset *_set_); +static treeset_iter ts_impl_it_end(treeset *_set_); +treeset *ts_new(int (*compare)(size_t, size_t)) +{ + treeset *_set_ = malloc(sizeof(treeset)); + if (!_set_) + return NULL; + _set_->count = 0; + _set_->root = NULL; + _set_->cmp = compare; + _set_->it_start = ts_impl_it_start; + _set_->it_end = ts_impl_it_end; + return _set_; +} +void ts_clear(treeset *_set_) +{ + treeset_node *scan = _set_->root; + treeset_node *up = NULL; + while (scan != NULL) + { + if (scan->left != NULL) + { + treeset_node *left = scan->left; + scan->left = up; + up = scan; + scan = left; + } + else if (scan->right != NULL) + { + treeset_node *right = scan->right; + scan->left = up; + scan->right = NULL; + up = scan; + scan = right; + } + else + { + if (up == NULL) + { + free(scan); + scan = NULL; + } + while (up != NULL) + { + free(scan); + if (up->right != NULL) + { + scan = up->right; + up->right = NULL; + break; + } + else + { + scan = up; + up = up->left; + } + } + } + } + _set_->count = 0; + _set_->root = NULL; +} +void ts_free(treeset *_set_) +{ + ts_clear(_set_); + free(_set_); +} +bool ts_insert(treeset *_set_, size_t element) +{ + if (ts_empty(_set_)) + { + _set_->root = ts_impl_new_node(element); + if (!_set_->root) + return false; + } + else + { + treeset_node *scan = _set_->root; + treeset_node *parent = scan; + while (scan != NULL) + { + parent = scan; + if (_set_->cmp(scan->value, element) > 0) + scan = scan->left; + else if (_set_->cmp(scan->value, element) < 0) + scan = scan->right; + else + return false; + } + treeset_node *node; + if (_set_->cmp(parent->value, element) > 0) + { + parent->left = ts_impl_new_node(element); + if (!parent->left) + return false; + parent->left->parent = parent; + node = parent->left; + } + else + { + parent->right = ts_impl_new_node(element); + if (!parent->right) + return false; + parent->right->parent = parent; + node = parent->right; + } + ts_impl_rebalance(_set_, node); + } + _set_->count++; + return true; +} +bool ts_remove(treeset *_set_, size_t element) +{ + treeset_node *node = ts_impl_get_node(_set_, element); + if (!node) + return false; + treeset_node *temp = NULL, *unbalanced = NULL; + bool is_root = node->parent == NULL; + if (node->left == NULL && node->right == NULL) + { + if (is_root) + _set_->root = NULL; + else + { + unbalanced = node->parent; + if (node->parent->right == node) + node->parent->right = NULL; + else + node->parent->left = NULL; + } + free(node); + } + else if (node->left == NULL) + { + if (is_root) + { + _set_->root = node->right; + _set_->root->parent = NULL; + } + else + { + unbalanced = node->parent; + node->right->parent = node->parent; + if (node->parent->right == node) + node->parent->right = node->right; + else + node->parent->left = node->right; + } + free(node); + } + else if (node->right == NULL) + { + if (is_root) + { + _set_->root = node->left; + _set_->root->parent = NULL; + } + else + { + unbalanced = node->parent; + node->left->parent = node->parent; + if (node->parent->right == node) + node->parent->right = node->left; + else + node->parent->left = node->left; + } + free(node); + } + else + { + temp = node->right; + while (temp->left != NULL) + temp = temp->left; + size_t temp_value = temp->value; + unbalanced = temp->parent; + if (temp->left == NULL && temp->right == NULL) + { + if (temp->parent->right == temp) + temp->parent->right = NULL; + else + temp->parent->left = NULL; + } + else if (temp->left == NULL) + { + temp->right->parent = temp->parent; + if (temp->parent->right == temp) + temp->parent->right = temp->right; + else + temp->parent->left = temp->right; + } + else if (temp->right == NULL) + { + temp->left->parent = temp->parent; + if (temp->parent->right == temp) + temp->parent->right = temp->left; + else + temp->parent->left = temp->left; + } + free(temp); + node->value = temp_value; + } + if (unbalanced != NULL) + ts_impl_rebalance(_set_, unbalanced); + _set_->count--; + if (_set_->count == 0) + _set_->root = NULL; + return true; +} +bool ts_insert_if(treeset *_set_, size_t element, bool condition) +{ + if (condition) + return ts_insert(_set_, element); + return false; +} +bool ts_remove_if(treeset *_set_, size_t element, bool condition) +{ + if (condition) + return ts_remove(_set_, element); + return false; +} +bool ts_max(treeset *_set_, size_t *value) +{ + if (ts_empty(_set_)) + return false; + treeset_node *scan = _set_->root; + while (scan->right != NULL) + scan = scan->right; + *value = scan->value; + return true; +} +bool ts_min(treeset *_set_, size_t *value) +{ + if (ts_empty(_set_)) + return false; + treeset_node *scan = _set_->root; + while (scan->left != NULL) + scan = scan->left; + *value = scan->value; + return true; +} +bool ts_contains(treeset *_set_, size_t element) +{ + treeset_node *scan = _set_->root; + while (scan != NULL) + { + if (_set_->cmp(scan->value, element) > 0) + scan = scan->left; + else if (_set_->cmp(scan->value, element) < 0) + scan = scan->right; + else + return true; + } + return false; +} +bool ts_empty(treeset *_set_) { return _set_->count == 0; } +size_t ts_count(treeset *_set_) { return _set_->count; } +treeset *ts_union(treeset *_set1_, treeset *_set2_) +{ + treeset *_set_r_ = ts_new(_set1_->cmp); + if (!_set_r_) + return false; + treeset_iter iter1, iter2; + ts_iter_init(&iter1, _set1_); + ts_iter_init(&iter2, _set2_); + for (ts_iter_to_start(&iter1); !ts_iter_end(&iter1); ts_iter_next(&iter1)) + { + ts_insert(_set_r_, ts_iter_value(&iter1)); + } + for (ts_iter_to_start(&iter2); !ts_iter_end(&iter2); ts_iter_next(&iter2)) + { + ts_insert(_set_r_, ts_iter_value(&iter2)); + } + return _set_r_; +} +treeset *ts_intersection(treeset *_set1_, treeset *_set2_) +{ + treeset *_set_r_ = ts_new(_set1_->cmp); + if (!_set_r_) + return false; + treeset *_set_A_ = _set1_->count < _set2_->count ? _set1_ : _set2_; + treeset *_set_B_ = _set_A_ == _set1_ ? _set2_ : _set1_; + treeset_iter iter; + ts_iter_init(&iter, _set_A_); + for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter)) + { + size_t value = ts_iter_value(&iter); + if (ts_impl_get_node(_set_B_, value) != NULL) + ts_insert(_set_r_, value); + } + return _set_r_; +} +treeset *ts_difference(treeset *_set1_, treeset *_set2_) +{ + treeset *_set_r_ = ts_new(_set1_->cmp); + if (!_set_r_) + return false; + treeset_iter iter; + ts_iter_init(&iter, _set1_); + for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter)) + { + size_t value = ts_iter_value(&iter); + if (ts_impl_get_node(_set2_, value) == NULL) + ts_insert(_set_r_, value); + } + return _set_r_; +} +treeset *ts_symmetric_difference(treeset *_set1_, treeset *_set2_) +{ + treeset *_set_r_ = ts_new(_set1_->cmp); + if (!_set_r_) + return false; + treeset_iter iter1, iter2; + ts_iter_init(&iter1, _set1_); + ts_iter_init(&iter2, _set2_); + for (ts_iter_to_start(&iter1); !ts_iter_end(&iter1); ts_iter_next(&iter1)) + { + size_t value = ts_iter_value(&iter1); + if (ts_impl_get_node(_set2_, value) == NULL) + ts_insert(_set_r_, value); + } + for (ts_iter_to_start(&iter2); !ts_iter_end(&iter2); ts_iter_next(&iter2)) + { + size_t value = ts_iter_value(&iter2); + if (ts_impl_get_node(_set1_, value) == NULL) + ts_insert(_set_r_, value); + } + return _set_r_; +} +bool ts_is_subset(treeset *_set1_, treeset *_set2_) +{ + if (ts_count(_set1_) > ts_count(_set2_)) + return false; + if (ts_empty(_set1_)) + return true; + treeset_iter iter; + ts_iter_init(&iter, _set1_); + for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter)) + { + size_t value = ts_iter_value(&iter); + if (!ts_contains(_set2_, value)) + return false; + } + return true; +} +bool ts_is_superset(treeset *_set1_, treeset *_set2_) { return ts_is_subset(_set2_, _set1_); } +bool ts_is_proper_subset(treeset *_set1_, treeset *_set2_) +{ + if (ts_count(_set1_) >= ts_count(_set2_)) + return false; + if (ts_empty(_set1_)) + { + if (!ts_empty(_set2_)) + return true; + else + return false; + } + treeset_iter iter; + ts_iter_init(&iter, _set1_); + for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter)) + { + size_t value = ts_iter_value(&iter); + if (!ts_contains(_set2_, value)) + return false; + } + return true; +} +bool ts_is_proper_superset(treeset *_set1_, treeset *_set2_) { return ts_is_proper_subset(_set2_, _set1_); } +bool ts_is_disjointset(treeset *_set1_, treeset *_set2_) +{ + if (ts_empty(_set1_)) + return true; + treeset_iter iter; + ts_iter_init(&iter, _set1_); + for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter)) + { + size_t value = ts_iter_value(&iter); + if (ts_contains(_set2_, value)) + return false; + } + return true; +} +treeset_iter *ts_iter_new(treeset *target) +{ + treeset_iter *iter = malloc(sizeof(treeset_iter)); + if (!iter) + return NULL; + ts_iter_init(iter, target); + return iter; +} +void ts_iter_free(treeset_iter *iter) { free(iter); } +void ts_iter_init(treeset_iter *iter, treeset *target) +{ + iter->target = target; + iter->index = 0; + iter->start = true; + iter->end = ts_empty(target); + iter->cursor = target->root; + while (iter->cursor->left != NULL) + iter->cursor = iter->cursor->left; + iter->first = iter->cursor; + iter->last = target->root; + while (iter->last->right != NULL) + iter->last = iter->last->right; +} +bool ts_iter_start(treeset_iter *iter) { return ts_empty(iter->target) || iter->start; } +bool ts_iter_end(treeset_iter *iter) { return ts_empty(iter->target) || iter->end; } +void ts_iter_to_start(treeset_iter *iter) +{ + iter->index = 0; + iter->start = true; + iter->end = ts_empty(iter->target); + iter->cursor = iter->first; +} +void ts_iter_to_end(treeset_iter *iter) +{ + iter->index = iter->target->count - 1; + iter->start = ts_empty(iter->target); + iter->end = true; + iter->cursor = iter->last; +} +bool ts_iter_next(treeset_iter *iter) +{ + if (iter->end) + return false; + iter->start = ts_empty(iter->target); + if (iter->cursor->right != NULL) + { + iter->cursor = iter->cursor->right; + while (iter->cursor->left != NULL) + iter->cursor = iter->cursor->left; + iter->index++; + return true; + } + while (true) + { + if (iter->cursor == iter->last) + { + iter->end = true; + return true; + } + if (iter->cursor->parent->left == iter->cursor) + { + iter->cursor = iter->cursor->parent; + iter->index++; + return true; + } + iter->cursor = iter->cursor->parent; + } +} +bool ts_iter_prev(treeset_iter *iter) +{ + if (iter->start) + return false; + iter->end = ts_empty(iter->target); + if (iter->cursor->left != NULL) + { + iter->cursor = iter->cursor->left; + while (iter->cursor->right != NULL) + iter->cursor = iter->cursor->right; + iter->index--; + return true; + } + while (true) + { + if (iter->cursor == iter->first) + { + iter->start = true; + return true; + } + if (iter->cursor->parent->right == iter->cursor) + { + iter->cursor = iter->cursor->parent; + iter->index--; + return true; + } + iter->cursor = iter->cursor->parent; + } +} +size_t ts_iter_value(treeset_iter *iter) +{ + if (ts_empty(iter->target)) + return ts_impl_default_value(); + return iter->cursor->value; +} +size_t ts_iter_index(treeset_iter *iter) { return iter->index; } +static treeset_node *ts_impl_new_node(size_t element) +{ + treeset_node *node = malloc(sizeof(treeset_node)); + if (!node) + return NULL; + node->value = element; + node->right = NULL; + node->left = NULL; + node->parent = NULL; + node->height = 0; + return node; +} +static treeset_node *ts_impl_get_node(treeset *_set_, size_t element) +{ + if (ts_empty(_set_)) + return NULL; + treeset_node *scan = _set_->root; + while (scan != NULL) + { + if (_set_->cmp(scan->value, element) > 0) + scan = scan->left; + else if (_set_->cmp(scan->value, element) < 0) + scan = scan->right; + else + return scan; + } + return NULL; +} +static unsigned char ts_impl_h(treeset_node *node) +{ + if (node == NULL) + return 0; + return node->height; +} +static unsigned char ts_impl_hupdate(treeset_node *node) +{ + if (node == NULL) + return 0; + unsigned char h_l = ts_impl_h(node->left); + unsigned char h_r = ts_impl_h(node->right); + return 1 + (h_l > h_r ? h_l : h_r); +} +static void ts_impl_rotate_right(treeset_node **Z) +{ + treeset_node *root = *Z; + treeset_node *new_root = root->left; + if (root->parent != NULL) + { + if (root->parent->left == root) + root->parent->left = new_root; + else + root->parent->right = new_root; + } + new_root->parent = root->parent; + root->parent = new_root; + root->left = new_root->right; + if (root->left) + root->left->parent = root; + new_root->right = root; + root->height = ts_impl_hupdate(root); + new_root->height = ts_impl_hupdate(new_root); + *Z = new_root; +} +static void ts_impl_rotate_left(treeset_node **Z) +{ + treeset_node *root = *Z; + treeset_node *new_root = root->right; + if (root->parent != NULL) + { + if (root->parent->right == root) + root->parent->right = new_root; + else + root->parent->left = new_root; + } + new_root->parent = root->parent; + root->parent = new_root; + root->right = new_root->left; + if (root->right) + root->right->parent = root; + new_root->left = root; + root->height = ts_impl_hupdate(root); + new_root->height = ts_impl_hupdate(new_root); + *Z = new_root; +} +static void ts_impl_rebalance(treeset *_set_, treeset_node *node) +{ + treeset_node *scan = node, *child = NULL; + int balance; + bool is_root = false; + while (scan != NULL) + { + if (scan->parent == NULL) + is_root = true; + scan->height = ts_impl_hupdate(scan); + balance = ts_impl_h(scan->right) - ts_impl_h(scan->left); + if (balance >= 2) + { + child = scan->right; + if (ts_impl_h(child->right) < ts_impl_h(child->left)) + ts_impl_rotate_right(&(scan->right)); + ts_impl_rotate_left(&scan); + } + else if (balance <= -2) + { + child = scan->left; + if (ts_impl_h(child->left) < ts_impl_h(child->right)) + ts_impl_rotate_left(&(scan->left)); + ts_impl_rotate_right(&scan); + } + if (is_root) + { + _set_->root = scan; + is_root = false; + } + scan = scan->parent; + } +} +static treeset_iter ts_impl_it_start(treeset *_set_) +{ + treeset_iter iter; + ts_iter_init(&iter, _set_); + return iter; +} +static treeset_iter ts_impl_it_end(treeset *_set_) +{ + treeset_iter iter; + ts_iter_init(&iter, _set_); + ts_iter_to_end(&iter); + return iter; +} diff --git a/tests/main/unt/deque.c b/tests/main/unt/deque.c index 07cfccb..09fd7cd 100644 --- a/tests/main/unt/deque.c +++ b/tests/main/unt/deque.c @@ -64,8 +64,9 @@ CMC_CREATE_UNIT(deque_test, true, { d_push_back(d, i); cmc_assert_equals(size_t, 50, d_count(d)); + cmc_assert_lesser_equals(size_t, d_capacity(d), d_count(d)); - CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 50); + CMC_TEST_PASS_ELSE_FAIL(d_count(d) == 50 && d_count(d) <= d_capacity(d)); d_free(d); }); diff --git a/tests/main/unt/queue.c b/tests/main/unt/queue.c new file mode 100644 index 0000000..08243a8 --- /dev/null +++ b/tests/main/unt/queue.c @@ -0,0 +1,73 @@ +#include "utl/assert.h" +#include "utl/test.h" +#include "../src/queue.c" + +CMC_CREATE_UNIT(queue_test, true, { + CMC_CREATE_TEST(new, { + queue *q = q_new(1000000); + + cmc_assert_not_equals(ptr, NULL, q); + + bool passed = q->capacity == 1000000 && q->count == 0 && q->buffer; + + cmc_assert_equals(size_t, 1000000, q->capacity); + cmc_assert_equals(size_t, 0, q_count(q)); + cmc_assert_not_equals(ptr, NULL, q->buffer); + + CMC_TEST_PASS_ELSE_FAIL(passed); + + q_free(q); + }); + + CMC_CREATE_TEST(new[edge_case:capacity = 0], { + queue *q = q_new(0); + + cmc_assert_equals(ptr, NULL, q); + + CMC_TEST_PASS_ELSE_FAIL(q == NULL); + }); + + CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], { + queue *q = q_new(UINT64_MAX); + + cmc_assert_equals(ptr, NULL, q); + + CMC_TEST_PASS_ELSE_FAIL(q == NULL); + }); + + CMC_CREATE_TEST(clear[count capacity], { + queue *q = q_new(100); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 0; i < 50; i++) + q_enqueue(q, i); + + cmc_assert_equals(size_t, 50, q_count(q)); + + q_clear(q); + + cmc_assert_equals(size_t, 0, q_count(q)); + cmc_assert_equals(size_t, 100, q_capacity(q)); + + CMC_TEST_PASS_ELSE_FAIL(q_count(q) == 0 && q_capacity(q) == 100); + + q_free(q); + }); + + CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], { + queue *q = q_new(1); + + cmc_assert_not_equals(ptr, NULL, q); + + for (size_t i = 0; i < 50; i++) + q_enqueue(q, i); + + cmc_assert_equals(size_t, 50, q_count(q)); + + CMC_TEST_PASS_ELSE_FAIL(q_count(q) == 50); + + q_free(q); + }); + +}); diff --git a/tests/main/unt/stack.c b/tests/main/unt/stack.c new file mode 100644 index 0000000..af5c7a9 --- /dev/null +++ b/tests/main/unt/stack.c @@ -0,0 +1,335 @@ +#include "utl/assert.h" +#include "utl/test.h" +#include "../src/stack.c" + +CMC_CREATE_UNIT(stack_test, true, { + CMC_CREATE_TEST(new, { + stack *s = s_new(1000000); + + cmc_assert_not_equals(ptr, NULL, s); + + bool passed = s->capacity == 1000000 && s->count == 0 && s->buffer; + + cmc_assert_equals(size_t, 1000000, s->capacity); + cmc_assert_equals(size_t, 0, s_count(s)); + cmc_assert_not_equals(ptr, NULL, s->buffer); + + CMC_TEST_PASS_ELSE_FAIL(passed); + + s_free(s); + }); + + CMC_CREATE_TEST(new[edge_case:capacity = 0], { + stack *s = s_new(0); + + cmc_assert_equals(ptr, NULL, s); + + CMC_TEST_PASS_ELSE_FAIL(s == NULL); + }); + + CMC_CREATE_TEST(new[edge_case:capacity = UINT64_MAX], { + stack *s = s_new(UINT64_MAX); + + cmc_assert_equals(ptr, NULL, s); + + CMC_TEST_PASS_ELSE_FAIL(s == NULL); + }); + + CMC_CREATE_TEST(clear[count capacity], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 50; i++) + cmc_assert(s_push(s, i)); + + cmc_assert_equals(size_t, 50, s_count(s)); + + s_clear(s); + + cmc_assert_equals(size_t, 0, s_count(s)); + cmc_assert_equals(size_t, 100, s_capacity(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 0 && s_capacity(s) == 100); + + s_free(s); + }); + + CMC_CREATE_TEST(buffer_growth[edge_case:capacity = 1], { + stack *s = s_new(1); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 50; i++) + cmc_assert(s_push(s, i)); + + cmc_assert_equals(size_t, 50, s_count(s)); + cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 50 && s_count(s) <= s_capacity(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(push[count], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + cmc_assert_equals(size_t, 250, s_count(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 250); + + s_free(s); + }); + + CMC_CREATE_TEST(push[capacity], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_count(s) <= s_capacity(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(push[item_preservation], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + bool passed = true; + + for (size_t i = 0; i < s_count(s); i++) + { + passed = s->buffer[i] == i; + + cmc_assert_equals(size_t, i, s->buffer[i]); + } + + CMC_TEST_PASS_ELSE_FAIL(passed); + + s_free(s); + }); + + CMC_CREATE_TEST(pop[count], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + cmc_assert(s_pop(s)); + + cmc_assert_equals(size_t, 249, s_count(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_count(s) == 249); + + s_free(s); + }); + + CMC_CREATE_TEST(pop[capacity], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + cmc_assert(s_pop(s)); + + cmc_assert_lesser_equals(size_t, s_capacity(s), s_count(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_count(s) <= s_capacity(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(pop[item_preservation], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + cmc_assert(s_pop(s)); + cmc_assert(s_pop(s)); + + bool passed = true; + + for (size_t i = 0; i < s_count(s); i++) + { + passed = s->buffer[i] == i; + + cmc_assert_equals(size_t, i, s->buffer[i]); + } + + CMC_TEST_PASS_ELSE_FAIL(passed); + + s_free(s); + }); + + CMC_CREATE_TEST(push_if, { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + s_push_if(s, i, i % 2 == 0); + + bool passed = true; + + for (size_t i = 0; i < s_count(s); i++) + { + passed = passed && s->buffer[i] % 2 == 0; + + cmc_assert(s->buffer[i] % 2 == 0); + } + + CMC_TEST_PASS_ELSE_FAIL(passed); + + s_free(s); + }); + + CMC_CREATE_TEST(pop_if, { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + { + s_push(s, i); + s_pop_if(s, s_top(s) % 2 == 0); + } + + bool passed = true; + + for (size_t i = 0; i < s_count(s); i++) + { + passed = passed && !(s->buffer[i] % 2 == 0); + + cmc_assert(!(s->buffer[i] % 2 == 0)); + } + + CMC_TEST_PASS_ELSE_FAIL(passed); + + s_free(s); + }); + + CMC_CREATE_TEST(top, { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < 250; i++) + cmc_assert(s_push(s, i)); + + cmc_assert(s_pop(s)); + cmc_assert(s_pop(s)); + + cmc_assert_equals(size_t, 247, s_top(s)); + + CMC_TEST_PASS_ELSE_FAIL(247 == s_top(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(top[edge_case:count = 0], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + cmc_assert(s_push(s, 1)); + + cmc_assert(s_pop(s)); + + cmc_assert_equals(size_t, s_impl_default_value(), s_top(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_impl_default_value() == s_top(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(top[edge_case:count = 1], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + cmc_assert(s_push(s, 10)); + cmc_assert_equals(size_t, 1, s_count(s)); + cmc_assert_equals(size_t, 10, s_top(s)); + + CMC_TEST_PASS_ELSE_FAIL(10 == s_top(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(empty, { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + cmc_assert(s_empty(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_empty(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(empty[after_io], { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + cmc_assert(s_push(s, 10)); + cmc_assert(s_pop(s)); + cmc_assert(s_empty(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_empty(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(full, { + stack *s = s_new(100); + + cmc_assert_not_equals(ptr, NULL, s); + + for (size_t i = 0; i < s_capacity(s); i++) + cmc_assert(s_push(s, i)); + + cmc_assert(s_full(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_full(s)); + + s_free(s); + }); + + CMC_CREATE_TEST(full[edge_case:capacity = 1], { + stack *s = s_new(1); + + cmc_assert_not_equals(ptr, NULL, s); + + cmc_assert(s_push(s, 10)); + + cmc_assert(s_full(s)); + + CMC_TEST_PASS_ELSE_FAIL(s_full(s)); + + s_free(s); + }); + +}); diff --git a/tests/main/unt/treemap.c b/tests/main/unt/treemap.c new file mode 100644 index 0000000..ae45fce --- /dev/null +++ b/tests/main/unt/treemap.c @@ -0,0 +1,38 @@ +#include "utl/assert.h" +#include "utl/test.h" +#include "../src/treemap.c" + +#include "utl.c" + +CMC_CREATE_UNIT(treemap_test, true, { + CMC_CREATE_TEST(new, { + treemap *map = tm_new(cmp); + + cmc_assert_not_equals(ptr, NULL, map); + + CMC_TEST_PASS_ELSE_FAIL(map); + + tm_free(map); + }); + + CMC_CREATE_TEST(clear[count], { + treemap *map = tm_new(cmp); + + cmc_assert_not_equals(ptr, NULL, map); + + for (size_t i = 0; i < 50; i++) + tm_insert(map, i, i); + + cmc_assert_equals(size_t, 50, tm_count(map)); + + tm_clear(map); + + cmc_assert_equals(size_t, 0, tm_count(map)); + cmc_assert_equals(ptr, NULL, map->root); + + CMC_TEST_PASS_ELSE_FAIL(tm_count(map) == 0); + + tm_free(map); + }); + +}); diff --git a/tests/main/unt/treeset.c b/tests/main/unt/treeset.c new file mode 100644 index 0000000..0d5afa1 --- /dev/null +++ b/tests/main/unt/treeset.c @@ -0,0 +1,39 @@ +#include "utl/assert.h" +#include "utl/test.h" +#include "../src/treeset.c" + +#include "utl.c" + +CMC_CREATE_UNIT(treeset_test, true, { + CMC_CREATE_TEST(new, { + treeset *set = ts_new(cmp); + + cmc_assert_not_equals(ptr, NULL, set); + + CMC_TEST_PASS_ELSE_FAIL(set); + + ts_free(set); + }); + + CMC_CREATE_TEST(clear[count], { + treeset *set = ts_new(cmp); + + cmc_assert_not_equals(ptr, NULL, set); + + for (size_t i = 0; i < 50; i++) + ts_insert(set, i); + + cmc_assert_equals(size_t, 50, ts_count(set)); + + ts_clear(set); + + cmc_assert_equals(size_t, 0, ts_count(set)); + cmc_assert_equals(ptr, NULL, set->root); + + + CMC_TEST_PASS_ELSE_FAIL(ts_count(set) == 0); + + ts_free(set); + }); + +});