Skip to content

Commit

Permalink
WIP: Support user data within container.
Browse files Browse the repository at this point in the history
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.
(Third version)
  • Loading branch information
P-p-H-d committed Feb 2, 2024
1 parent d7a2323 commit 2795bdf
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 8 deletions.
22 changes: 18 additions & 4 deletions m-array.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)), ) \
Expand Down Expand Up @@ -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) \
Expand All @@ -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 */ \
Expand All @@ -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, v, m_user_data); \
v->size = 0; \
v->alloc = 0; \
v->ptr = NULL; \
Expand All @@ -226,6 +229,7 @@
M_F(name, _clear)(array_t v) \
{ \
M_ARRA4_CONTRACT(v); \
M_USER_LINK(oplist, v); \
M_F(name, _reset)(v); \
M_CALL_FREE(oplist, v->ptr); \
/* This is so reusing the object implies an assertion failure */ \
Expand All @@ -239,6 +243,7 @@
{ \
M_ARRA4_CONTRACT(d); \
M_ARRA4_CONTRACT(s); \
M_USER_LINK(oplist, d); \
if (M_UNLIKELY (d == s)) return; \
if (s->size > d->alloc) { \
const size_t alloc = s->size; \
Expand Down Expand Up @@ -266,7 +271,7 @@
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 */) \
Expand Down Expand Up @@ -317,6 +322,7 @@
M_F(name, _push_raw)(array_t v) \
{ \
M_ARRA4_CONTRACT(v); \
M_USER_LINK(oplist, v); \
if (M_UNLIKELY (v->size >= v->alloc)) { \
M_ASSERT(v->size == v->alloc); \
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
Expand Down Expand Up @@ -356,6 +362,7 @@
M_INLINE type * \
M_F(name, _push_new)(array_t v) \
{ \
M_USER_LINK(oplist, v); \
type *data = M_F(name, _push_raw)(v); \
if (M_UNLIKELY (data == NULL) ) \
return NULL; \
Expand All @@ -382,6 +389,7 @@
{ \
M_ARRA4_CONTRACT(v); \
M_ASSERT_INDEX(key, v->size+1); \
M_USER_LINK(oplist, v); \
if (M_UNLIKELY (v->size >= v->alloc) ) { \
M_ASSERT(v->size == v->alloc); \
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
Expand Down Expand Up @@ -411,6 +419,7 @@
M_F(name, _resize)(array_t v, size_t size) \
{ \
M_ARRA4_CONTRACT(v); \
M_USER_LINK(oplist, v); \
if (v->size > size) { \
/* Decrease size of array */ \
for(size_t i = size ; i < v->size; i++) \
Expand Down Expand Up @@ -440,6 +449,7 @@
M_F(name, _reserve)(array_t v, size_t alloc) \
{ \
M_ARRA4_CONTRACT(v); \
M_USER_LINK(oplist, v); \
/* NOTE: Reserve below needed size to perform a shrink to fit */ \
if (v->size > alloc) { \
alloc = v->size; \
Expand All @@ -465,6 +475,7 @@
M_F(name, _safe_get)(array_t v, size_t idx) \
{ \
M_ARRA4_CONTRACT(v); \
M_USER_LINK(oplist, v); \
const size_t size = idx + 1; \
/* resize if needed */ \
if (v->size <= size) { \
Expand Down Expand Up @@ -589,6 +600,7 @@
{ \
M_ARRA4_CONTRACT(v); \
M_ASSERT_INDEX(i, v->size+1); \
M_USER_LINK(oplist, v); \
size_t size = v->size + num; \
/* Test for overflow of variable size */ \
if (M_UNLIKELY_NOMEM (size <= v->size)) { \
Expand Down Expand Up @@ -888,6 +900,7 @@
M_INLINE void \
M_F(name, _special_stable_sort)(array_t l) \
{ \
M_USER_LINK(oplist, l); \
if (M_UNLIKELY (l->size < 2)) \
return; \
/* NOTE: if size is <= 4, no need to perform an allocation */ \
Expand Down Expand Up @@ -941,6 +954,7 @@
{ \
M_ARRA4_CONTRACT(a1); \
M_ARRA4_CONTRACT(a2); \
M_USER_LINK(oplist, a1); \
if (M_LIKELY (a2->size > 0)) { \
size_t newSize = a1->size + a2->size; \
/* To overflow newSize, we need to a1 and a2 a little bit above \
Expand Down
79 changes: 75 additions & 4 deletions m-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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__)
Expand Down Expand Up @@ -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__)
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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) , m_user_data ,

#define M_REORDER_ARGLIST_FUNC_ID(arg) , arg , M_EAT

/* Perform the API translation of the return code depending
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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, 'm_user_data' refers to the provided user_data

// Expand to an instruction valid but without any effect.
#define M_USER_VOID(...) (void) 0

// 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 parameter, 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 m_user_data

// Expand to a user data parameter, 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 given value
#define M_USER_INIT(opl, v, value) M_IF_METHOD(USER_DATA, opl)(M_USER_INIT_EXPAND, M_USER_VOID)(opl, v, value)
#define M_USER_INIT_EXPAND(opl, v, value) v->user_data = value;

// Return the user data of an object (It is assumed the use is discarded if not enabled)
#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) \
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 m_user_data) { v->user_data = m_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)) M_DEFERRED_COMMA USER_DATA(M_GET_USER_DATA opl), \
INIT(M_F(name, _init)) )

// Create a link between the user data of the objet and the oplist CALLS which will try to use it:
// Create a temp variable named m_user_data
#define M_USER_LINK(opl, var) M_IF_METHOD(USER_DATA, opl)(M_USER_LINK_EXPAND, M_USER_VOID)(opl, var)
#define M_USER_LINK_EXPAND(opl, var) M_GET_USER_DATA opl const m_user_data = M_USER_DATA(var); (void) m_user_data

// To be used before a M_LET to link the variables of the M_LET to the provided user data for initialization
#define M_USING_USER_DATA(type, val) M_USING_USER_DATA_EXPAND(type, val, M_C(m_var_user_data, __LINE__))
#define M_USING_USER_DATA_EXPAND(type, val, cont) \
for(bool cont = true; cont; cont = false) \
for(type const m_user_data = val; cont ; cont = false)


/************************************************************/
/******************* Exponential Backoff ********************/
/************************************************************/
Expand Down

0 comments on commit 2795bdf

Please sign in to comment.