From 221c55cf2a9579ac0a4704a643b8f92d09deda86 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 13 May 2019 23:01:27 -0300 Subject: [PATCH] Second update on iterators - DEQUE --- examples/deque/README.md | 1 + examples/deque/iterator.c | 199 +++++++++++++++++++++++++++++++++++++ examples/iterators/deque.c | 24 +++-- examples/list/iterator.c | 2 +- src/deque.h | 151 ++++++++++++++++++++-------- src/list.h | 2 +- 6 files changed, 327 insertions(+), 52 deletions(-) create mode 100644 examples/deque/iterator.c diff --git a/examples/deque/README.md b/examples/deque/README.md index 1235002..ab0098f 100644 --- a/examples/deque/README.md +++ b/examples/deque/README.md @@ -1,3 +1,4 @@ # Deque examples * even_odd.c - separates odd numbers to one end of the deque and even number to the other. Sum only half of it to give the total sum of even numbers. +* iterator.c - A complete example of the deque iterator diff --git a/examples/deque/iterator.c b/examples/deque/iterator.c new file mode 100644 index 0000000..640281e --- /dev/null +++ b/examples/deque/iterator.c @@ -0,0 +1,199 @@ +/** + * iterator.c + * + * Creation Date: 13/05/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + * Iterator Example + */ +#include "deque.h" +#include +#include + +// Creates a deque of integers +DEQUE_GENERATE(d, deque, /* FMOD */, int) + +int main(int argc, char const *argv[]) +{ + // Create a new deque with an initial capacity of 100 + deque *my_deque = d_new(100); + + // Add elements to the deque + for (int i = 0; i < 20; i++) + { + // Add odd numbers to the front + d_push_front_if(my_deque, i, !(i % 2 == 0)); + + // And even numbers to the back + d_push_back_if(my_deque, i, i % 2 == 0); + } + + // Iterate from the start (index 0) to the end (index count - 1) of the deque + for (deque_iter it = my_deque->it_start(my_deque); // Initialize iterator 'it' to the start of the deque + !d_iter_end(&it); // Conditional stop (until it is not at the end) + d_iter_next(&it)) // Iterator goes one position forward + { + // Access the current element + int e = d_iter_value(&it); + + // Access the current index (index is relative to all the elements in the iteration) + size_t i = d_iter_index(&it); + + // Print deque + + // Index is useful in situations like this + // If it is the first element + if (i == 0) + printf("[ %d, ", e); + // If it is the last element + else if (i == d_count(my_deque) - 1) + printf("%d ]\n", e); + // For elements at the middle + else + printf("%d, ", e); + } + + // Index can also be used to iterate over a certain portion of a collection + size_t limit = d_count(my_deque) / 2; + for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it)) + { + // Access the current element + int e = d_iter_value(&it); + + // Access the current index (index is relative to all the elements in the iteration) + size_t i = d_iter_index(&it); + + // Print deque up until limit + + // If it is the first element + if (i == 0) + printf("[ %d, ", e); + // If it is the last element + else if (i == limit - 1) // -1 because index is 0 based and we want half of the deque + { + printf("%d ]\n", e); + break; + } + // For elements at the middle + else + printf("%d, ", e); + } + + // Going backwards + for (deque_iter it = my_deque->it_end(my_deque); // Initialize iterator 'it' to the end of the deque + !d_iter_start(&it); // Conditional stop (until it is not at the start) + d_iter_prev(&it)) // Iterator goes one position backwards + { + // Access the current element + int e = d_iter_value(&it); + + // Access the current index (index is relative to all the elements in the iteration) + size_t i = d_iter_index(&it); + + // Print deque + // Note how the conditions for the first and last elements are simply swapped + // Because iterating backwards make the first element be the index count - 1 + // and the last one be the index 0 + + // If it is the first element + if (i == d_count(my_deque) - 1) + printf("[ %d, ", e); + // If it is the last element + else if (i == 0) + printf("%d ]\n", e); + // For elements at the middle + else + printf("%d, ", e); + } + + // You can also use iterators in a while loop + // But to do so you must declare the iterator struct outside the loop first + deque_iter it; + + // You have three options: + // - Initialize it using the functions provided by the deque [ my_deque->it_start() and my_deque->it_end() ] + // - Initialize it using the init() function (when the iterator is already allocated) + // - Initialize it using the new() function (allocates on the heap, pointers only) + + it = my_deque->it_start(my_deque); + it = my_deque->it_end(my_deque); + + // This is equivalent to it_start() + d_iter_init(&it, my_deque); + + // For pointers + // Also equivalent to it_start() + deque_iter *iter = d_iter_new(my_deque); + + // The actual while loop + while (!d_iter_end(iter)) + { + // Accessing elements + int e = d_iter_value(iter); + size_t i = d_iter_index(iter); + + // Print index and element + printf("deque[%2" PRIuMAX "] = %2d\n", i, e); + + // Move iterator forwards + d_iter_next(iter); + } + + // Send the iterator to the start of the deque + d_iter_to_start(iter); + + // Send the iterator to the end of the deque + d_iter_to_end(iter); + + // Backwards loop + while (!d_iter_start(iter)) + { + // Accessing elements + int e = d_iter_value(iter); + size_t i = d_iter_index(iter); + + // Print index and element + printf("deque[%2" PRIuMAX "] = %2d\n", i, e); + + // Move iterator backwards + d_iter_prev(iter); + } + + // Certain iterators also allow you to modify the contents it is iterating over + // Exceptions are collections that depend of the current state of the element + // like tree-based collections and heap (collections that have some kind of ordering). + // You also can't change the keys of an associative collection + + // Change every element that is divisible by 3 to the number 7 + for (d_iter_to_start(&it); !d_iter_end(&it); d_iter_next(&it)) + { + // Get a reference to the current value + int *r = d_iter_rvalue(&it); + + if (r != NULL && *r % 3 == 0) + *r = 7; + } + + // Now print it to see the difference + for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it)) + { + int e = d_iter_value(&it); + size_t i = d_iter_index(&it); + + if (i == 0) + printf("[ %d, ", e); + else if (i == d_count(my_deque) - 1) + printf("%d ]\n", e); + else + printf("%d, ", e); + } + + // Dispose the iterator called by d_iter_new() + d_iter_free(iter); + // Dispose the deque created + d_free(my_deque); + + return 0; +} diff --git a/examples/iterators/deque.c b/examples/iterators/deque.c index 9ec8fb7..e655fba 100644 --- a/examples/iterators/deque.c +++ b/examples/iterators/deque.c @@ -32,26 +32,30 @@ int main(int argc, char const *argv[]) // Make the iterator go back and forward for (int j = 0; j < 4; j++) { - while (d_iter_next(&iter, &r, &i)) - printf("C[%2d] = %2d\n", i, r); + while (!d_iter_end(&iter)) + { + printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter)); + d_iter_next(&iter); + } printf("\n"); - while (d_iter_prev(&iter, &r, &i)) - printf("C[%2d] = %2d\n", i, r); + while (!d_iter_start(&iter)) + { + printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter)); + d_iter_prev(&iter); + } printf("\n\n"); } - for (d_iter_tostart(&iter); !d_iter_end(&iter); /**/) + for (d_iter_to_start(&iter); !d_iter_end(&iter); d_iter_next(&iter)) { - d_iter_next(&iter, &r, &i); - printf("D[%2d] = %2d\n", i, r); + printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter)); } printf("\n"); - for (d_iter_toend(&iter); !d_iter_start(&iter); /**/) + for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter)) { - d_iter_prev(&iter, &r, &i); - printf("D[%2d] = %2d\n", i, r); + printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter)); } d_free(d); diff --git a/examples/list/iterator.c b/examples/list/iterator.c index db1c23d..6147012 100644 --- a/examples/list/iterator.c +++ b/examples/list/iterator.c @@ -67,7 +67,7 @@ int main(int argc, char const *argv[]) if (i == 0) printf("[ %d, ", e); // If it is the last element - else if (i == limit) + else if (i == limit - 1) // -1 because index is 0 based and we want half of the list { printf("%d ]\n", e); break; diff --git a/src/deque.h b/src/deque.h index c6f10e7..2a03d57 100644 --- a/src/deque.h +++ b/src/deque.h @@ -37,65 +37,105 @@ #define DEQUE_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \ DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) /* STRUCT ********************************************************************/ -#define DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \ - \ - struct SNAME##_s \ - { \ - V *buffer; \ - size_t capacity; \ - size_t count; \ - size_t front; \ - size_t back; \ - }; \ - \ - struct SNAME##_iter_s \ - { \ - struct SNAME##_s *target; \ - size_t cursor; \ - size_t index; \ - bool start; \ - bool end; \ - }; \ - \ +#define DEQUE_GENERATE_STRUCT(PFX, SNAME, FMOD, V) + /* HEADER ********************************************************************/ #define DEQUE_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ \ - typedef struct SNAME##_s SNAME; \ - typedef struct SNAME##_iter_s SNAME##_iter; \ + typedef struct SNAME##_s \ + { \ + /* Dynamic circular array of elements */ \ + V *buffer; \ \ + /* Current circular array capacity */ \ + size_t capacity; \ + \ + /* Current amount of elements */ \ + size_t count; \ + \ + /* Index representing the front of the deque */ \ + size_t front; \ + \ + /* Index representing the back of the deque */ \ + size_t back; \ + \ + /* Function that returns an iterator to the start of the deque */ \ + struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ + \ + /* Function that returns an iterator to the end of the deque */ \ + struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ + \ + } SNAME, *SNAME##_ptr; \ + \ + typedef struct SNAME##_iter_s \ + { \ + /* Target deque */ \ + struct SNAME##_s *target; \ + \ + /* Cursor's position (index) */ \ + size_t cursor; \ + \ + /* Keeps track of relative index to the iteration of elements */ \ + size_t index; \ + \ + /* If the iterator has reached the start of the iteration */ \ + bool start; \ + \ + /* If the iterator has reached the end of the iteration */ \ + bool end; \ + \ + } SNAME##_iter, *SNAME##_iter_ptr; \ + \ + /* Collection Functions */ \ + /* Collection Allocation and Deallocation */ \ FMOD SNAME *PFX##_new(size_t size); \ FMOD void PFX##_clear(SNAME *_deque_); \ FMOD void PFX##_free(SNAME *_deque_); \ + /* Collection Input and Output */ \ FMOD bool PFX##_push_front(SNAME *_deque_, V element); \ FMOD bool PFX##_push_back(SNAME *_deque_, V element); \ FMOD bool PFX##_pop_front(SNAME *_deque_); \ FMOD bool PFX##_pop_back(SNAME *_deque_); \ + /* Conditional Input and Output */ \ FMOD bool PFX##_push_front_if(SNAME *_deque_, V element, bool condition); \ FMOD bool PFX##_push_back_if(SNAME *_deque_, V element, bool condition); \ FMOD bool PFX##_pop_front_if(SNAME *_deque_, bool condition); \ FMOD bool PFX##_pop_back_if(SNAME *_deque_, bool condition); \ + /* Element Access */ \ FMOD V PFX##_front(SNAME *_deque_); \ FMOD V PFX##_back(SNAME *_deque_); \ + /* Collection State */ \ FMOD bool PFX##_contains(SNAME *_deque_, V element, int (*comparator)(V, V)); \ FMOD bool PFX##_empty(SNAME *_deque_); \ FMOD bool PFX##_full(SNAME *_deque_); \ FMOD size_t PFX##_count(SNAME *_deque_); \ FMOD size_t PFX##_capacity(SNAME *_deque_); \ \ + /* Iterator Functions */ \ + /* Iterator Allocation and Deallocation */ \ FMOD SNAME##_iter *PFX##_iter_new(SNAME *target); \ FMOD void PFX##_iter_free(SNAME##_iter *iter); \ + /* Iterator Initialization */ \ FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target); \ + /* Iterator State */ \ 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, V *result, size_t *index); \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index); \ + /* Iterator Movement */ \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter); \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter); \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter); \ + /* Iterator Access */ \ + FMOD V PFX##_iter_value(SNAME##_iter *iter); \ + FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter); \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter); \ \ /* SOURCE ********************************************************************/ #define DEQUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ \ - FMOD bool PFX##_grow(SNAME *_deque_); \ + FMOD bool PFX##_impl_grow(SNAME *_deque_); \ + SNAME##_iter PFX##_impl_it_start(SNAME *_deque_); \ + SNAME##_iter PFX##_impl_it_end(SNAME *_deque_); \ \ FMOD SNAME *PFX##_new(size_t size) \ { \ @@ -122,6 +162,9 @@ _deque_->front = 0; \ _deque_->back = 0; \ \ + _deque_->it_start = PFX##_impl_it_start; \ + _deque_->it_end = PFX##_impl_it_end; \ + \ return _deque_; \ } \ \ @@ -144,7 +187,7 @@ { \ if (PFX##_full(_deque_)) \ { \ - if (!PFX##_grow(_deque_)) \ + if (!PFX##_impl_grow(_deque_)) \ return false; \ } \ \ @@ -161,7 +204,7 @@ { \ if (PFX##_full(_deque_)) \ { \ - if (!PFX##_grow(_deque_)) \ + if (!PFX##_impl_grow(_deque_)) \ return false; \ } \ \ @@ -317,7 +360,7 @@ return PFX##_empty(iter->target) || iter->end; \ } \ \ - FMOD void PFX##_iter_tostart(SNAME##_iter *iter) \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \ { \ iter->cursor = iter->target->front; \ iter->index = 0; \ @@ -325,7 +368,7 @@ iter->end = PFX##_empty(iter->target); \ } \ \ - FMOD void PFX##_iter_toend(SNAME##_iter *iter) \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \ { \ if (PFX##_empty(iter->target)) \ iter->cursor = 0; \ @@ -337,14 +380,11 @@ iter->end = true; \ } \ \ - FMOD bool PFX##_iter_next(SNAME##_iter *iter, V *result, size_t *index) \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter) \ { \ if (iter->end) \ return false; \ \ - *index = iter->index; \ - *result = iter->target->buffer[iter->cursor]; \ - \ iter->start = false; \ \ if (iter->index == iter->target->count - 1) \ @@ -358,14 +398,11 @@ return true; \ } \ \ - FMOD bool PFX##_iter_prev(SNAME##_iter *iter, V *result, size_t *index) \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \ { \ if (iter->start) \ return false; \ \ - *index = iter->index; \ - *result = iter->target->buffer[iter->cursor]; \ - \ iter->end = false; \ \ if (iter->index == 0) \ @@ -379,7 +416,22 @@ return true; \ } \ \ - FMOD bool PFX##_grow(SNAME *_deque_) \ + FMOD V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + return iter->target->buffer[iter->cursor]; \ + } \ + \ + FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \ + { \ + return &(iter->target->buffer[iter->cursor]); \ + } \ + \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->index; \ + } \ + \ + FMOD bool PFX##_impl_grow(SNAME *_deque_) \ { \ \ size_t new_capacity = _deque_->capacity * 2; \ @@ -402,6 +454,25 @@ _deque_->back = _deque_->count; \ \ return true; \ + } \ + \ + SNAME##_iter PFX##_impl_it_start(SNAME *_deque_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _deque_); \ + \ + return iter; \ + } \ + \ + SNAME##_iter PFX##_impl_it_end(SNAME *_deque_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _deque_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_DEQUE_H */ diff --git a/src/list.h b/src/list.h index e36ef0e..27e4b47 100644 --- a/src/list.h +++ b/src/list.h @@ -105,8 +105,8 @@ FMOD V *PFX##_get_ref(SNAME *_list_, size_t index); \ FMOD V PFX##_back(SNAME *_list_); \ FMOD size_t PFX##_indexof(SNAME *_list_, V element, int (*comparator)(V, V), bool from_start); \ - FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \ /* Collection State */ \ + FMOD bool PFX##_contains(SNAME *_list_, V element, int (*comparator)(V, V)); \ FMOD bool PFX##_empty(SNAME *_list_); \ FMOD bool PFX##_full(SNAME *_list_); \ FMOD size_t PFX##_count(SNAME *_list_); \