Reformat macro to 80 characters
This commit is contained in:
1 parent
8a0a556604
commit
54d4b80368
27 files changed
+12821
-12821
No files matched your search
@@ -31,18 +31,18 @@
|
||||
which oplist is 'contOp', as static inline functions.
|
||||
USAGE:
|
||||
ALGO_DEF(algogName, containerOplist|type if oplist has been registered) */
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ALGOI_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
#define ALGO_DEF(name, cont_oplist) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ALGOI_DEF_P1(name, M_GLOBAL_OPLIST(cont_oplist)) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Map a function (or a macro) to all elements of a container.
|
||||
USAGE:
|
||||
ALGO_FOR_EACH(container, containerOplist, function[, extra arguments of function]) */
|
||||
#define ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
|
||||
#define ALGO_FOR_EACH(container, cont_oplist, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_FOR_EACH(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__), \
|
||||
ALGOI_FOR_EACH_ARG(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__ ))
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
USAGE:
|
||||
ALGO_TRANSFORM(contDst, contDOplist, contSrc, contSrcOplist,
|
||||
function[, extra arguments of function]) */
|
||||
#define ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_TRANSFORM(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__), \
|
||||
ALGOI_TRANSFORM_ARG(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__ ))
|
||||
|
||||
@@ -61,10 +61,10 @@
|
||||
USAGE:
|
||||
ALGO_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist
|
||||
[, function [, extra arguments of function]]) */
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define ALGO_EXTRACT(contD, contDop, contS, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_EXTRACT(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_EXTRACT_FUNC(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__), \
|
||||
ALGOI_EXTRACT_ARG(contD, M_GLOBAL_OPLIST(contDop), M_GLOBAL_OPLIST(contS), __VA_ARGS__ )))
|
||||
|
||||
@@ -73,8 +73,8 @@
|
||||
USAGE:
|
||||
ALGO_REDUCE(dstVar, container, contOplist, reduceFunc
|
||||
[, mapFunc[, extraParameters of map function]]) */
|
||||
#define ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
M_IF(M_PARENTHESIS_P(dest)) \
|
||||
#define ALGO_REDUCE(dest, cont, contOp, ...) \
|
||||
M_IF(M_PARENTHESIS_P(dest)) \
|
||||
(ALGOI_REDUCE_DISPATCH(M_PAIR_1 dest, M_GLOBAL_OPLIST(M_PAIR_2 dest), M_GLOBAL_TYPE(M_PAIR_2 dest),cont, M_GLOBAL_OPLIST(contOp), __VA_ARGS__), \
|
||||
ALGOI_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
ALGO_INIT_VA(container, containerOplist, param1[, param2[, ...]]).
|
||||
OBSOLETE: WILL BE DELETED.
|
||||
*/
|
||||
#define ALGO_INIT_VA(dest, contOp, ...) \
|
||||
#define ALGO_INIT_VA(dest, contOp, ...) \
|
||||
ALGO_INIT_VAI(dest, M_GLOBAL_OPLIST(contOp), __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
}
|
||||
OBSOLETE: WILL BE DELETED.
|
||||
*/
|
||||
#define ALGO_LET_INIT_VA(dest, contOp, ...) \
|
||||
#define ALGO_LET_INIT_VA(dest, contOp, ...) \
|
||||
ALGO_LET_INIT_VAI(dest, M_GLOBAL_OPLIST(contOp), __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -104,16 +104,16 @@
|
||||
USAGE:
|
||||
ALGO_INSERT_AT(containerDst, containerDstOPLIST|containerDstType, containerDstIterator, containerSrc, containerSrcOPLIST|containerSrcType)
|
||||
*/
|
||||
#define ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
#define ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
|
||||
ALGOI_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
/* Try to expand the algorithms */
|
||||
#define ALGOI_DEF_P1(name, cont_oplist) \
|
||||
ALGOI_DEF_P2(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
M_GET_SUBTYPE cont_oplist, M_GET_OPLIST cont_oplist, \
|
||||
#define ALGOI_DEF_P1(name, cont_oplist) \
|
||||
ALGOI_DEF_P2(name, M_GET_TYPE cont_oplist, cont_oplist, \
|
||||
M_GET_SUBTYPE cont_oplist, M_GET_OPLIST cont_oplist, \
|
||||
M_GET_IT_TYPE cont_oplist)
|
||||
|
||||
/* First validate the first oplist */
|
||||
@@ -246,7 +246,7 @@
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
|
||||
type_t const *ref1 = M_CALL_IT_CREF(cont_oplist, it1); \
|
||||
type_t const *ref2 = M_CALL_IT_CREF(cont_oplist, it2); \
|
||||
if (!(cmp_func(name, sort_name, ref1, ref2) <= 0)) { \
|
||||
if (!(cmp_func(name, sort_name, ref1, ref2) <= 0)) { \
|
||||
return false; \
|
||||
} \
|
||||
M_CALL_IT_SET(cont_oplist, it1, it2); \
|
||||
@@ -260,11 +260,11 @@
|
||||
/* - an unstable merge sort (need 'splice_back' method) */ \
|
||||
/* - an insertion sort (need 'previous' method) */ \
|
||||
/* - a selection sort */ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
|
||||
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
|
||||
M_IF(M_AND(M_TEST_METHOD_P(SORT, cont_oplist), M_EMPTY_P(cmp_arg)))( \
|
||||
/******** OPTIMIZED SORT FOR CONTAINER *********/ \
|
||||
static inline void M_C(name,sort_name)(container_t l) \
|
||||
{ \
|
||||
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
|
||||
} \
|
||||
, \
|
||||
\
|
||||
@@ -279,7 +279,7 @@
|
||||
{ \
|
||||
it_t it; \
|
||||
bool b = false; \
|
||||
/* Split 'l' into 'l1' and 'l2' */ \
|
||||
/* Split 'l' into 'l1' and 'l2' */ \
|
||||
for (M_CALL_IT_FIRST(cont_oplist,it, l); \
|
||||
!M_CALL_IT_END_P(cont_oplist, it);) { \
|
||||
M_CALL_SPLICE_BACK(cont_oplist, (b ? l1 : l2), l, it); \
|
||||
@@ -300,14 +300,14 @@
|
||||
M_CALL_IT_FIRST(cont_oplist,it1, l1); \
|
||||
M_CALL_IT_FIRST(cont_oplist,it2, l2); \
|
||||
while (true) { \
|
||||
/* Compare current elements of the containers l1 and l2 */ \
|
||||
/* Compare current elements of the containers l1 and l2 */ \
|
||||
int c = cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
if (c <= 0) { \
|
||||
/* Move the element of l1 in the new container */ \
|
||||
/* Move the element of l1 in the new container */ \
|
||||
M_CALL_SPLICE_AT(cont_oplist, l, it, l1, it1); \
|
||||
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it1))) { \
|
||||
/* Move all remaining elements of l2 in 'l' */ \
|
||||
/* Move all remaining elements of l2 in 'l' */ \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
|
||||
M_CALL_SPLICE_AT(cont_oplist, l, it, l2, it2); \
|
||||
} \
|
||||
@@ -330,7 +330,7 @@
|
||||
\
|
||||
/* Sort the container 'l' */ \
|
||||
static inline void \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
M_C(name,sort_name)(container_t l cmp_param(name)) \
|
||||
{ \
|
||||
container_t l1; \
|
||||
container_t l2; \
|
||||
@@ -350,8 +350,8 @@
|
||||
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it))) { \
|
||||
/* Two elements */ \
|
||||
int c = cmp_func(name, sort_name, \
|
||||
M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2)); \
|
||||
if (c > 0) { \
|
||||
/* SWAP */ \
|
||||
M_CALL_SPLICE_BACK(cont_oplist, l, l, it2); \
|
||||
@@ -391,8 +391,8 @@
|
||||
M_CALL_IT_SET(cont_oplist, it2p1, it1); \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, it2) \
|
||||
&& !(cmp_func(name, sort_name, \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CONST_CAST(type_t, &x)) <= 0)) { \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CONST_CAST(type_t, &x)) <= 0)) { \
|
||||
/* TAB[jp1=j+1] := TAB[j] */ \
|
||||
memcpy(M_CALL_IT_REF(cont_oplist, it2p1), \
|
||||
M_CALL_IT_CREF(cont_oplist, it2), sizeof (type_t) ); \
|
||||
@@ -423,7 +423,7 @@
|
||||
!M_CALL_IT_END_P(cont_oplist, it2); \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2)) { \
|
||||
if (cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it2), \
|
||||
M_CALL_IT_CREF(cont_oplist, it_min)) < 0) { \
|
||||
M_CALL_IT_CREF(cont_oplist, it_min)) < 0) { \
|
||||
M_CALL_IT_SET(cont_oplist, it_min, it2); \
|
||||
} \
|
||||
} \
|
||||
@@ -463,23 +463,23 @@
|
||||
if (cmp <= 0) { \
|
||||
/* The element of dst is before. Go to next element of dst */ \
|
||||
M_CALL_IT_SET(cont_oplist, itIns, itDst); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itDst); \
|
||||
if (cmp == 0) { \
|
||||
/* Skip same arguments in both lists */ \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} else { \
|
||||
/* The element of src is before. */ \
|
||||
/* insert objSrc before */ \
|
||||
/* insert objSrc before */ \
|
||||
/* NOTE: IT_INSERT insert after ==> Need of another iterator */ \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} \
|
||||
while (!M_CALL_IT_END_P(cont_oplist, itSrc)) { \
|
||||
/* Finish inserting the element of src in dst */ \
|
||||
type_t *objSrc = M_CALL_IT_REF(cont_oplist, itSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_INSERT(cont_oplist, dst, itIns, *objSrc); \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
} \
|
||||
} \
|
||||
@@ -501,7 +501,7 @@
|
||||
&& !M_CALL_IT_END_P(cont_oplist, itDst)) { \
|
||||
type_t const *objSrc = M_CALL_IT_CREF(cont_oplist, itSrc); \
|
||||
type_t const *objDst = M_CALL_IT_CREF(cont_oplist, itDst); \
|
||||
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
|
||||
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
|
||||
if (cmp == 0) { \
|
||||
/* Keep it */ \
|
||||
M_CALL_IT_NEXT(cont_oplist, itSrc); \
|
||||
@@ -677,7 +677,7 @@
|
||||
M_CALL_IT_NEXT(cont_oplist, it1), \
|
||||
M_CALL_IT_NEXT(cont_oplist, it2)) { \
|
||||
if (!call_eq(func, *M_CALL_IT_CREF(cont_oplist, it1), \
|
||||
*M_CALL_IT_CREF(cont_oplist, it2))) \
|
||||
*M_CALL_IT_CREF(cont_oplist, it2))) \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
@@ -696,7 +696,7 @@
|
||||
/* Define the FILL algorithms */
|
||||
#define ALGOI_FILL_DEF_P5(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
|
||||
\
|
||||
/* Fill all the container with value (overwritten) */ \
|
||||
/* Fill all the container with value (overwritten) */ \
|
||||
static inline void \
|
||||
M_C(name, _fill) (container_t l, type_t const value) \
|
||||
{ \
|
||||
@@ -841,7 +841,7 @@
|
||||
\
|
||||
static inline bool \
|
||||
M_C4(name, _all_of, suffix, p) (container_t const l, \
|
||||
func_t func ) \
|
||||
func_t func ) \
|
||||
{ \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
if (!call(func, *item)) \
|
||||
@@ -1051,93 +1051,93 @@
|
||||
// _flatten (takes a set of containers and returns a new container containing all flatten objects)
|
||||
|
||||
|
||||
#define ALGOI_FOR_EACH(container, cont_oplist, func) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(*_item); \
|
||||
} \
|
||||
#define ALGOI_FOR_EACH(container, cont_oplist, func) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(*_item); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(__VA_ARGS__, *_item); \
|
||||
} \
|
||||
#define ALGOI_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
|
||||
for M_EACH(_item, container, cont_oplist) { \
|
||||
func(__VA_ARGS__, *_item); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
func(_tmp, *_item); \
|
||||
M_CALL_PUSH_MOVE(contDop, contD, &_tmp); \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDop) (M_CALL_REVERSE(contDop, contD);, ) \
|
||||
#define ALGOI_TRANSFORM(contD, contDop, contS, contSop, func) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
func(_tmp, *_item); \
|
||||
M_CALL_PUSH_MOVE(contDop, contD, &_tmp); \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDop) (M_CALL_REVERSE(contDop, contD);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
func(_tmp, *_item, __VA_ARGS__); \
|
||||
M_CALL_PUSH_MOVE(contDop, contD, &_tmp); \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDop) (M_CALL_REVERSE(contDop, contD);, ) \
|
||||
#define ALGOI_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
|
||||
M_CALL_CLEAN(contDop, contD); \
|
||||
for M_EACH(_item, contS, contSop) { \
|
||||
M_GET_SUBTYPE contDop _tmp; \
|
||||
M_CALL_INIT(M_GET_OPLIST contDop, _tmp); \
|
||||
func(_tmp, *_item, __VA_ARGS__); \
|
||||
M_CALL_PUSH_MOVE(contDop, contD, &_tmp); \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDop) (M_CALL_REVERSE(contDop, contD);, ) \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_EXTRACT(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
, \
|
||||
#define ALGOI_EXTRACT(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
, \
|
||||
M_CALL_SET_KEY(contDstOplist, contDst, (*_item).key, (*_item).value); \
|
||||
) \
|
||||
} \
|
||||
) \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_EXTRACT_FUNC(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
condFunc) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (*_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
, \
|
||||
#define ALGOI_EXTRACT_FUNC(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
condFunc) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (*_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
, \
|
||||
M_CALL_SET_KEY(contDstOplist, contDst, (*_item).key, (*_item).value); \
|
||||
) \
|
||||
} \
|
||||
} \
|
||||
) \
|
||||
} \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDst);, ) \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_EXTRACT_ARG(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
condFunc, ...) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (__VA_ARGS__, *_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
, \
|
||||
#define ALGOI_EXTRACT_ARG(contDst, contDstOplist, \
|
||||
contSrc, contSrcOplist, \
|
||||
condFunc, ...) do { \
|
||||
M_CALL_CLEAN(contDstOplist, contDst); \
|
||||
for M_EACH(_item, contSrc, contSrcOplist) { \
|
||||
if (condFunc (__VA_ARGS__, *_item)) { \
|
||||
M_IF_METHOD(PUSH, contDstOplist)( \
|
||||
M_CALL_PUSH(contDstOplist, contDst, *_item); \
|
||||
, \
|
||||
M_CALL_SET_KEY(contDstOplist, contDst, (*_item).key, (*_item).value); \
|
||||
) \
|
||||
} \
|
||||
} \
|
||||
) \
|
||||
} \
|
||||
} \
|
||||
M_IF_METHOD(REVERSE, contDstOplist) (M_CALL_REVERSE(contDstOplist, contDstOplist);, ) \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
#define ALGOI_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
M_IF_NARGS_EQ2(__VA_ARGS__) \
|
||||
(ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
|
||||
ALGOI_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, contOp, __VA_ARGS__) ) )
|
||||
|
||||
/* The special functions handled by ALGO_REDUCE */
|
||||
@@ -1149,94 +1149,94 @@
|
||||
/* Return the method associated to a reduce operation.
|
||||
It returns the special function handler if function is and, or, sum or add.
|
||||
Otherwise it returns the original function */
|
||||
#define ALGOI_REDUCE_FUNC(reduceFunc) \
|
||||
M_IF(M_KEYWORD_P(and, reduceFunc)) \
|
||||
(ALGOI_REDUCE_AND, \
|
||||
M_IF(M_KEYWORD_P(or, reduceFunc)) \
|
||||
(ALGOI_REDUCE_OR, \
|
||||
M_IF(M_KEYWORD_P(sum, reduceFunc)) \
|
||||
(ALGOI_REDUCE_SUM, \
|
||||
M_IF(M_KEYWORD_P(product, reduceFunc)) \
|
||||
(ALGOI_REDUCE_PRODUCT, \
|
||||
reduceFunc) \
|
||||
) \
|
||||
) \
|
||||
#define ALGOI_REDUCE_FUNC(reduceFunc) \
|
||||
M_IF(M_KEYWORD_P(and, reduceFunc)) \
|
||||
(ALGOI_REDUCE_AND, \
|
||||
M_IF(M_KEYWORD_P(or, reduceFunc)) \
|
||||
(ALGOI_REDUCE_OR, \
|
||||
M_IF(M_KEYWORD_P(sum, reduceFunc)) \
|
||||
(ALGOI_REDUCE_SUM, \
|
||||
M_IF(M_KEYWORD_P(product, reduceFunc)) \
|
||||
(ALGOI_REDUCE_PRODUCT, \
|
||||
reduceFunc) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
#define ALGOI_REDUCE_BASIC(dest, dest_t, destOp, cont, cont_oplist, reduceFunc) do { \
|
||||
bool _init_done = false; \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, *_item); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, *_item); \
|
||||
_init_done = true; \
|
||||
} \
|
||||
} \
|
||||
bool _init_done = false; \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, *_item); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, *_item); \
|
||||
_init_done = true; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc) do { \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
} \
|
||||
} \
|
||||
M_CALL_CLEAR(destOp, _tmp); \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
} \
|
||||
} \
|
||||
M_CALL_CLEAR(destOp, _tmp); \
|
||||
} while (0)
|
||||
|
||||
#define ALGOI_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, cont_oplist, reduceFunc, mapFunc, ...) do { \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, __VA_ARGS__, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
} \
|
||||
} \
|
||||
M_CALL_CLEAR(destOp, _tmp); \
|
||||
bool _init_done = false; \
|
||||
dest_t _tmp; \
|
||||
M_CALL_INIT(destOp, _tmp); \
|
||||
for M_EACH(_item, cont, cont_oplist) { \
|
||||
mapFunc(_tmp, __VA_ARGS__, *_item); \
|
||||
if (_init_done) { \
|
||||
ALGOI_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
|
||||
} else { \
|
||||
M_CALL_SET(destOp, dest, _tmp); \
|
||||
_init_done = true; \
|
||||
} \
|
||||
} \
|
||||
M_CALL_CLEAR(destOp, _tmp); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define ALGOI_INIT_VA_FUNC(d, a) \
|
||||
#define ALGOI_INIT_VA_FUNC(d, a) \
|
||||
M_RET_ARG2 d (M_RET_ARG1 d, a) M_DEFERRED_COMMA
|
||||
|
||||
#define ALGO_INIT_VAI(dest, contOp, ...) \
|
||||
(void)(M_CALL_INIT(contOp, dest) M_DEFERRED_COMMA \
|
||||
#define ALGO_INIT_VAI(dest, contOp, ...) \
|
||||
(void)(M_CALL_INIT(contOp, dest) M_DEFERRED_COMMA \
|
||||
M_MAP2(ALGOI_INIT_VA_FUNC, (dest, M_GET_PUSH contOp, ) , __VA_ARGS__) \
|
||||
true)
|
||||
|
||||
|
||||
#define ALGO_LET_INIT_VAI(dest, ...) \
|
||||
#define ALGO_LET_INIT_VAI(dest, ...) \
|
||||
ALGOI_LET_INIT_VAI(M_C3(m_cont_, __LINE__, dest), dest, __VA_ARGS__)
|
||||
|
||||
#define ALGOI_LET_INIT_VAI(cont, dest, contOp, ...) \
|
||||
for(bool cont = true; cont ; /* unused */) \
|
||||
for(M_GET_TYPE contOp dest; \
|
||||
cont && (ALGO_INIT_VAI (dest, contOp, __VA_ARGS__), true); \
|
||||
#define ALGOI_LET_INIT_VAI(cont, dest, contOp, ...) \
|
||||
for(bool cont = true; cont ; /* unused */) \
|
||||
for(M_GET_TYPE contOp dest; \
|
||||
cont && (ALGO_INIT_VAI (dest, contOp, __VA_ARGS__), true); \
|
||||
(M_CALL_CLEAR(contOp, dest), cont = false))
|
||||
|
||||
|
||||
#define ALGOI_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) do { \
|
||||
M_GET_IT_TYPE contSrcOp _itSrc; \
|
||||
M_GET_IT_TYPE contDstOp _itDst; \
|
||||
M_CALL_IT_SET(contDstOp, _itDst, position); \
|
||||
for (M_CALL_IT_FIRST(contSrcOp, _itSrc, contSrc) ; \
|
||||
!M_CALL_IT_END_P(contSrcOp, _itSrc) ; \
|
||||
M_CALL_IT_NEXT(contSrcOp, _itSrc) ) { \
|
||||
M_CALL_IT_INSERT(contDstOp, contDst, _itDst, \
|
||||
*M_CALL_IT_CREF(contSrcOp, _itSrc)); \
|
||||
} \
|
||||
M_GET_IT_TYPE contSrcOp _itSrc; \
|
||||
M_GET_IT_TYPE contDstOp _itDst; \
|
||||
M_CALL_IT_SET(contDstOp, _itDst, position); \
|
||||
for (M_CALL_IT_FIRST(contSrcOp, _itSrc, contSrc) ; \
|
||||
!M_CALL_IT_END_P(contSrcOp, _itSrc) ; \
|
||||
M_CALL_IT_NEXT(contSrcOp, _itSrc) ) { \
|
||||
M_CALL_IT_INSERT(contDstOp, contDst, _itDst, \
|
||||
*M_CALL_IT_CREF(contSrcOp, _itSrc)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
+36
-36
@@ -35,7 +35,7 @@
|
||||
APPLE Clang defines __GNUC__ to be only 4 despite having full support
|
||||
for atomic.
|
||||
*/
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
#if defined(__cplusplus) && __cplusplus >= 201103L \
|
||||
&& !(defined(__GNUC__) && __GNUC__ < 5 && !defined(__APPLE__))
|
||||
|
||||
/* NOTE: This is what the stdatomic.h header shall do in C++ mode. */
|
||||
@@ -128,7 +128,7 @@ using std::memory_order_seq_cst;
|
||||
*/
|
||||
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) ) \
|
||||
|| (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__cplusplus) && (__GNUC__*100 + __GNUC_MINOR__) >= 409) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4) \
|
||||
|| (defined(__clang__) && __clang_major__ >= 4) \
|
||||
|| (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1800)
|
||||
|
||||
#include <stdatomic.h>
|
||||
@@ -167,12 +167,12 @@ M_BEGIN_PROTECTED_CODE
|
||||
_lock : the mutex lock.
|
||||
Support up to sizeof (long long) type.
|
||||
*/
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
#define _Atomic(T) \
|
||||
struct { \
|
||||
T volatile _val; \
|
||||
T _zero; \
|
||||
T _previous; \
|
||||
m_mutex_t _lock; \
|
||||
}
|
||||
|
||||
/* Define the supported memory order.
|
||||
@@ -217,8 +217,8 @@ typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||
#endif
|
||||
|
||||
/* Detect if stdint.h was included */
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
#if (defined (INTMAX_C) && defined (UINTMAX_C) && !defined(__cplusplus)) || \
|
||||
defined (_STDINT_H) || defined (_STDINT_H_) || defined (_STDINT) || \
|
||||
defined (_SYS_STDINT_H_)
|
||||
/* Define additional atomic types */
|
||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||
@@ -241,10 +241,10 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
The trick is computing _val - _zero within the lock, then
|
||||
returns retvalue + _zero after the release of the lock.
|
||||
*/
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
#define atomic_fetch_op(ptr, val, op) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
(ptr)->_val op (val), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long)((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
/* Perform an atomic add (EMULATION) */
|
||||
@@ -264,49 +264,49 @@ static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val)
|
||||
#define ATOMIC_VAR_INIT(val) { val, 0, 0, M_MUTEXI_INIT_VALUE }
|
||||
|
||||
/* Initialize an atomic variable */
|
||||
#define atomic_init(ptr, val) \
|
||||
#define atomic_init(ptr, val) \
|
||||
(m_mutex_init((ptr)->_lock), (ptr)->_val = val, (ptr)->_zero = 0)
|
||||
|
||||
/* (INTERNAL) Load an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
#define atomic_load_lock(ptr) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_previous = (ptr)->_val, \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, (long long) ((ptr)->_previous-(ptr)->_zero))+(ptr)->_zero)
|
||||
|
||||
/* (INTERNAL) Store an atomic variable within a lock
|
||||
(needed for variable greater than CPU atomic size) */
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
#define atomic_store_lock(ptr, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
(ptr)->_val = (val), \
|
||||
m_mutex_unlock((ptr)->_lock))
|
||||
|
||||
/* Atomic load of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct read of the variable (much faster) */
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
#define atomic_load(ptr) \
|
||||
( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE \
|
||||
? (ptr)->_val \
|
||||
: atomic_load_lock(ptr))
|
||||
|
||||
/* Atomic store of a variable (EMULATION)
|
||||
If the atomic type size is not greater than the CPU atomic size,
|
||||
we can perform a direct write of the variable (much faster) */
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (long long) ((val) - (ptr)->_zero); \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
#define atomic_store(ptr, val) do { \
|
||||
if ( sizeof ((ptr)->_val) <= ATOMICI_MIN_RW_SIZE) { \
|
||||
(ptr)->_val = (val); \
|
||||
} else { \
|
||||
long long _offset = (long long) ((val) - (ptr)->_zero); \
|
||||
atomic_store_lock(ptr, (ptr)->_zero + _offset); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Perform a CAS (Compare and swap) operation (EMULATION) */
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
#define atomic_compare_exchange_strong(ptr, exp, val) \
|
||||
(m_mutex_lock((ptr)->_lock), \
|
||||
atomic_fetch_unlock(&(ptr)->_lock, \
|
||||
(ptr)->_val == *(exp) \
|
||||
? ((ptr)->_val = (val), true) \
|
||||
: (*(exp) = (ptr)->_val, false)))
|
||||
|
||||
|
||||
|
||||
+40
-40
@@ -47,13 +47,13 @@ typedef uint64_t bitset_limb_ct;
|
||||
#define BITSETI_FROM_ALLOC(n) ((n) * BITSET_LIMB_BIT)
|
||||
|
||||
// Contract of a bitset
|
||||
#define BITSETI_CONTRACT(t) do { \
|
||||
assert (t != NULL); \
|
||||
assert (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
|
||||
assert (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
|
||||
assert (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
|
||||
assert (t->size == 0 || t->ptr != NULL); \
|
||||
assert (t->alloc == 0 || t->ptr != NULL); \
|
||||
#define BITSETI_CONTRACT(t) do { \
|
||||
assert (t != NULL); \
|
||||
assert (t->size <= BITSETI_FROM_ALLOC (t->alloc)); \
|
||||
assert (t->alloc <= ((size_t)-1) / BITSET_LIMB_BIT); \
|
||||
assert (t->size < ((size_t)-1) - BITSET_LIMB_BIT); \
|
||||
assert (t->size == 0 || t->ptr != NULL); \
|
||||
assert (t->alloc == 0 || t->ptr != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -754,39 +754,39 @@ bitset_clz(const bitset_t set)
|
||||
}
|
||||
|
||||
/* Oplist for a bitset */
|
||||
#define BITSET_OPLIST \
|
||||
(INIT(bitset_init) \
|
||||
,INIT_SET(bitset_init_set) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(bitset_set) \
|
||||
,CLEAR(bitset_clear) \
|
||||
,INIT_MOVE(bitset_init_move) \
|
||||
,MOVE(bitset_move) \
|
||||
,SWAP(bitset_swap) \
|
||||
,TYPE(bitset_t) \
|
||||
,SUBTYPE(bool) \
|
||||
,TEST_EMPTY(bitset_empty_p), \
|
||||
,GET_SIZE(bitset_size) \
|
||||
,IT_TYPE(bitset_it_t) \
|
||||
,IT_FIRST(bitset_it) \
|
||||
,IT_SET(bitset_it_set) \
|
||||
,IT_LAST(bitset_it_last) \
|
||||
,IT_END(bitset_it_end) \
|
||||
,IT_END_P(bitset_end_p) \
|
||||
,IT_LAST_P(bitset_last_p) \
|
||||
,IT_EQUAL_P(bitset_it_equal_p) \
|
||||
,IT_NEXT(bitset_next) \
|
||||
,IT_PREVIOUS(bitset_previous) \
|
||||
,IT_CREF(bitset_cref) \
|
||||
,CLEAN(bitset_clean) \
|
||||
,PUSH(bitset_push_back) \
|
||||
,POP(bitset_pop_back) \
|
||||
,HASH(bitset_hash) \
|
||||
,GET_STR(bitset_get_str) \
|
||||
,OUT_STR(bitset_out_str) \
|
||||
,PARSE_STR(bitset_parse_str) \
|
||||
,IN_STR(bitset_in_str) \
|
||||
,EQUAL(bitset_equal_p) \
|
||||
#define BITSET_OPLIST \
|
||||
(INIT(bitset_init) \
|
||||
,INIT_SET(bitset_init_set) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(bitset_set) \
|
||||
,CLEAR(bitset_clear) \
|
||||
,INIT_MOVE(bitset_init_move) \
|
||||
,MOVE(bitset_move) \
|
||||
,SWAP(bitset_swap) \
|
||||
,TYPE(bitset_t) \
|
||||
,SUBTYPE(bool) \
|
||||
,TEST_EMPTY(bitset_empty_p), \
|
||||
,GET_SIZE(bitset_size) \
|
||||
,IT_TYPE(bitset_it_t) \
|
||||
,IT_FIRST(bitset_it) \
|
||||
,IT_SET(bitset_it_set) \
|
||||
,IT_LAST(bitset_it_last) \
|
||||
,IT_END(bitset_it_end) \
|
||||
,IT_END_P(bitset_end_p) \
|
||||
,IT_LAST_P(bitset_last_p) \
|
||||
,IT_EQUAL_P(bitset_it_equal_p) \
|
||||
,IT_NEXT(bitset_next) \
|
||||
,IT_PREVIOUS(bitset_previous) \
|
||||
,IT_CREF(bitset_cref) \
|
||||
,CLEAN(bitset_clean) \
|
||||
,PUSH(bitset_push_back) \
|
||||
,POP(bitset_pop_back) \
|
||||
,HASH(bitset_hash) \
|
||||
,GET_STR(bitset_get_str) \
|
||||
,OUT_STR(bitset_out_str) \
|
||||
,PARSE_STR(bitset_parse_str) \
|
||||
,IN_STR(bitset_in_str) \
|
||||
,EQUAL(bitset_equal_p) \
|
||||
)
|
||||
|
||||
/* Register the OPLIST as a global one */
|
||||
|
||||
+1201
-1201
File diff suppressed because it is too large.
Load diff
+924
-924
File diff suppressed because it is too large.
Load diff
+394
-394
@@ -34,74 +34,74 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Minimum number of nodes per group of nodes */
|
||||
#define C_MEMPOOL_MIN_NODE_PER_GROUP 16
|
||||
|
||||
#define C_MEMPOOL_DEF(name, type_t) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
#define C_MEMPOOL_DEF(name, type_t) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/* Classic internal Singly List without allocation */
|
||||
#define C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) { \
|
||||
struct M_C(name, _slist_node_s) *next; \
|
||||
type_t data; \
|
||||
} M_C(name, _slist_node_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) *M_C(name, _slist_ct)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_init)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
*list = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_push)(M_C(name, _slist_ct) list, \
|
||||
M_C(name, _slist_node_ct) *node) \
|
||||
{ \
|
||||
node->next = *list; \
|
||||
*list = node; \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name, _slist_node_ct) * \
|
||||
M_C(name, _slist_pop)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
assert (*list != NULL); \
|
||||
M_C(name, _slist_node_ct) *node = *list; \
|
||||
*list = node->next; \
|
||||
M_IF_DEBUG(node->next = NULL;) \
|
||||
return node; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _slist_empty_p)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
return *list == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_move)(M_C(name, _slist_ct) list, \
|
||||
M_C(name, _slist_ct) src) \
|
||||
{ \
|
||||
*list = *src; \
|
||||
*src = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_clear)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *it = *list, *next; \
|
||||
while (it) { \
|
||||
next = it->next; \
|
||||
M_MEMORY_DEL(it); \
|
||||
it = next; \
|
||||
} \
|
||||
*list = NULL; \
|
||||
} \
|
||||
#define C_MEMPOOL_DEF_SINGLY_LIST(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) { \
|
||||
struct M_C(name, _slist_node_s) *next; \
|
||||
type_t data; \
|
||||
} M_C(name, _slist_node_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _slist_node_s) *M_C(name, _slist_ct)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_init)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
*list = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_push)(M_C(name, _slist_ct) list, \
|
||||
M_C(name, _slist_node_ct) *node) \
|
||||
{ \
|
||||
node->next = *list; \
|
||||
*list = node; \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name, _slist_node_ct) * \
|
||||
M_C(name, _slist_pop)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
assert (*list != NULL); \
|
||||
M_C(name, _slist_node_ct) *node = *list; \
|
||||
*list = node->next; \
|
||||
M_IF_DEBUG(node->next = NULL;) \
|
||||
return node; \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _slist_empty_p)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
return *list == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_move)(M_C(name, _slist_ct) list, \
|
||||
M_C(name, _slist_ct) src) \
|
||||
{ \
|
||||
*list = *src; \
|
||||
*src = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _slist_clear)(M_C(name, _slist_ct) list) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *it = *list, *next; \
|
||||
while (it) { \
|
||||
next = it->next; \
|
||||
M_MEMORY_DEL(it); \
|
||||
it = next; \
|
||||
} \
|
||||
*list = NULL; \
|
||||
} \
|
||||
|
||||
|
||||
/* Lock Free free queue list (not generic one) of lists without allocation
|
||||
@@ -123,212 +123,212 @@ M_BEGIN_PROTECTED_CODE
|
||||
*/
|
||||
/* TODO: Optimize alignement to reduce memory consumption. NIL object can use []
|
||||
to reduce memory consumption too (non compatible with C++ ...) */
|
||||
#define C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lf_node_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(struct M_C(name, _lf_node_s) *) next; \
|
||||
m_gc_atomic_ticket_ct cpt; \
|
||||
M_C(name, _slist_ct) list; \
|
||||
} M_C(name, _lf_node_t); \
|
||||
\
|
||||
typedef struct M_C(name, _lflist_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) head; \
|
||||
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) tail; \
|
||||
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_C(name, _lf_node_t) nil; \
|
||||
} M_C(name, _lflist_ct)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_init)(M_C(name, _lflist_ct) list, \
|
||||
M_C(name, _lf_node_t) *node) \
|
||||
{ \
|
||||
atomic_init(&list->head, node); \
|
||||
atomic_init(&list->tail, node); \
|
||||
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _lflist_empty_p)(M_C(name, _lflist_ct) list) \
|
||||
{ \
|
||||
return atomic_load(&list->tail) == atomic_load(&list->head); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_push)(M_C(name, _lflist_ct) list, \
|
||||
#define C_MEMPOOL_DEF_LF_QUEUE(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lf_node_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(struct M_C(name, _lf_node_s) *) next; \
|
||||
m_gc_atomic_ticket_ct cpt; \
|
||||
M_C(name, _slist_ct) list; \
|
||||
} M_C(name, _lf_node_t); \
|
||||
\
|
||||
typedef struct M_C(name, _lflist_s) { \
|
||||
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) head; \
|
||||
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_ATTR_EXTENSION _Atomic(M_C(name, _lf_node_t) *) tail; \
|
||||
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
|
||||
M_C(name, _lf_node_t) nil; \
|
||||
} M_C(name, _lflist_ct)[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_init)(M_C(name, _lflist_ct) list, \
|
||||
M_C(name, _lf_node_t) *node) \
|
||||
{ \
|
||||
atomic_init(&list->head, node); \
|
||||
atomic_init(&list->tail, node); \
|
||||
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _lflist_empty_p)(M_C(name, _lflist_ct) list) \
|
||||
{ \
|
||||
return atomic_load(&list->tail) == atomic_load(&list->head); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_push)(M_C(name, _lflist_ct) list, \
|
||||
M_C(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
\
|
||||
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
tail = atomic_load(&list->tail); \
|
||||
next = atomic_load_explicit(&tail->next, memory_order_acquire); \
|
||||
if (M_UNLIKELY(next != &list->nil)) { \
|
||||
/* Tail was not pointing to the last node \
|
||||
Try to swing Tail to the next node */ \
|
||||
atomic_compare_exchange_weak_explicit(&list->tail, \
|
||||
&tail, next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Try to link node at the end of the linked list */ \
|
||||
if (atomic_compare_exchange_strong_explicit(&tail->next, \
|
||||
&next, node, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed)) \
|
||||
break; \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
/* Enqueue is done. Try to swing Tail to the inserted node \
|
||||
If it fails, someone else will do it or has already did it. */ \
|
||||
atomic_compare_exchange_strong_explicit(&list->tail, &tail, node, \
|
||||
memory_order_acq_rel, \
|
||||
memory_order_relaxed); \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
\
|
||||
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
tail = atomic_load(&list->tail); \
|
||||
next = atomic_load_explicit(&tail->next, memory_order_acquire); \
|
||||
if (M_UNLIKELY(next != &list->nil)) { \
|
||||
/* Tail was not pointing to the last node \
|
||||
Try to swing Tail to the next node */ \
|
||||
atomic_compare_exchange_weak_explicit(&list->tail, \
|
||||
&tail, next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Try to link node at the end of the linked list */ \
|
||||
if (atomic_compare_exchange_strong_explicit(&tail->next, \
|
||||
&next, node, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed)) \
|
||||
break; \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
/* Enqueue is done. Try to swing Tail to the inserted node \
|
||||
If it fails, someone else will do it or has already did it. */ \
|
||||
atomic_compare_exchange_strong_explicit(&list->tail, &tail, node, \
|
||||
memory_order_acq_rel, \
|
||||
memory_order_relaxed); \
|
||||
} \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _lflist_pop)(M_C(name, _lflist_ct) list, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *head; \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
\
|
||||
/* Reinitialize backoff */ \
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
head = atomic_load(&list->head); \
|
||||
tail = atomic_load(&list->tail); \
|
||||
next = atomic_load(&head->next); \
|
||||
/* Are head, tail, and next consistent?*/ \
|
||||
if (M_LIKELY(head == \
|
||||
atomic_load_explicit(&list->head, memory_order_relaxed))) \
|
||||
{ \
|
||||
/* Is queue empty or Tail falling behind? */ \
|
||||
if (head == tail) { \
|
||||
/* Is queue empty? */ \
|
||||
if (next == &list->nil) \
|
||||
return NULL; \
|
||||
/* Tail is falling behind. Try to advance it */ \
|
||||
atomic_compare_exchange_strong_explicit(&list->tail, &tail, \
|
||||
next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Try to swing Head to the next node */ \
|
||||
if (atomic_compare_exchange_strong_explicit(&list->head, \
|
||||
&head, next, \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *head; \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
\
|
||||
/* Reinitialize backoff */ \
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
head = atomic_load(&list->head); \
|
||||
tail = atomic_load(&list->tail); \
|
||||
next = atomic_load(&head->next); \
|
||||
/* Are head, tail, and next consistent?*/ \
|
||||
if (M_LIKELY(head == \
|
||||
atomic_load_explicit(&list->head, memory_order_relaxed))) \
|
||||
{ \
|
||||
/* Is queue empty or Tail falling behind? */ \
|
||||
if (head == tail) { \
|
||||
/* Is queue empty? */ \
|
||||
if (next == &list->nil) \
|
||||
return NULL; \
|
||||
/* Tail is falling behind. Try to advance it */ \
|
||||
atomic_compare_exchange_strong_explicit(&list->tail, &tail, \
|
||||
next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Try to swing Head to the next node */ \
|
||||
if (atomic_compare_exchange_strong_explicit(&list->head, \
|
||||
&head, next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed)) { \
|
||||
break; \
|
||||
} \
|
||||
/* Failure: perform a random exponential backoff */ \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
/* Failure: perform a random exponential backoff */ \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
/* dequeue returns an element that becomes the new dummy element (the new head), \
|
||||
and the former dummy element (the former head) is removed: \
|
||||
and the former dummy element (the former head) is removed: \
|
||||
Since we want a link of free list, and we don't care about the content itsef, \
|
||||
provided that the node we return is older than the one we should return, \
|
||||
Therefore, we return the previous dummy head. \
|
||||
As such, it is not the original MSqueue algorithm. */ \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
|
||||
return head; \
|
||||
} \
|
||||
\
|
||||
/* Dequeue a node if the node is old enough */ \
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _lflist_pop_if)(M_C(name, _lflist_ct) list, \
|
||||
m_gc_ticket_ct age, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *head; \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
\
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
head = atomic_load(&list->head); \
|
||||
tail = atomic_load(&list->tail); \
|
||||
next = atomic_load(&head->next); \
|
||||
Therefore, we return the previous dummy head. \
|
||||
As such, it is not the original MSqueue algorithm. */ \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
|
||||
return head; \
|
||||
} \
|
||||
\
|
||||
/* Dequeue a node if the node is old enough */ \
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _lflist_pop_if)(M_C(name, _lflist_ct) list, \
|
||||
m_gc_ticket_ct age, m_core_backoff_ct bkoff) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) *head; \
|
||||
M_C(name, _lf_node_t) *tail; \
|
||||
M_C(name, _lf_node_t) *next; \
|
||||
\
|
||||
m_core_backoff_reset(bkoff); \
|
||||
while (true) { \
|
||||
head = atomic_load(&list->head); \
|
||||
tail = atomic_load(&list->tail); \
|
||||
next = atomic_load(&head->next); \
|
||||
if (M_LIKELY(head == atomic_load_explicit(&list->head, memory_order_relaxed))) \
|
||||
{ \
|
||||
if (head == tail) { \
|
||||
if (next == &list->nil) \
|
||||
return NULL; \
|
||||
{ \
|
||||
if (head == tail) { \
|
||||
if (next == &list->nil) \
|
||||
return NULL; \
|
||||
atomic_compare_exchange_strong_explicit(&list->tail, &tail, next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Test if the node is old enought to be popped */ \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Test if the node is old enought to be popped */ \
|
||||
if (atomic_load_explicit(&next->cpt, memory_order_relaxed) >= age) \
|
||||
return NULL; \
|
||||
/* Try to swing Head to the next node */ \
|
||||
if (atomic_compare_exchange_strong_explicit(&list->head, \
|
||||
&head, next, \
|
||||
return NULL; \
|
||||
/* Try to swing Head to the next node */ \
|
||||
if (atomic_compare_exchange_strong_explicit(&list->head, \
|
||||
&head, next, \
|
||||
memory_order_release, \
|
||||
memory_order_relaxed)) { \
|
||||
break; \
|
||||
} \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
|
||||
return head; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_clear)(M_C(name, _lflist_ct) list) \
|
||||
{ \
|
||||
m_core_backoff_ct bkoff; \
|
||||
m_core_backoff_init(bkoff); \
|
||||
while (true) { \
|
||||
M_C(name, _lf_node_t) *node = M_C(name, _lflist_pop)(list, bkoff); \
|
||||
if (node == NULL) break; \
|
||||
M_C(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
|
||||
break; \
|
||||
} \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
M_IF_DEBUG(atomic_store(&head->next, (M_C(name, _lf_node_t) *) 0);) \
|
||||
return head; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lflist_clear)(M_C(name, _lflist_ct) list) \
|
||||
{ \
|
||||
m_core_backoff_ct bkoff; \
|
||||
m_core_backoff_init(bkoff); \
|
||||
while (true) { \
|
||||
M_C(name, _lf_node_t) *node = M_C(name, _lflist_pop)(list, bkoff); \
|
||||
if (node == NULL) break; \
|
||||
M_C(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
|
||||
memory_order_relaxed); \
|
||||
M_C(name, _slist_clear)(node->list); \
|
||||
M_MEMORY_DEL(node); \
|
||||
node = next; \
|
||||
} \
|
||||
/* Dummy node to free too */ \
|
||||
M_C(name, _lf_node_t) *dummy; \
|
||||
dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \
|
||||
M_C(name, _slist_clear)(dummy->list); \
|
||||
M_MEMORY_DEL(dummy); \
|
||||
} \
|
||||
M_C(name, _slist_clear)(node->list); \
|
||||
M_MEMORY_DEL(node); \
|
||||
node = next; \
|
||||
} \
|
||||
/* Dummy node to free too */ \
|
||||
M_C(name, _lf_node_t) *dummy; \
|
||||
dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \
|
||||
M_C(name, _slist_clear)(dummy->list); \
|
||||
M_MEMORY_DEL(dummy); \
|
||||
} \
|
||||
|
||||
/* System node allocator: request memory to the system.
|
||||
As such it is a non Lock-Free path. */
|
||||
#define C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _alloc_node)(unsigned int initial) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) * node; \
|
||||
node = M_MEMORY_ALLOC(M_C(name, _lf_node_t)); \
|
||||
if (M_UNLIKELY(node == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
atomic_init(&node->next, (M_C(name, _lf_node_t) *) 0); \
|
||||
atomic_init(&node->cpt, 0UL); \
|
||||
M_C(name, _slist_init)(node->list); \
|
||||
for(unsigned i = 0; i < initial; i++) { \
|
||||
M_C(name, _slist_node_ct) *n; \
|
||||
n = M_MEMORY_ALLOC(M_C(name, _slist_node_ct)); \
|
||||
if (M_UNLIKELY(n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_C(name, _slist_push)(node->list, n); \
|
||||
} \
|
||||
return node; \
|
||||
} \
|
||||
#define C_MEMPOOL_DEF_SYSTEM_ALLOC(name, type_t) \
|
||||
\
|
||||
static inline M_C(name, _lf_node_t) * \
|
||||
M_C(name, _alloc_node)(unsigned int initial) \
|
||||
{ \
|
||||
M_C(name, _lf_node_t) * node; \
|
||||
node = M_MEMORY_ALLOC(M_C(name, _lf_node_t)); \
|
||||
if (M_UNLIKELY(node == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
atomic_init(&node->next, (M_C(name, _lf_node_t) *) 0); \
|
||||
atomic_init(&node->cpt, 0UL); \
|
||||
M_C(name, _slist_init)(node->list); \
|
||||
for(unsigned i = 0; i < initial; i++) { \
|
||||
M_C(name, _slist_node_ct) *n; \
|
||||
n = M_MEMORY_ALLOC(M_C(name, _slist_node_ct)); \
|
||||
if (M_UNLIKELY(n == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _lf_node_t))); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_C(name, _slist_push)(node->list, n); \
|
||||
} \
|
||||
return node; \
|
||||
} \
|
||||
|
||||
/* Concurrent Memory pool
|
||||
The data structure is the following.
|
||||
@@ -386,161 +386,161 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
As such it won't support more than ULONG_MAX sleep for all threads.
|
||||
*/
|
||||
#define C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lfmp_thread_s) { \
|
||||
M_C(name, _slist_ct) free; \
|
||||
M_C(name, _slist_ct) to_be_reclaimed; \
|
||||
M_CACHELINE_ALIGN(align1, M_C(name, _slist_ct), M_C(name, _slist_ct)); \
|
||||
} M_C(name, _lfmp_thread_ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lfmp_thread_init)(M_C(name, _lfmp_thread_ct) *t) \
|
||||
{ \
|
||||
M_C(name, _slist_init)(t->free); \
|
||||
M_C(name, _slist_init)(t->to_be_reclaimed); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lfmp_thread_clear)(M_C(name, _lfmp_thread_ct) *t) \
|
||||
{ \
|
||||
assert(M_C(name, _slist_empty_p)(t->to_be_reclaimed)); \
|
||||
M_C(name, _slist_clear)(t->free); \
|
||||
M_C(name, _slist_clear)(t->to_be_reclaimed); \
|
||||
} \
|
||||
#define C_MEMPOOL_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _lfmp_thread_s) { \
|
||||
M_C(name, _slist_ct) free; \
|
||||
M_C(name, _slist_ct) to_be_reclaimed; \
|
||||
M_CACHELINE_ALIGN(align1, M_C(name, _slist_ct), M_C(name, _slist_ct)); \
|
||||
} M_C(name, _lfmp_thread_ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lfmp_thread_init)(M_C(name, _lfmp_thread_ct) *t) \
|
||||
{ \
|
||||
M_C(name, _slist_init)(t->free); \
|
||||
M_C(name, _slist_init)(t->to_be_reclaimed); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _lfmp_thread_clear)(M_C(name, _lfmp_thread_ct) *t) \
|
||||
{ \
|
||||
assert(M_C(name, _slist_empty_p)(t->to_be_reclaimed)); \
|
||||
M_C(name, _slist_clear)(t->free); \
|
||||
M_C(name, _slist_clear)(t->to_be_reclaimed); \
|
||||
} \
|
||||
|
||||
/* NOTE: once a node is deleted, its data are kept readable until the future GC */
|
||||
#define C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
unsigned initial; \
|
||||
M_C(name, _lfmp_thread_ct) *thread_data; \
|
||||
M_C(name, _lflist_ct) free; \
|
||||
M_C(name, _lflist_ct) to_be_reclaimed; \
|
||||
M_C(name, _lflist_ct) empty; \
|
||||
m_gc_mempool_list_ct mempool_node; \
|
||||
struct m_gc_s *gc_mem; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
/* Garbage collect of the nodes of the mempool on sleep */ \
|
||||
static inline void \
|
||||
M_C(name, _int_gc_on_sleep)(m_gc_t gc_mem, m_gc_mempool_list_ct *data, \
|
||||
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \
|
||||
{ \
|
||||
/* Get back the mempool from the node */ \
|
||||
struct M_C(name, _s) *mempool = \
|
||||
#define C_MEMPOOL_DEF_LF_MEMPOOL(name, type_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
unsigned initial; \
|
||||
M_C(name, _lfmp_thread_ct) *thread_data; \
|
||||
M_C(name, _lflist_ct) free; \
|
||||
M_C(name, _lflist_ct) to_be_reclaimed; \
|
||||
M_C(name, _lflist_ct) empty; \
|
||||
m_gc_mempool_list_ct mempool_node; \
|
||||
struct m_gc_s *gc_mem; \
|
||||
} M_C(name, _t)[1]; \
|
||||
\
|
||||
/* Garbage collect of the nodes of the mempool on sleep */ \
|
||||
static inline void \
|
||||
M_C(name, _int_gc_on_sleep)(m_gc_t gc_mem, m_gc_mempool_list_ct *data, \
|
||||
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \
|
||||
{ \
|
||||
/* Get back the mempool from the node */ \
|
||||
struct M_C(name, _s) *mempool = \
|
||||
M_TYPE_FROM_FIELD(struct M_C(name, _s), data, m_gc_mempool_list_ct, mempool_node); \
|
||||
\
|
||||
\
|
||||
/* Move the local nodes of the mempool to be reclaimed to the thread into the global pool */ \
|
||||
if (!M_C(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
/* Get a new empty group of nodes */ \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
/* Get a new empty group of nodes */ \
|
||||
node = M_C(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \
|
||||
if (M_UNLIKELY (node == NULL)) { \
|
||||
/* Fail to get an empty group of node. \
|
||||
Alloc a new one from the system */ \
|
||||
node = M_C(name, _alloc_node)(0); \
|
||||
assert(node != NULL); \
|
||||
} \
|
||||
assert(M_C(name, _slist_empty_p)(node->list)); \
|
||||
if (M_UNLIKELY (node == NULL)) { \
|
||||
/* Fail to get an empty group of node. \
|
||||
Alloc a new one from the system */ \
|
||||
node = M_C(name, _alloc_node)(0); \
|
||||
assert(node != NULL); \
|
||||
} \
|
||||
assert(M_C(name, _slist_empty_p)(node->list)); \
|
||||
M_C(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \
|
||||
atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); \
|
||||
atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); \
|
||||
M_C(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \
|
||||
} \
|
||||
\
|
||||
/* Perform a GC of the freelist of nodes */ \
|
||||
while (true) { \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
node = M_C(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
|
||||
} \
|
||||
\
|
||||
/* Perform a GC of the freelist of nodes */ \
|
||||
while (true) { \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
node = M_C(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
|
||||
min_ticket, gc_mem->thread_data[id].bkoff); \
|
||||
if (node == NULL) break; \
|
||||
if (node == NULL) break; \
|
||||
M_C(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) mem, m_gc_t gc_mem, \
|
||||
unsigned init_node_count, unsigned init_group_count) \
|
||||
{ \
|
||||
const size_t max_thread = gc_mem->max_thread; \
|
||||
/* Initialize the thread data of the mempool */ \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(M_C(name, _t) mem, m_gc_t gc_mem, \
|
||||
unsigned init_node_count, unsigned init_group_count) \
|
||||
{ \
|
||||
const size_t max_thread = gc_mem->max_thread; \
|
||||
/* Initialize the thread data of the mempool */ \
|
||||
mem->thread_data = M_MEMORY_REALLOC(M_C(name, _lfmp_thread_ct), NULL, max_thread); \
|
||||
if (mem->thread_data == NULL) { \
|
||||
M_MEMORY_FULL(max_thread * sizeof(M_C(name, _lfmp_thread_ct))); \
|
||||
return; \
|
||||
} \
|
||||
for(unsigned i = 0; i < max_thread;i++) { \
|
||||
M_C(name, _lfmp_thread_init)(&mem->thread_data[i]); \
|
||||
} \
|
||||
/* Preallocate some group of nodes for the mempool */ \
|
||||
mem->initial = M_MAX(C_MEMPOOL_MIN_NODE_PER_GROUP, init_node_count); \
|
||||
if (mem->thread_data == NULL) { \
|
||||
M_MEMORY_FULL(max_thread * sizeof(M_C(name, _lfmp_thread_ct))); \
|
||||
return; \
|
||||
} \
|
||||
for(unsigned i = 0; i < max_thread;i++) { \
|
||||
M_C(name, _lfmp_thread_init)(&mem->thread_data[i]); \
|
||||
} \
|
||||
/* Preallocate some group of nodes for the mempool */ \
|
||||
mem->initial = M_MAX(C_MEMPOOL_MIN_NODE_PER_GROUP, init_node_count); \
|
||||
M_C(name, _lflist_init)(mem->free, M_C(name, _alloc_node)(init_node_count)); \
|
||||
M_C(name, _lflist_init)(mem->to_be_reclaimed, M_C(name, _alloc_node)(init_node_count)); \
|
||||
M_C(name, _lflist_init)(mem->empty, M_C(name, _alloc_node)(0)); \
|
||||
for(unsigned i = 1; i < init_group_count; i++) { \
|
||||
M_C(name, _lflist_init)(mem->empty, M_C(name, _alloc_node)(0)); \
|
||||
for(unsigned i = 1; i < init_group_count; i++) { \
|
||||
M_C(name, _lflist_push)(mem->free, M_C(name, _alloc_node)(init_node_count), \
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
M_C(name, _lflist_push)(mem->empty, M_C(name, _alloc_node)(0), \
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
} \
|
||||
/* Register the mempool in the GC */ \
|
||||
mem->mempool_node.gc_on_sleep = M_C(name, _int_gc_on_sleep); \
|
||||
mem->mempool_node.next = gc_mem->mempool_list; \
|
||||
gc_mem->mempool_list = &mem->mempool_node; \
|
||||
mem->gc_mem = gc_mem; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) mem) \
|
||||
{ \
|
||||
const unsigned max_thread = mem->gc_mem->max_thread; \
|
||||
for(unsigned i = 0; i < max_thread;i++) { \
|
||||
M_C(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
|
||||
} \
|
||||
M_MEMORY_FREE(mem->thread_data); \
|
||||
mem->thread_data = NULL; \
|
||||
M_C(name, _lflist_clear)(mem->empty); \
|
||||
M_C(name, _lflist_clear)(mem->free); \
|
||||
assert(M_C(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
|
||||
M_C(name, _lflist_clear)(mem->to_be_reclaimed); \
|
||||
/* TODO: Unregister from the GC? */ \
|
||||
} \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _new)(M_C(name, _t) mem, m_gc_tid_t id) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *snode; \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
while (true) { \
|
||||
/* Fast & likely path where we access the thread pool of nodes */ \
|
||||
if (M_LIKELY(!M_C(name, _slist_empty_p)(mem->thread_data[id].free))) { \
|
||||
snode = M_C(name, _slist_pop)(mem->thread_data[id].free); \
|
||||
return &snode->data; \
|
||||
} \
|
||||
/* Request a group node to the freelist of groups */ \
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
M_C(name, _lflist_push)(mem->empty, M_C(name, _alloc_node)(0), \
|
||||
gc_mem->thread_data[0].bkoff); \
|
||||
} \
|
||||
/* Register the mempool in the GC */ \
|
||||
mem->mempool_node.gc_on_sleep = M_C(name, _int_gc_on_sleep); \
|
||||
mem->mempool_node.next = gc_mem->mempool_list; \
|
||||
gc_mem->mempool_list = &mem->mempool_node; \
|
||||
mem->gc_mem = gc_mem; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(M_C(name, _t) mem) \
|
||||
{ \
|
||||
const unsigned max_thread = mem->gc_mem->max_thread; \
|
||||
for(unsigned i = 0; i < max_thread;i++) { \
|
||||
M_C(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
|
||||
} \
|
||||
M_MEMORY_FREE(mem->thread_data); \
|
||||
mem->thread_data = NULL; \
|
||||
M_C(name, _lflist_clear)(mem->empty); \
|
||||
M_C(name, _lflist_clear)(mem->free); \
|
||||
assert(M_C(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
|
||||
M_C(name, _lflist_clear)(mem->to_be_reclaimed); \
|
||||
/* TODO: Unregister from the GC? */ \
|
||||
} \
|
||||
\
|
||||
static inline type_t * \
|
||||
M_C(name, _new)(M_C(name, _t) mem, m_gc_tid_t id) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *snode; \
|
||||
M_C(name, _lf_node_t) *node; \
|
||||
while (true) { \
|
||||
/* Fast & likely path where we access the thread pool of nodes */ \
|
||||
if (M_LIKELY(!M_C(name, _slist_empty_p)(mem->thread_data[id].free))) { \
|
||||
snode = M_C(name, _slist_pop)(mem->thread_data[id].free); \
|
||||
return &snode->data; \
|
||||
} \
|
||||
/* Request a group node to the freelist of groups */ \
|
||||
node = M_C(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \
|
||||
if (M_UNLIKELY (node == NULL)) { \
|
||||
/* Request a new group to the system. Non Lock Free path */ \
|
||||
assert(mem->initial > 0); \
|
||||
node = M_C(name, _alloc_node)(mem->initial); \
|
||||
assert(node != NULL); \
|
||||
assert(!M_C(name, _slist_empty_p)(node->list)); \
|
||||
} \
|
||||
M_C(name, _slist_move)(mem->thread_data[id].free, node->list); \
|
||||
/* Push back the empty group */ \
|
||||
assert (M_C(name, _slist_empty_p)(node->list)); \
|
||||
if (M_UNLIKELY (node == NULL)) { \
|
||||
/* Request a new group to the system. Non Lock Free path */ \
|
||||
assert(mem->initial > 0); \
|
||||
node = M_C(name, _alloc_node)(mem->initial); \
|
||||
assert(node != NULL); \
|
||||
assert(!M_C(name, _slist_empty_p)(node->list)); \
|
||||
} \
|
||||
M_C(name, _slist_move)(mem->thread_data[id].free, node->list); \
|
||||
/* Push back the empty group */ \
|
||||
assert (M_C(name, _slist_empty_p)(node->list)); \
|
||||
M_C(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _del)(M_C(name, _t) mem, type_t *d, m_gc_tid_t id) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *snode; \
|
||||
assert( d != NULL); \
|
||||
snode = M_TYPE_FROM_FIELD(M_C(name, _slist_node_ct), d, type_t, data); \
|
||||
M_C(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _del)(M_C(name, _t) mem, type_t *d, m_gc_tid_t id) \
|
||||
{ \
|
||||
M_C(name, _slist_node_ct) *snode; \
|
||||
assert( d != NULL); \
|
||||
snode = M_TYPE_FROM_FIELD(M_C(name, _slist_node_ct), d, type_t, data); \
|
||||
M_C(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
|
||||
} \
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
+692
-692
File diff suppressed because it is too large.
Load diff
+180
-180
@@ -32,8 +32,8 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF(name, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
#define FUNC_OBJ_ITF_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, M_C(name, _t), __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_ITF_DEF_AS(name, name_t, retcode type, type of param1, type of param 2, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
#define FUNC_OBJ_ITF_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_ITF_NO_PARAM_DEF, FUNCOBJI_ITF_PARAM_DEF)(name, name_t, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
@@ -67,8 +67,8 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF(name, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
#define FUNC_OBJ_INS_DEF(name, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, M_C(name, _t), base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
@@ -80,8 +80,8 @@
|
||||
* USAGE/EXAMPLE:
|
||||
* FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, (param1, ...), { return param1 * self->member1 }, (member1, int), ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
#define FUNC_OBJ_INS_DEF_AS(name, name_t, base_name, param_list, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_DEF, FUNCOBJI_INS_ATTR_DEF)(name, name_t, base_name, param_list, __VA_ARGS__) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
* USAGE:
|
||||
* FUNC_OBJ_INS_OPLIST(name, oplist of the attr1, ...)
|
||||
*/
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
#define FUNC_OBJ_INS_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)(FUNCOBJI_INS_NO_ATTR_OPLIST, FUNCOBJI_INS_ATTR_OPLIST_P1)( __VA_ARGS__)
|
||||
|
||||
|
||||
@@ -113,28 +113,28 @@
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT(M_C(name,_init)) \
|
||||
#define FUNCOBJI_INS_NO_ATTR_OPLIST(name) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT(M_C(name,_init)) \
|
||||
)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P1(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(FUNCOBJI_INS_ATTR_OPLIST_P3, FUNCOBJI_INS_ATTR_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_FUNC_OBJ_INS_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the oplist of the instance */
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
#define FUNCOBJI_INS_ATTR_OPLIST_P3(name, ...) ( \
|
||||
NAME(name), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
INIT_WITH(M_C(name, _init_with)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
)
|
||||
|
||||
|
||||
@@ -145,28 +145,28 @@
|
||||
* - M_C(name, _callback_ct): internal type of the callback.
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* Internal type for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* No parameters to the callback */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj); \
|
||||
#define FUNCOBJI_ITF_NO_PARAM_DEF(name, interface_t, retcode) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* Internal type for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* No parameters to the callback */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj) \
|
||||
{ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj); \
|
||||
}
|
||||
|
||||
|
||||
@@ -179,31 +179,31 @@
|
||||
* - M_C4(name, _param_, num, _ct) for each parameter defined
|
||||
* - M_C(name, _ct): synonym of main type used by oplist.
|
||||
*/
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* Internal types for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* Define types for all parameters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
/* Define callback type with all parameters */ \
|
||||
#define FUNCOBJI_ITF_PARAM_DEF(name, interface_t, retcode, ...) \
|
||||
\
|
||||
/* Forward declaration */ \
|
||||
struct M_C(name, _s); \
|
||||
\
|
||||
/* Internal types for instance */ \
|
||||
typedef retcode M_C(name, _retcode_ct); \
|
||||
/* Define types for all parameters */ \
|
||||
M_MAP3(FUNCOBJI_BASE_TYPE, name, __VA_ARGS__) \
|
||||
/* Define callback type with all parameters */ \
|
||||
typedef retcode(*M_C(name, _callback_ct))(struct M_C(name, _s) *, __VA_ARGS__); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
/* If the retcode is 'void', don't return the value of the callback */ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _callback_ct) callback; \
|
||||
} interface_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist & instance */ \
|
||||
typedef interface_t M_C(name, _ct); \
|
||||
\
|
||||
static inline retcode \
|
||||
M_C(name, _call)(interface_t funcobj \
|
||||
M_MAP3(FUNCOBJI_BASE_ARGLIST, name, __VA_ARGS__) ) \
|
||||
{ \
|
||||
/* If the retcode is 'void', don't return the value of the callback */ \
|
||||
M_IF(M_KEYWORD_P(void, retcode)) ( /* nothing */,return) \
|
||||
funcobj->callback(funcobj M_MAP3(FUNCOBJI_BASE_ARGCALL, name, __VA_ARGS__) ); \
|
||||
}
|
||||
|
||||
@@ -212,49 +212,49 @@
|
||||
* with no member attribute.
|
||||
*/
|
||||
#define FUNCOBJI_INS_NO_ATTR_DEF(name, instance_t, base_name, param_list, callback_core) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
(void) obj; /* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
(void) obj; /* nothing to do */ \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
} \
|
||||
|
||||
|
||||
/* Specialization of the definition a function object instance of name 'name'
|
||||
@@ -265,22 +265,22 @@
|
||||
FUNCOBJI_INS_ATTR_DEF_P2(name, instance_t, base_name, param_list, callback_core, FUNCOBJI_INJECT_GLOBAL(__VA_ARGS__) )
|
||||
|
||||
/* Inject the oplist within the list of arguments */
|
||||
#define FUNCOBJI_INJECT_GLOBAL(...) \
|
||||
#define FUNCOBJI_INJECT_GLOBAL(...) \
|
||||
M_MAP_C(FUNCOBJI_INJECT_OPLIST_A, __VA_ARGS__)
|
||||
|
||||
/* Transform (x, type) into (x, type, oplist) if there is global registered oplist
|
||||
or (x, type, M_DEFAULT_OPLIST) if there is no global one,
|
||||
or keep (x, type, oplist) if oplist was already present */
|
||||
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
#define FUNCOBJI_INJECT_OPLIST_A( duo_or_trio ) \
|
||||
FUNCOBJI_INJECT_OPLIST_B duo_or_trio
|
||||
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
|
||||
#define FUNCOBJI_INJECT_OPLIST_B( f, ... ) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) )
|
||||
|
||||
// Test if all third argument of all arguments is an oplist
|
||||
#define FUNCOBJI_IF_ALL_OPLIST(...) \
|
||||
#define FUNCOBJI_IF_ALL_OPLIST(...) \
|
||||
M_IF(M_REDUCE(FUNCOBJI_IS_OPLIST_P, M_AND, __VA_ARGS__))
|
||||
// Test if the third argument is an oplist. a is a trio (name, type, oplist)
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
#define FUNCOBJI_IS_OPLIST_P(a) \
|
||||
M_OPLIST_P(M_RET_ARG3 a)
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
@@ -293,109 +293,109 @@
|
||||
|
||||
/* Expand the Function Object with members */
|
||||
#define FUNCOBJI_INS_ATTR_DEF_P3(name, instance_t, base_name, param_list, callback_core, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
typedef struct M_C(name, _s) { \
|
||||
/* Callback is the mandatory first argument */ \
|
||||
M_C(base_name, _callback_ct) callback; \
|
||||
/* All the member attribute of the Function Object */ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_STRUCT, __VA_ARGS__) \
|
||||
} instance_t[1]; \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef instance_t M_C(name, _ct); \
|
||||
\
|
||||
FUNCOBJI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \
|
||||
\
|
||||
static inline M_C(base_name, _retcode_ct) \
|
||||
M_C(name, _callback)(M_C(base_name, _ct) _self \
|
||||
M_IF_EMPTY(M_OPFLAT param_list)( \
|
||||
/* No param */, \
|
||||
M_MAP3(FUNCOBJI_INS_ARGLIST, base_name, M_OPFLAT param_list)\
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
) \
|
||||
) \
|
||||
{ \
|
||||
struct M_C(name, _s) *self = (struct M_C(name, _s) *)_self; \
|
||||
(void) self; /* maybe unused */ \
|
||||
callback_core; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_with)(instance_t obj M_MAP(FUNCOBJI_INS_ATTR_LIST, __VA_ARGS__)) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT_SET, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(instance_t obj) \
|
||||
{ \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_CLEAR, __VA_ARGS__); \
|
||||
} \
|
||||
\
|
||||
static inline struct M_C(base_name, _s) * \
|
||||
M_C(name, _as_interface)(instance_t obj) \
|
||||
{ \
|
||||
return (struct M_C(base_name, _s) *) obj; \
|
||||
} \
|
||||
\
|
||||
M_IF(FUNCOBJI_TEST_METHOD_P(INIT, __VA_ARGS)) \
|
||||
( \
|
||||
static inline void \
|
||||
M_C(name, _init)(instance_t obj) \
|
||||
{ \
|
||||
obj->callback = M_C(name, _callback); \
|
||||
M_MAP(FUNCOBJI_INS_ATTR_INIT, __VA_ARGS__); \
|
||||
} \
|
||||
, /* END OF INIT METHOD */ ) \
|
||||
|
||||
|
||||
|
||||
/* Define a numbered type of a parameter of the callback*/
|
||||
#define FUNCOBJI_BASE_TYPE(name, num, type) \
|
||||
#define FUNCOBJI_BASE_TYPE(name, num, type) \
|
||||
typedef type M_C4(name, _param_, num, _ct);
|
||||
|
||||
/* Define a list of the type of arguments for a function definition */
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
#define FUNCOBJI_BASE_ARGLIST(name, num, type) \
|
||||
M_DEFERRED_COMMA type M_C(param_, num)
|
||||
|
||||
/* Define a list of arguments for a function call */
|
||||
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
|
||||
#define FUNCOBJI_BASE_ARGCALL(name, num, type) \
|
||||
M_DEFERRED_COMMA M_C(param_, num)
|
||||
|
||||
|
||||
/* Helper macros */
|
||||
/* arg = (name, type [, oplist]) */
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_STRUCT(arg) \
|
||||
M_RET_ARG2 arg M_RET_ARG1 arg;
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_LIST(arg) \
|
||||
M_DEFERRED_COMMA M_RET_ARG2 arg const M_RET_ARG1 arg
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_INIT(arg) \
|
||||
M_CALL_INIT(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_INIT_SET(arg) \
|
||||
M_CALL_INIT_SET(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg, M_RET_ARG1 arg);
|
||||
|
||||
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
|
||||
#define FUNCOBJI_INS_ATTR_CLEAR(arg) \
|
||||
M_CALL_CLEAR(M_RET_ARG3 arg, obj -> M_RET_ARG1 arg);
|
||||
|
||||
/* Define the list of arguments of the instance of the callback */
|
||||
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
|
||||
#define FUNCOBJI_INS_ARGLIST(name, num, param) \
|
||||
M_DEFERRED_COMMA M_C4(name, _param_, num, _ct) param
|
||||
|
||||
|
||||
/* Macros for testing for a method presence in all the attributes */
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
#define FUNCOBJI_TEST_METHOD2_P(method, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
|
||||
#define FUNCOBJI_TEST_METHOD1_P(method, arg) \
|
||||
M_APPLY(FUNCOBJI_TEST_METHOD2_P, method, M_RET_ARG3 arg)
|
||||
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
|
||||
#define FUNCOBJI_TEST_METHOD_P(method, ...) \
|
||||
M_IF(M_REDUCE2(FUNCOBJI_TEST_METHOD1_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
/* Macro for checking compatible type and oplist for all the attributes */
|
||||
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
#define FUNCOBJI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(FUNCOBJI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
|
||||
#define FUNCOBJI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, M_RET_ARG1 a, M_RET_ARG2 a, M_RET_ARG3 a)
|
||||
|
||||
|
||||
|
||||
+7
-7
@@ -67,11 +67,11 @@ typedef struct genint_s {
|
||||
#define GENINT_LIMBSIZE ((unsigned)(sizeof(genint_limb_ct) * CHAR_BIT))
|
||||
|
||||
// Define the contract of a genint
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
assert (s->data != NULL); \
|
||||
#define GENINT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n > 0 && s->n <= GENINT_MAX_ALLOC); \
|
||||
assert ((s->max+1) * GENINT_LIMBSIZE >= s->n); \
|
||||
assert (s->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
// Define the limb one
|
||||
@@ -89,12 +89,12 @@ typedef struct genint_s {
|
||||
#define GENINT_ABA_CPT_T uint32_t
|
||||
|
||||
// Set the bit 'i' of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
#define GENINT_MASTER_SET(master, i) \
|
||||
((((master)& (~((GENINT_ONE<< GENINT_ABA_CPT)-1))) | (GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
// Reset the bit i of the master limb, and increase ABA counter.
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
#define GENINT_MASTER_RESET(master, i) \
|
||||
(((master) & (~((GENINT_ONE<< GENINT_ABA_CPT)-1)) & ~(GENINT_ONE << (GENINT_LIMBSIZE - 1 - i))) \
|
||||
|((GENINT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
|
||||
+547
-547
File diff suppressed because it is too large.
Load diff
+118
-118
@@ -32,9 +32,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a intrusive shared pointer.
|
||||
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define ISHARED_PTR_OPLIST(...) \
|
||||
ISHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -42,15 +42,15 @@ M_BEGIN_PROTECTED_CODE
|
||||
name: name of the intrusive shared pointer.
|
||||
type: name of the type of the structure (aka. struct test_s) - not used currently.
|
||||
NOTE: There can be only one interface of this kind in a type! */
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
#define ISHARED_PTR_INTERFACE(name, type) \
|
||||
atomic_int M_C(name, _cpt)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -59,9 +59,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define the intrusive shared pointer type and its static inline functions
|
||||
as the name name_t
|
||||
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define ISHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
ISHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -73,131 +73,131 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
#define ISHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_OPLIST_P3, ISHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
#define ISHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
// Define the oplist
|
||||
#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(API_4(M_C(name, _init_set))), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_INIT_DEFAULT), \
|
||||
INIT_SET(API_4(M_C(name, _init_set))), \
|
||||
SET(M_C(name, _set) M_IPTR), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
CLEAN(M_C(name, _clean) M_IPTR), \
|
||||
TYPE(M_C(name, _ct)), \
|
||||
OPLIST(oplist), \
|
||||
SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
// Deferred evaluatioin
|
||||
#define ISHAREDI_PTR_DEF_P1(arg) ISHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define ISHAREDI_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
#define ISHAREDI_PTR_DEF_P2(name, type, oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(ISHAREDI_PTR_DEF_P3, ISHAREDI_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
#define ISHAREDI_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define ISHAREDI_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
\
|
||||
/* The shared pointer is only a pointer to the type */ \
|
||||
typedef type *shared_t; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
{ \
|
||||
/* Initialize the type referenced by the pointer */ \
|
||||
if (M_LIKELY (ptr != NULL)) { \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 1); \
|
||||
} \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init_set)(shared_t shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
(void) n; \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _init_set2)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
M_IF_DISABLED_METHOD(NEW, oplist) \
|
||||
( /* Nothing to do */, M_IF_METHOD(INIT, oplist) \
|
||||
( \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
type *ptr = M_CALL_NEW(oplist, type); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT(oplist, *ptr); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 1); \
|
||||
return ptr; \
|
||||
} \
|
||||
, /* End of INIT */) \
|
||||
/* End of NEW */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
|
||||
M_CALL_CLEAR(oplist, *shared); \
|
||||
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear_ptr)(shared_t *shared) \
|
||||
{ \
|
||||
assert(shared != NULL); \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
if (M_LIKELY (*ptr != shared)) { \
|
||||
M_C(name, _clear)(*ptr); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
#define ISHAREDI_PTR_DEF_P3(name, type, oplist, shared_t) \
|
||||
\
|
||||
/* The shared pointer is only a pointer to the type */ \
|
||||
typedef type *shared_t; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init)(type *ptr) \
|
||||
{ \
|
||||
/* Initialize the type referenced by the pointer */ \
|
||||
if (M_LIKELY (ptr != NULL)) { \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 1); \
|
||||
} \
|
||||
return ptr; \
|
||||
} \
|
||||
\
|
||||
static inline shared_t \
|
||||
M_C(name, _init_set)(shared_t shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
(void) n; \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
\
|
||||
static inline void M_ATTR_DEPRECATED \
|
||||
M_C(name, _init_set2)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
M_IF_DISABLED_METHOD(NEW, oplist) \
|
||||
( /* Nothing to do */, M_IF_METHOD(INIT, oplist) \
|
||||
( \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
type *ptr = M_CALL_NEW(oplist, type); \
|
||||
if (ptr == NULL) { \
|
||||
M_MEMORY_FULL(sizeof(type)); \
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT(oplist, *ptr); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 1); \
|
||||
return ptr; \
|
||||
} \
|
||||
, /* End of INIT */) \
|
||||
/* End of NEW */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
|
||||
M_CALL_CLEAR(oplist, *shared); \
|
||||
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear_ptr)(shared_t *shared) \
|
||||
{ \
|
||||
assert(shared != NULL); \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t *shared) \
|
||||
{ \
|
||||
M_C(name, _clear)(*shared); \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t *ptr, shared_t shared) \
|
||||
{ \
|
||||
assert (ptr != NULL); \
|
||||
if (M_LIKELY (*ptr != shared)) { \
|
||||
M_C(name, _clear)(*ptr); \
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+112
-112
@@ -39,9 +39,9 @@
|
||||
mempool_uint_clear(m); // Give back memory to system
|
||||
NOTE: Can not use m-list since it may be expanded from LIST_DEF
|
||||
*/
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, M_C(name, _t) ) \
|
||||
#define MEMPOOL_DEF(name, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, M_C(name, _t) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
USAGE:
|
||||
MEMPOOL_DEF_AS(memppol_uint, name_t, unsigned int)
|
||||
*/
|
||||
#define MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, name_t ) \
|
||||
#define MEMPOOL_DEF_AS(name, name_t, type) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
MEMPOOL_DEF_P2(name, type, name_t ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -60,121 +60,121 @@
|
||||
The default is the number of elements that fits in 16KB.
|
||||
*/
|
||||
#ifndef MEMPOOL_MAX_PER_SEGMENT
|
||||
#define MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
#define MEMPOOL_MAX_PER_SEGMENT(type) \
|
||||
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
|
||||
#endif
|
||||
|
||||
|
||||
/********************************** INTERNAL ************************************/
|
||||
|
||||
#define MEMPOOL_DEF_P2(name, type, name_t) \
|
||||
\
|
||||
/* Define the type of element in a segment of the mempool. \
|
||||
Either it is the basic type or a pointer to another one. */ \
|
||||
typedef union M_C(name,_union_s) { \
|
||||
type t; \
|
||||
union M_C(name,_union_s) *next; \
|
||||
} M_C(name,_union_ct); \
|
||||
\
|
||||
/* Define a segment of a mempool. \
|
||||
It is an array of basic type, each segment is in a linked list */ \
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_ct); \
|
||||
\
|
||||
/* Define a mempool. \
|
||||
It is a pointer to the first free object within the segments \
|
||||
and the segments themselves */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name,_union_ct) *free_list; \
|
||||
M_C(name,_segment_ct) *current_segment; \
|
||||
} name_t[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_init)(name_t mem) \
|
||||
{ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_ct)); \
|
||||
if (mem->current_segment == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
return; \
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
mem->current_segment->count = 0; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_ct) *next = segment->next; \
|
||||
M_MEMORY_DEL (segment); \
|
||||
segment = next; \
|
||||
} \
|
||||
/* Clean pointers to be safer */ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* Test if one object is in the free list */ \
|
||||
M_C(name,_union_ct) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
/* Yes, so return it, and pop it from the free list */ \
|
||||
mem->free_list = ret->next; \
|
||||
return &ret->t; \
|
||||
} \
|
||||
/* No cheap free object exist. Test within a segment */ \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
assert(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
/* If segment is full, allocate a new one from the system */ \
|
||||
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
#define MEMPOOL_DEF_P2(name, type, name_t) \
|
||||
\
|
||||
/* Define the type of element in a segment of the mempool. \
|
||||
Either it is the basic type or a pointer to another one. */ \
|
||||
typedef union M_C(name,_union_s) { \
|
||||
type t; \
|
||||
union M_C(name,_union_s) *next; \
|
||||
} M_C(name,_union_ct); \
|
||||
\
|
||||
/* Define a segment of a mempool. \
|
||||
It is an array of basic type, each segment is in a linked list */ \
|
||||
typedef struct M_C(name,_segment_s) { \
|
||||
unsigned int count; \
|
||||
struct M_C(name,_segment_s) *next; \
|
||||
M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \
|
||||
} M_C(name,_segment_ct); \
|
||||
\
|
||||
/* Define a mempool. \
|
||||
It is a pointer to the first free object within the segments \
|
||||
and the segments themselves */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name,_union_ct) *free_list; \
|
||||
M_C(name,_segment_ct) *current_segment; \
|
||||
} name_t[1]; \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_init)(name_t mem) \
|
||||
{ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = M_MEMORY_ALLOC(M_C(name,_segment_ct)); \
|
||||
if (mem->current_segment == NULL) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
return; \
|
||||
} \
|
||||
mem->current_segment->next = NULL; \
|
||||
mem->current_segment->count = 0; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_clear)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
while (segment != NULL) { \
|
||||
M_C(name,_segment_ct) *next = segment->next; \
|
||||
M_MEMORY_DEL (segment); \
|
||||
segment = next; \
|
||||
} \
|
||||
/* Clean pointers to be safer */ \
|
||||
mem->free_list = NULL; \
|
||||
mem->current_segment = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name,_alloc)(name_t mem) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* Test if one object is in the free list */ \
|
||||
M_C(name,_union_ct) *ret = mem->free_list; \
|
||||
if (ret != NULL) { \
|
||||
/* Yes, so return it, and pop it from the free list */ \
|
||||
mem->free_list = ret->next; \
|
||||
return &ret->t; \
|
||||
} \
|
||||
/* No cheap free object exist. Test within a segment */ \
|
||||
M_C(name,_segment_ct) *segment = mem->current_segment; \
|
||||
assert(segment != NULL); \
|
||||
unsigned int count = segment->count; \
|
||||
/* If segment is full, allocate a new one from the system */ \
|
||||
if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \
|
||||
M_C(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_ct)); \
|
||||
if (M_UNLIKELY (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
return NULL; \
|
||||
} \
|
||||
new_segment->next = segment; \
|
||||
new_segment->count = 0; \
|
||||
mem->current_segment = new_segment; \
|
||||
segment = new_segment; \
|
||||
count = 0; \
|
||||
} \
|
||||
/* Return the object as the last element of the current segment */ \
|
||||
ret = &segment->tab[count]; \
|
||||
segment->count = count + 1; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(name_t mem, type *ptr) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* NOTE: Unsafe cast: suppose that the given pointer \
|
||||
was allocated by the previous alloc function. */ \
|
||||
M_C(name,_union_ct) *ret = (M_C(name,_union_ct) *)(uintptr_t)ptr; \
|
||||
/* Add the object back in the free list */ \
|
||||
ret->next = mem->free_list; \
|
||||
mem->free_list = ret; \
|
||||
/* NOTE: the objects are NOT given back to the system until the mempool \
|
||||
is fully cleared */ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
if (M_UNLIKELY (new_segment == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (M_C(name,_segment_ct))); \
|
||||
return NULL; \
|
||||
} \
|
||||
new_segment->next = segment; \
|
||||
new_segment->count = 0; \
|
||||
mem->current_segment = new_segment; \
|
||||
segment = new_segment; \
|
||||
count = 0; \
|
||||
} \
|
||||
/* Return the object as the last element of the current segment */ \
|
||||
ret = &segment->tab[count]; \
|
||||
segment->count = count + 1; \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
return &ret->t; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name,_free)(name_t mem, type *ptr) \
|
||||
{ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
/* NOTE: Unsafe cast: suppose that the given pointer \
|
||||
was allocated by the previous alloc function. */ \
|
||||
M_C(name,_union_ct) *ret = (M_C(name,_union_ct) *)(uintptr_t)ptr; \
|
||||
/* Add the object back in the free list */ \
|
||||
ret->next = mem->free_list; \
|
||||
mem->free_list = ret; \
|
||||
/* NOTE: the objects are NOT given back to the system until the mempool \
|
||||
is fully cleared */ \
|
||||
MEMPOOLI_CONTRACT(mem, type); \
|
||||
} \
|
||||
|
||||
/* MEMPOOL contract */
|
||||
#define MEMPOOLI_CONTRACT(mempool, type) do { \
|
||||
assert((mempool) != NULL); \
|
||||
assert((mempool)->current_segment != NULL); \
|
||||
#define MEMPOOLI_CONTRACT(mempool, type) do { \
|
||||
assert((mempool) != NULL); \
|
||||
assert((mempool)->current_segment != NULL); \
|
||||
assert((mempool)->current_segment->count <= MEMPOOL_MAX_PER_SEGMENT(type)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Auto-detect the thread backend to use if the user has not override it */
|
||||
#ifndef M_USE_THREAD_BACKEND
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
|
||||
&& !defined(__STDC_NO_THREADS__)
|
||||
# define M_USE_THREAD_BACKEND 1
|
||||
# elif defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
@@ -503,25 +503,25 @@ M_END_PROTECTED_CODE
|
||||
or using C11's ONCE mechanism */
|
||||
#ifdef M_MUTEXI_INIT_VALUE
|
||||
# define M_LOCK_DECL(name) m_mutex_t name = M_MUTEXI_INIT_VALUE
|
||||
# define M_LOCK(name) \
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), m_mutexi_lazy_lock, m_mutex_unlock)
|
||||
#else
|
||||
# define M_LOCK_DECL(name) \
|
||||
m_mutex_t name; \
|
||||
static void M_C(m_mutex_init_, name)(void) { \
|
||||
m_mutex_init(name); \
|
||||
} \
|
||||
# define M_LOCK_DECL(name) \
|
||||
m_mutex_t name; \
|
||||
static void M_C(m_mutex_init_, name)(void) { \
|
||||
m_mutex_init(name); \
|
||||
} \
|
||||
m_once_ct M_C(m_once_, name) = M_ONCEI_INIT_VALUE
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
# define M_LOCKI_BY_ONCE(name) \
|
||||
(m_oncei_call(M_C(m_once_, name), M_C(m_mutex_init_, name)), \
|
||||
m_mutex_lock(name), (void) 0 )
|
||||
# define M_LOCK(name) \
|
||||
# define M_LOCK(name) \
|
||||
M_LOCKI_DO(name, M_C(local_cont_, __LINE__), M_LOCKI_BY_ONCE, m_mutex_unlock)
|
||||
#endif
|
||||
|
||||
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
|
||||
for(bool cont = true \
|
||||
; cont && (lock_func (name), true); \
|
||||
#define M_LOCKI_DO(name, cont, lock_func, unlock_func) \
|
||||
for(bool cont = true \
|
||||
; cont && (lock_func (name), true); \
|
||||
(unlock_func (name), cont = false))
|
||||
|
||||
#endif
|
||||
+330
-330
@@ -32,9 +32,9 @@
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define PRIOQUEUE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name,_t), M_C(name,_it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t)))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -43,9 +43,9 @@
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
as the name name_t with an iterator named it_t
|
||||
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
PRIOQUEUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -53,9 +53,9 @@
|
||||
|
||||
/* Define the oplist of a prioqueue of type.
|
||||
USAGE: PRIOQUEUE_OPLIST(name[, oplist of the type]) */
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
#define PRIOQUEUE_OPLIST(...) \
|
||||
PRIOQUEUEI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -67,40 +67,40 @@
|
||||
#define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
#define PRIOQUEUEI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_OPLIST_P3, PRIOQUEUEI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
#define PRIOQUEUEI_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* Define oplist of a priority queue */
|
||||
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,TEST_EMPTY(M_C(name, _empty_p)), \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,IT_TYPE(M_C(name, _it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
#define PRIOQUEUEI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,INIT_WITH(API_1(M_INIT_VAI)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,INIT_MOVE(M_C(name, _init_move)) \
|
||||
,MOVE(M_C(name, _move)) \
|
||||
,SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name,_ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,CLEAN(M_C(name,_clean)) \
|
||||
,PUSH(M_C(name,_push)) \
|
||||
,POP(M_C(name,_pop)) \
|
||||
,OPLIST(oplist) \
|
||||
,TEST_EMPTY(M_C(name, _empty_p)), \
|
||||
,GET_SIZE(M_C(name, _size)) \
|
||||
,IT_TYPE(M_C(name, _it_ct)), \
|
||||
IT_FIRST(M_C(name,_it)), \
|
||||
IT_END(M_C(name,_it_end)), \
|
||||
IT_SET(M_C(name,_it_set)), \
|
||||
IT_END_P(M_C(name,_end_p)), \
|
||||
IT_EQUAL_P(M_C(name,_it_equal_p)), \
|
||||
IT_LAST_P(M_C(name,_last_p)), \
|
||||
IT_NEXT(M_C(name,_next)), \
|
||||
IT_CREF(M_C(name,_cref)), \
|
||||
)
|
||||
|
||||
|
||||
@@ -109,11 +109,11 @@
|
||||
#define PRIOQUEUEI_DEF_P1(arg) PRIOQUEUEI_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define PRIOQUEUEI_DEF_P2(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(PRIOQUEUEI_DEF_P3, PRIOQUEUEI_DEF_FAILURE)(name, type, oplist, prioqueue_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
#define PRIOQUEUEI_DEF_FAILURE(name, type, oplist, prioqueue_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(PRIOQUEUE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Define the priority queue:
|
||||
@@ -123,299 +123,299 @@
|
||||
- prioqueue_t: type of the container,
|
||||
- it_t: iterator of the container
|
||||
*/
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
#define PRIOQUEUEI_DEF_P3(name, type, oplist, prioqueue_t, it_t) \
|
||||
\
|
||||
/* Definition of the internal array used to construct the priority queue */ \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
\
|
||||
/* Define the priority queue over the defined array */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _array_t) array; \
|
||||
} prioqueue_t[1]; \
|
||||
/* Define the pointer references to the priority queue */ \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* The iterator is the same one as the one of the internal array */ \
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
\
|
||||
/* Definition of the internal types used by the oplist */ \
|
||||
typedef prioqueue_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef it_t M_C(name, _it_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_init)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_init_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clear)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_init_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_swap)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clean)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_parent)(size_t i) \
|
||||
{ \
|
||||
assert (i > 0); \
|
||||
return (i - 1) / 2; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_lchild)(size_t i) \
|
||||
{ \
|
||||
assert(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 1; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_rchild)(size_t i) \
|
||||
{ \
|
||||
assert(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 2; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
||||
{ \
|
||||
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
|
||||
*M_C(name, _array_cget)(p->array, j)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_empty_p)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_size)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
/* Push back the new element at the end of the array */ \
|
||||
M_C(name, _array_push_back)(p->array, x); \
|
||||
\
|
||||
/* Reorder the array by swapping with its parent \
|
||||
* until it reaches the right position */ \
|
||||
size_t i = M_C(name, _array_size)(p->array)-1; \
|
||||
while (i > 0) { \
|
||||
size_t j = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, j); \
|
||||
i = j; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _front)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_cget)(p->array, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop)(type *x, prioqueue_t p) \
|
||||
{ \
|
||||
/* Swap the front element with the last element */ \
|
||||
size_t size = M_C(name, _array_size)(p->array)-1; \
|
||||
M_C(name, _array_swap_at) (p->array, 0, size); \
|
||||
/* Swap the new last element */ \
|
||||
M_C(name, _array_pop_back)(x, p->array); \
|
||||
\
|
||||
/* Reorder the heap */ \
|
||||
size_t i = 0; \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) \
|
||||
break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Define iterators over the array iterator */ \
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_C(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_C(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_cref)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist) \
|
||||
( \
|
||||
/* EQUAL & CMP may be uncorrelated */ \
|
||||
static inline bool \
|
||||
M_C(name, _erase)(prioqueue_t p, type x) \
|
||||
{ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
/* NOTE: An HASHMAP may be a good idea to optimize this pass. */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
|
||||
break; \
|
||||
} \
|
||||
/* If x is not found, then stop */ \
|
||||
if (i >= size) \
|
||||
return false; \
|
||||
/* Swap the found item and the last element */ \
|
||||
size--; \
|
||||
M_C(name, _array_swap_at) (p->array, i, size); \
|
||||
M_C(name, _array_pop_back)(NULL, p->array); \
|
||||
ARRAY_DEF(M_C(name, _array), type, oplist) \
|
||||
\
|
||||
/* Define the priority queue over the defined array */ \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _array_t) array; \
|
||||
} prioqueue_t[1]; \
|
||||
/* Define the pointer references to the priority queue */ \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* The iterator is the same one as the one of the internal array */ \
|
||||
typedef M_C(name, _array_it_t) it_t; \
|
||||
\
|
||||
/* Definition of the internal types used by the oplist */ \
|
||||
typedef prioqueue_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
typedef it_t M_C(name, _it_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_init)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_init_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(prioqueue_t p, prioqueue_t const o) \
|
||||
{ \
|
||||
M_C(name, _array_set)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clear)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_init_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_move)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(prioqueue_t p, prioqueue_t o) \
|
||||
{ \
|
||||
M_C(name, _array_swap)(p->array, o->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(prioqueue_t p) \
|
||||
{ \
|
||||
M_C(name, _array_clean)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_parent)(size_t i) \
|
||||
{ \
|
||||
assert (i > 0); \
|
||||
return (i - 1) / 2; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_lchild)(size_t i) \
|
||||
{ \
|
||||
assert(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 1; \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _i_rchild)(size_t i) \
|
||||
{ \
|
||||
assert(i <= ((SIZE_MAX)-2)/2); \
|
||||
return 2*i + 2; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
M_C(name, _i_cmp)(const prioqueue_t p, size_t i, size_t j) \
|
||||
{ \
|
||||
return M_CALL_CMP(oplist, *M_C(name, _array_cget)(p->array, i), \
|
||||
*M_C(name, _array_cget)(p->array, j)); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _empty_p)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_empty_p)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline size_t \
|
||||
M_C(name, _size)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_size)(p->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _push)(prioqueue_t p, type const x) \
|
||||
{ \
|
||||
/* Push back the new element at the end of the array */ \
|
||||
M_C(name, _array_push_back)(p->array, x); \
|
||||
\
|
||||
/* Reorder the array by swapping with its parent \
|
||||
* until it reaches the right position */ \
|
||||
size_t i = M_C(name, _array_size)(p->array)-1; \
|
||||
while (i > 0) { \
|
||||
size_t j = M_C(name, _i_parent)(i); \
|
||||
if (M_C(name, _i_cmp)(p, j, i) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, j); \
|
||||
i = j; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _front)(prioqueue_t const p) \
|
||||
{ \
|
||||
return M_C(name, _array_cget)(p->array, 0); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _pop)(type *x, prioqueue_t p) \
|
||||
{ \
|
||||
/* Swap the front element with the last element */ \
|
||||
size_t size = M_C(name, _array_size)(p->array)-1; \
|
||||
M_C(name, _array_swap_at) (p->array, 0, size); \
|
||||
/* Swap the new last element */ \
|
||||
M_C(name, _array_pop_back)(x, p->array); \
|
||||
\
|
||||
/* Reorder the heap */ \
|
||||
size_t i = 0; \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) \
|
||||
break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) \
|
||||
break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Define iterators over the array iterator */ \
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_last)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_last)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_end)(it_t it, prioqueue_t const v) \
|
||||
{ \
|
||||
M_C(name, _array_it_end)(it, v->array); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t it, const it_t org) \
|
||||
{ \
|
||||
M_C(name, _array_it_set)(it, org); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_end_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _last_p)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_last_p)(it); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _it_equal_p)(const it_t it1, \
|
||||
const it_t it2) \
|
||||
{ \
|
||||
return M_C(name, _array_it_equal_p)(it1, it2); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _next)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_next)(it); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _previous)(it_t it) \
|
||||
{ \
|
||||
M_C(name, _array_previous)(it); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const it_t it) \
|
||||
{ \
|
||||
return M_C(name, _array_cref)(it); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(EQUAL, oplist) \
|
||||
( \
|
||||
/* EQUAL & CMP may be uncorrelated */ \
|
||||
static inline bool \
|
||||
M_C(name, _erase)(prioqueue_t p, type x) \
|
||||
{ \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
/* NOTE: An HASHMAP may be a good idea to optimize this pass. */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), x)) \
|
||||
break; \
|
||||
} \
|
||||
/* If x is not found, then stop */ \
|
||||
if (i >= size) \
|
||||
return false; \
|
||||
/* Swap the found item and the last element */ \
|
||||
size--; \
|
||||
M_C(name, _array_swap_at) (p->array, i, size); \
|
||||
M_C(name, _array_pop_back)(NULL, p->array); \
|
||||
/* Move back the last swapped element to its right position in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _update_further)(prioqueue_t p, type xold, type xnew) \
|
||||
{ \
|
||||
/* This update assumes that the new position is further in the heap */ \
|
||||
assert (M_CALL_CMP(oplist, xold, xnew) > 0); \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), xold)) \
|
||||
break; \
|
||||
} \
|
||||
/* We shall have found the item */ \
|
||||
assert (i < size); \
|
||||
/* Set the found item to the new element */ \
|
||||
M_C(name, _array_set_at) (p->array, i, xnew); \
|
||||
/* Move back the updated element to its right position in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
, /* No EQUAL */ ) \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _update_further)(prioqueue_t p, type xold, type xnew) \
|
||||
{ \
|
||||
/* This update assumes that the new position is further in the heap */ \
|
||||
assert (M_CALL_CMP(oplist, xold, xnew) > 0); \
|
||||
/* First pass: search for an item EQUAL to x */ \
|
||||
size_t size = M_C(name, _array_size)(p->array); \
|
||||
size_t i = 0; \
|
||||
for(i = 0; i < size; i++) { \
|
||||
if (M_CALL_EQUAL(oplist, *M_C(name, _array_cget)(p->array, i), xold)) \
|
||||
break; \
|
||||
} \
|
||||
/* We shall have found the item */ \
|
||||
assert (i < size); \
|
||||
/* Set the found item to the new element */ \
|
||||
M_C(name, _array_set_at) (p->array, i, xnew); \
|
||||
/* Move back the updated element to its right position in the heap */ \
|
||||
while (true) { \
|
||||
size_t child = M_C(name, _i_lchild)(i); \
|
||||
if (child >= size) break; \
|
||||
size_t otherChild = M_C(name, _i_rchild)(i); \
|
||||
if (otherChild < size \
|
||||
&& M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \
|
||||
child = otherChild; \
|
||||
} \
|
||||
if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \
|
||||
M_C(name, _array_swap_at) (p->array, i, child); \
|
||||
i = child; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
, /* No EQUAL */ ) \
|
||||
|
||||
|
||||
// TODO: set all & remove all function
|
||||
|
||||
+1004
-1004
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -271,7 +271,7 @@ static inline void m_serial_json_write_clear(m_serial_write_t serial)
|
||||
|
||||
/* Define a synonym to the JSON serializer with a proper OPLIST */
|
||||
typedef m_serial_write_t m_serial_json_write_t;
|
||||
#define M_OPL_m_serial_json_write_t() \
|
||||
#define M_OPL_m_serial_json_write_t() \
|
||||
(INIT_WITH(m_serial_json_write_init), CLEAR(m_serial_json_write_clear), TYPE(m_serial_json_write_t) )
|
||||
|
||||
|
||||
@@ -572,7 +572,7 @@ static inline void m_serial_json_read_clear(m_serial_read_t serial)
|
||||
/* Define a synonym of m_serial_read_t
|
||||
to the JSON serializer with its proper OPLIST */
|
||||
typedef m_serial_read_t m_serial_json_read_t;
|
||||
#define M_OPL_m_serial_json_read_t() \
|
||||
#define M_OPL_m_serial_json_read_t() \
|
||||
(INIT_WITH(m_serial_json_read_init), CLEAR(m_serial_json_read_clear), TYPE(m_serial_json_read_t) )
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
+362
-362
@@ -33,17 +33,17 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a shared pointer.
|
||||
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
#define SHARED_PTR_OPLIST(...) \
|
||||
SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_DEFAULT_OPLIST ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define shared pointer and its function.
|
||||
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SHARED_PTR_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -52,9 +52,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define shared pointer and its function
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
|
||||
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SHARED_PTR_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_ATOMIC_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__ , SHAREDI_ATOMIC_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -62,9 +62,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define relaxed shared pointer and its function (thread unsafe).
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SHARED_PTR_RELAXED_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -73,9 +73,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define relaxed shared pointer and its function (thread unsafe)
|
||||
as the given name name_t
|
||||
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), SHAREDI_INTEGER_OPLIST, name_t ), \
|
||||
(name, __VA_ARGS__, SHAREDI_INTEGER_OPLIST, name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -84,9 +84,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define shared resource and its function.
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SHARED_RESOURCE_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t), M_C(name, _it_t) ), \
|
||||
(name, __VA_ARGS__, M_C(name, _t), M_C(name, _it_t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -96,9 +96,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
as the given name named_t and the iterator it_t
|
||||
This is a bounded pool of resource shared by multiple owners.
|
||||
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
|
||||
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SHAREDI_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
|
||||
(name, __VA_ARGS__, name_t, it_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -111,40 +111,40 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given, shared_t oplist */
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
#define SHAREDI_PTR_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_OPLIST_P3, SHAREDI_PTR_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
#define SHAREDI_PTR_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
#define SHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)) \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
#define SHAREDI_PTR_OPLIST_P3(name, oplist) ( \
|
||||
INIT(M_C(name, _init)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
SET(M_C(name, _set)) \
|
||||
INIT_MOVE(M_C(name, _init_move)), \
|
||||
CLEAN(M_C(name, _clean)), \
|
||||
MOVE(M_C(name, _move)), \
|
||||
SWAP(M_C(name, _swap)) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \
|
||||
,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC oplist),) \
|
||||
,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \
|
||||
)
|
||||
|
||||
// OPLIST to handle a counter of atomic type
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
#define SHAREDI_ATOMIC_OPLIST (TYPE(atomic_int), \
|
||||
INIT_SET(atomic_init), \
|
||||
ADD(atomic_fetch_add), \
|
||||
SUB(atomic_fetch_sub), \
|
||||
IT_CREF(atomic_load))
|
||||
|
||||
// OPLIST to handle a counter of non-atomic type
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
#define SHAREDI_INTEGER_OPLIST (TYPE(int), \
|
||||
INIT_SET(sharedi_integer_init_set), \
|
||||
ADD(sharedi_integer_add), \
|
||||
SUB(sharedi_integer_sub), \
|
||||
IT_CREF(sharedi_integer_cref))
|
||||
|
||||
/* Atomic like interface for basic integers */
|
||||
@@ -154,8 +154,8 @@ static inline int sharedi_integer_sub(int *p, int val) { int r = *p; *p -= val;
|
||||
static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
|
||||
/* Contract of a shared pointer */
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
assert(shared != NULL); \
|
||||
#define SHAREDI_CONTRACT(shared, cpt_oplist) do { \
|
||||
assert(shared != NULL); \
|
||||
assert(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
|
||||
} while (0)
|
||||
|
||||
@@ -163,344 +163,344 @@ static inline int sharedi_integer_cref(int *p) { return *p; }
|
||||
#define SHAREDI_PTR_DEF_P1(arg) SHAREDI_PTR_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
#define SHAREDI_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_PTR_DEF_P3, SHAREDI_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
#define SHAREDI_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Code generation */
|
||||
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \
|
||||
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
|
||||
} *shared_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
\
|
||||
typedef struct M_C(name, combine_s) { \
|
||||
type data; \
|
||||
struct M_C(name, _s) ptr; \
|
||||
} M_C(name, combine_ct)[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t shared) \
|
||||
{ \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init2)(shared_t shared, type *data) \
|
||||
{ \
|
||||
assert (shared != NULL); \
|
||||
/* The shared ptr get exclusive access to data */ \
|
||||
struct M_C(name, _s) *ptr; \
|
||||
if (M_UNLIKELY (data == NULL)) { \
|
||||
*shared = NULL; \
|
||||
return; \
|
||||
} \
|
||||
ptr = M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
if (M_UNLIKELY (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_C(name, combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_C(name, combine_s)); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_C(name, _s) *ptr = &p->ptr; \
|
||||
type *data = &p->data; \
|
||||
M_CALL_INIT( oplist, *data); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
/* Note: if combineAlloc is true, the address of the slot \
|
||||
combining both data & ptr is the same as the address of the \
|
||||
first element, aka data itself. Static analyzer tools don't \
|
||||
seem to detect this and report error. */ \
|
||||
M_CALL_CLEAR(oplist, *(*dest)->data); \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
if (combineAlloc == false) \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(shared_t p1, \
|
||||
shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
/* NOTE: SWAP is not atomic */ \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const shared_t p1, \
|
||||
const shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return M_CONST_CAST (type, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return data; \
|
||||
} \
|
||||
#define SHAREDI_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
|
||||
\
|
||||
typedef struct M_C(name, _s){ \
|
||||
type *data; /* Pointer to the data */ \
|
||||
M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \
|
||||
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
|
||||
} *shared_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* Internal type for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
\
|
||||
typedef struct M_C(name, combine_s) { \
|
||||
type data; \
|
||||
struct M_C(name, _s) ptr; \
|
||||
} M_C(name, combine_ct)[1]; \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t shared) \
|
||||
{ \
|
||||
*shared = NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init2)(shared_t shared, type *data) \
|
||||
{ \
|
||||
assert (shared != NULL); \
|
||||
/* The shared ptr get exclusive access to data */ \
|
||||
struct M_C(name, _s) *ptr; \
|
||||
if (M_UNLIKELY (data == NULL)) { \
|
||||
*shared = NULL; \
|
||||
return; \
|
||||
} \
|
||||
ptr = M_CALL_NEW(oplist, struct M_C(name, _s)); \
|
||||
if (M_UNLIKELY (ptr == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, _s))); \
|
||||
return; \
|
||||
} \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = false; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_new)(shared_t shared) \
|
||||
{ \
|
||||
/* NOTE: Alloc 1 struct with both structures. */ \
|
||||
struct M_C(name, combine_s) *p = \
|
||||
M_CALL_NEW(oplist, struct M_C(name, combine_s)); \
|
||||
if (M_UNLIKELY (p == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(struct M_C(name, combine_s))); \
|
||||
return; \
|
||||
} \
|
||||
struct M_C(name, _s) *ptr = &p->ptr; \
|
||||
type *data = &p->data; \
|
||||
M_CALL_INIT( oplist, *data); \
|
||||
ptr->data = data; \
|
||||
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
|
||||
ptr->combineAlloc = true; \
|
||||
*shared = ptr; \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _NULL_p)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
return *shared == NULL; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
*dest = *shared; \
|
||||
if (*dest != NULL) { \
|
||||
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
|
||||
(void) n; /* unused return value */ \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t dest) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
if (*dest != NULL) { \
|
||||
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
|
||||
bool combineAlloc = (*dest)->combineAlloc; \
|
||||
/* Note: if combineAlloc is true, the address of the slot \
|
||||
combining both data & ptr is the same as the address of the \
|
||||
first element, aka data itself. Static analyzer tools don't \
|
||||
seem to detect this and report error. */ \
|
||||
M_CALL_CLEAR(oplist, *(*dest)->data); \
|
||||
M_CALL_DEL(oplist, (*dest)->data); \
|
||||
if (combineAlloc == false) \
|
||||
M_CALL_DEL(oplist, *dest); \
|
||||
} \
|
||||
*dest = NULL; \
|
||||
} \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clean)(shared_t dest) \
|
||||
{ \
|
||||
/* NOTE: Clear will also set dest to NULL */ \
|
||||
M_C(name, _clear)(dest); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _set)(shared_t dest, \
|
||||
const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_set)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init_move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != NULL && dest != shared); \
|
||||
*dest = *shared; \
|
||||
*shared = NULL; \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _move)(shared_t dest, \
|
||||
shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(dest, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert (dest != shared); \
|
||||
M_C(name, _clear)(dest); \
|
||||
M_C(name, _init_move)(dest, shared); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _swap)(shared_t p1, \
|
||||
shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
/* NOTE: SWAP is not atomic */ \
|
||||
M_SWAP (struct M_C(name, _s)*, *p1, *p2); \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _equal_p)(const shared_t p1, \
|
||||
const shared_t p2) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(p1, cpt_oplist); \
|
||||
SHAREDI_CONTRACT(p2, cpt_oplist); \
|
||||
return *p1 == *p2; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(const shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return M_CONST_CAST (type, data); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(shared_t shared) \
|
||||
{ \
|
||||
SHAREDI_CONTRACT(shared, cpt_oplist); \
|
||||
assert(*shared != NULL); \
|
||||
type *data = (*shared)->data; \
|
||||
assert (data != NULL); \
|
||||
return data; \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
/********************************** SHARED RESOURCE ************************************/
|
||||
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->buffer != NULL); \
|
||||
#define SHAREDI_RESOURCE_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->buffer != NULL); \
|
||||
} while (0)
|
||||
|
||||
// deferred
|
||||
#define SHAREDI_RESOURCE_DEF_P1(arg) SHAREDI_RESOURCE_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
#define SHAREDI_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
|
||||
M_IF_OPLIST(oplist)(SHAREDI_RESOURCE_DEF_P3, SHAREDI_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
#define SHAREDI_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
atomic_uint cpt; \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type, atomic_uint); \
|
||||
} M_C(name, _atype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
M_C(name, _atype_ct) *buffer; \
|
||||
} shared_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
unsigned int idx; \
|
||||
struct M_C(name, _s) *ref; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Internal Types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef it_t M_C(name, _it__ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t s, size_t n) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
assert (n > 0 && n < UINT_MAX); \
|
||||
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_ct), NULL, n); \
|
||||
if (M_UNLIKELY (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _atype_ct)) * n); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->idx == GENINT_ERROR; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
assert (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = GENINT_ERROR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t itd, it_t its) \
|
||||
{ \
|
||||
assert (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
assert (c >= 1); \
|
||||
} \
|
||||
} \
|
||||
#define SHAREDI_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _atype_s) { \
|
||||
atomic_uint cpt; \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type, atomic_uint); \
|
||||
} M_C(name, _atype_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
genint_t core; \
|
||||
M_C(name, _atype_ct) *buffer; \
|
||||
} shared_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _it_s) { \
|
||||
unsigned int idx; \
|
||||
struct M_C(name, _s) *ref; \
|
||||
} it_t[1]; \
|
||||
\
|
||||
/* Internal Types for oplist */ \
|
||||
typedef shared_t M_C(name, _ct); \
|
||||
typedef it_t M_C(name, _it__ct); \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(shared_t s, size_t n) \
|
||||
{ \
|
||||
assert(s != NULL); \
|
||||
assert (n > 0 && n < UINT_MAX); \
|
||||
s->buffer = M_CALL_REALLOC(oplist, M_C(name, _atype_ct), NULL, n); \
|
||||
if (M_UNLIKELY (s->buffer == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _atype_ct)) * n); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_INIT(oplist, s->buffer[i].x); \
|
||||
atomic_init (&s->buffer[i].cpt, 0U); \
|
||||
} \
|
||||
genint_init(s->core, (unsigned int) n); \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
size_t n = genint_size(s->core); \
|
||||
for(size_t i = 0; i < n; i++) { \
|
||||
M_CALL_CLEAR(oplist, s->buffer[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, s->buffer); \
|
||||
s->buffer = NULL; \
|
||||
genint_clear(s->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
unsigned int idx = genint_pop(s->core); \
|
||||
it->idx = idx; \
|
||||
it->ref = s; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
assert(atomic_load(&s->buffer[idx].cpt) == 0); \
|
||||
atomic_store(&s->buffer[idx].cpt, 1U); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline bool \
|
||||
M_C(name, _end_p)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL); \
|
||||
return it->idx == GENINT_ERROR; \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _ref)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return &it->ref->buffer[it->idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _cref)(it_t it) \
|
||||
{ \
|
||||
assert (it != NULL && it->ref != NULL && it->idx != GENINT_ERROR); \
|
||||
SHAREDI_RESOURCE_CONTRACT(it->ref); \
|
||||
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _end)(it_t it, shared_t s) \
|
||||
{ \
|
||||
SHAREDI_RESOURCE_CONTRACT(s); \
|
||||
assert (it != NULL); \
|
||||
assert (it->ref == s); \
|
||||
unsigned int idx = it->idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
|
||||
if (c == 1) { \
|
||||
genint_push(it->ref->core, idx); \
|
||||
} \
|
||||
it->idx = GENINT_ERROR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _it_set)(it_t itd, it_t its) \
|
||||
{ \
|
||||
assert (itd != NULL && its != NULL); \
|
||||
SHAREDI_RESOURCE_CONTRACT(its->ref); \
|
||||
itd->ref = its->ref; \
|
||||
unsigned int idx = its->idx; \
|
||||
itd->idx = idx; \
|
||||
if (M_LIKELY (idx != GENINT_ERROR)) { \
|
||||
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
|
||||
assert (c >= 1); \
|
||||
} \
|
||||
} \
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
+371
-371
@@ -33,9 +33,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -44,9 +44,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -54,9 +54,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -65,9 +65,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
|
||||
#define SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_SPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -75,9 +75,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_C(name, _t) ), \
|
||||
(name, __VA_ARGS__ , M_C(name, _t) ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -86,9 +86,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
SNAPSHOTI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
|
||||
(name, __VA_ARGS__ , name_t ))) \
|
||||
M_END_PROTECTED_CODE
|
||||
@@ -96,8 +96,8 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the oplist of a snapshot (SPSC, SPMC or MPMC).
|
||||
USAGE: SNAPSHOT_OPLIST(name[, oplist]) */
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
SNAPSHOTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
#define SNAPSHOT_OPLIST(...) \
|
||||
SNAPSHOTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
((__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)() ), \
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
@@ -108,24 +108,24 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define SNAPSHOTI_OPLIST_P1(arg) SNAPSHOTI_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplist */
|
||||
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
|
||||
#define SNAPSHOTI_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_OPLIST_P3, SNAPSHOTI_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define SNAPSHOTI_OPLIST_FAILURE(name, oplist) \
|
||||
#define SNAPSHOTI_OPLIST_FAILURE(name, oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_SNAPSHOT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
|
||||
|
||||
/* Define the oplist of a snapshot */
|
||||
#define SNAPSHOTI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
|
||||
#define SNAPSHOTI_OPLIST_P3(name, oplist) \
|
||||
(INIT(M_C(name, _init)) \
|
||||
,INIT_SET(M_C(name, _init_set)) \
|
||||
,SET(M_C(name, _set)) \
|
||||
,CLEAR(M_C(name, _clear)) \
|
||||
,TYPE(M_C(name, _ct)) \
|
||||
,SUBTYPE(M_C(name, _subtype_ct)) \
|
||||
,OPLIST(oplist) \
|
||||
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \
|
||||
,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \
|
||||
)
|
||||
|
||||
|
||||
@@ -138,28 +138,28 @@ M_BEGIN_PROTECTED_CODE
|
||||
* - b: Boolean indicating that the read buffer shall be updated
|
||||
* all fields packed in an unsigned char type.
|
||||
*/
|
||||
#define SNAPSHOTI_SPSC_FLAG(r, w, f, b) \
|
||||
#define SNAPSHOTI_SPSC_FLAG(r, w, f, b) \
|
||||
((unsigned char)( ( (r) << 4) | ((w) << 2) | ((f)) | ((b) << 6)))
|
||||
#define SNAPSHOTI_SPSC_R(flags) \
|
||||
#define SNAPSHOTI_SPSC_R(flags) \
|
||||
(((unsigned int) (flags) >> 4) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_W(flags) \
|
||||
#define SNAPSHOTI_SPSC_W(flags) \
|
||||
(((unsigned int) (flags) >> 2) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_F(flags) \
|
||||
#define SNAPSHOTI_SPSC_F(flags) \
|
||||
(((unsigned int) (flags) >> 0) & 0x03u)
|
||||
#define SNAPSHOTI_SPSC_B(flags) \
|
||||
#define SNAPSHOTI_SPSC_B(flags) \
|
||||
(((unsigned int) (flags) >> 6) & 0x01u)
|
||||
|
||||
/* NOTE: Due to atomic_load only accepting non-const pointer,
|
||||
we can't have any const in the interface. */
|
||||
#define SNAPSHOTI_SPSC_FLAGS_CONTRACT(flags) \
|
||||
assert(SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_W(flags) \
|
||||
&& SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_F(flags) \
|
||||
#define SNAPSHOTI_SPSC_FLAGS_CONTRACT(flags) \
|
||||
assert(SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_W(flags) \
|
||||
&& SNAPSHOTI_SPSC_R(flags) != SNAPSHOTI_SPSC_F(flags) \
|
||||
&& SNAPSHOTI_SPSC_W(flags) != SNAPSHOTI_SPSC_F(flags))
|
||||
|
||||
#define SNAPSHOTI_SPSC_CONTRACT(snap) do { \
|
||||
assert((snap) != NULL); \
|
||||
unsigned char f = atomic_load (&(snap)->flags); \
|
||||
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
|
||||
#define SNAPSHOTI_SPSC_CONTRACT(snap) do { \
|
||||
assert((snap) != NULL); \
|
||||
unsigned char f = atomic_load (&(snap)->flags); \
|
||||
SNAPSHOTI_SPSC_FLAGS_CONTRACT(f); \
|
||||
} while (0)
|
||||
|
||||
// A snapshot is basically an atomic triple buffer (Lock Free)
|
||||
@@ -170,182 +170,182 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define SNAPSHOTI_SPSC_DEF_P1(arg) SNAPSHOTI_SPSC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
#define SNAPSHOTI_SPSC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPSC_DEF_P3, SNAPSHOTI_SPSC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPSC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define SNAPSHOTI_SPSC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPSC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a SPSC snapshot */
|
||||
#define SNAPSHOTI_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type); \
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) data[SNAPSHOTI_SPSC_MAX_BUFFER]; \
|
||||
atomic_uchar flags; \
|
||||
} snapshot_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap) \
|
||||
{ \
|
||||
assert(snap != NULL); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, SNAPSHOTI_SPSC_FLAG(0, 1, 2, 0)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _init_set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
M_IF_METHOD(MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _move)(snapshot_t snap, \
|
||||
snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
assert(snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* Swap F and W buffer, setting exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_R(origFlags), \
|
||||
SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), 1); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return new write buffer for new updating */ \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(nextFlags)].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* If no exchange registered, do nothing and keep the same */ \
|
||||
if (!SNAPSHOTI_SPSC_B(origFlags)) { \
|
||||
nextFlags = origFlags; \
|
||||
break; \
|
||||
} \
|
||||
/* Swap R and F buffer, clearing exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), \
|
||||
SNAPSHOTI_SPSC_R(origFlags), 0); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return current read buffer */ \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(nextFlags)].x); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline bool \
|
||||
M_C(name, _updated_p)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load (&snap->flags); \
|
||||
return SNAPSHOTI_SPSC_B(flags); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(flags)].x; \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type const * \
|
||||
M_C(name, _get_read_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(flags)].x); \
|
||||
} \
|
||||
#define SNAPSHOTI_SPSC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type); \
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) data[SNAPSHOTI_SPSC_MAX_BUFFER]; \
|
||||
atomic_uchar flags; \
|
||||
} snapshot_t[1]; \
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap) \
|
||||
{ \
|
||||
assert(snap != NULL); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, SNAPSHOTI_SPSC_FLAG(0, 1, 2, 0)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _init_set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
/* const is missing for org due to use of atomic_load of org */ \
|
||||
static inline void \
|
||||
M_C(name, _set)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_init (&snap->flags, atomic_load(&org->flags)); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT_MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _init_move)(snapshot_t snap, snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
assert(snap != NULL && snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_INIT_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (INIT_MOVE) */ \
|
||||
\
|
||||
M_IF_METHOD(MOVE, oplist)( \
|
||||
static inline void \
|
||||
M_C(name, _move)(snapshot_t snap, \
|
||||
snapshot_t org) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(org); \
|
||||
assert(snap != org); \
|
||||
for(int i = 0; i < SNAPSHOTI_SPSC_MAX_BUFFER; i++) { \
|
||||
M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \
|
||||
} \
|
||||
atomic_store (&snap->flags, atomic_load(&org->flags)); \
|
||||
atomic_store (&org->flags, SNAPSHOTI_SPSC_FLAG(0,0,0,0) ); \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
} \
|
||||
,) /* IF_METHOD (MOVE) */ \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* Swap F and W buffer, setting exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_R(origFlags), \
|
||||
SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), 1); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return new write buffer for new updating */ \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(nextFlags)].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char nextFlags, origFlags = atomic_load (&snap->flags); \
|
||||
/* Atomic CAS operation */ \
|
||||
do { \
|
||||
/* If no exchange registered, do nothing and keep the same */ \
|
||||
if (!SNAPSHOTI_SPSC_B(origFlags)) { \
|
||||
nextFlags = origFlags; \
|
||||
break; \
|
||||
} \
|
||||
/* Swap R and F buffer, clearing exchange flag */ \
|
||||
nextFlags = SNAPSHOTI_SPSC_FLAG(SNAPSHOTI_SPSC_F(origFlags), \
|
||||
SNAPSHOTI_SPSC_W(origFlags), \
|
||||
SNAPSHOTI_SPSC_R(origFlags), 0); \
|
||||
/* exponential backoff is not needed as there can't be more \
|
||||
than 2 threads which try to update the data. */ \
|
||||
} while (!atomic_compare_exchange_weak (&snap->flags, &origFlags, \
|
||||
nextFlags)); \
|
||||
/* Return current read buffer */ \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(nextFlags)].x); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline bool \
|
||||
M_C(name, _updated_p)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load (&snap->flags); \
|
||||
return SNAPSHOTI_SPSC_B(flags); \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return &snap->data[SNAPSHOTI_SPSC_W(flags)].x; \
|
||||
} \
|
||||
\
|
||||
/* Non const due to use of atomic_load */ \
|
||||
static inline type const * \
|
||||
M_C(name, _get_read_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPSC_CONTRACT(snap); \
|
||||
unsigned char flags = atomic_load(&snap->flags); \
|
||||
return M_CONST_CAST(type, &snap->data[SNAPSHOTI_SPSC_R(flags)].x); \
|
||||
} \
|
||||
|
||||
|
||||
|
||||
@@ -376,12 +376,12 @@ typedef struct snapshot_mrsw_int_s {
|
||||
} snapshot_mrsw_int_ct[1];
|
||||
|
||||
// can't check currentWrite due to potential data race on it
|
||||
#define SNAPSHOTI_SPMC_INT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n_reader > 0 && s->n_reader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
assert ((size_t)SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
assert (s->cptTab != NULL); \
|
||||
#define SNAPSHOTI_SPMC_INT_CONTRACT(s) do { \
|
||||
assert (s != NULL); \
|
||||
assert (s->n_reader > 0 && s->n_reader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
assert ((size_t)SNAPSHOTI_SPMC_INT_FLAG_W(atomic_load(&s->lastNext)) \
|
||||
<= s->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
assert (s->cptTab != NULL); \
|
||||
} while (0)
|
||||
|
||||
/* Initialize snapshot_mrsw_int_ct for n readers (constructor) */
|
||||
@@ -595,9 +595,9 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
|
||||
/* Contract of a SPMC snapshot.
|
||||
Nothing notable as it can be accessed concurrently */
|
||||
#define SNAPSHOTI_SPMC_CONTRACT(snap) do { \
|
||||
assert (snap != NULL); \
|
||||
assert (snap->data != NULL); \
|
||||
#define SNAPSHOTI_SPMC_CONTRACT(snap) do { \
|
||||
assert (snap != NULL); \
|
||||
assert (snap->data != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -605,102 +605,102 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
#define SNAPSHOTI_SPMC_DEF_P1(arg) SNAPSHOTI_SPMC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
#define SNAPSHOTI_SPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_SPMC_DEF_P3, SNAPSHOTI_SPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_SPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define SNAPSHOTI_SPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_SPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a SPMC snapshot */
|
||||
#define SNAPSHOTI_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type); \
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) *data; \
|
||||
snapshot_mrsw_int_ct core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader) \
|
||||
{ \
|
||||
assert (snap != NULL); \
|
||||
assert (nReader > 0 && nReader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_ct), \
|
||||
NULL, nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
if (M_UNLIKELY (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_ct)) * \
|
||||
(nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER)); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
snapshot_mrsw_int_init(snap->core, nReader); \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = snapshot_mrsw_int_size(snap->core); \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, snap->data); \
|
||||
snapshot_mrsw_int_clear(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_read_start(snap->core); \
|
||||
return M_CONST_CAST(type, &snap->data[idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
assert (old != NULL); \
|
||||
const M_C(name, _aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_ct), old, type, x); \
|
||||
assert (oldx >= snap->data); \
|
||||
#define SNAPSHOTI_SPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
/* Create an aligned type to avoid false sharing between threads */ \
|
||||
typedef struct M_C(name, _aligned_type_s) { \
|
||||
type x; \
|
||||
M_CACHELINE_ALIGN(align, type); \
|
||||
} M_C(name, _aligned_type_ct); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _aligned_type_ct) *data; \
|
||||
snapshot_mrsw_int_ct core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader) \
|
||||
{ \
|
||||
assert (snap != NULL); \
|
||||
assert (nReader > 0 && nReader <= SNAPSHOTI_SPMC_MAX_READER); \
|
||||
snap->data = M_CALL_REALLOC(oplist, M_C(name, _aligned_type_ct), \
|
||||
NULL, nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
if (M_UNLIKELY (snap->data == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof(M_C(name, _aligned_type_ct)) * \
|
||||
(nReader+SNAPSHOTI_SPMC_EXTRA_BUFFER)); \
|
||||
return; \
|
||||
} \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_INIT(oplist, snap->data[i].x); \
|
||||
} \
|
||||
snapshot_mrsw_int_init(snap->core, nReader); \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
size_t nReader = snapshot_mrsw_int_size(snap->core); \
|
||||
for(size_t i = 0; i < nReader + SNAPSHOTI_SPMC_EXTRA_BUFFER; i++) { \
|
||||
M_CALL_CLEAR(oplist, snap->data[i].x); \
|
||||
} \
|
||||
M_CALL_FREE(oplist, snap->data); \
|
||||
snapshot_mrsw_int_clear(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_read_start(snap->core); \
|
||||
return M_CONST_CAST(type, &snap->data[idx].x); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
assert (old != NULL); \
|
||||
const M_C(name, _aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _aligned_type_ct), old, type, x); \
|
||||
assert (oldx >= snap->data); \
|
||||
assert (oldx < snap->data + snap->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
assert(snap->core->n_reader +SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->data); \
|
||||
snapshot_mrsw_int_read_end(snap->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_get_write_idx(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
assert(snap->core->n_reader +SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->data); \
|
||||
snapshot_mrsw_int_read_end(snap->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _get_write_buffer)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap); \
|
||||
const unsigned int idx = snapshot_mrsw_int_get_write_idx(snap->core); \
|
||||
return &snap->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
|
||||
//FIXME: Evaluate the needs for the methods _set_, _init_set.
|
||||
|
||||
@@ -714,76 +714,76 @@ snapshot_mrsw_int_read_end(snapshot_mrsw_int_ct s, unsigned int idx)
|
||||
#define SNAPSHOTI_MPMC_DEF_P1(arg) SNAPSHOTI_MPMC_DEF_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
#define SNAPSHOTI_MPMC_DEF_P2(name, type, oplist, snapshot_t) \
|
||||
M_IF_OPLIST(oplist)(SNAPSHOTI_MPMC_DEF_P3, SNAPSHOTI_MPMC_DEF_FAILURE)(name, type, oplist, snapshot_t)
|
||||
|
||||
/* Stop processing with a compilation failure */
|
||||
#define SNAPSHOTI_MPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
#define SNAPSHOTI_MPMC_DEF_FAILURE(name, type, oplist, snapshot_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SNAPSHOT_MPMC_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
/* Expand the type and the functions of a MPMC snapshot */
|
||||
#define SNAPSHOTI_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
#define SNAPSHOTI_MPMC_DEF_P3(name, type, oplist, snapshot_t) \
|
||||
\
|
||||
SNAPSHOTI_SPMC_DEF_P1((M_C(name, _mrsw), type, oplist, M_C(name, _mrsw_pct))) \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _mrsw_pct) core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
|
||||
{ \
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
unsigned int idx = snap->core->core->currentWrite; \
|
||||
snap->core->core->currentWrite = GENINT_ERROR; \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
M_C(name, _mrsw_clear)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
\
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_C(name, _mrsw_pct) core; \
|
||||
} snapshot_t[1]; \
|
||||
\
|
||||
/* Define internal types for oplist */ \
|
||||
typedef snapshot_t M_C(name, _ct); \
|
||||
typedef type M_C(name, _subtype_ct); \
|
||||
\
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
|
||||
{ \
|
||||
M_C(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
|
||||
unsigned int idx = snap->core->core->currentWrite; \
|
||||
snap->core->core->currentWrite = GENINT_ERROR; \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(snapshot_t snap) \
|
||||
{ \
|
||||
M_C(name, _mrsw_clear)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline type * \
|
||||
M_C(name, _write_start)(snapshot_t snap) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const unsigned int idx = snapshot_mrsw_int_write_start(snap->core->core); \
|
||||
return &snap->core->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _write_end)(snapshot_t snap, type *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const M_C(name, _mrsw_aligned_type_ct) *oldx; \
|
||||
return &snap->core->data[idx].x; \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _write_end)(snapshot_t snap, type *old) \
|
||||
{ \
|
||||
SNAPSHOTI_SPMC_CONTRACT(snap->core); \
|
||||
const M_C(name, _mrsw_aligned_type_ct) *oldx; \
|
||||
oldx = M_CTYPE_FROM_FIELD(M_C(name, _mrsw_aligned_type_ct), old, type, x); \
|
||||
assert (oldx >= snap->core->data); \
|
||||
assert (oldx >= snap->core->data); \
|
||||
assert (oldx < snap->core->data + snap->core->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER); \
|
||||
assert(snap->core->core->n_reader + SNAPSHOTI_SPMC_EXTRA_BUFFER < UINT_MAX); \
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->core->data); \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
return M_C(name, _mrsw_read_start)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
M_C(name, _mrsw_read_end)(snap->core, old); \
|
||||
} \
|
||||
\
|
||||
const unsigned int idx = (unsigned int) (oldx - snap->core->data); \
|
||||
snapshot_mrsw_int_write_end(snap->core->core, idx); \
|
||||
} \
|
||||
\
|
||||
static inline type const * \
|
||||
M_C(name, _read_start)(snapshot_t snap) \
|
||||
{ \
|
||||
return M_C(name, _mrsw_read_start)(snap->core); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _read_end)(snapshot_t snap, type const *old) \
|
||||
{ \
|
||||
M_C(name, _mrsw_read_end)(snap->core, old); \
|
||||
} \
|
||||
\
|
||||
|
||||
//TODO: _set_, _init_set
|
||||
|
||||
|
||||
+460
-460
File diff suppressed because it is too large.
Load diff
@@ -32,9 +32,9 @@
|
||||
/* Define the tuple type and functions.
|
||||
USAGE:
|
||||
TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, M_C(name, _t) TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
#define TUPLE_DEF2(name, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, M_C(name, _t) TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
@@ -42,17 +42,17 @@
|
||||
as the given name.
|
||||
USAGE:
|
||||
TUPLE_DEF2_AS(name, name_t, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */
|
||||
#define TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, name_t TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
#define TUPLE_DEF2_AS(name, name_t, ...) \
|
||||
M_BEGIN_PROTECTED_CODE \
|
||||
TUPLEI_DEF2_P1( (name, name_t TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) \
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a tuple.
|
||||
USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */
|
||||
#define TUPLE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(TUPLEI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
#define TUPLE_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
(TUPLEI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST )), \
|
||||
TUPLEI_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
@@ -202,152 +202,152 @@ namespace m_tuple {
|
||||
|
||||
|
||||
/* Define the type of a tuple */
|
||||
#define TUPLEI_DEFINE_TYPE(name, name_t, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_MAP(TUPLEI_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
} name_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
/* Define internal type for oplist */ \
|
||||
#define TUPLEI_DEFINE_TYPE(name, name_t, ...) \
|
||||
typedef struct M_C(name, _s) { \
|
||||
M_MAP(TUPLEI_DEFINE_RECUR_TYPE_ELE , __VA_ARGS__) \
|
||||
} name_t[1]; \
|
||||
\
|
||||
typedef struct M_C(name, _s) *M_C(name, _ptr); \
|
||||
typedef const struct M_C(name, _s) *M_C(name, _srcptr); \
|
||||
/* Define internal type for oplist */ \
|
||||
typedef name_t M_C(name, _ct);
|
||||
|
||||
#define TUPLEI_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
#define TUPLEI_DEFINE_RECUR_TYPE_ELE(a) \
|
||||
TUPLEI_GET_TYPE a TUPLEI_GET_FIELD a ;
|
||||
|
||||
/* Define the basic enumerate, identifying a parameter */
|
||||
#define TUPLEI_DEFINE_ENUM(name, ...) \
|
||||
typedef enum { \
|
||||
M_C(name, _first_one_val), \
|
||||
M_MAP2_C(TUPLEI_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_ENUM(name, ...) \
|
||||
typedef enum { \
|
||||
M_C(name, _first_one_val), \
|
||||
M_MAP2_C(TUPLEI_DEFINE_ENUM_ELE , name, __VA_ARGS__) \
|
||||
} M_C(name,_field_e);
|
||||
|
||||
#define TUPLEI_DEFINE_ENUM_ELE(name, a) \
|
||||
#define TUPLEI_DEFINE_ENUM_ELE(name, a) \
|
||||
M_C4(name, _, TUPLEI_GET_FIELD a, _value)
|
||||
|
||||
/* Control that all given oplists of all parameters are really oplists */
|
||||
#define TUPLEI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
#define TUPLEI_CONTROL_ALL_OPLIST(name, ...) \
|
||||
M_MAP2(TUPLEI_CONTROL_OPLIST, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, TUPLEI_GET_FIELD a, \
|
||||
#define TUPLEI_CONTROL_OPLIST(name, a) \
|
||||
M_CHECK_COMPATIBLE_OPLIST(name, TUPLEI_GET_FIELD a, \
|
||||
TUPLEI_GET_TYPE a, TUPLEI_GET_OPLIST a)
|
||||
|
||||
/* Define the INIT method calling the INIT method for all params */
|
||||
#define TUPLEI_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_ct) my) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_INIT(name, ...) \
|
||||
static inline void M_C(name, _init)(M_C(name,_ct) my) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_INIT_FUNC(a) \
|
||||
TUPLEI_CALL_INIT(a, my -> TUPLEI_GET_FIELD a );
|
||||
|
||||
/* Define the INIT_SET method calling the INIT_SET method for all params */
|
||||
#define TUPLEI_DEFINE_INIT_SET(name, ...) \
|
||||
#define TUPLEI_DEFINE_INIT_SET(name, ...) \
|
||||
static inline void M_C(name, _init_set)(M_C(name,_ct) my , M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLEI_DEFINE_INIT_SET_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_INIT_SET_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_SET(a, my -> TUPLEI_GET_FIELD a , org -> TUPLEI_GET_FIELD a );
|
||||
|
||||
/* Define the INIT_WITH method calling the INIT_SET method for all params. */
|
||||
/* FIXME: To rename? */
|
||||
#define TUPLEI_DEFINE_INIT_SET2(name, ...) \
|
||||
static inline void M_C(name, _init_set2)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_INIT_SET2(name, ...) \
|
||||
static inline void M_C(name, _init_set2)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_SET2_PROTO(a) \
|
||||
#define TUPLEI_DEFINE_INIT_SET2_PROTO(a) \
|
||||
, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_SET2_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_INIT_SET2_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_SET(a, my -> TUPLEI_GET_FIELD a , TUPLEI_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the SET method calling the SET method for all params. */
|
||||
#define TUPLEI_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_ct) my , \
|
||||
M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_SET(name, ...) \
|
||||
static inline void M_C(name, _set)(M_C(name,_ct) my , \
|
||||
M_C(name,_ct) const org) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CONTRACT(org); \
|
||||
M_MAP(TUPLEI_DEFINE_SET_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_SET_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_SET_FUNC(a) \
|
||||
TUPLEI_CALL_SET(a, my -> TUPLEI_GET_FIELD a , org -> TUPLEI_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the SET_WITH method calling the SET method for all params. */
|
||||
/* FIXME: To rename? */
|
||||
#define TUPLEI_DEFINE_SET2(name, ...) \
|
||||
static inline void M_C(name, _set2)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_SET2(name, ...) \
|
||||
static inline void M_C(name, _set2)(M_C(name,_ct) my \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_PROTO, __VA_ARGS__) \
|
||||
) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_SET2_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
#define TUPLEI_DEFINE_SET2_PROTO(a) \
|
||||
#define TUPLEI_DEFINE_SET2_PROTO(a) \
|
||||
, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a
|
||||
|
||||
#define TUPLEI_DEFINE_SET2_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_SET2_FUNC(a) \
|
||||
TUPLEI_CALL_SET(a, my -> TUPLEI_GET_FIELD a , TUPLEI_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the CLEAR method calling the CLEAR method for all params. */
|
||||
#define TUPLEI_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_CLEAR(name, ...) \
|
||||
static inline void M_C(name, _clear)(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CLEAR_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_CLEAR_FUNC(a) \
|
||||
TUPLEI_CALL_CLEAR(a, my -> TUPLEI_GET_FIELD a );
|
||||
|
||||
|
||||
/* Define the GET_AT_field & CGET_AT methods for all params. */
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD(name, ...) \
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_DEFINE_GETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD_PROTO(name, a) \
|
||||
static inline TUPLEI_GET_TYPE a * M_C3(name, _get_at_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
} \
|
||||
#define TUPLEI_DEFINE_GETTER_FIELD_PROTO(name, a) \
|
||||
static inline TUPLEI_GET_TYPE a * M_C3(name, _get_at_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
} \
|
||||
static inline TUPLEI_GET_TYPE a const * M_C3(name, _cget_at_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) const my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
(M_C(name,_ct) const my) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
return &(my->TUPLEI_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the SET_field methods for all params. */
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD(name, ...) \
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_DEFINE_SETTER_FIELD_PROTO, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) my, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CALL_SET(a, my ->TUPLEI_GET_FIELD a, TUPLEI_GET_FIELD a); \
|
||||
#define TUPLEI_DEFINE_SETTER_FIELD_PROTO(name, a) \
|
||||
static inline void M_C3(name, _set_, TUPLEI_GET_FIELD a) \
|
||||
(M_C(name,_ct) my, TUPLEI_GET_TYPE a const TUPLEI_GET_FIELD a) { \
|
||||
TUPLEI_CONTRACT(my); \
|
||||
TUPLEI_CALL_SET(a, my ->TUPLEI_GET_FIELD a, TUPLEI_GET_FIELD a); \
|
||||
}
|
||||
|
||||
|
||||
/* Define the CMP method by calling CMP methods for all params. */
|
||||
#define TUPLEI_DEFINE_CMP(name, ...) \
|
||||
static inline int M_C(name, _cmp)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
int i; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_CMP_FUNC , __VA_ARGS__) \
|
||||
return 0; \
|
||||
#define TUPLEI_DEFINE_CMP(name, ...) \
|
||||
static inline int M_C(name, _cmp)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
int i; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_CMP_FUNC , __VA_ARGS__) \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_CMP_FUNC(a) \
|
||||
i = TUPLEI_CALL_CMP(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
if (i != 0) return i;
|
||||
|
||||
@@ -356,321 +356,321 @@ namespace m_tuple {
|
||||
In the right order
|
||||
FIXME: _cmp_order is not supported by algorithm yet.
|
||||
*/
|
||||
#define TUPLEI_DEFINE_CMP_ORDER(name, ...) \
|
||||
static inline int M_C(name, _cmp_order)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2, \
|
||||
const int order[]) { \
|
||||
int i, r; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
while (true) { \
|
||||
i=*order++; \
|
||||
switch (i) { \
|
||||
case 0: return 0; \
|
||||
M_MAP2(TUPLEI_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
default: assert(0); \
|
||||
} \
|
||||
} \
|
||||
#define TUPLEI_DEFINE_CMP_ORDER(name, ...) \
|
||||
static inline int M_C(name, _cmp_order)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2, \
|
||||
const int order[]) { \
|
||||
int i, r; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
while (true) { \
|
||||
i=*order++; \
|
||||
switch (i) { \
|
||||
case 0: return 0; \
|
||||
M_MAP2(TUPLEI_DEFINE_CMP_ORDER_FUNC , name, __VA_ARGS__) \
|
||||
default: assert(0); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_ORDER_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
case -M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
#define TUPLEI_DEFINE_CMP_ORDER_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
case -M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
r = TUPLEI_CALL_CMP(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
if (r != 0) return i < 0 ? -r : r; \
|
||||
if (r != 0) return i < 0 ? -r : r; \
|
||||
break;
|
||||
|
||||
|
||||
/* Define a CMP_field method for all given params that export a CMP method */
|
||||
#define TUPLEI_DEFINE_CMP_FIELD(name, ...) \
|
||||
#define TUPLEI_DEFINE_CMP_FIELD(name, ...) \
|
||||
M_MAP2(TUPLEI_MAP_CMP_FIELD, name, __VA_ARGS__)
|
||||
|
||||
#define TUPLEI_MAP_CMP_FIELD(name, a) \
|
||||
M_IF_METHOD(CMP, TUPLEI_GET_OPLIST a)( \
|
||||
#define TUPLEI_MAP_CMP_FIELD(name, a) \
|
||||
M_IF_METHOD(CMP, TUPLEI_GET_OPLIST a)( \
|
||||
TUPLEI_DEFINE_CMP_FIELD_FUNC(name, TUPLEI_GET_FIELD a, TUPLEI_GET_CMP a), \
|
||||
)
|
||||
|
||||
#define TUPLEI_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
static inline int M_C3(name, _cmp_, field)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
return func_cmp ( e1 -> field , e2 -> field ); \
|
||||
#define TUPLEI_DEFINE_CMP_FIELD_FUNC(name, field, func_cmp) \
|
||||
static inline int M_C3(name, _cmp_, field)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
return func_cmp ( e1 -> field , e2 -> field ); \
|
||||
}
|
||||
|
||||
|
||||
/* Define a EQUAL method by calling the EQUAL methods for all params */
|
||||
#define TUPLEI_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
bool b; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
|
||||
return true; \
|
||||
#define TUPLEI_DEFINE_EQUAL(name, ...) \
|
||||
static inline bool M_C(name, _equal_p)(M_C(name,_ct) const e1 , \
|
||||
M_C(name,_ct) const e2) { \
|
||||
bool b; \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
TUPLEI_CONTRACT(e2); \
|
||||
M_MAP(TUPLEI_DEFINE_EQUAL_FUNC , __VA_ARGS__) \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_EQUAL_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_EQUAL_FUNC(a) \
|
||||
b = TUPLEI_CALL_EQUAL(a, e1 -> TUPLEI_GET_FIELD a , e2 -> TUPLEI_GET_FIELD a ); \
|
||||
if (!b) return false;
|
||||
|
||||
|
||||
/* Define a HASH method by calling the HASH methods for all params */
|
||||
#define TUPLEI_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_MAP(TUPLEI_DEFINE_HASH_FUNC , __VA_ARGS__) \
|
||||
return M_HASH_FINAL (hash); \
|
||||
#define TUPLEI_DEFINE_HASH(name, ...) \
|
||||
static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \
|
||||
TUPLEI_CONTRACT(e1); \
|
||||
M_HASH_DECL(hash); \
|
||||
M_MAP(TUPLEI_DEFINE_HASH_FUNC , __VA_ARGS__) \
|
||||
return M_HASH_FINAL (hash); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_HASH_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_HASH_FUNC(a) \
|
||||
M_HASH_UP(hash, TUPLEI_CALL_HASH(a, e1 -> TUPLEI_GET_FIELD a) );
|
||||
|
||||
|
||||
/* Define a GET_STR method by calling the GET_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
M_MAP(TUPLEI_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
#define TUPLEI_DEFINE_GET_STR(name, ...) \
|
||||
static inline void M_C(name, _get_str)(string_t str, \
|
||||
M_C(name,_ct) const el, \
|
||||
bool append) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (str != NULL); \
|
||||
(append ? string_cat_str : string_set_str) (str, "("); \
|
||||
M_MAP(TUPLEI_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
|
||||
string_push_back (str, ')'); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) string_push_back (str, ','); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_GET_STR(a, str, el -> TUPLEI_GET_FIELD a, true); \
|
||||
#define TUPLEI_DEFINE_GET_STR_FUNC(a) \
|
||||
if (comma) string_push_back (str, ','); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_GET_STR(a, str, el -> TUPLEI_GET_FIELD a, true); \
|
||||
|
||||
|
||||
/* Define a OUT_STR method by calling the OUT_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL); \
|
||||
fputc('(', f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
fputc (')', f); \
|
||||
#define TUPLEI_DEFINE_OUT_STR(name, ...) \
|
||||
static inline void M_C(name, _out_str)(FILE *f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL); \
|
||||
fputc('(', f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_STR_FUNC , __VA_ARGS__) \
|
||||
fputc (')', f); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_OUT_STR_FUNC(a) \
|
||||
if (comma) fputc (',', f); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_OUT_STR(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
#define TUPLEI_DEFINE_OUT_STR_FUNC(a) \
|
||||
if (comma) fputc (',', f); \
|
||||
comma = true; \
|
||||
TUPLEI_CALL_OUT_STR(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
|
||||
|
||||
/* Define a IN_STR method by calling the IN_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_ct) el, FILE *f) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL); \
|
||||
int c = fgetc(f); \
|
||||
if (c != '(') return false; \
|
||||
M_MAP(TUPLEI_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
c = fgetc(f); \
|
||||
return (c == ')'); \
|
||||
#define TUPLEI_DEFINE_IN_STR(name, ...) \
|
||||
static inline bool M_C(name, _in_str)(M_C(name,_ct) el, FILE *f) { \
|
||||
bool comma = false; \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL); \
|
||||
int c = fgetc(f); \
|
||||
if (c != '(') return false; \
|
||||
M_MAP(TUPLEI_DEFINE_IN_STR_FUNC , __VA_ARGS__) \
|
||||
c = fgetc(f); \
|
||||
return (c == ')'); \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_IN_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = fgetc (f); \
|
||||
if (c != ',' || c == EOF) return false; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_IN_STR(a, el -> TUPLEI_GET_FIELD a, f) == false) \
|
||||
return false ; \
|
||||
#define TUPLEI_DEFINE_IN_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = fgetc (f); \
|
||||
if (c != ',' || c == EOF) return false; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_IN_STR(a, el -> TUPLEI_GET_FIELD a, f) == false) \
|
||||
return false ; \
|
||||
|
||||
|
||||
/* Define a PARSE_STR method by calling the PARSE_STR methods for all params */
|
||||
#define TUPLEI_DEFINE_PARSE_STR(name, ...) \
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \
|
||||
const char str[], \
|
||||
const char **endptr) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (str != NULL); \
|
||||
bool success = false; \
|
||||
bool comma = false; \
|
||||
int c = *str++; \
|
||||
if (c != '(') goto exit; \
|
||||
M_MAP(TUPLEI_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
c = *str++; \
|
||||
success = (c == ')'); \
|
||||
exit: \
|
||||
if (endptr) *endptr = str; \
|
||||
return success; \
|
||||
#define TUPLEI_DEFINE_PARSE_STR(name, ...) \
|
||||
static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \
|
||||
const char str[], \
|
||||
const char **endptr) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (str != NULL); \
|
||||
bool success = false; \
|
||||
bool comma = false; \
|
||||
int c = *str++; \
|
||||
if (c != '(') goto exit; \
|
||||
M_MAP(TUPLEI_DEFINE_PARSE_STR_FUNC , __VA_ARGS__) \
|
||||
c = *str++; \
|
||||
success = (c == ')'); \
|
||||
exit: \
|
||||
if (endptr) *endptr = str; \
|
||||
return success; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_PARSE_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = *str++; \
|
||||
if (c != ',' || c == 0) goto exit; \
|
||||
} \
|
||||
comma = true; \
|
||||
#define TUPLEI_DEFINE_PARSE_STR_FUNC(a) \
|
||||
if (comma) { \
|
||||
c = *str++; \
|
||||
if (c != ',' || c == 0) goto exit; \
|
||||
} \
|
||||
comma = true; \
|
||||
if (TUPLEI_CALL_PARSE_STR(a, el -> TUPLEI_GET_FIELD a, str, &str) == false) \
|
||||
goto exit ; \
|
||||
goto exit ; \
|
||||
|
||||
|
||||
/* Return the parameter name as a C string */
|
||||
#define TUPLEI_STRINGIFY_NAME(a) \
|
||||
#define TUPLEI_STRINGIFY_NAME(a) \
|
||||
M_APPLY(M_AS_STR, TUPLEI_GET_FIELD a)
|
||||
|
||||
|
||||
/* Define a OUT_SERIAL method by calling the OUT_SERIAL methods for all params */
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
/* Define a constant static table of all fields names */ \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
int index = 0; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->write_tuple_start(local, f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
assert( index == field_max); \
|
||||
ret |= f->m_interface->write_tuple_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _out_serial)(m_serial_write_t f, \
|
||||
M_C(name,_ct) const el) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
/* Define a constant static table of all fields names */ \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
int index = 0; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->write_tuple_start(local, f); \
|
||||
M_MAP(TUPLEI_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
|
||||
assert( index == field_max); \
|
||||
ret |= f->m_interface->write_tuple_end(local, f); \
|
||||
return ret & M_SERIAL_FAIL; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
f->m_interface->write_tuple_id(local, f, field_name, field_max, index); \
|
||||
TUPLEI_CALL_OUT_SERIAL(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
index++; \
|
||||
#define TUPLEI_DEFINE_OUT_SERIAL_FUNC(a) \
|
||||
f->m_interface->write_tuple_id(local, f, field_name, field_max, index); \
|
||||
TUPLEI_CALL_OUT_SERIAL(a, f, el -> TUPLEI_GET_FIELD a); \
|
||||
index++; \
|
||||
|
||||
|
||||
/* Define a IN_SERIAL method by calling the IN_SERIAL methods for all params */
|
||||
#define TUPLEI_DEFINE_IN_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_ct) el, m_serial_read_t f) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
int index = -1; \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->read_tuple_start(local, f); \
|
||||
while (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
#define TUPLEI_DEFINE_IN_SERIAL(name, ...) \
|
||||
static inline m_serial_return_code_t \
|
||||
M_C(name, _in_serial)(M_C(name,_ct) el, m_serial_read_t f) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
assert (f != NULL && f->m_interface != NULL); \
|
||||
int index = -1; \
|
||||
const int field_max = M_NARGS(__VA_ARGS__); \
|
||||
static const char *const field_name[] = \
|
||||
{ M_REDUCE(TUPLEI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \
|
||||
m_serial_local_t local; \
|
||||
m_serial_return_code_t ret; \
|
||||
ret = f->m_interface->read_tuple_start(local, f); \
|
||||
while (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
ret = f->m_interface->read_tuple_id(local, f, field_name, field_max, &index); \
|
||||
if (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
assert (index >= 0 && index < field_max); \
|
||||
switch (1+index) { \
|
||||
M_MAP2(TUPLEI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: assert(0); \
|
||||
} \
|
||||
if (ret == M_SERIAL_OK_CONTINUE) { \
|
||||
assert (index >= 0 && index < field_max); \
|
||||
switch (1+index) { \
|
||||
M_MAP2(TUPLEI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \
|
||||
default: assert(0); \
|
||||
} \
|
||||
ret = (ret == M_SERIAL_OK_DONE) ? M_SERIAL_OK_CONTINUE : M_SERIAL_FAIL; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
ret = TUPLEI_CALL_IN_SERIAL(a, el -> TUPLEI_GET_FIELD a, f); \
|
||||
break; \
|
||||
#define TUPLEI_DEFINE_IN_SERIAL_FUNC(name, a) \
|
||||
case M_C4(name, _, TUPLEI_GET_FIELD a, _value): \
|
||||
ret = TUPLEI_CALL_IN_SERIAL(a, el -> TUPLEI_GET_FIELD a, f); \
|
||||
break; \
|
||||
|
||||
|
||||
/* Define a INIT_MOVE method by calling the INIT_MOVE methods for all params */
|
||||
#define TUPLEI_DEFINE_INIT_MOVE(name, ...) \
|
||||
#define TUPLEI_DEFINE_INIT_MOVE(name, ...) \
|
||||
static inline void M_C(name, _init_move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_INIT_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_INIT_MOVE_FUNC(a) \
|
||||
TUPLEI_CALL_INIT_MOVE(a, el -> TUPLEI_GET_FIELD a, org -> TUPLEI_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a MOVE method by calling the MOVE methods for all params */
|
||||
#define TUPLEI_DEFINE_MOVE(name, ...) \
|
||||
static inline void M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_MOVE(name, ...) \
|
||||
static inline void M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \
|
||||
TUPLEI_CONTRACT(el); \
|
||||
M_MAP(TUPLEI_DEFINE_MOVE_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_MOVE_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_MOVE_FUNC(a) \
|
||||
TUPLEI_CALL_MOVE(a, el -> TUPLEI_GET_FIELD a, org -> TUPLEI_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a SWAP method by calling the SWAP methods for all params */
|
||||
#define TUPLEI_DEFINE_SWAP(name, ...) \
|
||||
#define TUPLEI_DEFINE_SWAP(name, ...) \
|
||||
static inline void M_C(name, _swap)(M_C(name,_ct) el1, M_C(name,_ct) el2) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
TUPLEI_CONTRACT(el2); \
|
||||
M_MAP(TUPLEI_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
TUPLEI_CONTRACT(el2); \
|
||||
M_MAP(TUPLEI_DEFINE_SWAP_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_SWAP_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_SWAP_FUNC(a) \
|
||||
TUPLEI_CALL_SWAP(a, el1 -> TUPLEI_GET_FIELD a, el2 -> TUPLEI_GET_FIELD a);
|
||||
|
||||
|
||||
/* Define a CLEAN method by calling the CLEAN methods for all params */
|
||||
#define TUPLEI_DEFINE_CLEAN(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_ct) el1) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
|
||||
#define TUPLEI_DEFINE_CLEAN(name, ...) \
|
||||
static inline void M_C(name, _clean)(M_C(name,_ct) el1) { \
|
||||
TUPLEI_CONTRACT(el1); \
|
||||
M_MAP(TUPLEI_DEFINE_CLEAN_FUNC , __VA_ARGS__) \
|
||||
}
|
||||
|
||||
#define TUPLEI_DEFINE_CLEAN_FUNC(a) \
|
||||
#define TUPLEI_DEFINE_CLEAN_FUNC(a) \
|
||||
TUPLEI_CALL_CLEAN(a, el1 -> TUPLEI_GET_FIELD a);
|
||||
|
||||
|
||||
/* Macros for testing for the presence of a method in the parameter (name, type, oplist) */
|
||||
#define TUPLEI_TEST_METHOD_P(method, trio) \
|
||||
#define TUPLEI_TEST_METHOD_P(method, trio) \
|
||||
M_APPLY(TUPLEI_TEST_METHOD2_P, method, M_OPFLAT trio)
|
||||
|
||||
#define TUPLEI_TEST_METHOD2_P(method, f, t, op) \
|
||||
#define TUPLEI_TEST_METHOD2_P(method, f, t, op) \
|
||||
M_TEST_METHOD_P(method, op)
|
||||
|
||||
|
||||
/* Macros for testing for the presence of a method in all the params */
|
||||
#define TUPLEI_IF_ALL(method, ...) \
|
||||
#define TUPLEI_IF_ALL(method, ...) \
|
||||
M_IF(M_REDUCE2(TUPLEI_TEST_METHOD_P, M_AND, method, __VA_ARGS__))
|
||||
|
||||
// deferred evaluation
|
||||
#define TUPLEI_OPLIST_P1(arg) TUPLEI_OPLIST_P2 arg
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
#define TUPLEI_OPLIST_P2(name, ...) \
|
||||
#define TUPLEI_OPLIST_P2(name, ...) \
|
||||
M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(TUPLEI_OPLIST_P3, TUPLEI_OPLIST_FAILURE)(name, __VA_ARGS__)
|
||||
|
||||
/* Prepare a clean compilation failure */
|
||||
#define TUPLEI_OPLIST_FAILURE(name, ...) \
|
||||
#define TUPLEI_OPLIST_FAILURE(name, ...) \
|
||||
((M_LIB_ERROR(ONE_ARGUMENT_OF_TUPLEI_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
|
||||
|
||||
/* Define the TUPLE oplist */
|
||||
#define TUPLEI_OPLIST_P3(name, ...) \
|
||||
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(M_C(name, _init_set2)), \
|
||||
SET(M_C(name,_set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_C(name, _cmp)),), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
|
||||
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_C(name, _equal_p)),), \
|
||||
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(M_C(name, _get_str)),), \
|
||||
#define TUPLEI_OPLIST_P3(name, ...) \
|
||||
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_C(name,_init)),), \
|
||||
INIT_SET(M_C(name, _init_set)), \
|
||||
INIT_WITH(M_C(name, _init_set2)), \
|
||||
SET(M_C(name,_set)), \
|
||||
CLEAR(M_C(name, _clear)), \
|
||||
TYPE(M_C(name,_ct)), \
|
||||
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_C(name, _cmp)),), \
|
||||
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_C(name, _hash)),), \
|
||||
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_C(name, _equal_p)),), \
|
||||
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(M_C(name, _get_str)),), \
|
||||
M_IF_METHOD_ALL(PARSE_STR, __VA_ARGS__)(PARSE_STR(M_C(name, _parse_str)),), \
|
||||
M_IF_METHOD_ALL(IN_STR, __VA_ARGS__)(IN_STR(M_C(name, _in_str)),), \
|
||||
M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_C(name, _out_str)),), \
|
||||
M_IF_METHOD_ALL(IN_STR, __VA_ARGS__)(IN_STR(M_C(name, _in_str)),), \
|
||||
M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_C(name, _out_str)),), \
|
||||
M_IF_METHOD_ALL(IN_SERIAL, __VA_ARGS__)(IN_SERIAL(M_C(name, _in_serial)),), \
|
||||
M_IF_METHOD_ALL(OUT_SERIAL, __VA_ARGS__)(OUT_SERIAL(M_C(name, _out_serial)),), \
|
||||
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_C(name, _init_move)),), \
|
||||
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
|
||||
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \
|
||||
M_IF_METHOD_ALL(CLEAN, __VA_ARGS__)(CLEAN(M_C(name, _clean)),), \
|
||||
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \
|
||||
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \
|
||||
M_IF_METHOD_ALL(CLEAN, __VA_ARGS__)(CLEAN(M_C(name, _clean)),), \
|
||||
M_IF_METHOD(NEW, M_RET_ARG1(__VA_ARGS__,))(NEW(M_DELAY2(M_GET_NEW) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
M_IF_METHOD(REALLOC, M_RET_ARG1(__VA_ARGS__,))(REALLOC(M_DELAY2(M_GET_REALLOC) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
M_IF_METHOD(DEL, M_RET_ARG1(__VA_ARGS__,))(DEL(M_DELAY2(M_GET_DEL) M_RET_ARG1(__VA_ARGS__,)),), \
|
||||
|
||||
+468
-468
File diff suppressed because it is too large.
Load diff
+46
-46
@@ -43,8 +43,8 @@
|
||||
/* Include needed system header for detection of how many core on the system */
|
||||
#if defined(_WIN32)
|
||||
# include <windows.h>
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
#elif (defined(__APPLE__) && defined(__MACH__)) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD__) \
|
||||
|| defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
@@ -453,77 +453,77 @@ worker_count(worker_t g)
|
||||
TODO: Support oplist for input & outputs parameters
|
||||
*/
|
||||
#if M_USE_WORKER_CLANG_BLOCK
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
worker_spawn_block ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
#elif M_USE_WORKER_CPP_FUNCTION
|
||||
// TODO: Explicit pass all arguments by reference.
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
worker_spawn_function ((_block), [&](void *param) {(void)param ; _core } , NULL)
|
||||
#else
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
#define WORKER_SPAWN(_block, _input, _core, _output) \
|
||||
WORKER_DEF_DATA(_input, _output) \
|
||||
WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
worker_spawn ((_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
|
||||
#endif
|
||||
|
||||
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
|
||||
#define WORKER_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
|
||||
#define WORKER_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
|
||||
#define WORKER_DEF_DATA(_input, _output) \
|
||||
struct WORKER_SPAWN_STRUCT_NAME { \
|
||||
WORKER_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
|
||||
} WORKER_SPAWN_DATA_NAME = { \
|
||||
WORKER_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
|
||||
#define WORKER_DEF_DATA(_input, _output) \
|
||||
struct WORKER_SPAWN_STRUCT_NAME { \
|
||||
WORKER_DEF_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_DEF_DATA_OUTPUT _output) \
|
||||
} WORKER_SPAWN_DATA_NAME = { \
|
||||
WORKER_INIT_DATA_INPUT _input \
|
||||
M_IF_EMPTY _output (, WORKER_INIT_DATA_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SINGLE_INPUT(var) __typeof__(var) var;
|
||||
#define WORKER_DEF_DATA_INPUT(...) \
|
||||
#define WORKER_DEF_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SINGLE_OUTPUT(var) \
|
||||
#define WORKER_DEF_SINGLE_OUTPUT(var) \
|
||||
__typeof__(var) *M_C(var, _ptr);
|
||||
#define WORKER_DEF_DATA_OUTPUT(...) \
|
||||
#define WORKER_DEF_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_DEF_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_INPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_INPUT(var) \
|
||||
.var = var,
|
||||
#define WORKER_INIT_DATA_INPUT(...) \
|
||||
#define WORKER_INIT_DATA_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_OUTPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_OUTPUT(var) \
|
||||
.M_C(var, _ptr) = &var,
|
||||
#define WORKER_INIT_DATA_OUTPUT(...) \
|
||||
#define WORKER_INIT_DATA_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
#define WORKER_DEF_SUBFUNC(_input, _output, _core) \
|
||||
__extension__ auto void WORKER_SPAWN_SUBFUNC_NAME(void *) ; \
|
||||
__extension__ void WORKER_SPAWN_SUBFUNC_NAME(void *_data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
#define WORKER_DEF_SUBBLOCK(_input, _output, _core) \
|
||||
void (^WORKER_SPAWN_SUBFUNC_NAME) (void *) = ^ void (void * _data) \
|
||||
{ \
|
||||
struct WORKER_SPAWN_STRUCT_NAME *_s_data = _data ; \
|
||||
WORKER_INIT_LOCAL_INPUT _input \
|
||||
M_IF_EMPTY _output ( , WORKER_INIT_LOCAL_OUTPUT _output) \
|
||||
do { _core } while (0); \
|
||||
M_IF_EMPTY _output ( , WORKER_PROPAGATE_LOCAL_OUTPUT _output) \
|
||||
};
|
||||
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_LOCAL_INPUT(var) \
|
||||
__typeof__(var) var = _s_data->var;
|
||||
#define WORKER_INIT_LOCAL_INPUT(...) \
|
||||
#define WORKER_INIT_LOCAL_INPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_INPUT, __VA_ARGS__)
|
||||
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
#define WORKER_INIT_SINGLE_LOCAL_OUTPUT(var) \
|
||||
__typeof__(var) var;
|
||||
#define WORKER_INIT_LOCAL_OUTPUT(...) \
|
||||
#define WORKER_INIT_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_INIT_SINGLE_LOCAL_OUTPUT, __VA_ARGS__)
|
||||
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
#define WORKER_PROPAGATE_SINGLE_OUTPUT(var) \
|
||||
*(_s_data->M_C(var, _ptr)) = var;
|
||||
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
#define WORKER_PROPAGATE_LOCAL_OUTPUT(...) \
|
||||
M_MAP(WORKER_PROPAGATE_SINGLE_OUTPUT, __VA_ARGS__)
|
||||
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
Reference in new issue
Block a user