diff --git a/array.h b/array.h new file mode 100644 index 0000000..1b41c0c --- /dev/null +++ b/array.h @@ -0,0 +1,177 @@ +#ifndef sizeof_fam_struct + #define sizeof_fam_struct(type, len) (sizeof(type) + (len)*sizeof(((type*)NULL)->data[0])) +#endif + +#ifndef map + #include + #include + #include + + #define map(arr, fun) __extension__({ \ + typeof(arr) map_copy_arr = arr; \ + size_t data_len = sizeof(typeof(fun(NULL))); \ + void *res = malloc(sizeof(size_t) + map_copy_arr->len*data_len); \ + *((size_t*)res) = map_copy_arr->len; \ + for(size_t i = 0; i < map_copy_arr->len; i++){ \ + *((typeof(fun(NULL))*)(((uint8_t*)res) + sizeof(size_t)) + i) = fun(&(arr->data[i])); \ + } \ + res; \ + }) +#endif + +#ifndef fold + #include + + #define fold(arr,fun, init) __extension__({ \ + typeof(arr) fold_copy_arr = arr; \ + typeof(init) accu = init; \ + for(size_t i = 0; i < fold_copy_arr->len;i++){ \ + accu = fun(accu, (fold_copy_arr->data[i]));\ + }\ + accu;\ + }) +#endif + +#ifndef filter + #include + #include + #include + + #define filter(arr, fun) __extension__({ \ + typeof(arr) filter_copy_arr = arr; \ + typeof(arr) res = malloc(sizeof_fam_struct(typeof(*arr), filter_copy_arr->len)); \ + res->len = 0; \ + for(size_t i = 0; i < filter_copy_arr->len; i++){ \ + if(fun(filter_copy_arr->data[i])){ \ + res->data[(res->len)++] = filter_copy_arr->data[i]; \ + } \ + } \ + res; \ + }) +#endif + +#ifndef apply + #include + #include + #include + + #define apply(arr, fun) __extension__({ \ + typeof(arr) apply_copy_arr = arr; \ + for(size_t i = 0; i < apply_copy_arr->len; i++){ \ + fun(&(apply_copy_arr->data[i])); \ + } \ + apply_copy_arr; \ + }) +#endif + +#ifndef ARR_T_GENERIC_MACROS + #define ARR_T_GENERIC_MACROS + #include + + #define arr_t(T) struct ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, s){ \ + size_t cap; \ + size_t len; \ + T data[]; \ + }\ + + #define ARR_T_NOT_EXPOSED__ARR_NAME_COMBINE(T, name) T##_arr_##name + #define ARR_T_NOT_EXPOSED__ARR_NAME_EXPAND(T, name) ARR_T_NOT_EXPOSED__ARR_NAME_COMBINE(T, name) + #define ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, name) ARR_T_NOT_EXPOSED__ARR_NAME_EXPAND(ARR_T_NOT_EXPOSED__GET_TYPE(T), name) + + + #define ARR_T_NOT_EXPOSED__GET_TYPE_CONTAINS_struct 0, + #define ARR_T_NOT_EXPOSED__GET_TYPE_CONTAINS_enum 1, + + #define ARR_T_NOT_EXPOSED__RETURN_TYPE(T, ...) T + #define ARR_T_NOT_EXPOSED__GET_TYPE_EXPAND(maybe_T, _, ...) ARR_T_NOT_EXPOSED__RETURN_TYPE(__VA_OPT__(__VA_ARGS__ ,) maybe_T) + #define ARR_T_NOT_EXPOSED__GET_TYPE_EXTRACT_PREFIX(maybe_T, _) ARR_T_NOT_EXPOSED__GET_TYPE_EXPAND(maybe_T, _) + #define ARR_T_NOT_EXPOSED__GET_TYPE(T) ARR_T_NOT_EXPOSED__GET_TYPE_EXTRACT_PREFIX(T, ARR_T_NOT_EXPOSED__GET_TYPE_CONTAINS_##T) +#endif + +#ifndef array_of + #define array_of(T) ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, t) +#endif + +#ifndef autofree + #define autofree_array_of(T) [[gnu::__cleanup__(ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, autofree))]] array_of(T) +#endif + +#ifndef ARRAY_OF + #warning "ARRAY_OF not defined. This includes does nothing." +#else + #include + + #define arr__stringify_expand(x) #x + #define arr__stringify(x) arr__stringify_expand(x) + + #define arr_init_declare(T) [[maybe_unused]] static array_of(T) *ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, init)(size_t cap) + #define arr_init_body(T) [[maybe_unused]] static array_of(T) *ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, init)(size_t cap){ \ + array_of(T) *arr = malloc(sizeof_fam_struct(array_of(T), cap)); \ + arr->cap = cap; \ + arr->len = 0; \ + return arr; \ + } + + #define arr_push_declare(T) [[maybe_unused]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, push)(array_of(T) *arr, T val) + #define arr_push_body(T) [[maybe_unused]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, push)(array_of(T) *arr, T val){ \ + if(arr->len < arr->cap){ \ + arr->data[(arr->len)++] = val; \ + } \ + } + + #define arr_pop_declare(T) [[maybe_unused]] static T ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, pop)(array_of(T) *arr) + #define arr_pop_body(T) [[maybe_unused]] static T ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, pop)(array_of(T) *arr){ \ + return arr->data[--(arr->len)]; \ + } + + + #define arr_free_declare(T) [[maybe_unused]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, free)(array_of(T) *arr) + #define arr_free_body(T) [[maybe_unused]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, free)(array_of(T) *arr){ \ + free(arr); \ + } + + #ifdef CUSTOM_AUTOFREE + #define arr_autofree_declare(T) [[maybe_unused,gnu::alias(arr__stringify(CUSTOM_AUTOFREE))]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, autofree)(array_of(T) **p) + #define arr_autofree_body(T) + #else + #define arr_autofree_declare(T) [[maybe_unused]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, autofree)(array_of(T) **p) + #define arr_autofree_body(T) [[maybe_unused]] static void ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(T, autofree)(array_of(T) **p){\ + free(*p);\ + } + #endif + + typedef arr_t(ARRAY_OF) ARR_T_NOT_EXPOSED__ARR_MAKE_NAME(ARRAY_OF, t); + + + arr_init_declare(ARRAY_OF); + arr_push_declare(ARRAY_OF); + arr_pop_declare(ARRAY_OF); + arr_free_declare(ARRAY_OF); + arr_autofree_declare(ARRAY_OF); + + #ifndef ARRAY_NO_IMPLEM + arr_init_body(ARRAY_OF) + arr_push_body(ARRAY_OF) + arr_pop_body(ARRAY_OF) + arr_free_body(ARRAY_OF) + arr_autofree_body(ARRAY_OF) + #endif + + + #undef arr_init_declare + #undef arr_init_body + #undef arr_push_declare + #undef arr_push_body + #undef arr_pop_declare + #undef arr_pop_body + #undef arr_free_declare + #undef arr_free_body + #undef arr_autofree_declare + #undef arr_autofree_body + + #undef arr__stringify_expand + #undef arr__stringify + + #undef CUSTOM_AUTOFREE + #undef ARRAY_OF +#endif diff --git a/describe.c b/describe.c new file mode 100644 index 0000000..fbf6147 --- /dev/null +++ b/describe.c @@ -0,0 +1,171 @@ +#include "describe.h" +#include "linked_list.h" +#include +#include + + +typedef struct{ + linked_list_t list; + struct_descriptor_t descriptor; +} struct_descriptor_node_t; + +static linked_list_t descriptors; + +[[gnu::constructor]] static void struct_descriptor_module_constructor(void){ + linked_list_init_head(&descriptors); +} + +[[gnu::destructor]] static void struct_descriptor_module_destructor(void){ + struct_descriptor_node_t *node, *n; + list_for_each_entry_safe(node, n, &descriptors, list){ + free(node); + } +} + +static struct_descriptor_t *struct_descriptor_find_type(char const *name){ + struct_descriptor_node_t *node, *n; + list_for_each_entry_safe(node, n, &descriptors, list){ + if(strcmp(name, node->descriptor.name) == 0){ + return &(node->descriptor); + } + } + + return NULL; +} + +static struct_descriptor_t *struct_descriptor_init_va_list(char const *name, size_t size, size_t count, va_list list){ + struct_descriptor_t *descriptor; + size_t real_count = count == 0 ? 1 : count; + + + descriptor = malloc(sizeof(struct_descriptor_t) - sizeof(descriptor->fields) + sizeof_fam_struct(field_descriptor_arr_t, real_count)); + descriptor->fields.len = real_count; + descriptor->name = name; + descriptor->size = size; + + descriptor->fields.data[0] = (field_descriptor_t){.name = name, .offset = 0, .size = size}; + + for(size_t i = 0; i < count; i++){ + descriptor->fields.data[i] = va_arg(list, field_descriptor_t); + } + + return descriptor; +} + +struct_descriptor_t *struct_descriptor_init(char const *name, size_t size, size_t count, ...){ + va_list list; + va_start(list, count); + struct_descriptor_t *descriptor = struct_descriptor_init_va_list(name, size, count, list); + va_end(list); + + return descriptor; +} + +void struct_descriptor_register(char const *name, size_t size, size_t count, ...){ + va_list list; + + struct_descriptor_t *descriptor = struct_descriptor_find_type(name); + struct_descriptor_node_t *node; + if(descriptor != NULL){ + node = container_of(descriptor, struct_descriptor_node_t, descriptor); + linked_list_del(&node->list); + free(node); + } + + va_start(list, count); + size_t real_count = count == 0 ? 1 : count; + descriptor = struct_descriptor_init_va_list(name, size, count, list); + node = malloc(sizeof(struct_descriptor_node_t) - sizeof(descriptor->fields) + sizeof_fam_struct(field_descriptor_arr_t, real_count)); + va_end(list); + + memcpy(&(node->descriptor), descriptor, sizeof(struct_descriptor_t) - sizeof(descriptor->fields) + sizeof_fam_struct(field_descriptor_arr_t, real_count)); + linked_list_add_head(&descriptors, &(node->list)); + + free(descriptor); + +} + + +void print_struct_descriptor(struct_descriptor_t *descriptor){ + printf("Type %s:\n", descriptor->name); + for(size_t i = 0; i < descriptor->fields.len; i++){ + printf(" Field %s at offset %zd and size %zu\n", descriptor->fields.data[i].name, descriptor->fields.data[i].offset, descriptor->fields.data[i].size); + } +} + + +static uint8_arr_t *struct_descriptor_serialize_data_internal(char const *name, void *data, struct_descriptor_t *descriptor){ + uint8_arr_t *arr = NULL; + arr = uint8_arr_init(descriptor->size); + for(size_t i = 0; i < descriptor->fields.len; i++){ + char const * field_name = descriptor->fields.data[i].name; + if (struct_descriptor_find_type(field_name) != NULL){ + + } + else{ + memcpy(&(arr->data[arr->len]), ((uint8_t *)data) + descriptor->fields.data[i].offset, descriptor->fields.data[i].size); + descriptor->fields.data[i].serializer(&(arr->data[arr->len])); + arr->len += descriptor->fields.data[i].size; + } + + } + return arr; +} + +uint8_arr_t *struct_descriptor_serialize_data(char const *name, void *data){ + uint8_arr_t *arr = NULL; + struct_descriptor_t *descriptor = struct_descriptor_find_type(name); + if(descriptor != NULL){ + arr = struct_descriptor_serialize_data_internal(name, data, descriptor); + } + return arr; +} + +void *struct_descriptor_deserialize_data(char const *name, uint8_arr_t *arr){ + void *res = NULL; + struct_descriptor_t *descriptor = struct_descriptor_find_type(name); + if(descriptor != NULL){ + size_t offset = 0; + res = malloc(descriptor->size); + for(size_t i = 0; i < descriptor->fields.len; i++){ + memcpy(((uint8_t *)res) + descriptor->fields.data[i].offset, &(arr->data[offset]), descriptor->fields.data[i].size); + descriptor->fields.data[i].serializer(((uint8_t *)res) + descriptor->fields.data[i].offset); + offset += descriptor->fields.data[i].size; + } + } + + return res; +} + +bool struct_descriptor_set_serializer(char const *name, char const *field, serializer_function_t serializer){ + struct_descriptor_node_t *node, *n; + list_for_each_entry_safe(node, n, &descriptors, list){ + if(strcmp(name, node->descriptor.name) == 0){ + for(size_t i = 0; i < node->descriptor.fields.len; i++){ + if(strcmp(field, node->descriptor.fields.data[i].name) == 0){ + node->descriptor.fields.data[i].serializer = serializer; + return true; + } + } + } + } + + return false; +} + + +void serialize_generic(void *data){ } + +void serialize_64bits(void *data){ + uint64_t *data64 = (uint64_t *)data; + *data64 = hton(*data64); +} +void serialize_32bits(void *data){ + uint32_t *data32 = (uint32_t *)data; + *data32 = hton(*data32); +} + +void serialize_16bits(void *data){ + uint16_t *data16 = (uint16_t *)data; + *data16 = hton(*data16); +} \ No newline at end of file diff --git a/describe.h b/describe.h new file mode 100644 index 0000000..073dda8 --- /dev/null +++ b/describe.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include "network_byte_order.h" + +typedef uint8_t uint8; + +#define ARRAY_OF uint8 +#include "array.h" + +typedef struct struct_descriptor_s struct_descriptor_t; +typedef void (*serializer_function_t)(uint8_t *); + + + +typedef struct field_descriptor{ + char const *name; + ptrdiff_t offset; + size_t size; + serializer_function_t serializer; +} field_descriptor_t; + + +#define ARRAY_OF struct field_descriptor +#include "array.h" + +typedef struct struct_descriptor_s{ + char const *name; + size_t size; + field_descriptor_arr_t fields; +} struct_descriptor_t; + + +#include "narg.h" +#include "for_each.h" + + +#define default_serializer_function(s) __extension__({ \ + (s == 64) ? serialize_64bits : ( \ + (s == 32) ? serialize_32bits : ( \ + (s == 16) ? serialize_16bits : \ + serialize_generic ));\ +}) + +#define sizeof_field(T, field) sizeof(((T *)NULL)->field) + +#define describe_field(T, field) ((field_descriptor_t) {.name = #field, .offset = offsetof(T, field), .size = sizeof_field(T, field), .serializer = default_serializer_function(sizeof_field(T, field))}) +#define describe_fields(T, ...) for_each_pair(describe_field, T, __VA_ARGS__) + + +#define describe_type(T, ...) struct_descriptor_init(#T, sizeof(T), NARG(__VA_ARGS__) __VA_OPT__(, describe_fields(T, __VA_ARGS__))) +struct_descriptor_t *struct_descriptor_init(char const *name, size_t size, size_t count, ...); + +#define register_type(T, ...) struct_descriptor_register(#T, sizeof(T), NARG(__VA_ARGS__) __VA_OPT__(, describe_fields(T, __VA_ARGS__))) +void struct_descriptor_register(char const *name, size_t size, size_t count, ...); + +#define serialize_type(T, data) struct_descriptor_serialize_data(#T, data) +uint8_arr_t *struct_descriptor_serialize_data(char const *name, void *data); + +#define deserialize_data(T, data) (T *) struct_descriptor_deserialize_data(#T, data) +void *struct_descriptor_deserialize_data(char const *name, uint8_arr_t *data); + +bool struct_descriptor_set_serializer(char const *name, char const *field, serializer_function_t serializer); + +void print_struct_descriptor(struct_descriptor_t *descriptor); + + +void serialize_64bits(void *data); +void serialize_32bits(void *data); +void serialize_16bits(void *data); +void serialize_generic(void *data); diff --git a/for_each.h b/for_each.h new file mode 100644 index 0000000..2c8a6bc --- /dev/null +++ b/for_each.h @@ -0,0 +1,51 @@ +#ifndef FOR_EACH_H +#define FOR_EACH_H + +/* + * for_each - apply a function-like object (fun) to each + * following argument (a1, a2, ..., an) + * resulting in (fun(a1)), (fun(a2)), ..., (fun(an)) + * + * @fun: the function-like object to apply + * @...: the list of agurments on which to apply + * + * Note: fun can be either a macro, a function or a cast + * in parenthesis (e.g. for_each((char), 67, 10)) + */ +#define for_each(fun, ...) __VA_OPT__(FOR_EACH_NOT_EXPOSED__EXPAND(FOR_EACH_NOT_EXPOSED__HELPER(fun, __VA_ARGS__))) + +/* + * for_each_pair - apply a function-like object (fun) to the same + * value (s) and each following argument (a1, a2, ..., an) + * resulting in (fun(s, a1)), (fun(s, a2)), ..., (fun(s, an)) + * + * @fun: the function-like object to apply + * @s: the repeated first argument + * @...: the list of seconds agurments on which to apply + * + * Note: fun can be either a macro or a function +*/ +#define for_each_pair(fun, s, ...) __VA_OPT__(FOR_EACH_NOT_EXPOSED__EXPAND(FOR_EACH_NOT_EXPOSED__HELPER_PAIR(fun, s, __VA_ARGS__))) + + + +#define FOR_EACH_NOT_EXPOSED__LEFT_PAREN ( +#define FOR_EACH_NOT_EXPOSED__RIGHT_PAREN ) + +#define FOR_EACH_NOT_EXPOSED__EXPAND(...) FOR_EACH_NOT_EXPOSED__EXPAND1(FOR_EACH_NOT_EXPOSED__EXPAND1(FOR_EACH_NOT_EXPOSED__EXPAND1(FOR_EACH_NOT_EXPOSED__EXPAND1(__VA_ARGS__)))) +#define FOR_EACH_NOT_EXPOSED__EXPAND1(...) FOR_EACH_NOT_EXPOSED__EXPAND2(FOR_EACH_NOT_EXPOSED__EXPAND2(FOR_EACH_NOT_EXPOSED__EXPAND2(FOR_EACH_NOT_EXPOSED__EXPAND2(__VA_ARGS__)))) +#define FOR_EACH_NOT_EXPOSED__EXPAND2(...) FOR_EACH_NOT_EXPOSED__EXPAND3(FOR_EACH_NOT_EXPOSED__EXPAND3(FOR_EACH_NOT_EXPOSED__EXPAND3(FOR_EACH_NOT_EXPOSED__EXPAND3(__VA_ARGS__)))) +#define FOR_EACH_NOT_EXPOSED__EXPAND3(...) FOR_EACH_NOT_EXPOSED__EXPAND4(FOR_EACH_NOT_EXPOSED__EXPAND4(FOR_EACH_NOT_EXPOSED__EXPAND4(FOR_EACH_NOT_EXPOSED__EXPAND4(__VA_ARGS__)))) +#define FOR_EACH_NOT_EXPOSED__EXPAND4(...) FOR_EACH_NOT_EXPOSED__EXPAND5(FOR_EACH_NOT_EXPOSED__EXPAND5(FOR_EACH_NOT_EXPOSED__EXPAND5(FOR_EACH_NOT_EXPOSED__EXPAND5(__VA_ARGS__)))) +#define FOR_EACH_NOT_EXPOSED__EXPAND5(...) FOR_EACH_NOT_EXPOSED__EXPAND6(FOR_EACH_NOT_EXPOSED__EXPAND6(FOR_EACH_NOT_EXPOSED__EXPAND6(FOR_EACH_NOT_EXPOSED__EXPAND6(__VA_ARGS__)))) +#define FOR_EACH_NOT_EXPOSED__EXPAND6(...) __VA_ARGS__ + + +#define FOR_EACH_NOT_EXPOSED__RECURSE(helper) FOR_EACH_NOT_EXPOSED__ ## helper +#define FOR_EACH_NOT_EXPOSED__HELPER(fun, a1, ...) (fun(a1)) \ + __VA_OPT__(, FOR_EACH_NOT_EXPOSED__RECURSE FOR_EACH_NOT_EXPOSED__LEFT_PAREN HELPER FOR_EACH_NOT_EXPOSED__RIGHT_PAREN(fun, __VA_ARGS__)) + +#define FOR_EACH_NOT_EXPOSED__HELPER_PAIR(fun, a1, a2, ...) (fun(a1, a2)) \ + __VA_OPT__(, FOR_EACH_NOT_EXPOSED__RECURSE FOR_EACH_NOT_EXPOSED__LEFT_PAREN HELPER_PAIR FOR_EACH_NOT_EXPOSED__RIGHT_PAREN(fun, a1, __VA_ARGS__)) + +#endif //FOR_EACH_H \ No newline at end of file diff --git a/linked_list.h b/linked_list.h new file mode 100644 index 0000000..142512c --- /dev/null +++ b/linked_list.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include + +#define container_of(ptr, type, member) ((type *) ((uint8_t *)(ptr) - offsetof(type, member))) + +typedef struct linked_list { + struct linked_list *prev; + struct linked_list *next; +} linked_list_t; + +static inline void linked_list_init_head(linked_list_t *head){ + head->prev = head; + head->next = head; +} + +static inline void linked_list_add_internal(linked_list_t *prev, linked_list_t *elem, linked_list_t *next){ + prev->next = elem; + elem->prev = prev; + + elem->next = next; + next->prev = elem; +} + +[[maybe_unused]] static inline void linked_list_add_head(linked_list_t *head, linked_list_t *elem){ + linked_list_add_internal(head, elem, head->next); +} + +[[maybe_unused]] static inline void linked_list_add_tail(linked_list_t *elem, linked_list_t *head) +{ + linked_list_add_internal(head->prev, elem, head); +} + + +[[maybe_unused]] static inline bool list_empty(linked_list_t const *list){ + return list->next == list; +} + + +static inline void linked_list_del_internal(linked_list_t *prev, linked_list_t *next){ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +[[maybe_unused]] static inline void linked_list_del(linked_list_t *elem){ + linked_list_del_internal(elem->prev, elem->next); + elem->next = NULL; + elem->prev = NULL; +} + + + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +[[maybe_unused]] static inline void linked_list_extract(linked_list_t *elem){ + linked_list_del_internal(elem->prev, elem->next); + linked_list_init_head(elem); +} + +/** + * list_for_each_entry - iterate over list of given type + * @current_elem: the type * to use as a loop counter. + * @list: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(current_elem, list, member) \ + for (current_elem = container_of((list)->next, typeof(*current_elem), member); \ + ¤t_elem->member != (list); \ + current_elem = container_of(current_elem->member.next, typeof(*current_elem), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @current_elem: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @list: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(current_elem, n, list, member) \ + for (current_elem = container_of((list)->next, typeof(*current_elem), member), \ + n = container_of(current_elem->member.next, typeof(*current_elem), member); \ + ¤t_elem->member != (list); \ + current_elem = n, n = container_of(n->member.next, typeof(*n), member)) diff --git a/narg.h b/narg.h new file mode 100644 index 0000000..7d8c40f --- /dev/null +++ b/narg.h @@ -0,0 +1,70 @@ +#ifndef NARG_MACRO_H +#define NARG_MACRO_H + +#define ARG_N( \ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ + _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, _63, N, ...) N + +#define RSEQ_N() \ + 63, 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define RSEQ_N_2() \ + 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 + +#define NARG_(...) ARG_N(__VA_ARGS__) + +#define COMMASEQ_N() \ + 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 + +#define COMMA(...) , + +#define HASCOMMA(...) \ + NARG_(__VA_ARGS__, COMMASEQ_N()) + +#define NARG(...) \ + NARG_HELPER1( \ + HASCOMMA(__VA_ARGS__), \ + HASCOMMA(COMMA __VA_ARGS__ ()), \ + NARG_(__VA_ARGS__, RSEQ_N())) + +#define NARG_2(...) \ + NARG_HELPER1( \ + HASCOMMA(__VA_ARGS__), \ + HASCOMMA(COMMA __VA_ARGS__ ()), \ + NARG_(__VA_ARGS__, RSEQ_N_2())) + + +#define NARG_HELPER1(a, b, N) NARG_HELPER2(a, b, N) +#define NARG_HELPER2(a, b, N) NARG_HELPER3_ ## a ## b(N) +#define NARG_HELPER3_01(N) 0 +#define NARG_HELPER3_00(N) 1 +#define NARG_HELPER3_11(N) N + + +#define COMBINE_EXPANDED(A, B) A ## B +#define COMBINE(A, B) COMBINE_EXPANDED(A,B) + +#endif //NARG_MACRO_H diff --git a/network_byte_order.h b/network_byte_order.h new file mode 100644 index 0000000..6a51119 --- /dev/null +++ b/network_byte_order.h @@ -0,0 +1,89 @@ +#ifndef NETWORK_BYTE_ORDER_H +#define NETWORK_BYTE_ORDER_H + +#include + + +static inline uint64_t hton64(uint64_t host); +static inline uint32_t hton32(uint32_t host); +static inline uint16_t hton16(uint16_t host); +static inline uint8_t hton8 (uint8_t host); + +#define hton(x) _Generic( (x), \ + uint64_t : hton64, \ + uint32_t : hton32, \ + uint16_t : hton16, \ + uint8_t : hton8 \ +)(x) + +[[gnu::alias("hton64")]] static inline uint64_t ntoh64(uint64_t network); +[[gnu::alias("hton32")]] static inline uint32_t ntoh32(uint32_t network); +[[gnu::alias("hton16")]] static inline uint16_t ntoh16(uint16_t network); +[[gnu::alias("hton8") ]] static inline uint8_t ntoh8 (uint8_t network); + +#define ntoh(x) _Generic( (x), \ + uint64_t : ntoh64, \ + uint32_t : ntoh32, \ + uint16_t : ntoh16, \ + uint8_t : ntoh8 \ +)(x) + +#ifndef NETWORK_BYTE_ORDER_IMPLEMENTED + #define NETWORK_BYTE_ORDER_IMPLEMENTED + #include + + #define bswap64(x) \ + ((((x) & 0xff00000000000000ull) >> 56) \ + | (((x) & 0x00ff000000000000ull) >> 40) \ + | (((x) & 0x0000ff0000000000ull) >> 24) \ + | (((x) & 0x000000ff00000000ull) >> 8) \ + | (((x) & 0x00000000ff000000ull) << 8) \ + | (((x) & 0x0000000000ff0000ull) << 24) \ + | (((x) & 0x000000000000ff00ull) << 40) \ + | (((x) & 0x00000000000000ffull) << 56)) + #define bswap32(x) \ + ((((x) & 0xff000000ul) >> 24) \ + | (((x) & 0x00ff0000ul) >> 8) \ + | (((x) & 0x0000ff00ul) << 8) \ + | (((x) & 0x000000fful) << 24)) + #define bswap16(x) \ + ((((x) & 0xff00u) >> 8) \ + | (((x) & 0x00ffu) << 8)) + + static inline bool is_big_endian(void){ + return ((const union { uint16_t full; struct{ uint8_t high; uint8_t low; } __attribute__((packed)); } __attribute__((packed))) { .full = 1 }).low == 1; + } + + static inline uint64_t hton64(uint64_t host){ + if(is_big_endian()){ + return host; + } + else{ + return bswap64(host); + } + } + + static inline uint32_t hton32(uint32_t host){ + if(is_big_endian()){ + return host; + } + else{ + return bswap32(host); + } + } + + static inline uint16_t hton16(uint16_t host){ + if(is_big_endian()){ + return host; + } + else{ + return bswap16(host); + } + } + + static inline uint8_t hton8 (uint8_t host){ + return host; + } +#endif + +#endif diff --git a/runtime_assert.h b/runtime_assert.h new file mode 100644 index 0000000..57e4e6a --- /dev/null +++ b/runtime_assert.h @@ -0,0 +1,14 @@ +#ifndef RUNTIME_ASSERT_H +#define RUNTIME_ASSERT_H + +#include +#include +#include +#include +#include + +#define runtime_assert(x, ...) for (bool expression = x; !(expression); assert(expression && # x)) __VA_OPT__(fprintf(stderr, __VA_ARGS__), fprintf(stderr, " (errno : %s)", (errno == 0) ? "OK" : strerror(errno)), fprintf(stderr, "\n")) + +#endif //RUNTIME_ASSERT_H + + diff --git a/test.c b/test.c new file mode 100644 index 0000000..20d5f91 --- /dev/null +++ b/test.c @@ -0,0 +1,140 @@ +#define ARRAY_OF int +#include "array.h" +#include "time_it.h" +#include "describe.h" + +#include +#include +#include + + + +#include + +typedef double_arr_t *double_arr; +#define ARRAY_OF double_arr + +#define CUSTOM_AUTOFREE double_arr_arr_cleanup + +#include "array.h" + +void double_arr_arr_cleanup(double_arr_arr_t **arr){ + if(*arr != NULL){ + for(size_t i = 0; i < (*arr)->len; i++){ + double_arr_free((*arr)->data[i]); + } + free(*arr); + } +} + +#define SLEEP_DURATION 2 + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + + + +int hello(int* _){ + printf("%d, ", *_); + return 0; +} + +#define generic _Generic +#define sum(a, e) generic((a), int : sumi, double : sumd)(a,e) + + +int sumi(int accu, int e){ + return accu + e; +} + +double sumd(double accu, double e){ + return accu + e; +} + +double average(double_arr_t *arr){ + return fold(arr, sum, 0)/(arr->len == 0 ? 1 : arr->len); +} + +bool over_5(int e){ + return e > 5; +} + +typedef struct type_{ + size_t foo; + float bar; +} type_; + +void wrapper(void){ + register_type(field_descriptor_t, name, offset, size); + register_type(field_descriptor_t, offset, size); + register_type(field_descriptor_t); + register_type(struct type_); + + autofree_array_of(uint8) *ser = serialize_type(struct type_, &((struct type_){ .foo = 5, .bar = .05f})); + if(ser != NULL){ + struct type_ *des = deserialize_data(struct type_, ser); + + printf("%zu, %f\n", des->foo, des->bar); + free(des); + } +} + + + +int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv){ + //#define test_macro(x) (constexpr serializer_function_t _ = (serializer_function_t)(NULL), _) + + + + wrapper(); + autofree_array_of(int) *zozo = int_arr_init(10); + for(size_t i = 0; i < zozo->cap; i++){ + int_arr_push(zozo, i); + } + + autofree_array_of(int) *over = filter(zozo, over_5); + + apply(zozo, hello); + + printf("\n"); + printf("%d\n", fold(zozo, sum, 0)); + + for(size_t i = 0; i < over->len; i++){ + printf("%d, ", over->data[i]); + } + printf("\n"); + //free(over); + + // for(size_t i = 0; i < 64; i++){ + // printf("log2(%zu) = %zu\n", i, log2(i)); + // } + + //free(zozo); + + autofree_array_of(double_arr) *results = double_arr_arr_init(10); + + + double_arr_arr_push(results, time_it_repeat(sleep(SLEEP_DURATION), .repeat = 0, .number = 2)); + double_arr_arr_push(results, time_it_repeat(sleep(SLEEP_DURATION), .number = 7)); + double_arr_arr_push(results, time_it_repeat(sleep(SLEEP_DURATION), .repeat = 0)); + double_arr_arr_push(results, time_it_repeat(sleep(SLEEP_DURATION))); + + printf("##############################\n"); + printf("sleep(" STRINGIFY(SLEEP_DURATION) "), .repeat = 0, .number = 2 took %f seconds\n", average(results->data[0])); + printf("sleep(" STRINGIFY(SLEEP_DURATION) "), .number = 7 took %f seconds\n", average(results->data[1])); + printf("sleep(" STRINGIFY(SLEEP_DURATION) "), .repeat = 0 took %f seconds\n", average(results->data[2])); + printf("sleep(" STRINGIFY(SLEEP_DURATION) ") took %f seconds\n", average(results->data[3])); + + + printf("##############################\n"); + printf("sleep(" STRINGIFY(SLEEP_DURATION) "), .repeat = 0, .number = 2 took %f seconds\n", time_it(sleep(SLEEP_DURATION), .number = 2)); + printf("sleep(" STRINGIFY(SLEEP_DURATION) "), .number = 7 took %f seconds\n", time_it(sleep(SLEEP_DURATION), .number = 7)); + printf("sleep(" STRINGIFY(SLEEP_DURATION) "), .repeat = 0 took %f seconds\n", time_it(sleep(SLEEP_DURATION), .number = 0)); + printf("sleep(" STRINGIFY(SLEEP_DURATION) ") took %f seconds\n", time_it(sleep(SLEEP_DURATION))); + + free(double_arr_arr_pop(results)); + + return 0; +} + + diff --git a/time_it.h b/time_it.h new file mode 100644 index 0000000..8fd4a04 --- /dev/null +++ b/time_it.h @@ -0,0 +1,75 @@ +#ifndef TIME_IT_H +#define TIME_IT_H + +#include +#include + +#define ARRAY_OF double +#include "array.h" + + +/* + * time_it - executes the provided code and returns a + * following argument (a1, a2, ..., an) + * resulting in (fun(a1)), (fun(a2)), ..., (fun(an)) + * + * @code: the code to time; It can be a simple function call or + * a full block code + * @...: the optional argument number that + * + * @return: the elapsed execution time in seconds + * Note: fun can be either a macro, a function or a cast + * in parenthesis (e.g. for_each((char), 67, 10)) + */ +#define time_it(code, ...) TIME_IT_NOT_EXPOSED__GENERIC_IMPLEMENTATION(, code, __VA_ARGS__) + +/* + * for_each - apply a function-like object (fun) to each + * following argument (a1, a2, ..., an) + * resulting in (fun(a1)), (fun(a2)), ..., (fun(an)) + * + * @fun: the function-like object to apply + * @...: the list of agurments on which to apply + * + * Note: fun can be either a macro, a function or a cast + * in parenthesis (e.g. for_each((char), 67, 10)) + */ +#define time_it_repeat(code, ...) TIME_IT_NOT_EXPOSED__GENERIC_IMPLEMENTATION(REPEAT, code, __VA_ARGS__) + + +#define TIME_IT_NOT_EXPOSED__GENERIC_IMPLEMENTATION(type, code, ...) __extension__({ \ + struct time_it_params { TIME_IT_NOT_EXPOSED__IF_REPEAT(type, size_t repeat;) size_t number;} time_it_params = (struct time_it_params){ TIME_IT_NOT_EXPOSED__IF_REPEAT(type, .repeat = 1, _) .number = 1}; \ + __VA_OPT__(time_it_params TIME_IT_NOT_EXPOSED__FIRST_ARG(__VA_ARGS__);) \ + __VA_OPT__(TIME_IT_NOT_EXPOSED__MAYBE_SECOND_ARG(time_it_params TIME_IT_NOT_EXPOSED__FIRST_ARG, __VA_ARGS__);) \ + TIME_IT_NOT_EXPOSED__INIT_RES(type, time_it_params.repeat);\ + TIME_IT_NOT_EXPOSED__IF_REPEAT(type, for(size_t i = 0; i < time_it_params.repeat; i++){) \ + double time_it_time = 0; \ + for(size_t j = 0; j < time_it_params.number; j++){ \ + struct timespec time_it_start, time_it_stop; \ + clock_gettime(CLOCK_MONOTONIC, &time_it_start); \ + code; \ + clock_gettime(CLOCK_MONOTONIC, &time_it_stop); \ + time_it_time += ((time_it_stop.tv_sec - time_it_start.tv_sec) + (time_it_stop.tv_nsec - time_it_start.tv_nsec) / 1000000000.0); \ + }\ + TIME_IT_NOT_EXPOSED__WRITE_RES(type, time_it_time); \ + TIME_IT_NOT_EXPOSED__IF_REPEAT(type, }) \ + res;\ +}) + + +#define TIME_IT_NOT_EXPOSED__MAYBE_SECOND_ARG(macro, a1, ...) __VA_OPT__(macro(__VA_ARGS__)) +#define TIME_IT_NOT_EXPOSED__FIRST_ARG(a1, ...) a1 + +#define TIME_IT_NOT_EXPOSED__INIT_RES_REPEAT(repeat) double_arr_t *res = double_arr_init(repeat) +#define TIME_IT_NOT_EXPOSED__INIT_RES_(_) double res = 0 +#define TIME_IT_NOT_EXPOSED__INIT_RES(type, repeat) TIME_IT_NOT_EXPOSED__INIT_RES_ ## type (repeat) + +#define TIME_IT_NOT_EXPOSED__WRITE_RES_REPEAT(value) double_arr_push(res, value) +#define TIME_IT_NOT_EXPOSED__WRITE_RES_(value) res = value +#define TIME_IT_NOT_EXPOSED__WRITE_RES(type, value) TIME_IT_NOT_EXPOSED__WRITE_RES_ ## type(value) + +#define TIME_IT_NOT_EXPOSED__IF_REPEAT_REPEAT(code, ...) code __VA_OPT__(,) +#define TIME_IT_NOT_EXPOSED__IF_REPEAT_(...) +#define TIME_IT_NOT_EXPOSED__IF_REPEAT(type, ...) TIME_IT_NOT_EXPOSED__IF_REPEAT_ ## type (__VA_ARGS__) + +#endif //TIME_IT_H