From f25dd06062a7b7a1ad055b13f0f8f6dc4d4f7e55 Mon Sep 17 00:00:00 2001 From: Felipe Lavratti Date: Sat, 11 Feb 2017 23:49:08 -0200 Subject: [PATCH] Finished release --- fl-lib.h | 293 ++++++++++++++++++++++++++++ fl-lib.hpp | 385 +++++++++++++++++++++++++++++++++++++ headers/Makefile | 44 +++-- headers/macro_offsetof.h | 2 +- headers/macro_sizeof.h | 2 + headers/macro_typeof.hpp | 6 - headers/time.h | 19 +- tests/Makefile | 12 +- tests/test_c_wrapper.cpp | 25 +++ tests/test_from_c_code.c | 87 +++++++++ tests/test_linked_list.cpp | 251 ++++++++++++++++++++++++ tests/test_macros.cpp | 32 +++ tests/test_ring_fifo.cpp | 4 +- tests/test_time.cpp | 91 +++++++++ 14 files changed, 1220 insertions(+), 33 deletions(-) create mode 100644 fl-lib.hpp create mode 100644 headers/macro_sizeof.h create mode 100644 tests/test_c_wrapper.cpp create mode 100644 tests/test_from_c_code.c create mode 100644 tests/test_linked_list.cpp create mode 100644 tests/test_macros.cpp create mode 100644 tests/test_time.cpp diff --git a/fl-lib.h b/fl-lib.h index 4737f24..e87ed31 100644 --- a/fl-lib.h +++ b/fl-lib.h @@ -5,6 +5,46 @@ #include #include +#define fl_typeof(___zarg) typeof(___zarg) + +#define fl_auto_type(___zcxzzarg) fl_typeof(___zcxzzarg) + +#include +#define fl_offsetof(___j1h3oi1bob,___j1h3oi1bob2) offsetof(___j1h3oi1bob,___j1h3oi1bob2) + +#define fl_container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - fl_offsetof(type,member) );}) + +#define FL_BUILD_BUG_ON_ZERO(e) \ + (sizeof(struct { int:-!!(e)*1234; })) + +#if defined(__GNUC__) && defined(__GNUC_MINOR__) + #define FL_GNUC_VERSION \ + (__GNUC__ << 16) + __GNUC_MINOR__ + #define FL_GNUC_PREREQ(maj, min) \ + (FL_GNUC_VERSION >= ((maj) << 16) + (min)) +#else + #define FL_GNUC_PREREQ(maj, min) 0 +#endif + +#include +#define fl_sizeof(___j1h32314141) sizeof(___j1h32314141) + +#if FL_GNUC_PREREQ(3, 1) +#define FL_SAME_TYPE(a, b) \ + __builtin_types_compatible_p(fl_typeof(a), fl_typeof(b)) +#define FL_MUST_BE_ARRAY(a) \ + FL_BUILD_BUG_ON_ZERO(FL_SAME_TYPE((a), &(*a))) +#else +#define FL_MUST_BE_ARRAY(a) \ + FL_BUILD_BUG_ON_ZERO(fl_sizeof(a) % fl_sizeof(*a)) +#endif + +#define FL_ARRAY_SIZE(a) ( \ + (fl_sizeof(a) / fl_sizeof(*a)) \ + + FL_MUST_BE_ARRAY(a)) + typedef struct fl_struct_ring_fifo_private { size_t mask; size_t wrIdx; @@ -85,4 +125,257 @@ static inline size_t fl_ring_fifo_count(fl_ring_fifo_t * obj) return obj->mask & (obj->wrIdx - obj->rdIdx); } +struct fl_struct_linked_list_head +{ + struct fl_struct_linked_list_head * next; + struct fl_struct_linked_list_head * prev; +}; + +typedef struct fl_struct_linked_list_head fl_linked_list_t; + +/** + * Initialize a fl_linked_list_t within structure + * @param + */ +#define fl_linked_list_init(structure, field) \ +({ \ + fl_auto_type(structure) ___str = structure; \ + if (___str) {\ + ___str->field.next = (fl_linked_list_t *)0;\ + ___str->field.prev = (fl_linked_list_t *)0;\ + } \ +}) + +/** + * Get the number of nodes of the list. + * + * @param ptr_to_current + * @return Pointer to the last node of the list, including ptr_to_current. + */ +#define fl_linked_list_count(ptr_to_current, field) \ +({ \ + int ___ret = 0; \ + fl_auto_type(ptr_to_current) ___cur = fl_linked_list_first(ptr_to_current, field); fl_linked_list_t * ___head;\ + if (___cur) ___ret++; \ + if (___ret) \ + { \ + ___head = &___cur->field; \ + if (___head->next) { while (___head->next){ ___head = ___head->next; ___ret++;}} \ + } \ + ___ret; \ +}) + + +/** + * Get the next node. + * @param ptr_to_current + * @return Pointer to the next node. + */ +#define fl_linked_list_next(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret) \ + { \ + ___head = ___ret->field.next; \ + if (___head) { ___ret = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); }\ + else {___ret = 0; } \ + } \ + ___ret; \ +}) + +/** + * Get the previous node. + * @param ptr_to_current + * @return Pointer to the previous node. + */ +#define fl_linked_list_previous(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret) \ + { \ + ___head = ___ret->field.prev; \ + if (___head) { ___ret = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); }\ + else {___ret = 0; } \ + } \ + ___ret; \ +}) + +/** + * Get the last node of the list, including ptr_to_current. + * + * @param ptr_to_current + * @return Pointer to the last node of the list, including ptr_to_current. + */ +#define fl_linked_list_last(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret) \ + { \ + ___head = &___ret->field; \ + if (___head->next) { while (___head->next) ___head = ___head->next;} \ + if (___head) { ___ret = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); } \ + else {___ret = 0; } \ + } \ + ___ret; \ +}) + +/** + * Get the first node of the list, including ptr_to_current. + * + * @param ptr_to_current + * @return Pointer to the first node of the list, including ptr_to_current. + */ +#define fl_linked_list_first(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret2 = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret2) \ + { \ + ___head = &___ret2->field; \ + if (___head->prev) { while (___head->prev) ___head = ___head->prev;} \ + if (___head) { ___ret2 = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); } \ + else {___ret2 = 0; } \ + } \ + ___ret2; \ +}) + +/** + * Insert new node between current and current's next. + * + * @param ptr_to_current + * @param ptr_to_new + */ +#define fl_linked_list_insert_after(ptr_to_current, ptr_to_new, field) \ +({ \ + fl_auto_type(ptr_to_current) ___curr = ptr_to_current; \ + fl_auto_type(ptr_to_new) ___new = ptr_to_new; \ + if (___curr && ___new) \ + { \ + ___new->field.next = ___curr->field.next; \ + ___new->field.prev = &___curr->field; \ + if (___curr->field.next) ___curr->field.next->prev = &___new->field; \ + ___curr->field.next = &___new->field; \ + } \ +}) + +/** + * Insert new node between current and current's previous. + * + * @param ptr_to_current + * @param ptr_to_new + */ +#define fl_linked_list_insert_before(ptr_to_current, ptr_to_new, field) \ +({ \ + fl_auto_type(ptr_to_current) ___curr = ptr_to_current; \ + fl_auto_type(ptr_to_new) ___new = ptr_to_new; \ + if (___curr && ___new) \ + { \ + ___new->field.prev = ___curr->field.prev; \ + ___new->field.next = &___curr->field; \ + if(___curr->field.prev) ___curr->field.prev->next = &___new->field; \ + ___curr->field.prev = &___new->field; \ + } \ +}) + +/** + * Remove the current node and return it. + * + * @param current + * @return Return the new or old beginning of the list. + */ +#define fl_linked_list_remove(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___cur = ptr_to_current; \ + fl_auto_type(ptr_to_current) ___ret = (fl_typeof(ptr_to_current))0; \ + fl_linked_list_t * ___head_next = (fl_linked_list_t*)0; \ + fl_linked_list_t * ___head_prev = (fl_linked_list_t*)0; \ + if (___cur) \ + { \ + ___head_next = ___cur->field.next; \ + ___head_prev = ___cur->field.prev; \ + if (___head_prev) ___head_prev->next = ___head_next; \ + if (___head_next) ___head_next->prev = ___head_prev; \ + fl_linked_list_init(___cur, field); \ + if (___head_prev) ___ret = fl_linked_list_first(fl_container_of(___head_prev, fl_typeof(*(ptr_to_current)), field), field); \ + else if(___head_next) ___ret = fl_linked_list_first(fl_container_of(___head_next, fl_typeof(*(ptr_to_current)), field), field); \ + } \ + ___ret; \ +}) + +/** + * Free all list members, + * but instead calling free itself, this function calls + * user free function passed on free_callback. + * + * @param ptr_to_current + * + * @warning + * Any pointer to the a list node will be invalid. + */ +#define fl_linked_list_free(ptr_to_current, field, free_callback) \ +({ \ + fl_auto_type(ptr_to_current) ___item = fl_linked_list_first(ptr_to_current, field); \ + fl_typeof(___item) ___item_to_delete; \ + while (___item) \ + { \ + ___item_to_delete = ___item; \ + ___item = fl_linked_list_next(___item_to_delete, field); \ + free_callback(___item_to_delete); \ + } \ +}) + +/** + */ +#define fl_linked_list_find(ptr_to_current, field, comparator_func, comparator_seed) \ +({ \ + fl_auto_type(ptr_to_current) ___item = ptr_to_current; \ + while (___item) \ + { \ + if (comparator_func(comparator_seed, ___item) == true) break; \ + ___item = fl_linked_list_next(___item, field); \ + } \ + ___item; \ +}) + +#ifdef FL_ENABLE_TIME_MODULE + + #ifndef FL_TIME_TYPE + #error "You must define `FL_TIME_TYPE` with a unsigned integer type such as `uint32_t`, `uin64_t`, etc. " + #endif + + typedef FL_TIME_TYPE fl_time_t; + + /* This is a elapsed time checker that protects against wrap around. + Now must always be (physically) bigger than before.*/ + static inline bool fl_time_check_elapsed(fl_time_t now, fl_time_t before, fl_time_t desired_wait) + { + return (now - before) >= desired_wait; + } + + #ifdef FL_TIME_INT_TYPE + /* Return the remaining time to timeout expiration.*/ + static inline FL_TIME_INT_TYPE fl_time_remaining(fl_time_t now, fl_time_t before, fl_time_t desired_wait) + { + return (FL_TIME_INT_TYPE)desired_wait - (FL_TIME_INT_TYPE)(now - before); + } + #endif + + /* This is a reached time checker that protects against wrap around. + It checks if now has reached timestamp. Timestamp must always be bigger than + now when first stored. */ + static inline bool fl_time_check_reached(fl_time_t timestamp, fl_time_t now) + { + /* First we subtract from timestamp a stupid_big_number, + to create a "before" number. + Then we use a stupid_big_number as the elapsed variable + to the check_elapsed function. */ + + const fl_time_t max = (fl_time_t)-1; + const fl_time_t stupid_big_number = (max/2) + 1; + fl_time_t before = timestamp - stupid_big_number; + + return fl_time_check_elapsed(now, before, stupid_big_number); + } + +#endif /* FL_ENABLE_TIME_MODULE */ + #endif /* _FL_LIB_H_ */ diff --git a/fl-lib.hpp b/fl-lib.hpp new file mode 100644 index 0000000..89e76ea --- /dev/null +++ b/fl-lib.hpp @@ -0,0 +1,385 @@ +#ifndef _FL_LIB_HPP_ +#define _FL_LIB_HPP_ + +#include +#include +#include + +#include +#include + +#define fl_auto_type(___zcxzzarg) auto +#define fl_typeof(___zarg) std::remove_reference::type + +#define fl_auto_type(___zcxzzarg) auto + +template +size_t fl_offsetof(const M P::*member) +{ + return (size_t) &( reinterpret_cast(0)->*member); +} + +template +P* fl_container_of_impl(M* ptr, const M P::*member) +{ + return (P*)( (char*)ptr - fl_offsetof(member)); +} + +#define fl_container_of(ptr, type, member) \ + fl_container_of_impl (ptr, &type::member) + +#define FL_BUILD_BUG_ON_ZERO(e) \ + (sizeof(struct { int:-!!(e)*1234; })) + +#if defined(__GNUC__) && defined(__GNUC_MINOR__) + #define FL_GNUC_VERSION \ + (__GNUC__ << 16) + __GNUC_MINOR__ + #define FL_GNUC_PREREQ(maj, min) \ + (FL_GNUC_VERSION >= ((maj) << 16) + (min)) +#else + #define FL_GNUC_PREREQ(maj, min) 0 +#endif + +#include +#define fl_sizeof(___j1h32314141) sizeof(___j1h32314141) + +template +char ( &FL_ARRAY_SIZE_HELPER( T (&array)[N] ))[N]; + +#define FL_ARRAY_SIZE( array ) \ + (sizeof( FL_ARRAY_SIZE_HELPER( array ) )) + +typedef struct fl_struct_ring_fifo_private { + size_t mask; + size_t wrIdx; + size_t rdIdx; +} fl_ring_fifo_t; + +/* + * num_of_slots must be base of two, i.e. 2, 4, 8, 16, 32, 64, ... + */ +static inline int fl_ring_fifo_init(fl_ring_fifo_t * obj, size_t num_of_slots) +{ + size_t pre_mask = (SIZE_MAX >> 1) + 1; + + while (pre_mask) + { + if (num_of_slots & pre_mask) { + break; + } + + pre_mask >>= 1; + } + + if (pre_mask <= 1) { + obj->mask = 0; + return -1; + } + + obj->mask = pre_mask - 1; + obj->rdIdx = 0; + obj->wrIdx = 0; + + return (int)pre_mask; +} + +static inline size_t fl_ring_fifo_num_of_slots(fl_ring_fifo_t * obj) +{ + return obj->mask + 1; +} + +static inline size_t fl_ring_fifo_write_index(fl_ring_fifo_t * obj) +{ + return obj->mask & obj->wrIdx; +} + +static inline size_t fl_ring_fifo_read_index(fl_ring_fifo_t * obj) +{ + return obj->mask & obj->rdIdx; +} + +static inline void fl_ring_fifo_write_increment(fl_ring_fifo_t * obj) +{ + obj->wrIdx++; +} + +static inline void fl_ring_fifo_read_increment(fl_ring_fifo_t * obj) +{ + obj->rdIdx++; +} + +static inline void fl_ring_fifo_read_reset(fl_ring_fifo_t * obj) +{ + obj->rdIdx = 0; + obj->wrIdx = 0; +} + +static inline bool fl_ring_fifo_empty(fl_ring_fifo_t * obj) +{ + return obj->rdIdx == obj->wrIdx; +} + +static inline bool fl_ring_fifo_full(fl_ring_fifo_t * obj) +{ + return (obj->mask & obj->rdIdx) == (obj->mask & (obj->wrIdx+1)); +} + +static inline size_t fl_ring_fifo_count(fl_ring_fifo_t * obj) +{ + return obj->mask & (obj->wrIdx - obj->rdIdx); +} + +struct fl_struct_linked_list_head +{ + struct fl_struct_linked_list_head * next; + struct fl_struct_linked_list_head * prev; +}; + +typedef struct fl_struct_linked_list_head fl_linked_list_t; + +/** + * Initialize a fl_linked_list_t within structure + * @param + */ +#define fl_linked_list_init(structure, field) \ +({ \ + fl_auto_type(structure) ___str = structure; \ + if (___str) {\ + ___str->field.next = (fl_linked_list_t *)0;\ + ___str->field.prev = (fl_linked_list_t *)0;\ + } \ +}) + +/** + * Get the number of nodes of the list. + * + * @param ptr_to_current + * @return Pointer to the last node of the list, including ptr_to_current. + */ +#define fl_linked_list_count(ptr_to_current, field) \ +({ \ + int ___ret = 0; \ + fl_auto_type(ptr_to_current) ___cur = fl_linked_list_first(ptr_to_current, field); fl_linked_list_t * ___head;\ + if (___cur) ___ret++; \ + if (___ret) \ + { \ + ___head = &___cur->field; \ + if (___head->next) { while (___head->next){ ___head = ___head->next; ___ret++;}} \ + } \ + ___ret; \ +}) + + +/** + * Get the next node. + * @param ptr_to_current + * @return Pointer to the next node. + */ +#define fl_linked_list_next(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret) \ + { \ + ___head = ___ret->field.next; \ + if (___head) { ___ret = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); }\ + else {___ret = 0; } \ + } \ + ___ret; \ +}) + +/** + * Get the previous node. + * @param ptr_to_current + * @return Pointer to the previous node. + */ +#define fl_linked_list_previous(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret) \ + { \ + ___head = ___ret->field.prev; \ + if (___head) { ___ret = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); }\ + else {___ret = 0; } \ + } \ + ___ret; \ +}) + +/** + * Get the last node of the list, including ptr_to_current. + * + * @param ptr_to_current + * @return Pointer to the last node of the list, including ptr_to_current. + */ +#define fl_linked_list_last(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret) \ + { \ + ___head = &___ret->field; \ + if (___head->next) { while (___head->next) ___head = ___head->next;} \ + if (___head) { ___ret = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); } \ + else {___ret = 0; } \ + } \ + ___ret; \ +}) + +/** + * Get the first node of the list, including ptr_to_current. + * + * @param ptr_to_current + * @return Pointer to the first node of the list, including ptr_to_current. + */ +#define fl_linked_list_first(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___ret2 = ptr_to_current; fl_linked_list_t * ___head;\ + if (___ret2) \ + { \ + ___head = &___ret2->field; \ + if (___head->prev) { while (___head->prev) ___head = ___head->prev;} \ + if (___head) { ___ret2 = fl_container_of(___head, fl_typeof(*(ptr_to_current)), field); } \ + else {___ret2 = 0; } \ + } \ + ___ret2; \ +}) + +/** + * Insert new node between current and current's next. + * + * @param ptr_to_current + * @param ptr_to_new + */ +#define fl_linked_list_insert_after(ptr_to_current, ptr_to_new, field) \ +({ \ + fl_auto_type(ptr_to_current) ___curr = ptr_to_current; \ + fl_auto_type(ptr_to_new) ___new = ptr_to_new; \ + if (___curr && ___new) \ + { \ + ___new->field.next = ___curr->field.next; \ + ___new->field.prev = &___curr->field; \ + if (___curr->field.next) ___curr->field.next->prev = &___new->field; \ + ___curr->field.next = &___new->field; \ + } \ +}) + +/** + * Insert new node between current and current's previous. + * + * @param ptr_to_current + * @param ptr_to_new + */ +#define fl_linked_list_insert_before(ptr_to_current, ptr_to_new, field) \ +({ \ + fl_auto_type(ptr_to_current) ___curr = ptr_to_current; \ + fl_auto_type(ptr_to_new) ___new = ptr_to_new; \ + if (___curr && ___new) \ + { \ + ___new->field.prev = ___curr->field.prev; \ + ___new->field.next = &___curr->field; \ + if(___curr->field.prev) ___curr->field.prev->next = &___new->field; \ + ___curr->field.prev = &___new->field; \ + } \ +}) + +/** + * Remove the current node and return it. + * + * @param current + * @return Return the new or old beginning of the list. + */ +#define fl_linked_list_remove(ptr_to_current, field) \ +({ \ + fl_auto_type(ptr_to_current) ___cur = ptr_to_current; \ + fl_auto_type(ptr_to_current) ___ret = (fl_typeof(ptr_to_current))0; \ + fl_linked_list_t * ___head_next = (fl_linked_list_t*)0; \ + fl_linked_list_t * ___head_prev = (fl_linked_list_t*)0; \ + if (___cur) \ + { \ + ___head_next = ___cur->field.next; \ + ___head_prev = ___cur->field.prev; \ + if (___head_prev) ___head_prev->next = ___head_next; \ + if (___head_next) ___head_next->prev = ___head_prev; \ + fl_linked_list_init(___cur, field); \ + if (___head_prev) ___ret = fl_linked_list_first(fl_container_of(___head_prev, fl_typeof(*(ptr_to_current)), field), field); \ + else if(___head_next) ___ret = fl_linked_list_first(fl_container_of(___head_next, fl_typeof(*(ptr_to_current)), field), field); \ + } \ + ___ret; \ +}) + +/** + * Free all list members, + * but instead calling free itself, this function calls + * user free function passed on free_callback. + * + * @param ptr_to_current + * + * @warning + * Any pointer to the a list node will be invalid. + */ +#define fl_linked_list_free(ptr_to_current, field, free_callback) \ +({ \ + fl_auto_type(ptr_to_current) ___item = fl_linked_list_first(ptr_to_current, field); \ + fl_typeof(___item) ___item_to_delete; \ + while (___item) \ + { \ + ___item_to_delete = ___item; \ + ___item = fl_linked_list_next(___item_to_delete, field); \ + free_callback(___item_to_delete); \ + } \ +}) + +/** + */ +#define fl_linked_list_find(ptr_to_current, field, comparator_func, comparator_seed) \ +({ \ + fl_auto_type(ptr_to_current) ___item = ptr_to_current; \ + while (___item) \ + { \ + if (comparator_func(comparator_seed, ___item) == true) break; \ + ___item = fl_linked_list_next(___item, field); \ + } \ + ___item; \ +}) + +#ifdef FL_ENABLE_TIME_MODULE + + #ifndef FL_TIME_TYPE + #error "You must define `FL_TIME_TYPE` with a unsigned integer type such as `uint32_t`, `uin64_t`, etc. " + #endif + + typedef FL_TIME_TYPE fl_time_t; + + /* This is a elapsed time checker that protects against wrap around. + Now must always be (physically) bigger than before.*/ + static inline bool fl_time_check_elapsed(fl_time_t now, fl_time_t before, fl_time_t desired_wait) + { + return (now - before) >= desired_wait; + } + + #ifdef FL_TIME_INT_TYPE + /* Return the remaining time to timeout expiration.*/ + static inline FL_TIME_INT_TYPE fl_time_remaining(fl_time_t now, fl_time_t before, fl_time_t desired_wait) + { + return (FL_TIME_INT_TYPE)desired_wait - (FL_TIME_INT_TYPE)(now - before); + } + #endif + + /* This is a reached time checker that protects against wrap around. + It checks if now has reached timestamp. Timestamp must always be bigger than + now when first stored. */ + static inline bool fl_time_check_reached(fl_time_t timestamp, fl_time_t now) + { + /* First we subtract from timestamp a stupid_big_number, + to create a "before" number. + Then we use a stupid_big_number as the elapsed variable + to the check_elapsed function. */ + + const fl_time_t max = (fl_time_t)-1; + const fl_time_t stupid_big_number = (max/2) + 1; + fl_time_t before = timestamp - stupid_big_number; + + return fl_time_check_elapsed(now, before, stupid_big_number); + } + +#endif /* FL_ENABLE_TIME_MODULE */ + +#endif /* _FL_LIB_HPP_ */ diff --git a/headers/Makefile b/headers/Makefile index d3cc450..e2f9a92 100644 --- a/headers/Makefile +++ b/headers/Makefile @@ -1,13 +1,25 @@ .phony: all -output =../fl-lib.h +output_h =../fl-lib.h +output_hpp =../fl-lib.hpp headers = \ includes.h \ - ring_fifo.h + macro_typeof.hXX \ + macro_auto_type.hXX \ + macro_offsetof.hXX \ + macro_container_of.hXX \ + macro_build_bug_on_zero.h \ + macro_gnuc_prereq.h \ + macro_sizeof.h \ + macro_array_size.hXX \ + ring_fifo.h \ + linked_list.h \ + time.h \ -processed_headers = $(foreach f, $(headers), $(f) .tmp_file ) +processed_headers_h = $(subst .hXX,.h,$(foreach f, $(headers), $(f) .tmp_file )) +processed_headers_hpp = $(subst .hXX,.hpp,$(foreach f, $(headers), $(f) .tmp_file )) -all: $(output) +all: $(output_h) $(output_hpp) rm_tmp_file clean: @rm -f $(output) @@ -15,11 +27,21 @@ clean: .tmp_file: @echo "" > .tmp_file -$(output): $(processed_headers) - @echo "#ifndef _FL_LIB_H_" > $(output) - @echo "#define _FL_LIB_H_" >> $(output) - @echo "" >> $(output) - @cat $(processed_headers) >> $(output) - @echo "#endif /* _FL_LIB_H_ */" >> $(output) +rm_tmp_file: @rm .tmp_file - @echo "Generated $(output)." + +$(output_h): $(processed_headers_h) + @echo "#ifndef _FL_LIB_H_" > $@ + @echo "#define _FL_LIB_H_" >> $@ + @echo "" >> $@ + @cat $(processed_headers_h) >> $@ + @echo "#endif /* _FL_LIB_H_ */" >> $@ + @echo "Generated $@." + +$(output_hpp): $(processed_headers_hpp) + @echo "#ifndef _FL_LIB_HPP_" > $@ + @echo "#define _FL_LIB_HPP_" >> $@ + @echo "" >> $@ + @cat $(processed_headers_hpp) >> $@ + @echo "#endif /* _FL_LIB_HPP_ */" >> $@ + @echo "Generated $@." diff --git a/headers/macro_offsetof.h b/headers/macro_offsetof.h index d864778..08a19b6 100644 --- a/headers/macro_offsetof.h +++ b/headers/macro_offsetof.h @@ -1,2 +1,2 @@ #include -#define fl_offsetof(___j1h3oi1bob) offsetof(___j1h3oi1bob) +#define fl_offsetof(___j1h3oi1bob,___j1h3oi1bob2) offsetof(___j1h3oi1bob,___j1h3oi1bob2) diff --git a/headers/macro_sizeof.h b/headers/macro_sizeof.h new file mode 100644 index 0000000..93d6705 --- /dev/null +++ b/headers/macro_sizeof.h @@ -0,0 +1,2 @@ +#include +#define fl_sizeof(___j1h32314141) sizeof(___j1h32314141) diff --git a/headers/macro_typeof.hpp b/headers/macro_typeof.hpp index b1d419a..46aa0a1 100644 --- a/headers/macro_typeof.hpp +++ b/headers/macro_typeof.hpp @@ -3,9 +3,3 @@ #define fl_auto_type(___zcxzzarg) auto #define fl_typeof(___zarg) std::remove_reference::type - -template -size_t fl_offsetof(const M P::*member) -{ - return (size_t) &( reinterpret_cast(0)->*member); -} diff --git a/headers/time.h b/headers/time.h index a50d389..2a52e6e 100644 --- a/headers/time.h +++ b/headers/time.h @@ -4,6 +4,8 @@ #error "You must define `FL_TIME_TYPE` with a unsigned integer type such as `uint32_t`, `uin64_t`, etc. " #endif + typedef FL_TIME_TYPE fl_time_t; + /* This is a elapsed time checker that protects against wrap around. Now must always be (physically) bigger than before.*/ static inline bool fl_time_check_elapsed(fl_time_t now, fl_time_t before, fl_time_t desired_wait) @@ -11,14 +13,13 @@ return (now - before) >= desired_wait; } - /* Return the remaining time to timeout expiration.*/ - static inline fl_time_t fl_time_remaining(fl_time_t now, fl_time_t before, fl_time_t desired_wait) - { - if (fl_time_check_elapsed(now, before, desired_wait - 1)) - return 0; - - return desired_wait - (now - before); - } + #ifdef FL_TIME_INT_TYPE + /* Return the remaining time to timeout expiration.*/ + static inline FL_TIME_INT_TYPE fl_time_remaining(fl_time_t now, fl_time_t before, fl_time_t desired_wait) + { + return (FL_TIME_INT_TYPE)desired_wait - (FL_TIME_INT_TYPE)(now - before); + } + #endif /* This is a reached time checker that protects against wrap around. It checks if now has reached timestamp. Timestamp must always be bigger than @@ -29,7 +30,7 @@ to create a "before" number. Then we use a stupid_big_number as the elapsed variable to the check_elapsed function. */ - + const fl_time_t max = (fl_time_t)-1; const fl_time_t stupid_big_number = (max/2) + 1; fl_time_t before = timestamp - stupid_big_number; diff --git a/tests/Makefile b/tests/Makefile index f93784d..48bae62 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,13 +3,17 @@ output = fl-lib-tests cpp_sources = \ main.cpp \ + test_c_wrapper.cpp \ + test_macros.cpp \ test_ring_fifo.cpp \ + test_linked_list.cpp \ + test_time.cpp \ c_sources = \ -# test_c.c + test_from_c_code.c \ -cpp_flags = -I ../ -Wall -c_flags = -I ../ -Wall +cpp_flags = -I ../ -Wall -std=gnu++14 +c_flags = -I ../ -Wall -std=gnu11 cpp_objs = $(patsubst %.cpp,%.o,$(cpp_sources)) c_objs = $(patsubst %.c,%.o,$(c_sources)) @@ -23,7 +27,7 @@ clean: gcc -c $(c_flags) -o $@ $^ %.o: %.cpp - g++ -c $(c_flags) -o $@ $^ + g++ -c $(cpp_flags) -o $@ $^ $(output): $(c_objs) $(cpp_objs) g++ $(ld_flags) -o $(output) $^ diff --git a/tests/test_c_wrapper.cpp b/tests/test_c_wrapper.cpp new file mode 100644 index 0000000..2612dcc --- /dev/null +++ b/tests/test_c_wrapper.cpp @@ -0,0 +1,25 @@ +#include "catch.hpp" + +extern "C" { + + void check (bool assert, const char * error) { + if (!assert) FAIL(error); + } + + void test_auto_type (void (*checkfunc)(bool, const char *)); + void test_container_of (void (*checkfunc)(bool, const char *)); + void test_array_size (void (*checkfunc)(bool, const char *)); + void test_linked_list (void (*checkfunc)(bool, const char *)); + void test_ring_fifo (void (*checkfunc)(bool, const char *)); +} + +#define A_C_TEST(func_name) SECTION(#func_name) {func_name(check);} + +TEST_CASE ("c_code: C Wrapper test group") +{ + A_C_TEST(test_auto_type); + A_C_TEST(test_container_of); + A_C_TEST(test_array_size); + A_C_TEST(test_linked_list); + A_C_TEST(test_ring_fifo); +} diff --git a/tests/test_from_c_code.c b/tests/test_from_c_code.c new file mode 100644 index 0000000..c8def5d --- /dev/null +++ b/tests/test_from_c_code.c @@ -0,0 +1,87 @@ +#include +#include +#include + +#define CHECK(__condition) checkfunc (__condition, #__condition) +#define CHECK_EQUAL(__expected, __actual) CHECK(__expected==__actual) + +void test_auto_type (void (*checkfunc)(bool, const char *)) +{ + const char * t; + fl_auto_type(t) s = "blablabla"; + CHECK(strcmp(s, "blablabla") == 0); +} + +void test_container_of (void (*checkfunc)(bool, const char *)) +{ + struct s_container { + int a, b, c; + char d; + char t; + int z; + } container; + + CHECK(&container == fl_container_of (&container.t, struct s_container, t)); +} + +void test_array_size (void (*checkfunc)(bool, const char *)) +{ + const char s[] = "blablabla"; + CHECK(FL_ARRAY_SIZE(s) == 10); +} + +void test_linked_list (void (*checkfunc)(bool, const char *)) +{ + struct test_t + { + uint8_t b1; + fl_linked_list_t h; + uint8_t b2; + }; + typedef struct test_t test_t; + + test_t * root = NULL; + test_t cut = {0xAA, {0, 0}, 0x55}; + + fl_linked_list_init(&cut, h); + CHECK_EQUAL(0, cut.h.next); + CHECK_EQUAL(0, cut.h.prev); + + test_t cuts[10]; + root = &cut; + + for (int i = 0; i<10; i++) + fl_linked_list_init(&cuts[i], h); + fl_linked_list_init(root, h); + + CHECK_EQUAL(root, fl_linked_list_last(root, h)); + + for (int i = 0; i<10; i++) + fl_linked_list_insert_after( + fl_linked_list_last(root, h), + &cuts[i], + h); + + CHECK_EQUAL(11, fl_linked_list_count(root, h)); +} + +void test_ring_fifo (void (*checkfunc)(bool, const char *)) +{ + fl_ring_fifo_t cut; + int sz; + + sz = fl_ring_fifo_init(&cut, 0); + CHECK (-1 == sz); + + sz = fl_ring_fifo_init(&cut, 1); + CHECK (-1 == sz); + + sz = fl_ring_fifo_init(&cut, 2); + CHECK (2 == sz); + + sz = fl_ring_fifo_init(&cut, 3); + CHECK (2 == sz); + + sz = fl_ring_fifo_init(&cut, 4); + CHECK (4 == sz); +} diff --git a/tests/test_linked_list.cpp b/tests/test_linked_list.cpp new file mode 100644 index 0000000..f0f9a7f --- /dev/null +++ b/tests/test_linked_list.cpp @@ -0,0 +1,251 @@ +#include "catch.hpp" +#include + +#define CHECK_EQUAL(___a,___b) CHECK(___a == ___b) + +struct test_t +{ + uint8_t b1; + fl_linked_list_t h; + uint8_t b2; +}; + +static bool compare (test_t * element, test_t * seed) +{ + return element == seed; +} + +static void freefunc (test_t * element) +{ + element->b1 = 0xF1; +} + +TEST_CASE ("fl_linked_list api only") +{ + test_t * root; + test_t cut; + + root = NULL; + cut = {0xAA, {0, 0}, 0x55}; + + SECTION ("initialization") + { + fl_linked_list_init(&cut, h); + CHECK_EQUAL(0, cut.h.next); + CHECK_EQUAL(0, cut.h.prev); + } + + SECTION ("tests with multiple entries using insert_after") + { + test_t cuts[10]; + root = &cut; + + for (int i = 0; i<10; i++) + fl_linked_list_init(&cuts[i], h); + fl_linked_list_init(root, h); + + CHECK_EQUAL(root, fl_linked_list_last(root, h)); + + for (int i = 0; i<10; i++) + fl_linked_list_insert_after( + fl_linked_list_last(root, h), + &cuts[i], + h); + + CHECK_EQUAL(11, fl_linked_list_count(root, h)); + + SECTION ("test insertions and end of list") + { + test_t * p = root; + for (int i = 0; i<10; i++) + { + p = fl_linked_list_next(p, h); + CHECK_EQUAL(&cuts[i], p); + } + + p = fl_linked_list_next(p, h); + CHECK_EQUAL(0, p); + } + + SECTION ("remove one from the middle") + { + root = fl_linked_list_remove(&cuts[4], h); + test_t * p = root; + for (int i = 0; i<10; i++) + { + if (i == 4) continue; + p = fl_linked_list_next(p, h); + CHECK_EQUAL(&cuts[i], p); + } + + p = fl_linked_list_next(p, h); + CHECK_EQUAL(0, p); + } + + SECTION ("remove the first") + { + /* Root relocation */ + root = fl_linked_list_remove(root, h); + CHECK_EQUAL(root, &cuts[0]); + + test_t * p = &cuts[9]; + for (int i = 9; i>=0; i--) + { + CHECK_EQUAL(&cuts[i], p); + p = fl_linked_list_previous(p, h); + } + + CHECK_EQUAL(0, p); + } + + SECTION ("traverse reverse") + { + test_t * p = &cuts[9]; + for (int i = 9; i>=0; i--) + { + CHECK_EQUAL(&cuts[i], p); + p = fl_linked_list_previous(p, h); + } + CHECK_EQUAL(root, p); + } + + SECTION ("find") + { + CHECK_EQUAL(&cuts[9], fl_linked_list_find(root, h, compare, &cuts[9])); + } + + SECTION ("free") + { + fl_linked_list_free(root, h, freefunc); + + for (int i = 0; i<10; i++) + { + CHECK_EQUAL(0xF1, cuts[i].b1); + cuts[i].b1 = 0xAA; + } + + CHECK_EQUAL(0xF1, root->b1); + root->b1 = 0xAA; + } + } + + SECTION ("tests with multiple entries using insert_before for reverse order") + { + test_t cuts[10]; + root = &cut; + + for (int i = 0; i<10; i++) + fl_linked_list_init(&cuts[i], h); + fl_linked_list_init(root, h); + + CHECK_EQUAL(root, fl_linked_list_last(root, h)); + + for (int i = 0; i<10; i++) + fl_linked_list_insert_before( + fl_linked_list_first(root, h), + &cuts[i], + h); + + /* root is the last node */ + CHECK_EQUAL(11, fl_linked_list_count(root, h)); + + SECTION ("list in reverse order") + { + test_t * p = fl_linked_list_first(root, h); + for (int i = 9; i>=0; i--) + { + CHECK_EQUAL(&cuts[i], p); + p = fl_linked_list_next(p, h); + } + + CHECK_EQUAL(root, p); + } + } + + SECTION ("remove the only one") + { + root = &cut; + + fl_linked_list_init(root, h); + CHECK_EQUAL(root, fl_linked_list_last(root, h)); + + root = fl_linked_list_remove(root, h); + CHECK_EQUAL(0, root); + } + + + SECTION ("remove not inserted") + { + test_t not_inserted; + fl_linked_list_init(¬_inserted, h); + CHECK_EQUAL(0, fl_linked_list_remove(¬_inserted, h)); + } + + CHECK_EQUAL(0xAA, cut.b1); + CHECK_EQUAL(0x55, cut.b2); +} + +TEST_CASE ("fl_linked_list internals") +{ + struct s { + fl_linked_list_t ll; + } d0, d1, d2, d3, d4, * r; + + fl_linked_list_init(&d0, ll); + fl_linked_list_init(&d1, ll); + fl_linked_list_init(&d2, ll); + fl_linked_list_init(&d3, ll); + fl_linked_list_init(&d4, ll); + + r = &d0; + CHECK_EQUAL(&d0, r); + + SECTION ("check next and prev pointers after some insertions") + { + fl_linked_list_insert_after(r, &d4, ll); + + CHECK_EQUAL(&d4.ll, d0.ll.next); + CHECK_EQUAL(0, d0.ll.prev); + + CHECK_EQUAL(0, d4.ll.next); + CHECK_EQUAL(&d0.ll, d4.ll.prev); + + fl_linked_list_insert_before(&d4, &d1, ll); + + CHECK_EQUAL(&d4.ll, d1.ll.next); + CHECK_EQUAL(&d0.ll, d1.ll.prev); + + CHECK_EQUAL(&d1.ll, d0.ll.next); + CHECK_EQUAL(&d1.ll, d4.ll.prev); + + fl_linked_list_insert_before(&d4, &d2, ll); + + CHECK_EQUAL(&d4.ll, d2.ll.next); + CHECK_EQUAL(&d1.ll, d2.ll.prev); + + CHECK_EQUAL(&d2.ll, d1.ll.next); + CHECK_EQUAL(&d2.ll, d4.ll.prev); + + fl_linked_list_insert_after(&d2, &d3, ll); + + CHECK_EQUAL(&d4.ll, d3.ll.next); + CHECK_EQUAL(&d2.ll, d3.ll.prev); + + CHECK_EQUAL(&d3.ll, d2.ll.next); + CHECK_EQUAL(&d3.ll, d4.ll.prev); + + SECTION ("now remove and re check") + { + fl_linked_list_remove(&d2, ll); + + CHECK_EQUAL(0, d2.ll.next); + CHECK_EQUAL(0, d2.ll.prev); + + CHECK_EQUAL(&d3.ll, d1.ll.next); + CHECK_EQUAL(&d1.ll, d3.ll.prev); + + CHECK_EQUAL(&d0.ll, d1.ll.prev); + CHECK_EQUAL(&d4.ll, d3.ll.next); + } + } +} diff --git a/tests/test_macros.cpp b/tests/test_macros.cpp new file mode 100644 index 0000000..e6deac2 --- /dev/null +++ b/tests/test_macros.cpp @@ -0,0 +1,32 @@ +#include "catch.hpp" +#include +#include + +TEST_CASE ("macros") +{ + + SECTION ("auto_type") + { + const char * t; + fl_auto_type(t) s = "blablabla"; + CHECK(strcmp(s, "blablabla") == 0); + } + + SECTION ("container_of") + { + struct s_container { + int a, b, c; + char d; + char t; + int z; + } container; + + CHECK(&container == fl_container_of (&container.t, s_container, t)); + } + + SECTION ("array_size") + { + const char s[] = "blablabla"; + CHECK(FL_ARRAY_SIZE(s) == 10); + } +} diff --git a/tests/test_ring_fifo.cpp b/tests/test_ring_fifo.cpp index 76cb69b..e0907b4 100644 --- a/tests/test_ring_fifo.cpp +++ b/tests/test_ring_fifo.cpp @@ -1,8 +1,8 @@ #include "catch.hpp" -#include +#include #include -TEST_CASE( "fl_ring_fifo: initialization size") +TEST_CASE("fl_ring_fifo: initialization size") { fl_ring_fifo_t cut; int sz; diff --git a/tests/test_time.cpp b/tests/test_time.cpp new file mode 100644 index 0000000..b29ced9 --- /dev/null +++ b/tests/test_time.cpp @@ -0,0 +1,91 @@ +#include "catch.hpp" + +#include +#define FL_ENABLE_TIME_MODULE +#define FL_TIME_TYPE uint32_t +#define FL_TIME_INT_TYPE int64_t /* only used for remaining function */ +#include + +TEST_CASE("time") +{ + const fl_time_t max = (fl_time_t)-1; + + SECTION ("elapsed") + { + + /* Comparator margin */ + CHECK_FALSE(fl_time_check_elapsed(10, 0, 11)); + CHECK (fl_time_check_elapsed(10, 0, 10)); + + /* Considering timer wrap */ + CHECK_FALSE(fl_time_check_elapsed(max - 1, max - 1, 3)); + CHECK_FALSE(fl_time_check_elapsed(max, max - 1, 3)); + CHECK_FALSE(fl_time_check_elapsed(max + 1, max - 1, 3)); + CHECK (fl_time_check_elapsed(max + 2, max - 1, 3)); + CHECK (fl_time_check_elapsed(max + 3, max - 1, 3)); + CHECK (fl_time_check_elapsed(max + 4, max - 1, 3)); + CHECK (fl_time_check_elapsed(max + 5, max - 1, 3)); + CHECK (fl_time_check_elapsed(max + 6, max - 1, 3)); + + CHECK_FALSE(fl_time_check_elapsed(max - 1, max - 1, 1)); + CHECK (fl_time_check_elapsed(max, max - 1, 1)); + CHECK (fl_time_check_elapsed(max + 1, max - 1, 1)); + CHECK (fl_time_check_elapsed(max + 2, max - 1, 1)); + CHECK (fl_time_check_elapsed(max + 3, max - 1, 1)); + CHECK (fl_time_check_elapsed(max + 4, max - 1, 1)); + CHECK (fl_time_check_elapsed(max + 5, max - 1, 1)); + CHECK (fl_time_check_elapsed(max + 6, max - 1, 1)); + + CHECK_FALSE(fl_time_check_elapsed(max - 1, max + 1, max)); + CHECK (fl_time_check_elapsed(max, max + 1, max)); + + CHECK_FALSE(fl_time_check_elapsed(0xE, 0x10, max)); + CHECK (fl_time_check_elapsed(0xF, 0x10, max)); + + /* Tests pass because the subtraction made in check_elapsed + * removes the wrap effect. + * It only works if "now" is bigger than "before", considering + * we are dealing with time, now is bigger than before, always. + */ + + /* Elapsed 0 always return true! */ + CHECK (fl_time_check_elapsed(max - 2, max - 1, 0)); + CHECK (fl_time_check_elapsed(max - 1, max - 1, 0)); + + /* Ok, what if I wanted to test now against a number in the future? + * Simple! Transform later in before with a stupid big number and + * check against it! */ + fl_time_t stupid_big_number = (max/2) + 1; + fl_time_t later = 0x00000010; + fl_time_t before = later - stupid_big_number; + + CHECK_FALSE(fl_time_check_elapsed(max - 255, before, stupid_big_number)); + CHECK_FALSE(fl_time_check_elapsed(max, before, stupid_big_number)); + CHECK_FALSE(fl_time_check_elapsed(max + 1, before, stupid_big_number)); + CHECK_FALSE(fl_time_check_elapsed(0x0F, before, stupid_big_number)); + CHECK (fl_time_check_elapsed(0x10, before, stupid_big_number)); + CHECK (fl_time_check_elapsed(0x11, before, stupid_big_number)); + } + + SECTION ("reached") + { + /* As we are good programmers, we wrapped the algorithm in a new function */ + CHECK_FALSE(fl_time_check_reached(0x10, max - 255)); + CHECK_FALSE(fl_time_check_reached(0x10, max)); + CHECK_FALSE(fl_time_check_reached(0x10, max + 1)); + CHECK_FALSE(fl_time_check_reached(0x10, 0x0F)); + CHECK (fl_time_check_reached(0x10, 0x10)); + CHECK (fl_time_check_reached(0x10, 0x11)); + + /* Wrap around whooooooooooooooooooooooooooooooo? */ + } + + SECTION ("remaining") + { + CHECK (fl_time_remaining(0, 0, 10) == 10); + CHECK (fl_time_remaining(8, 0, 10) == 2); + CHECK (fl_time_remaining(9, 0, 10) == 1); + CHECK (fl_time_remaining(10, 0, 10) == 0); + CHECK (fl_time_remaining(11, 0, 10) < 0); + } +}