From 9062415322ebe944f1f9cab92d25589f544a18d3 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 24 Jun 2019 02:09:02 -0300 Subject: [PATCH] Added sac/queue.h, moved timer.h to utl folder, new queue benchmark --- README.md | 1 + benchmarks/benchmark.c | 2 +- benchmarks/queue/Makefile | 10 + benchmarks/queue/queue.c | 82 ++++++ src/sac/queue.h | 357 +++++++++++++++++++++++++++ src/sac/stack.h | 9 +- {benchmarks/util => src/utl}/timer.h | 9 +- 7 files changed, 460 insertions(+), 10 deletions(-) create mode 100644 benchmarks/queue/Makefile create mode 100644 benchmarks/queue/queue.c create mode 100644 src/sac/queue.h rename {benchmarks/util => src/utl}/timer.h (81%) diff --git a/README.md b/README.md index 7abccd9..e57367c 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Only Collections located in __cmc__ are to be documented at *Documentation.md*. * Extra Collections Library * LinkedQueue * Stack Allocated Collections Library + * Queue * Stack ### More to Come diff --git a/benchmarks/benchmark.c b/benchmarks/benchmark.c index cc967c8..c5dc53a 100644 --- a/benchmarks/benchmark.c +++ b/benchmarks/benchmark.c @@ -13,7 +13,7 @@ * - Output */ #include "macro_collections.h" -#include "util/timer.h" +#include "utl/timer.h" #include "util/twister.c" #include #include diff --git a/benchmarks/queue/Makefile b/benchmarks/queue/Makefile new file mode 100644 index 0000000..addee4c --- /dev/null +++ b/benchmarks/queue/Makefile @@ -0,0 +1,10 @@ +CFLAGS = -Wall -Wextra +INCLUDE = ../../src + +main: + gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DCMC_QUEUE + a.exe + gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DSAC_QUEUE + a.exe + gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DEXT_QUEUE + a.exe diff --git a/benchmarks/queue/queue.c b/benchmarks/queue/queue.c new file mode 100644 index 0000000..84d3bae --- /dev/null +++ b/benchmarks/queue/queue.c @@ -0,0 +1,82 @@ +/** + * queue.c + * + * Creation Date: 24/06/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/* Showing off how different queue implementations affect runtime cost */ + +#include "utl/timer.h" +#include +#include + +#define MAX 200000 + +#if defined(CMC_QUEUE) +#include "cmc/queue.h" +QUEUE_GENERATE(q, queue, , int) +#define TARGET "QUEUE" +#elif defined(SAC_QUEUE) +#include "sac/queue.h" +SAC_QUEUE_GENERATE(q, queue, , int, MAX) +#define TARGET "SAC QUEUE" +#elif defined(EXT_QUEUE) +#include "ext/linkedqueue.h" +LINKEDQUEUE_GENERATE(q, queue, , int) +#define TARGET "LINKED QUEUE" +#else +#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE +#endif + +int main(void) +{ + +#if defined(CMC_QUEUE) + queue *q = q_new(MAX); +#elif defined(SAC_QUEUE) + queue _q = q_new(); + queue_ptr q = &_q; +#elif defined(EXT_QUEUE) + queue *q = q_new(); +#endif + + size_t sum = 0; + int i = 0; + + timer_t timer; + TIMER_START(timer); + + while (q_count(q) != MAX) + { + q_enqueue(q, i++); + + if (i % 10 == 0) + { + for (size_t i = 0; i < 9; i++) + { + sum += q_peek(q); + q_dequeue(q); + } + } + + } + + TIMER_STOP(timer); + TIMER_CALC(timer); + + printf("----------------------------------------\n"); + printf("%s\n", TARGET); + printf("Execution time: %.0lf milliseconds\n", timer.result); + printf("SUM: %" PRIuMAX "\n", sum); + printf("----------------------------------------\n"); + +#if defined(CMC_QUEUE) || defined(EXT_QUEUE) + q_free(q); +#endif + + return 0; +} diff --git a/src/sac/queue.h b/src/sac/queue.h new file mode 100644 index 0000000..e9c86a6 --- /dev/null +++ b/src/sac/queue.h @@ -0,0 +1,357 @@ +/** + * queue.h + * + * Creation Date: 24/06/2019 + * + * Authors: + * Leonardo Vencovsky (https://github.com/LeoVen) + * + */ + +/** + * A Purely Stack Allocated Queue + * + * This means that the Queue has a fixed size, but it also has the advantage of + * not requiring for manually allocating and deallocating the struct. + * + * Generating a collection with too big of a storage can be dangerous and might + * quickly cause a stack overflow. + * + * It is recommended to not generate any Stack Allocated Collection with less + * than 1000 internal storage. + */ + +#ifndef CMC_SAC_QUEUE_H +#define CMC_SAC_QUEUE_H + +#include +#include +#include + +#define SAC_QUEUE_GENERATE(PFX, SNAME, FMOD, V, SIZE) \ + SAC_QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V, SIZE) \ + SAC_QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V, SIZE) + +#define SAC_QUEUE_WRAPGEN_HEADER(PFX, SNAME, FMOD, K, V, SIZE) \ + SAC_QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V, SIZE) + +#define SAC_QUEUE_WRAPGEN_SOURCE(PFX, SNAME, FMOD, K, V, SIZE) \ + SAC_QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V, SIZE) + +/* HEADER ********************************************************************/ +#define SAC_QUEUE_GENERATE_HEADER(PFX, SNAME, FMOD, V, SIZE) \ + \ + /* Queue Structure */ \ + typedef struct SNAME##_s \ + { \ + /* Internal Storage */ \ + V buffer[SIZE]; \ + \ + /* Current amount of elements */ \ + size_t count; \ + \ + /* Index representing the front of the queue */ \ + size_t front; \ + \ + /* Index representing the back of the queue */ \ + size_t rear; \ + \ + /* Function that returns an iterator to the start of the queue */ \ + struct SNAME##_iter_s (*it_start)(struct SNAME##_s *); \ + \ + /* Function that returns an iterator to the end of the queue */ \ + struct SNAME##_iter_s (*it_end)(struct SNAME##_s *); \ + \ + } SNAME, *SNAME##_ptr; \ + \ + /* Queue Iterator */ \ + typedef struct SNAME##_iter_s \ + { \ + /* Target queue */ \ + 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(void); \ + FMOD void PFX##_clear(SNAME *_queue_); \ + /* Collection Input and Output */ \ + FMOD bool PFX##_enqueue(SNAME *_queue_, V element); \ + FMOD bool PFX##_dequeue(SNAME *_queue_); \ + /* Conditional Input and Output */ \ + FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition); \ + FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition); \ + /* Element Access */ \ + FMOD V PFX##_peek(SNAME *_queue_); \ + /* Collection State */ \ + FMOD bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)); \ + FMOD bool PFX##_empty(SNAME *_queue_); \ + FMOD bool PFX##_full(SNAME *_queue_); \ + FMOD size_t PFX##_count(SNAME *_queue_); \ + FMOD size_t PFX##_capacity(void); \ + \ + /* Iterator Functions */ \ + /* 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); \ + /* 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); \ + \ + /* Default Value */ \ + static inline V PFX##_impl_default_value(void) \ + { \ + V _empty_value_; \ + \ + memset(&_empty_value_, 0, sizeof(V)); \ + \ + return _empty_value_; \ + } \ + \ +/* SOURCE ********************************************************************/ +#define SAC_QUEUE_GENERATE_SOURCE(PFX, SNAME, FMOD, V, SIZE) \ + \ + /* Implementation Detail Functions */ \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_); \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_); \ + \ + FMOD SNAME PFX##_new(void) \ + { \ + SNAME result; \ + \ + memset(&result, 0, sizeof(SNAME)); \ + \ + result.it_start = PFX##_impl_it_start; \ + result.it_end = PFX##_impl_it_end; \ + \ + return result; \ + } \ + \ + FMOD void PFX##_clear(SNAME *_queue_) \ + { \ + memset(_queue_->buffer, 0, sizeof(_queue_->buffer)); \ + \ + _queue_->count = 0; \ + _queue_->front = 0; \ + _queue_->rear = 0; \ + } \ + \ + FMOD bool PFX##_enqueue(SNAME *_queue_, V element) \ + { \ + if (PFX##_full(_queue_)) \ + return false; \ + \ + _queue_->buffer[_queue_->rear] = element; \ + \ + _queue_->rear = (_queue_->rear == SIZE - 1) ? 0 : _queue_->rear + 1; \ + _queue_->count++; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_dequeue(SNAME *_queue_) \ + { \ + if (PFX##_empty(_queue_)) \ + return false; \ + \ + _queue_->buffer[_queue_->front] = PFX##_impl_default_value(); \ + \ + _queue_->front = (_queue_->front == SIZE - 1) ? 0 : _queue_->front + 1; \ + _queue_->count--; \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_enqueue_if(SNAME *_queue_, V element, bool condition) \ + { \ + if (condition) \ + return PFX##_enqueue(_queue_, element); \ + \ + return false; \ + } \ + \ + FMOD bool PFX##_dequeue_if(SNAME *_queue_, bool condition) \ + { \ + if (condition) \ + return PFX##_dequeue(_queue_); \ + \ + return false; \ + } \ + \ + FMOD V PFX##_peek(SNAME *_queue_) \ + { \ + if (PFX##_empty(_queue_)) \ + PFX##_impl_default_value(); \ + \ + return _queue_->buffer[_queue_->front]; \ + } \ + \ + FMOD bool PFX##_contains(SNAME *_queue_, V element, int (*comparator)(V, V)) \ + { \ + for (size_t i = _queue_->front, j = 0; j < _queue_->count; i = (i + 1) % _queue_->count, j++) \ + { \ + if (comparator(_queue_->buffer[i], element) == 0) \ + return true; \ + } \ + \ + return false; \ + } \ + \ + FMOD bool PFX##_empty(SNAME *_queue_) \ + { \ + return _queue_->count == 0; \ + } \ + \ + FMOD bool PFX##_full(SNAME *_queue_) \ + { \ + return _queue_->count >= SIZE; \ + } \ + \ + FMOD size_t PFX##_count(SNAME *_queue_) \ + { \ + return _queue_->count; \ + } \ + \ + FMOD size_t PFX##_capacity(void) \ + { \ + return SIZE; \ + } \ + \ + FMOD void PFX##_iter_init(SNAME##_iter *iter, SNAME *target) \ + { \ + iter->target = target; \ + iter->cursor = target->front; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(target); \ + } \ + \ + FMOD bool PFX##_iter_start(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->start; \ + } \ + \ + FMOD bool PFX##_iter_end(SNAME##_iter *iter) \ + { \ + return PFX##_empty(iter->target) || iter->end; \ + } \ + \ + FMOD void PFX##_iter_to_start(SNAME##_iter *iter) \ + { \ + iter->cursor = iter->target->front; \ + iter->index = 0; \ + iter->start = true; \ + iter->end = PFX##_empty(iter->target); \ + } \ + \ + FMOD void PFX##_iter_to_end(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + iter->cursor = 0; \ + else \ + iter->cursor = (iter->target->rear == 0) ? SIZE - 1 : iter->target->rear - 1; \ + \ + iter->index = iter->target->count - 1; \ + iter->start = PFX##_empty(iter->target); \ + iter->end = true; \ + } \ + \ + FMOD bool PFX##_iter_next(SNAME##_iter *iter) \ + { \ + if (iter->end) \ + return false; \ + \ + iter->start = PFX##_empty(iter->target); \ + \ + if (iter->index == iter->target->count - 1) \ + iter->end = true; \ + else \ + { \ + iter->cursor = (iter->cursor + 1) % (SIZE); \ + iter->index++; \ + } \ + \ + return true; \ + } \ + \ + FMOD bool PFX##_iter_prev(SNAME##_iter *iter) \ + { \ + if (iter->start) \ + return false; \ + \ + iter->end = PFX##_empty(iter->target); \ + \ + if (iter->index == 0) \ + iter->start = true; \ + else \ + { \ + iter->cursor = (iter->cursor == 0) ? SIZE - 1 : iter->cursor - 1; \ + iter->index--; \ + } \ + \ + return true; \ + } \ + \ + FMOD V PFX##_iter_value(SNAME##_iter *iter) \ + { \ + if (PFX##_empty(iter->target)) \ + PFX##_impl_default_value(); \ + \ + 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->index; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_start(SNAME *_queue_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _queue_); \ + PFX##_iter_to_start(&iter); \ + \ + return iter; \ + } \ + \ + static SNAME##_iter PFX##_impl_it_end(SNAME *_queue_) \ + { \ + SNAME##_iter iter; \ + \ + PFX##_iter_init(&iter, _queue_); \ + PFX##_iter_to_end(&iter); \ + \ + return iter; \ + } + +#endif /* CMC_SAC_QUEUE_H */ diff --git a/src/sac/stack.h b/src/sac/stack.h index a8f3425..402cd95 100644 --- a/src/sac/stack.h +++ b/src/sac/stack.h @@ -79,7 +79,6 @@ /* Collection Allocation and Deallocation */ \ FMOD SNAME PFX##_new(void); \ 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_); \ @@ -142,17 +141,11 @@ \ FMOD void PFX##_clear(SNAME *_stack_) \ { \ - memset(_stack_->buffer, 0, sizeof(V) * SIZE); \ + memset(_stack_->buffer, 0, sizeof(_stack_->buffer)); \ \ _stack_->count = 0; \ } \ \ - FMOD void PFX##_free(SNAME *_stack_) \ - { \ - free(_stack_->buffer); \ - free(_stack_); \ - } \ - \ FMOD bool PFX##_push(SNAME *_stack_, V element) \ { \ if (PFX##_full(_stack_)) \ diff --git a/benchmarks/util/timer.h b/src/utl/timer.h similarity index 81% rename from benchmarks/util/timer.h rename to src/utl/timer.h index 07858c6..583000c 100644 --- a/benchmarks/util/timer.h +++ b/src/utl/timer.h @@ -6,8 +6,13 @@ * Authors: * Leonardo Vencovsky (https://github.com/LeoVen) * - * Simple timer macros. */ + +/* Simple timer macros utility */ + +#ifndef CMC_TIMER_H +#define CMC_TIMER_H + #include typedef struct timer_s @@ -25,3 +30,5 @@ typedef struct timer_s #define TIMER_CALC(timer) \ timer.result = (double)(((timer.stop - timer.start) * 1000.0) / CLOCKS_PER_SEC); + +#endif /* CMC_TIMER_H */