diff --git a/examples/stack/README.md b/examples/stack/README.md index 36b1c1a..cb88b71 100644 --- a/examples/stack/README.md +++ b/examples/stack/README.md @@ -1,3 +1,4 @@ # Stack examples * hanoi.c - Animated example of solving the hanoi tower. +* iterator.c - A complete example of the stack iterator diff --git a/examples/stack/hanoi.c b/examples/stack/hanoi.c index 1eeac16..a61fafa 100644 --- a/examples/stack/hanoi.c +++ b/examples/stack/hanoi.c @@ -13,8 +13,6 @@ STACK_GENERATE(s, stack, /* static */, int) -#define MAX(a, b) a > b ? a : b - void print_hanoi(stack *t1, stack *t2, stack *t3); const char *draw(int value); void move_disc(stack *from, stack *to); diff --git a/examples/stack/iterator.c b/examples/stack/iterator.c new file mode 100644 index 0000000..add90ce --- /dev/null +++ b/examples/stack/iterator.c @@ -0,0 +1,195 @@ +/** + * iterator.c + * + * Creation Date: 15/05/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + * Iterator Example + */ +#include "stack.h" +#include +#include + +// Creates a stack of integers +STACK_GENERATE(s, stack, /* FMOD */, int) + +int main(int argc, char const *argv[]) +{ + // Create a new stack with an initial capacity of 100 + stack *my_stack = s_new(100); + + // Add elements to the stack + for (int i = 0; i < 20; i++) + { + s_push(my_stack, i); + } + + // Iterate from the start (top) to the end (bottom) of the stack + for (stack_iter it = my_stack->it_start(my_stack); // Initialize iterator 'it' to the start of the stack + !s_iter_end(&it); // Conditional stop (until it is not at the end) + s_iter_next(&it)) // Iterator goes one position forward + { + // Access the current element + int e = s_iter_value(&it); + + // Access the current index (index is relative to all the elements in the iteration) + size_t i = s_iter_index(&it); + + // Print stack + + // 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 == s_count(my_stack) - 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 = s_count(my_stack) / 2; + for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it)) + { + // Access the current element + int e = s_iter_value(&it); + + // Access the current index (index is relative to all the elements in the iteration) + size_t i = s_iter_index(&it); + + // Print stack 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 stack + { + printf("%d ]\n", e); + break; + } + // For elements at the middle + else + printf("%d, ", e); + } + + // Going backwards + for (stack_iter it = my_stack->it_end(my_stack); // Initialize iterator 'it' to the end of the stack + !s_iter_start(&it); // Conditional stop (until it is not at the start) + s_iter_prev(&it)) // Iterator goes one position backwards + { + // Access the current element + int e = s_iter_value(&it); + + // Access the current index (index is relative to all the elements in the iteration) + size_t i = s_iter_index(&it); + + // Print stack + // 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 == s_count(my_stack) - 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 + stack_iter it; + + // You have three options: + // - Initialize it using the functions provided by the stack [ my_stack->it_start() and my_stack->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_stack->it_start(my_stack); + it = my_stack->it_end(my_stack); + + // This is equivalent to it_start() + s_iter_init(&it, my_stack); + + // For pointers + // Also equivalent to it_start() + stack_iter *iter = s_iter_new(my_stack); + + // The actual while loop + while (!s_iter_end(iter)) + { + // Accessing elements + int e = s_iter_value(iter); + size_t i = s_iter_index(iter); + + // Print index and element + printf("stack[%2" PRIuMAX "] = %2d\n", i, e); + + // Move iterator forwards + s_iter_next(iter); + } + + // Send the iterator to the start of the stack + s_iter_to_start(iter); + + // Send the iterator to the end of the stack + s_iter_to_end(iter); + + // Backwards loop + while (!s_iter_start(iter)) + { + // Accessing elements + int e = s_iter_value(iter); + size_t i = s_iter_index(iter); + + // Print index and element + printf("stack[%2" PRIuMAX "] = %2d\n", i, e); + + // Move iterator backwards + s_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 (s_iter_to_start(&it); !s_iter_end(&it); s_iter_next(&it)) + { + // Get a reference to the current value + int *r = s_iter_rvalue(&it); + + if (r != NULL && *r % 3 == 0) + *r = 7; + } + + // Now print it to see the difference + for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it)) + { + int e = s_iter_value(&it); + size_t i = s_iter_index(&it); + + if (i == 0) + printf("[ %d, ", e); + else if (i == s_count(my_stack) - 1) + printf("%d ]\n", e); + else + printf("%d, ", e); + } + + // Dispose the iterator called by s_iter_new() + s_iter_free(iter); + // Dispose the stack created + s_free(my_stack); + + return 0; +} diff --git a/src/deque.h b/src/deque.h index 2e415f9..f769988 100644 --- a/src/deque.h +++ b/src/deque.h @@ -421,11 +421,17 @@ \ FMOD V PFX##_iter_value(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ return iter->target->buffer[iter->cursor]; \ } \ \ FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ return &(iter->target->buffer[iter->cursor]); \ } \ \ diff --git a/src/hashmap.h b/src/hashmap.h index f430f9d..b116928 100644 --- a/src/hashmap.h +++ b/src/hashmap.h @@ -586,16 +586,25 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ FMOD K PFX##_iter_key(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ return iter->target->buffer[iter->cursor].key; \ } \ \ FMOD V PFX##_iter_value(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ return iter->target->buffer[iter->cursor].value; \ } \ \ FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ return &(iter->target->buffer[iter->cursor].value); \ } \ \ diff --git a/src/hashset.h b/src/hashset.h index af24a23..5ac2409 100644 --- a/src/hashset.h +++ b/src/hashset.h @@ -639,6 +639,9 @@ static const size_t cmc_hashtable_primes[] = {53, 97, 191, 383, 769, 1531, \ FMOD V PFX##_iter_value(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ return iter->target->buffer[iter->cursor].value; \ } \ \ diff --git a/src/heap.h b/src/heap.h index dd055e5..d2d5c83 100644 --- a/src/heap.h +++ b/src/heap.h @@ -373,6 +373,9 @@ typedef enum HeapOrder \ FMOD V PFX##_iter_value(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ return iter->target->buffer[iter->cursor]; \ } \ \ diff --git a/src/linkedlist.h b/src/linkedlist.h index 88b7b8e..c47b247 100644 --- a/src/linkedlist.h +++ b/src/linkedlist.h @@ -711,11 +711,17 @@ \ FMOD V PFX##_iter_value(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ return iter->cursor->data; \ } \ \ FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \ { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ return &(iter->cursor->data); \ } \ \ diff --git a/src/stack.h b/src/stack.h index 17524cc..85892ef 100644 --- a/src/stack.h +++ b/src/stack.h @@ -37,57 +37,94 @@ #define STACK_GENERATE_SOURCE_PUBLIC(PFX, SNAME, FMOD, K, V) \ STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V) /* STRUCT ********************************************************************/ -#define STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, V) \ - \ - struct SNAME##_s \ - { \ - V *buffer; \ - size_t capacity; \ - size_t count; \ - }; \ - \ - struct SNAME##_iter_s \ - { \ - struct SNAME##_s *target; \ - size_t cursor; \ - bool start; \ - bool end; \ - }; \ - \ +#define STACK_GENERATE_STRUCT(PFX, SNAME, FMOD, V) + /* HEADER ********************************************************************/ #define STACK_GENERATE_HEADER(PFX, SNAME, FMOD, V) \ \ - typedef struct SNAME##_s SNAME; \ - typedef struct SNAME##_iter_s SNAME##_iter; \ + /* Stack Structure */ \ + typedef struct SNAME##_s \ + { \ + /* Dynamic array of elements */ \ + V *buffer; \ \ + /* Current array capacity */ \ + size_t capacity; \ + \ + /* Current amount of elements */ \ + size_t count; \ + \ + /* Function that returns an iterator to the start of the stack */ \ + struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ + \ + /* Function that returns an iterator to the end of the stack */ \ + struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ + \ + } SNAME, *SNAME##_ptr; \ + \ + /* Stack Iterator */ \ + typedef struct SNAME##_iter_s \ + { \ + /* Target stack */ \ + struct SNAME##_s *target; \ + \ + /* Cursor's position (index) */ \ + size_t cursor; \ + \ + /* 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 *_stack_); \ FMOD void PFX##_free(SNAME *_stack_); \ + /* Collection Input and Output */ \ FMOD bool PFX##_push(SNAME *_stack_, V element); \ FMOD bool PFX##_pop(SNAME *_stack_); \ + /* Conditional Input and Output */ \ FMOD bool PFX##_push_if(SNAME *_stack_, V element, bool condition); \ FMOD bool PFX##_pop_if(SNAME *_stack_, bool condition); \ + /* Element Access */ \ FMOD V PFX##_top(SNAME *_stack_); \ + /* Collection State */ \ FMOD bool PFX##_contains(SNAME *_stack_, V element, int (*comparator)(V, V)); \ FMOD bool PFX##_empty(SNAME *_stack_); \ FMOD bool PFX##_full(SNAME *_stack_); \ FMOD size_t PFX##_count(SNAME *_stack_); \ FMOD size_t PFX##_capacity(SNAME *_stack_); \ \ + /* 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 STACK_GENERATE_SOURCE(PFX, SNAME, FMOD, V) \ \ - FMOD bool PFX##_grow(SNAME *_stack_); \ + /* Implementation Detail Functions */ \ + FMOD bool PFX##_impl_grow(SNAME *_stack_); \ + SNAME##_iter PFX##_impl_it_start(SNAME *_list_); \ + SNAME##_iter PFX##_impl_it_end(SNAME *_list_); \ \ FMOD SNAME *PFX##_new(size_t size) \ { \ @@ -112,6 +149,9 @@ _stack_->capacity = size; \ _stack_->count = 0; \ \ + _stack_->it_start = PFX##_impl_it_start; \ + _stack_->it_end = PFX##_impl_it_end; \ + \ return _stack_; \ } \ \ @@ -132,7 +172,7 @@ { \ if (PFX##_full(_stack_)) \ { \ - if (!PFX##_grow(_stack_)) \ + if (!PFX##_impl_grow(_stack_)) \ return false; \ } \ \ @@ -241,28 +281,26 @@ 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->count - 1; \ iter->start = true; \ iter->end = PFX##_empty(iter->target); \ } \ \ - FMOD void PFX##_iter_toend(SNAME##_iter *iter) \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \ { \ iter->cursor = 0; \ iter->start = PFX##_empty(iter->target); \ 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->target->count - iter->cursor - 1; \ - *result = iter->target->buffer[iter->cursor]; \ - iter->start = false; \ + iter->start = PFX##_empty(iter->target); \ \ if (iter->cursor == 0) \ iter->end = true; \ @@ -272,14 +310,12 @@ 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->target->count - iter->cursor - 1; \ - *result = iter->target->buffer[iter->cursor]; \ - iter->end = false; \ + iter->end = PFX##_empty(iter->target); \ \ if (iter->cursor == iter->target->count - 1) \ iter->start = true; \ @@ -289,7 +325,28 @@ return true; \ } \ \ - FMOD bool PFX##_grow(SNAME *_stack_) \ + FMOD V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return 0; \ + \ + return iter->target->buffer[iter->cursor]; \ + } \ + \ + FMOD V *PFX##_iter_rvalue(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + return NULL; \ + \ + return &(iter->target->buffer[iter->cursor]); \ + } \ + \ + FMOD size_t PFX##_iter_index(SNAME##_iter *iter) \ + { \ + return iter->target->count - 1 - iter->cursor; \ + } \ + \ + FMOD bool PFX##_impl_grow(SNAME *_stack_) \ { \ size_t new_capacity = _stack_->capacity * 2; \ \ @@ -302,6 +359,26 @@ _stack_->capacity = new_capacity; \ \ return true; \ + } \ + \ + SNAME##_iter PFX##_impl_it_start(SNAME *_list_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _list_); \ + PFX##_iter_to_start(&iter); \ + \ + return iter; \ + } \ + \ + SNAME##_iter PFX##_impl_it_end(SNAME *_list_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _list_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ } #endif /* CMC_STACK_H */