From 55dc524ae099de9825886b7b4b2350bb61068b59 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 25 Jan 2024 23:21:57 +0100 Subject: [PATCH] WIP: Support user data within container. It is useful for calling methods with another user data argument. It is mainly useful for custom allocations, so for now, only custom allocations methods can access the user data. Port it to array container. --- m-array.h | 74 +++++++++++++++++++++++++++------------------------ m-core.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 114 insertions(+), 39 deletions(-) diff --git a/m-array.h b/m-array.h index 4b2499e6..2f30f924 100644 --- a/m-array.h +++ b/m-array.h @@ -81,7 +81,7 @@ /* FIXME: Do we want to export some methods as they are slow and are not fit to be used for building other methods (like _it_remove)? */ #define M_ARRA4_OPLIST_P3(name, oplist) \ - (INIT(M_F(name, _init)) \ + ( M_USER_INIT_OPERATOR(name, oplist), \ ,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_F(name, _init_set)),) \ ,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_WITH_VAI)),) \ ,M_IF_METHOD2(INIT_SET,SET, oplist)(SET(M_F(name, _set)), ) \ @@ -173,7 +173,8 @@ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_ARRA4_DEF_CORE(name, type, oplist, array_t, it_t) \ M_ARRA4_DEF_IO(name, type, oplist, array_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, array_t, M_F(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF) + M_EMPLACE_QUEUE_DEF(name, array_t, M_F(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF) \ + M_USER_DEF_GEN(oplist, name, array_t) /* Define the types */ #define M_ARRA4_DEF_TYPE(name, type, oplist, array_t, it_t) \ @@ -183,6 +184,7 @@ size_t size; /* Number of elements in the array */ \ size_t alloc; /* Allocated size for the array base */ \ type *ptr; /* Pointer to the array base */ \ + M_USER_FIELD(oplist) \ } array_t[1]; \ \ /* Define an iterator over an array */ \ @@ -202,10 +204,11 @@ #define M_ARRA4_DEF_CORE(name, type, oplist, array_t, it_t) \ \ M_INLINE void \ - M_F(name, _init)(array_t v) \ + M_F(name, _init)(array_t v M_USER_PARAM(oplist)) \ { \ M_ASSERT (v != NULL); \ /* Initially, the array is empty with nothing allocated */ \ + M_USER_INIT(oplist, user_data); \ v->size = 0; \ v->alloc = 0; \ v->ptr = NULL; \ @@ -235,38 +238,38 @@ \ M_IF_METHOD2(INIT_SET, SET, oplist)( \ M_INLINE void \ - M_F(name, _set)(array_t d, const array_t s) \ + M_F(name, _set)(array_t v, const array_t s) \ { \ - M_ARRA4_CONTRACT(d); \ + M_ARRA4_CONTRACT(v); \ M_ARRA4_CONTRACT(s); \ - if (M_UNLIKELY (d == s)) return; \ - if (s->size > d->alloc) { \ + if (M_UNLIKELY (v == s)) return; \ + if (s->size > v->alloc) { \ const size_t alloc = s->size; \ - type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return ; \ } \ - d->ptr = ptr; \ - d->alloc = alloc; \ + v->ptr = ptr; \ + v->alloc = alloc; \ } \ size_t i; \ - size_t step1 = M_MIN(s->size, d->size); \ + size_t step1 = M_MIN(s->size, v->size); \ for(i = 0; i < step1; i++) \ - M_CALL_SET(oplist, d->ptr[i], s->ptr[i]); \ + M_CALL_SET(oplist, v->ptr[i], s->ptr[i]); \ for( ; i < s->size; i++) \ - M_CALL_INIT_SET(oplist, d->ptr[i], s->ptr[i]); \ - for( ; i < d->size; i++) \ - M_CALL_CLEAR(oplist, d->ptr[i]); \ - d->size = s->size; \ - M_ARRA4_CONTRACT(d); \ + M_CALL_INIT_SET(oplist, v->ptr[i], s->ptr[i]); \ + for( ; i < v->size; i++) \ + M_CALL_CLEAR(oplist, v->ptr[i]); \ + v->size = s->size; \ + M_ARRA4_CONTRACT(v); \ } \ \ M_INLINE void \ M_F(name, _init_set)(array_t d, const array_t s) \ { \ M_ASSERT (d != s); \ - M_F(name, _init)(d); \ + M_F(name, _init)(d M_USER_CALL(oplist, M_USER_DATA(s))); \ M_F(name, _set)(d, s); \ } \ , /* No SET & INIT_SET */) \ @@ -276,10 +279,11 @@ { \ M_ASSERT (d != s); \ M_ARRA4_CONTRACT(s); \ + M_USER_INIT(opl, M_USER_DATA(s)); \ d->size = s->size; \ d->alloc = s->alloc; \ d->ptr = s->ptr; \ - /* Robustness */ \ + /* Robustness: invalid representation of an array */ \ s->alloc = 1; \ s->ptr = NULL; \ M_ARRA4_CONTRACT(d); \ @@ -886,17 +890,17 @@ } \ \ M_INLINE void \ - M_F(name, _special_stable_sort)(array_t l) \ + M_F(name, _special_stable_sort)(array_t v) \ { \ - if (M_UNLIKELY (l->size < 2)) \ + if (M_UNLIKELY (v->size < 2)) \ return; \ /* NOTE: if size is <= 4, no need to perform an allocation */ \ - type *temp = M_CALL_REALLOC(oplist, type, NULL, l->size); \ + type *temp = M_CALL_REALLOC(oplist, type, NULL, v->size); \ if (M_UNLIKELY_NOMEM (temp == NULL)) { \ - M_MEMORY_FULL(sizeof (type) * l->size); \ + M_MEMORY_FULL(sizeof (type) * v->size); \ return ; \ } \ - M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \ + M_C3(m_arra4_,name,_stable_sort_noalloc)(v->ptr, v->size, temp); \ M_CALL_FREE(oplist, temp); \ } \ ,) /* IF SWAP & SET methods */ \ @@ -937,31 +941,31 @@ , /* no HASH */ ) \ \ M_INLINE void \ - M_F(name, _splice)(array_t a1, array_t a2) \ + M_F(name, _splice)(array_t v, array_t a2) \ { \ - M_ARRA4_CONTRACT(a1); \ + M_ARRA4_CONTRACT(v); \ M_ARRA4_CONTRACT(a2); \ if (M_LIKELY (a2->size > 0)) { \ - size_t newSize = a1->size + a2->size; \ + size_t newSize = v->size + a2->size; \ /* To overflow newSize, we need to a1 and a2 a little bit above \ SIZE_MAX/2, which is not possible in the classic memory model as we \ should have exhausted all memory before reaching such sizes. */ \ - M_ASSERT_INDEX(a1->size, newSize); \ - if (newSize > a1->alloc) { \ - type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \ + M_ASSERT_INDEX(v->size, newSize); \ + if (newSize > v->alloc) { \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, newSize); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * newSize); \ } \ - a1->ptr = ptr; \ - a1->alloc = newSize; \ + v->ptr = ptr; \ + v->alloc = newSize; \ } \ - M_ASSERT(a1->ptr != NULL); \ + M_ASSERT(v->ptr != NULL); \ M_ASSERT(a2->ptr != NULL); \ - memcpy(&a1->ptr[a1->size], &a2->ptr[0], a2->size * sizeof (type)); \ + memcpy(&v->ptr[v->size], &a2->ptr[0], a2->size * sizeof (type)); \ /* a2 is now empty */ \ a2->size = 0; \ /* a1 has been expanded with the items of a2 */ \ - a1->size = newSize; \ + v->size = newSize; \ } \ } \ diff --git a/m-core.h b/m-core.h index 2782664b..14dcc05a 100644 --- a/m-core.h +++ b/m-core.h @@ -3404,6 +3404,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_LIMITS_LIMITS(a) ,a, #define M_PROPERTIES_PROPERTIES(a) ,a, #define M_EMPLACE_TYPE_EMPLACE_TYPE(a) ,a, +#define M_USER_DATA_USER_DATA(a) ,a, // As attribute customization #define M_NEW_NEW(a) ,a, #define M_DEL_DEL(a) ,a, @@ -3495,6 +3496,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_GET_LIMITS(...) M_GET_METHOD(LIMITS, M_LIMITS_DEFAULT, __VA_ARGS__) #define M_GET_PROPERTIES(...) M_GET_METHOD(PROPERTIES, (), __VA_ARGS__) #define M_GET_EMPLACE_TYPE(...) M_GET_METHOD(EMPLACE_TYPE, M_NO_DEFAULT, __VA_ARGS__) +#define M_GET_USER_DATA(...) M_GET_METHOD(USER_DATA, M_NO_DEFAULT, __VA_ARGS__) // As attribute customization #define M_GET_NEW(...) M_GET_METHOD(NEW, M_NEW_DEFAULT, __VA_ARGS__) #define M_GET_DEL(...) M_GET_METHOD(DEL, M_DEL_DEFAULT, __VA_ARGS__) @@ -3573,6 +3575,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) //#define M_CALL_LIMITS(oplist, ...) M_APPLY_API(M_GET_LIMITS oplist, oplist, __VA_ARGS__) //#define M_CALL_PROPERTIES(oplist, ...) M_APPLY_API(M_GET_PROPERTIES oplist, oplist, __VA_ARGS__) //#define M_CALL_EMPLACE_TYPE(oplist, ...) M_APPLY_API(M_GET_EMPLACE_TYPE oplist, oplist, __VA_ARGS__) +//#define M_CALL_USER_DATA(oplist, ...) M_APPLY_API(M_GET_USER_DATA oplist, oplist, __VA_ARGS__) // As attribute customization #define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, __VA_ARGS__) #define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, __VA_ARGS__) @@ -3632,7 +3635,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_OPLAPI_EXTRACT_API_7(...) __VA_ARGS__ -/* Generic API transformation. +/* Generic API transformation (GAIA). * The API itself is described in the operator mapping with the method name. * * Usage in oplist: @@ -3649,6 +3652,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) * - ARG[1-9] : the associated argument number of the operator * - ARGPTR[1-9] : the pointer of the associated argument number of the operator * - OPLIST: the oplist + * - USER: The user data provided by the user to the container */ /* Needed duplicate of M_RET_ARG2 as we call it within a M_RET_ARG2 @@ -3690,6 +3694,18 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_REORDER_ARGLIST_FUNC_ARGPTR8(arglist) , & M_RET_ARG9 arglist , #define M_REORDER_ARGLIST_FUNC_ARGPTR9(arglist) , & M_RET_ARG10 arglist , +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG1(arglist) , sizeof ( M_RET_ARG2 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG2(arglist) , sizeof ( M_RET_ARG3 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG3(arglist) , sizeof ( M_RET_ARG4 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG4(arglist) , sizeof ( M_RET_ARG5 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG5(arglist) , sizeof ( M_RET_ARG6 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG6(arglist) , sizeof ( M_RET_ARG7 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG7(arglist) , sizeof ( M_RET_ARG8 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG8(arglist) , sizeof ( M_RET_ARG9 arglist ), +#define M_REORDER_ARGLIST_FUNC_SIZEOFARG9(arglist) , sizeof ( M_RET_ARG10 arglist ), + +#define M_REORDER_ARGLIST_FUNC_USER(arglist) , v->user_data , + #define M_REORDER_ARGLIST_FUNC_ID(arg) , arg , M_EAT /* Perform the API translation of the return code depending @@ -4287,11 +4303,11 @@ m_core_parse2_enum (const char str[], const char **endptr) oplist has been recorded for this type. */ #define M_LET(a, ...) \ - M_ID(M_LETI0 ((M_REVERSE(a, __VA_ARGS__, \ - M_IF(M_PARENTHESIS_P(a))(M_LETI_VAR_NAME_A, \ - M_LETI_VAR_NAME_B)(a) )))) + M_ID(M_LETI0 ((M_REVERSE(a, __VA_ARGS__, M_LETI_VAR_NAME(a) )))) // 1b. Generate a unique name based on the first variable and the line number +#define M_LETI_VAR_NAME(a) \ + M_IF(M_PARENTHESIS_P(a))(M_LETI_VAR_NAME_A, M_LETI_VAR_NAME_B)(a) #define M_LETI_VAR_NAME_A(var) M_C3(_local_cont_, M_RET_ARG1 var, __LINE__) #define M_LETI_VAR_NAME_B(var) M_C3(_local_cont_, var, __LINE__) // 2. Evaluate with or without and inject oplist @@ -4964,6 +4980,61 @@ m_core_parse2_enum (const char str[], const char **endptr) } +/************************************************************/ +/******************* EMBEDDED USER DATA ********************/ +/************************************************************/ + +// LIMITATION: USER_DATA shall be compatible with M_BASIC_OPLIST or M_PTR_OPLIST +// Only integer or pointers are supported. +// Nothing is called on destruction + +// Within a generated service, 'v' refers to the main object + +// Expand to a user data field, to be embedded in the structure +#define M_USER_FIELD(opl) M_IF_METHOD(USER_DATA, opl)(M_USER_FIELD_EXPAND, M_EAT)(opl) +#define M_USER_FIELD_EXPAND(opl) M_GET_USER_DATA opl user_data; + +// Expand to a user data param, to be used in a function prototype +#define M_USER_PARAM(opl) M_IF_METHOD(USER_DATA, opl)(M_USER_PARAM_EXPAND, M_EAT)(opl) +#define M_USER_PARAM_EXPAND(opl) , M_GET_USER_DATA opl user_data + +// Expand to a user data param, to be used for calling a function +#define M_USER_CALL(opl, value) M_IF_METHOD(USER_DATA, opl)(M_USER_CALL_EXPAND, M_EAT)(opl, value) +#define M_USER_CALL_EXPAND(opl, value) , value + +// Initialize a user data from its param +#define M_USER_INIT(opl, value) M_IF_METHOD(USER_DATA, opl)(M_USER_INIT_EXPAND, M_USER_VOID)(opl, value) +#define M_USER_INIT_EXPAND(opl, value) v->user_data = value; + +// Expand to an instruction valid but without any effect. +#define M_USER_VOID(...) (void) 0 + +// Return the user data of an object +#define M_USER_DATA(obj) obj->user_data + +// generate set / get user_data method +#define M_USER_DEF_GEN(opl, name, type) M_IF_METHOD(USER_DATA, opl)(M_USER_DEF_GEN_EXPAND, M_EAT)(opl, name, type) +#define M_USER_DEF_GEN_EXPAND(opl, name, type) \ + struct M_F(name, _user_s) { M_GET_USER_DATA opl user_data; }; \ + M_INLINE M_GET_USER_DATA opl M_F(name, _user_data)(type const v) { return v->user_data; } \ + M_INLINE void M_F(name, _update_user_data)(type v, M_GET_USER_DATA opl user_data) { v->user_data = user_data; } + +// To be used in oplist instead of INIT method +#define M_USER_INIT_OPERATOR(name, opl) \ + M_IF_METHOD(USER_DATA, opl)( INIT(API(M_F(name,_init), NONE, ARG1, USER)), INIT(M_F(name, _init)) ) + +// FIXME: 'v' disturb user namespace. +// Give 'value' as user data for the initialization of the following variables +#define M_USING_IN_LET(value, a, ...) \ + M_ID(M_USING_LETI0 ((value, M_REVERSE(a, __VA_ARGS__, M_LETI_VAR_NAME(a) )))) +#define M_USING_LETI0(list) M_USING_LETI1 list +#define M_USING_LETI1(value, cont, oplist, ...) \ + for(bool cont = true; cont; cont = false) \ + for(M_USING_SELF_TYPE(M_GLOBAL_OPLIST(oplist)) v[1] = { { value } }; cont ; cont = false) \ + M_LETI2(cont, M_GLOBAL_OPLIST(oplist), __VA_ARGS__) +#define M_USING_SELF_TYPE(op) struct M_F(M_GET_NAME op , _user_s) + + /************************************************************/ /******************* Exponential Backoff ********************/ /************************************************************/