From a92ea132b6958784fd899b88b1ffc0c534ce995b Mon Sep 17 00:00:00 2001 From: Leonardo Date: Fri, 22 Mar 2019 19:45:19 -0300 Subject: [PATCH] Added linkedlist and reverse for_each --- examples/ex3/main.c | 38 ++++ src/foreach.h | 14 ++ src/linkedlist.h | 428 ++++++++++++++++++++++++++++++++++++++++ src/macro_collections.h | 1 + tests/foreach.c | 26 ++- 5 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 examples/ex3/main.c create mode 100644 src/linkedlist.h diff --git a/examples/ex3/main.c b/examples/ex3/main.c new file mode 100644 index 0000000..e2069ba --- /dev/null +++ b/examples/ex3/main.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include "../../src/macro_collections.h" + +CONTAINER_GENERATE(LINKEDLIST, PUBLIC, ll, linked, static, , int) + +int main(int argc, char const *argv[]) +{ + size_t i; + int r; + + // Initliazie linked list and add some elements + linked *ll = ll_new(); + for (int i = 0; i < 100; i++) + ll_push_back(ll, i); + + // Initialize iterator + linked_iter iter; + ll_iter(&iter, ll); + + // Move cursor to the end of the list + ll_iter_toend(&iter); + // While there is a previous element on the list + while (ll_iter_prev(&iter, &r, &i)) + printf("list[%d] = %d\n", i, r); + + // Move cursor to the start of the list + ll_iter_tostart(&iter); + // While there is a next element on the list + while (ll_iter_next(&iter, &r, &i)) + printf("list[%d] = %d\n", i, r); + + ll_free(ll); + + return 0; +} diff --git a/src/foreach.h b/src/foreach.h index 6c94761..345f927 100644 --- a/src/foreach.h +++ b/src/foreach.h @@ -20,3 +20,17 @@ BODY; \ } \ } while (0); + +#define FOR_EACH_REV(PFX, SNAME, K, T, TARGET, BODY) \ + do \ + { \ + size_t index; \ + T var; \ + SNAME##_iter iter; \ + PFX##_iter(&iter, TARGET); \ + PFX##_iter_toend(&iter); \ + while (PFX##_iter_prev(&iter, &var, &index)) \ + { \ + BODY; \ + } \ + } while (0); diff --git a/src/linkedlist.h b/src/linkedlist.h new file mode 100644 index 0000000..ca842f1 --- /dev/null +++ b/src/linkedlist.h @@ -0,0 +1,428 @@ +/** + * linkedlist.h + * + * Last Update: 22/03/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/*****************************************************************************/ +/**************************************************************** LINKEDLIST */ +/*****************************************************************************/ + +#ifndef CMC_LINKEDLIST_H +#define CMC_LINKEDLIST_H + +#include +#include +#include + +/* PRIVATE *******************************************************************/ +#define LINKEDLIST_GENERATE_HEADER_PRIVATE(PFX, SNAME, FMOD, K, T) \ + LINKEDLIST_GENERATE_HEADER(PFX, SNAME, FMOD, K, T) +#define LINKEDLIST_GENERATE_SOURCE_PRIVATE(PFX, SNAME, FMOD, K, T) \ + LINKEDLIST_GENERATE_STRUCT(PFX, SNAME, FMOD, K, T) \ + LINKEDLIST_GENERATE_SOURCE(PFX, SNAME, FMOD, K, T) +/* PUBLIC ********************************************************************/ +#define LINKEDLIST_GENERATE_HEADER_PUBLIC(PFX, SNAME, FMOD, K, T) \ + LINKEDLIST_GENERATE_STRUCT(PFX, SNAME, FMOD, K, T) \ + LINKEDLIST_GENERATE_HEADER(PFX, SNAME, FMOD, K, T) +#define LINKEDLIST_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, T) \ + LINKEDLIST_GENERATE_SOURCE(PFX, SNAME, FMOD, K, T) +/* STRUCT ********************************************************************/ +#define LINKEDLIST_GENERATE_STRUCT(PFX, SNAME, FMOD, K, T) \ + \ + struct SNAME##_s \ + { \ + struct SNAME##_node_s *head; \ + struct SNAME##_node_s *tail; \ + size_t count; \ + }; \ + \ + struct SNAME##_node_s \ + { \ + struct SNAME##_node_s *next; \ + struct SNAME##_node_s *prev; \ + T data; \ + }; \ + \ + struct SNAME##_iter_s \ + { \ + struct SNAME##_s *target; \ + struct SNAME##_node_s *cursor; \ + intmax_t count; \ + }; \ + \ +/* HEADER ********************************************************************/ +#define LINKEDLIST_GENERATE_HEADER(PFX, SNAME, FMOD, K, T) \ + \ + typedef struct SNAME##_s SNAME; \ + typedef struct SNAME##_node_s SNAME##_node; \ + typedef struct SNAME##_iter_s SNAME##_iter; \ + \ + FMOD SNAME *PFX##_new(void); \ + FMOD void PFX##_free(SNAME *_list_); \ + FMOD bool PFX##_push_front(SNAME *_list_, T element); \ + FMOD bool PFX##_push(SNAME *_list_, T element, size_t index); \ + FMOD bool PFX##_push_back(SNAME *_list_, T element); \ + FMOD bool PFX##_pop_front(SNAME *_list_); \ + FMOD bool PFX##_pop(SNAME *_list_, size_t index); \ + FMOD bool PFX##_pop_back(SNAME *_list_); \ + FMOD bool PFX##_insert_if(SNAME *_list_, T element, size_t index, bool condition); \ + FMOD bool PFX##_remove_if(SNAME *_list_, size_t index, bool condition); \ + FMOD T PFX##_back(SNAME *_list_); \ + FMOD T PFX##_get(SNAME *_list_, size_t index); \ + FMOD T PFX##_front(SNAME *_list_); \ + FMOD bool PFX##_empty(SNAME *_list_); \ + FMOD size_t PFX##_count(SNAME *_list_); \ + \ + FMOD void PFX##_iter(SNAME##_iter *iter, SNAME *target); \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter); \ + FMOD void PFX##_iter_tostart(SNAME##_iter *iter); \ + FMOD void PFX##_iter_toend(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter, T *result, size_t *index); \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter, T *result, size_t *index); \ + \ +/* SOURCE ********************************************************************/ +#define LINKEDLIST_GENERATE_SOURCE(PFX, SNAME, FMOD, K, T) \ + \ + FMOD SNAME##_node *PFX##_new_node(T element); \ + FMOD SNAME##_node *PFX##_get_node(SNAME *_list_, size_t index); \ + \ + FMOD SNAME *PFX##_new(void) \ + { \ + SNAME *_list_ = malloc(sizeof(SNAME)); \ + \ + if (!_list_) \ + return NULL; \ + \ + _list_->count = 0; \ + _list_->head = NULL; \ + _list_->tail = NULL; \ + \ + return _list_; \ + } \ + \ + FMOD void PFX##_free(SNAME *_list_) \ + { \ + SNAME##_node *scan = _list_->head; \ + while (_list_->head != NULL) \ + { \ + _list_->head = _list_->head->next; \ + free(scan); \ + scan = _list_->head; \ + } \ + free(_list_); \ + } \ + \ + FMOD bool PFX##_push_front(SNAME *_list_, T element) \ + { \ + SNAME##_node *node = PFX##_new_node(element); \ + \ + if (!node) \ + return false; \ + \ + if (PFX##_empty(_list_)) \ + { \ + _list_->head = node; \ + _list_->tail = node; \ + } \ + else \ + { \ + node->next = _list_->head; \ + _list_->head->prev = node; \ + _list_->head = node; \ + } \ + \ + _list_->count++; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_push(SNAME *_list_, T element, size_t index) \ + { \ + if (index > _list_->count) \ + return false; \ + \ + if (index == 0) \ + { \ + return PFX##_push_front(_list_, element); \ + } \ + else if (index == _list_->count) \ + { \ + return PFX##_push_back(_list_, element); \ + } \ + \ + SNAME##_node *node = PFX##_new_node(element); \ + \ + if (!node) \ + return false; \ + \ + SNAME##_node *scan = PFX##_get_node(_list_, index - 1); \ + \ + node->next = scan->next; \ + node->prev = scan; \ + node->next->prev = node; \ + node->prev->next = node; \ + \ + _list_->count++; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_push_back(SNAME *_list_, T element) \ + { \ + SNAME##_node *node = PFX##_new_node(element); \ + \ + if (!node) \ + return false; \ + \ + if (PFX##_empty(_list_)) \ + { \ + _list_->head = node; \ + _list_->tail = node; \ + } \ + else \ + { \ + node->prev = _list_->tail; \ + _list_->tail->next = node; \ + _list_->tail = node; \ + } \ + \ + _list_->count++; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_pop_front(SNAME *_list_) \ + { \ + if (PFX##_empty(_list_)) \ + return false; \ + \ + SNAME##_node *node = _list_->head; \ + _list_->head = _list_->head->next; \ + \ + free(node); \ + \ + if (_list_->head == NULL) \ + _list_->tail = NULL; \ + else \ + _list_->head->prev = NULL; \ + \ + _list_->count--; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_pop(SNAME *_list_, size_t index) \ + { \ + if (PFX##_empty(_list_)) \ + return false; \ + \ + if (index == 0) \ + { \ + return PFX##_pop_front(_list_); \ + } \ + else if (index == _list_->count - 1) \ + { \ + return PFX##_pop_back(_list_); \ + } \ + \ + SNAME##_node *node = PFX##_get_node(_list_, index); \ + \ + if (!node) \ + return false; \ + \ + node->next->prev = node->prev; \ + node->prev->next = node->next; \ + \ + free(node); \ + \ + _list_->count--; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_pop_back(SNAME *_list_) \ + { \ + if (PFX##_empty(_list_)) \ + return false; \ + \ + SNAME##_node *node = _list_->tail; \ + _list_->tail = _list_->tail->prev; \ + \ + free(node); \ + \ + if (_list_->tail == NULL) \ + _list_->head = NULL; \ + else \ + _list_->tail->next = NULL; \ + \ + _list_->count--; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_insert_if(SNAME *_list_, T element, size_t index, bool condition) \ + { \ + if (condition) \ + return PFX##_push(_list_, element, index); \ + \ + return false; \ + } \ + \ + FMOD bool PFX##_remove_if(SNAME *_list_, size_t index, bool condition) \ + { \ + if (condition) \ + return PFX##_pop(_list_, index); \ + \ + return false; \ + } \ + \ + FMOD T PFX##_front(SNAME *_list_) \ + { \ + if (PFX##_empty(_list_)) \ + return 0; \ + \ + return _list_->head->data; \ + } \ + \ + FMOD T PFX##_get(SNAME *_list_, size_t index) \ + { \ + if (index >= _list_->count) \ + return 0; \ + \ + if (PFX##_empty(_list_)) \ + return 0; \ + \ + SNAME##_node *scan = PFX##_get_node(_list_, index); \ + \ + if (scan == NULL) \ + return 0; \ + \ + return scan->data; \ + } \ + \ + FMOD T PFX##_back(SNAME *_list_) \ + { \ + if (PFX##_empty(_list_)) \ + return 0; \ + \ + return _list_->tail->data; \ + } \ + \ + FMOD bool PFX##_empty(SNAME *_list_) \ + { \ + return _list_->count == 0; \ + } \ + \ + FMOD size_t PFX##_count(SNAME *_list_) \ + { \ + return _list_->count; \ + } \ + \ + FMOD SNAME##_node *PFX##_new_node(T element) \ + { \ + SNAME##_node *node = malloc(sizeof(SNAME##_node)); \ + \ + if (!node) \ + return NULL; \ + \ + node->data = element; \ + node->next = NULL; \ + node->prev = NULL; \ + \ + return node; \ + } \ + \ + FMOD SNAME##_node *PFX##_get_node(SNAME *_list_, size_t index) \ + { \ + if (index >= _list_->count) \ + return NULL; \ + \ + if (PFX##_empty(_list_)) \ + return NULL; \ + \ + SNAME##_node *scan = NULL; \ + \ + if (index <= _list_->count / 2) \ + { \ + scan = _list_->head; \ + for (size_t i = 0; i < index; i++) \ + { \ + scan = scan->next; \ + } \ + } \ + else \ + { \ + scan = _list_->tail; \ + for (size_t i = _list_->count - 1; i > index; i--) \ + { \ + scan = scan->prev; \ + } \ + } \ + \ + return scan; \ + } \ + \ + FMOD void PFX##_iter(SNAME##_iter *iter, SNAME *target) \ + { \ + iter->target = target; \ + iter->cursor = target->head; \ + iter->count = -1; \ + } \ + \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter) \ + { \ + return iter->count < 0; \ + } \ + \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter) \ + { \ + return iter->count == iter->target->count; \ + } \ + \ + FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \ + { \ + iter->cursor = iter->target->head; \ + iter->count = 0; \ + } \ + \ + FMOD void PFX##_iter_toend(SNAME##_iter *iter) \ + { \ + iter->cursor = iter->target->tail; \ + iter->count = iter->target->count - 1; \ + } \ + \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter, T *result, size_t *index) \ + { \ + if (PFX##_iter_start(iter)) \ + PFX##_iter_tostart(iter); \ + if (PFX##_iter_end(iter)) \ + return false; \ + \ + *index = iter->count++; \ + *result = iter->cursor->data; \ + iter->cursor = iter->cursor->next; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter, T *result, size_t *index) \ + { \ + if (PFX##_iter_end(iter)) \ + PFX##_iter_toend(iter); \ + if (PFX##_iter_start(iter)) \ + return false; \ + \ + *index = iter->count--; \ + *result = iter->cursor->data; \ + iter->cursor = iter->cursor->prev; \ + \ + return true; \ + } + +#endif /* CMC_LINKEDLIST_H */ diff --git a/src/macro_collections.h b/src/macro_collections.h index b7d2edf..9eacd7d 100644 --- a/src/macro_collections.h +++ b/src/macro_collections.h @@ -33,6 +33,7 @@ (PFX, SNAME, FMOD, K, V) #include "list.h" +#include "linkedlist.h" #include "stack.h" #include "queue.h" #include "deque.h" diff --git a/tests/foreach.c b/tests/foreach.c index 6dd2e77..f4144fb 100644 --- a/tests/foreach.c +++ b/tests/foreach.c @@ -6,6 +6,7 @@ CONTAINER_GENERATE(LIST, PUBLIC, l, list, /**/, /**/, int) CONTAINER_GENERATE(STACK, PUBLIC, s, stack, /**/, /**/, int) CONTAINER_GENERATE(QUEUE, PUBLIC, q, queue, /**/, /**/, int) CONTAINER_GENERATE(DEQUE, PUBLIC, d, deque, /**/, /**/, int) +CONTAINER_GENERATE(LINKEDLIST, PUBLIC, ll, linked, /**/, /**/, int) int main(int argc, char const *argv[]) { @@ -13,6 +14,7 @@ int main(int argc, char const *argv[]) stack *s = s_new(1000); queue *q = q_new(1000); deque *d = d_new(1000); + linked *ll = ll_new(); for (int i = 1; i < 10001; i++) { @@ -20,18 +22,20 @@ int main(int argc, char const *argv[]) { d_push_front(d, i); l_push_front(l, i); + ll_push_front(ll, i); } else { d_push_back(d, i); l_push_back(l, i); + ll_push_back(ll, i); } s_push(s, i); q_enqueue(q, i); } - int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; + int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0; FOR_EACH(l, list, , int, l, { sum0 += var; @@ -49,8 +53,14 @@ int main(int argc, char const *argv[]) sum3 += var; }) + FOR_EACH(ll, linked, , int, ll, { + sum4 += var; + }) + if (sum0 == 50005000) printf("%10s PASSED\n", "LIST"); + if (sum4 == 50005000) + printf("%10s PASSED\n", "LINKEDLIST"); if (sum1 == 50005000) printf("%10s PASSED\n", "STACK"); if (sum2 == 50005000) @@ -58,7 +68,21 @@ int main(int argc, char const *argv[]) if (sum3 == 50005000) printf("%10s PASSED\n", "DEQUE"); + printf("\n\n"); + + sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0; + + FOR_EACH_REV(ll, linked, , int, ll, { + sum4 += var; + }) + + if (sum4 == 50005000) + printf("%10s PASSED\n", "LINKEDLIST"); + else + printf("%10s ERROR %d", "LINKEDLIST", sum4); + l_free(l); + ll_free(ll); s_free(s); q_free(q); d_free(d);