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 ********************/ /************************************************************/