diff --git a/m-algo.h b/m-algo.h index 451ba11f..11c7939d 100644 --- a/m-algo.h +++ b/m-algo.h @@ -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 diff --git a/m-array.h b/m-array.h index dd83b647..013af12b 100644 --- a/m-array.h +++ b/m-array.h @@ -29,9 +29,9 @@ /* Define a dynamic array of the given type and its associated functions. USAGE: ARRAY_DEF(name, type [, oplist_of_the_type]) */ -#define ARRAY_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - ARRAYI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define ARRAY_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + ARRAYI_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 @@ -40,9 +40,9 @@ /* Define a dynamic array of the given type and its associated functions as the provided type name_t with the iterator named it_t USAGE: ARRAY_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */ -#define ARRAY_DEF_AS(name, name_t, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - ARRAYI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define ARRAY_DEF_AS(name, name_t, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + ARRAYI_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 @@ -51,9 +51,9 @@ /* Define the oplist of a dynamic array given its name and its oplist. If no oplist is given it is assumed to be M_DEFAULT_OPLIST USAGE: ARRAY_OPLIST(name[, oplist of the type]) */ -#define ARRAY_OPLIST(...) \ - ARRAYI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST), \ +#define ARRAY_OPLIST(...) \ + ARRAYI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST), \ (__VA_ARGS__ ))) @@ -133,10 +133,10 @@ ) /* Define the internal contract of an array */ -#define ARRAYI_CONTRACT(a) do { \ - assert (a != NULL); \ - assert (a->size <= a->alloc); \ - assert (a->size == 0 || a->ptr != NULL); \ +#define ARRAYI_CONTRACT(a) do { \ + assert (a != NULL); \ + assert (a->size <= a->alloc); \ + assert (a->size == 0 || a->ptr != NULL); \ } while (0) /* Deferred evaluation for the array definition, @@ -144,11 +144,11 @@ #define ARRAYI_DEF_P1(arg) ARRAYI_DEF_P2 arg /* Validate the oplist before going further */ -#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \ +#define ARRAYI_DEF_P2(name, type, oplist, array_t, it_t) \ M_IF_OPLIST(oplist)(ARRAYI_DEF_P3, ARRAYI_DEF_FAILURE)(name, type, oplist, array_t, it_t) /* Stop processing with a compilation failure */ -#define ARRAYI_DEF_FAILURE(name, type, oplist, array_t, it_t) \ +#define ARRAYI_DEF_FAILURE(name, type, oplist, array_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ARRAY_DEF): the given argument is not a valid oplist: " #oplist) /* Internal definition: @@ -158,942 +158,942 @@ - array_t: alias for the type of the array - it_t: alias for the iterator of the array */ -#define ARRAYI_DEF_P3(name, type, oplist, array_t, it_t) \ - \ - /* Define a dynamic array */ \ - typedef struct M_C(name, _s) { \ - size_t size; /* Number of elements in the array */ \ - size_t alloc; /* Allocated size for the array base */ \ - type *ptr; /* Pointer to the array base */ \ - } array_t[1]; \ - \ - /* Define an iterator over an array */ \ - typedef struct M_C(name, _it_s) { \ - size_t index; /* Index of the element */ \ - const struct M_C(name, _s) *array; /* Reference of the array */ \ - } it_t[1]; \ - \ - /* Definition of the synonyms of the type */ \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - typedef array_t M_C(name, _ct); \ - typedef it_t M_C(name, _it_ct); \ - typedef type M_C(name, _subtype_ct); \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ - static inline void \ - M_C(name, _init)(array_t v) \ - { \ - assert (v != NULL); \ - /* Initially, the array is empty with nothing allocated */ \ - v->size = 0; \ - v->alloc = 0; \ - v->ptr = NULL; \ - ARRAYI_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _clean)(array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - for(size_t i = 0; i < v->size; i++) \ - M_CALL_CLEAR(oplist, v->ptr[i]); \ - v->size = 0; \ - ARRAYI_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _clear)(array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - M_C(name, _clean)(v); \ - M_CALL_FREE(oplist, v->ptr); \ - v->alloc = 0; \ - v->ptr = NULL; \ - } \ - \ - M_IF_METHOD2(INIT_SET, SET, oplist)( \ - static inline void \ - M_C(name, _set)(array_t d, const array_t s) \ - { \ - ARRAYI_CONTRACT(d); \ - ARRAYI_CONTRACT(s); \ - if (M_UNLIKELY (d == s)) return; \ - if (s->size > d->alloc) { \ - const size_t alloc = s->size; \ - type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return ; \ - } \ - d->ptr = ptr; \ - d->alloc = alloc; \ - } \ - size_t i; \ - size_t step1 = M_MIN(s->size, d->size); \ - for(i = 0; i < step1; i++) \ - M_CALL_SET(oplist, d->ptr[i], s->ptr[i]); \ - for( ; i < s->size; i++) \ - M_CALL_INIT_SET(oplist, d->ptr[i], s->ptr[i]); \ - for( ; i < d->size; i++) \ - M_CALL_CLEAR(oplist, d->ptr[i]); \ - d->size = s->size; \ - ARRAYI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _init_set)(array_t d, const array_t s) \ - { \ - assert (d != s); \ - M_C(name, _init)(d); \ - M_C(name, _set)(d, s); \ - } \ - , /* No SET & INIT_SET */) \ - \ - static inline void \ - M_C(name, _init_move)(array_t d, array_t s) \ - { \ - assert (d != s); \ - ARRAYI_CONTRACT(s); \ - d->size = s->size; \ - d->alloc = s->alloc; \ - d->ptr = s->ptr; \ - s->alloc = 0; \ - s->ptr = NULL; \ - ARRAYI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _move)(array_t d, array_t s) \ - { \ - assert (d != s); \ - M_C(name, _clear)(d); \ - M_C(name, _init_move)(d, s); \ - } \ - \ - M_IF_METHOD(SET, oplist)( \ - static inline void \ - M_C(name, _set_at)(array_t v, size_t i, type const x) \ - { \ - ARRAYI_CONTRACT(v); \ - assert(v->size > 0 && v->ptr != NULL); \ - M_ASSERT_INDEX(i, v->size); \ - M_CALL_SET(oplist, v->ptr[i], x); \ - } \ - , /* No SET */) \ - \ - static inline type const * \ - M_C(name, _back)(array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - assert(v->ptr != NULL); \ - M_ASSERT_INDEX(0, v->size); \ - return M_CONST_CAST(type, &v->ptr[v->size-1]); \ - } \ - \ - static inline type * \ - M_C(name, _push_raw)(array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - if (M_UNLIKELY (v->size >= v->alloc)) { \ - assert(v->size == v->alloc); \ - size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ - if (M_UNLIKELY (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return NULL; \ - } \ - assert (alloc > v->size); \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return NULL; \ - } \ - v->ptr = ptr; \ - v->alloc = alloc; \ - } \ - assert(v->ptr != NULL); \ - type *ret = &v->ptr[v->size]; \ - v->size++; \ - ARRAYI_CONTRACT(v); \ - M_ASSUME(ret != NULL); \ - return ret; \ - } \ - \ - M_IF_METHOD(INIT_SET, oplist)( \ - static inline void \ - M_C(name, _push_back)(array_t v, type const x) \ - { \ - type *data = M_C(name, _push_raw)(v); \ - if (M_UNLIKELY (data == NULL) ) \ - return; \ - M_CALL_INIT_SET(oplist, *data, x); \ - } \ - , /* No INIT_SET */ ) \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _push_new)(array_t v) \ - { \ - type *data = M_C(name, _push_raw)(v); \ - if (M_UNLIKELY (data == NULL) ) \ - return NULL; \ - M_CALL_INIT(oplist, *data); \ - return data; \ - } \ - , /* No INIT */ ) \ - \ - M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ - static inline void \ - M_C(name, _push_move)(array_t v, type *x) \ - { \ - assert (x != NULL); \ - type *data = M_C(name, _push_raw)(v); \ - if (M_UNLIKELY (data == NULL) ) \ - return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ - } \ - , /* INIT_SET | INIT_MOVE */ ) \ - \ - M_IF_METHOD(INIT_SET, oplist)( \ - static inline void \ - M_C(name, _push_at)(array_t v, size_t key, type const x) \ - { \ - ARRAYI_CONTRACT(v); \ - M_ASSERT_INDEX(key, v->size+1); \ - if (M_UNLIKELY (v->size >= v->alloc) ) { \ - assert(v->size == v->alloc); \ - size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ - if (M_UNLIKELY (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return ; \ - } \ - assert (alloc > v->size); \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return; \ - } \ - v->ptr = ptr; \ - v->alloc = alloc; \ - } \ - assert(v->ptr != NULL); \ - memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \ - v->size++; \ - M_CALL_INIT_SET(oplist, v->ptr[key], x); \ - ARRAYI_CONTRACT(v); \ - } \ - , /* No INIT_SET */ ) \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline void \ - M_C(name, _resize)(array_t v, size_t size) \ - { \ - ARRAYI_CONTRACT(v); \ - if (v->size > size) { \ - /* Decrease size of array */ \ - for(size_t i = size ; i < v->size; i++) \ - M_CALL_CLEAR(oplist, v->ptr[i]); \ - v->size = size; \ - } else if (v->size < size) { \ - /* Increase size of array */ \ - if (size > v->alloc) { \ - size_t alloc = size ; \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return; \ - } \ - v->ptr = ptr; \ - v->alloc = alloc; \ - } \ - for(size_t i = v->size ; i < size; i++) \ - M_CALL_INIT(oplist, v->ptr[i]); \ - v->size = size; \ - } \ - ARRAYI_CONTRACT(v); \ - } \ - , /* No INIT */ ) \ - \ - static inline void \ - M_C(name, _reserve)(array_t v, size_t alloc) \ - { \ - ARRAYI_CONTRACT(v); \ - /* NOTE: Reserve below needed size to perform a shrink to fit */ \ - if (v->size > alloc) { \ - alloc = v->size; \ - } \ - if (M_UNLIKELY (alloc == 0)) { \ - M_CALL_FREE(oplist, v->ptr); \ - v->size = v->alloc = 0; \ - v->ptr = NULL; \ - } else { \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return; \ - } \ - v->ptr = ptr; \ - v->alloc = alloc; \ - } \ - ARRAYI_CONTRACT(v); \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _get_at)(array_t v, size_t idx) \ - { \ - ARRAYI_CONTRACT(v); \ - const size_t size = idx + 1; \ - /* resize if needed */ \ - if (v->size <= size) { \ - /* Increase size of array */ \ - if (M_UNLIKELY (size > v->alloc) ) { \ - size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ - /* In case of overflow of size_t */ \ - if (M_UNLIKELY (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return NULL; \ - } \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return NULL; \ - } \ - v->ptr = ptr; \ - v->alloc = alloc; \ - } \ - for(size_t i = v->size ; i < size; i++) \ - M_CALL_INIT(oplist, v->ptr[i]); \ - v->size = size; \ - } \ - assert (idx < v->size); \ - ARRAYI_CONTRACT(v); \ - return &v->ptr[idx]; \ - } \ - , /* No INIT */) \ - \ - M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ - static inline void \ - M_C(name, _pop_back)(type *dest, array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (v->ptr != NULL); \ - M_ASSERT_INDEX(0, v->size); \ - v->size--; \ - if (dest) { \ - M_DO_MOVE (oplist, *dest, v->ptr[v->size]); \ - } else { \ - M_CALL_CLEAR(oplist, v->ptr[v->size]); \ - } \ - ARRAYI_CONTRACT(v); \ - } \ - , /* SET | INIT_MOVE */ ) \ - \ - M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ - static inline void \ - M_C(name, _pop_move)(type *dest, array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (v->ptr != NULL); \ - M_ASSERT_INDEX(0, v->size); \ - assert (dest != NULL); \ - v->size--; \ - M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \ - ARRAYI_CONTRACT(v); \ - } \ - , /* INIT_SET | INIT_MOVE */ ) \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline void \ - M_C(name, _pop_until)(array_t v, it_t pos) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (v == pos->array); \ - M_ASSERT_INDEX(pos->index, v->size+1); \ - M_C(name, _resize)(v, pos->index); \ - } \ - , /* No INIT */ ) \ - \ - static inline bool \ - M_C(name, _empty_p)(const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - return v->size == 0; \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - return v->size; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity)(const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - return v->alloc; \ - } \ - \ - M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ - static inline void \ - M_C(name, _pop_at)(type *dest, array_t v, size_t i) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (v->size > 0 && v->ptr != NULL); \ - M_ASSERT_INDEX(i, v->size); \ - if (dest) \ - M_DO_MOVE (oplist, *dest, v->ptr[i]); \ - else \ - M_CALL_CLEAR(oplist, v->ptr[i]); \ - memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size - i) ); \ - v->size--; \ - ARRAYI_CONTRACT(v); \ - } \ - \ - static inline bool \ - M_C(name, _erase)(array_t a, size_t i) \ - { \ - ARRAYI_CONTRACT(a); \ - if (i >= a->size) return false; \ - M_C(name, _pop_at)(NULL, a, i); \ - return true; \ - } \ - , /* SET | INIT_MOVE */ ) \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline void \ - M_C(name, _insert_v)(array_t v, size_t i, size_t num) \ - { \ - ARRAYI_CONTRACT(v); \ - M_ASSERT_INDEX(i, v->size+1); \ - size_t size = v->size + num; \ - /* Test for overflow of variable size */ \ - if (M_UNLIKELY (size <= v->size)) { \ - /* Unlikely case of nothing to do */ \ - if (num == 0) return; \ - M_MEMORY_FULL(sizeof (type) * v->size); \ - return ; \ - } \ - /* Test if alloc array is sufficient */ \ - if (size > v->alloc) { \ - size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ - if (M_UNLIKELY (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return ; \ - } \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ - return; \ - } \ - v->ptr = ptr; \ - v->alloc = alloc; \ - } \ - memmove(&v->ptr[i+num], &v->ptr[i], sizeof(type)*(v->size - i) ); \ - for(size_t k = i ; k < i+num; k++) \ - M_CALL_INIT(oplist, v->ptr[k]); \ - v->size = size; \ - ARRAYI_CONTRACT(v); \ - } \ - , /* No INIT */) \ - \ - static inline void \ - M_C(name, _remove_v)(array_t v, size_t i, size_t j) \ - { \ - ARRAYI_CONTRACT(v); \ - assert(i < j && v->ptr != NULL); \ - M_ASSERT_INDEX(i, v->size); \ - M_ASSERT_INDEX(j, v->size+1); \ - for(size_t k = i ; k < j; k++) \ - M_CALL_CLEAR(oplist, v->ptr[k]); \ - memmove(&v->ptr[i], &v->ptr[j], sizeof(type)*(v->size - j) ); \ - v->size -= (j-i); \ - ARRAYI_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _swap)(array_t v1, array_t v2) \ - { \ - ARRAYI_CONTRACT(v1); \ - ARRAYI_CONTRACT(v2); \ - size_t tmp = v1->size; \ - v1->size = v2->size; \ - v2->size = tmp; \ - tmp = v1->alloc; \ - v1->alloc = v2->alloc; \ - v2->alloc = tmp; \ - type *p = v1->ptr; \ - v1->ptr = v2->ptr; \ - v2->ptr = p; \ - ARRAYI_CONTRACT(v1); \ - ARRAYI_CONTRACT(v2); \ - } \ - \ - M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist) ( \ - static inline void \ - M_C(name, _swap_at)(array_t v, size_t i, size_t j) \ - { \ - ARRAYI_CONTRACT(v); \ - assert(v->ptr != NULL); \ - M_ASSERT_INDEX(i, v->size); \ - M_ASSERT_INDEX(j, v->size); \ - type tmp; \ - M_DO_INIT_MOVE(oplist, tmp, v->ptr[i]); \ - M_DO_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \ - M_DO_INIT_MOVE(oplist, v->ptr[j], tmp); \ - ARRAYI_CONTRACT(v); \ - } \ - , /* INIT_SET | INIT_MOVE */ ) \ - \ - static inline type * \ - M_C(name, _get)(const array_t v, size_t i) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (v->ptr != NULL); \ - M_ASSERT_INDEX(i, v->size); \ - return &v->ptr[i]; \ - } \ - \ - static inline type const * \ - M_C(name, _cget)(const array_t v, size_t i) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (v->ptr != NULL); \ - M_ASSERT_INDEX(i, v->size); \ - return M_CONST_CAST(type, &v->ptr[i]); \ - } \ - \ - static inline type const * \ - M_C(name, _front)(const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - M_ASSERT_INDEX(0, v->size); \ - return M_C(name, _cget)(v, 0); \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (it != NULL); \ - it->index = 0; \ - it->array = v; \ - } \ - \ - static inline void \ - M_C(name, _it_last)(it_t it, const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (it != NULL); \ - /* If size is 0, index is set -1U, so it is greater than end */ \ - it->index = v->size - 1; \ - it->array = v; \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it, const array_t v) \ - { \ - ARRAYI_CONTRACT(v); \ - assert (it != NULL); \ - it->index = v->size; \ - it->array = v; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t it, const it_t org) \ - { \ - assert (it != NULL && org != NULL); \ - it->index = org->index; \ - it->array = org->array; \ - ARRAYI_CONTRACT(it->array); \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const it_t it) \ - { \ - assert(it != NULL && it->array != NULL); \ - return it->index >= it->array->size; \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(const it_t it) \ - { \ - assert(it != NULL && it->array != NULL); \ - /* NOTE: Can not compute 'size-1' due to potential overflow \ - if size is 0 */ \ - return it->index + 1 >= it->array->size; \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const it_t it1, \ - const it_t it2) \ - { \ - assert(it1 != NULL && it2 != NULL); \ - return it1->array == it2->array && it1->index == it2->index; \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - assert(it != NULL && it->array != NULL); \ - it->index ++; \ - } \ - \ - static inline void \ - M_C(name, _previous)(it_t it) \ - { \ - assert(it != NULL && it->array != NULL); \ - /* NOTE: In the case index=0, it will be set to (unsigned) -1 \ - ==> it will be greater than size ==> end_p will return true */ \ - it->index --; \ - } \ - \ - static inline type * \ - M_C(name, _ref)(const it_t it) \ - { \ - assert(it != NULL); \ - return M_C(name, _get)(it->array, it->index); \ - } \ - \ - static inline type const * \ - M_C(name, _cref)(const it_t it) \ - { \ - assert(it != NULL); \ - return M_C(name, _cget)(it->array, it->index); \ - } \ - \ - M_IF_METHOD(INIT_SET, oplist)( \ - static inline void \ - M_C(name, _insert)(array_t a, it_t it, type const x) \ - { \ - assert (it != NULL && a == it->array); \ - M_C(name, _push_at)(a, it->index + 1, x); \ - it->index ++; \ - } \ - , /* End of INIT_SET */ ) \ - \ - M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ - static inline void \ - M_C(name, _remove)(array_t a, it_t it) \ - { \ - assert (it != NULL && a == it->array); \ - M_C(name, _pop_at)(NULL, a, it->index); \ - /* NOTE: it->index will naturaly point to the next element */ \ - } \ - , /* End of SET | INIT_SET */ ) \ - \ - M_IF_METHOD(CMP, oplist) \ - ( \ - static inline void M_C(name, _special_sort)(array_t l, \ - int (*func_type) (type const *a, type const *b)) \ - { \ - /* Using qsort is more compact but slower than a full templated \ - version which can be twice faster */ \ - int (*func_void)(const void*, const void*); \ - /* There is no way (?) to avoid the cast */ \ - func_void = (int (*)(const void*, const void*))func_type; \ - qsort (l->ptr, l->size, sizeof(type), func_void); \ - } \ - \ - M_IF_METHOD2(SWAP, SET, oplist)( \ - static inline void \ +#define ARRAYI_DEF_P3(name, type, oplist, array_t, it_t) \ + \ + /* Define a dynamic array */ \ + typedef struct M_C(name, _s) { \ + size_t size; /* Number of elements in the array */ \ + size_t alloc; /* Allocated size for the array base */ \ + type *ptr; /* Pointer to the array base */ \ + } array_t[1]; \ + \ + /* Define an iterator over an array */ \ + typedef struct M_C(name, _it_s) { \ + size_t index; /* Index of the element */ \ + const struct M_C(name, _s) *array; /* Reference of the array */ \ + } it_t[1]; \ + \ + /* Definition of the synonyms of the type */ \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + typedef array_t M_C(name, _ct); \ + typedef it_t M_C(name, _it_ct); \ + typedef type M_C(name, _subtype_ct); \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ + static inline void \ + M_C(name, _init)(array_t v) \ + { \ + assert (v != NULL); \ + /* Initially, the array is empty with nothing allocated */ \ + v->size = 0; \ + v->alloc = 0; \ + v->ptr = NULL; \ + ARRAYI_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _clean)(array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + for(size_t i = 0; i < v->size; i++) \ + M_CALL_CLEAR(oplist, v->ptr[i]); \ + v->size = 0; \ + ARRAYI_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _clear)(array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + M_C(name, _clean)(v); \ + M_CALL_FREE(oplist, v->ptr); \ + v->alloc = 0; \ + v->ptr = NULL; \ + } \ + \ + M_IF_METHOD2(INIT_SET, SET, oplist)( \ + static inline void \ + M_C(name, _set)(array_t d, const array_t s) \ + { \ + ARRAYI_CONTRACT(d); \ + ARRAYI_CONTRACT(s); \ + if (M_UNLIKELY (d == s)) return; \ + if (s->size > d->alloc) { \ + const size_t alloc = s->size; \ + type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL)) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return ; \ + } \ + d->ptr = ptr; \ + d->alloc = alloc; \ + } \ + size_t i; \ + size_t step1 = M_MIN(s->size, d->size); \ + for(i = 0; i < step1; i++) \ + M_CALL_SET(oplist, d->ptr[i], s->ptr[i]); \ + for( ; i < s->size; i++) \ + M_CALL_INIT_SET(oplist, d->ptr[i], s->ptr[i]); \ + for( ; i < d->size; i++) \ + M_CALL_CLEAR(oplist, d->ptr[i]); \ + d->size = s->size; \ + ARRAYI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(array_t d, const array_t s) \ + { \ + assert (d != s); \ + M_C(name, _init)(d); \ + M_C(name, _set)(d, s); \ + } \ + , /* No SET & INIT_SET */) \ + \ + static inline void \ + M_C(name, _init_move)(array_t d, array_t s) \ + { \ + assert (d != s); \ + ARRAYI_CONTRACT(s); \ + d->size = s->size; \ + d->alloc = s->alloc; \ + d->ptr = s->ptr; \ + s->alloc = 0; \ + s->ptr = NULL; \ + ARRAYI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _move)(array_t d, array_t s) \ + { \ + assert (d != s); \ + M_C(name, _clear)(d); \ + M_C(name, _init_move)(d, s); \ + } \ + \ + M_IF_METHOD(SET, oplist)( \ + static inline void \ + M_C(name, _set_at)(array_t v, size_t i, type const x) \ + { \ + ARRAYI_CONTRACT(v); \ + assert(v->size > 0 && v->ptr != NULL); \ + M_ASSERT_INDEX(i, v->size); \ + M_CALL_SET(oplist, v->ptr[i], x); \ + } \ + , /* No SET */) \ + \ + static inline type const * \ + M_C(name, _back)(array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + assert(v->ptr != NULL); \ + M_ASSERT_INDEX(0, v->size); \ + return M_CONST_CAST(type, &v->ptr[v->size-1]); \ + } \ + \ + static inline type * \ + M_C(name, _push_raw)(array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + if (M_UNLIKELY (v->size >= v->alloc)) { \ + assert(v->size == v->alloc); \ + size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ + if (M_UNLIKELY (alloc <= v->alloc)) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return NULL; \ + } \ + assert (alloc > v->size); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return NULL; \ + } \ + v->ptr = ptr; \ + v->alloc = alloc; \ + } \ + assert(v->ptr != NULL); \ + type *ret = &v->ptr[v->size]; \ + v->size++; \ + ARRAYI_CONTRACT(v); \ + M_ASSUME(ret != NULL); \ + return ret; \ + } \ + \ + M_IF_METHOD(INIT_SET, oplist)( \ + static inline void \ + M_C(name, _push_back)(array_t v, type const x) \ + { \ + type *data = M_C(name, _push_raw)(v); \ + if (M_UNLIKELY (data == NULL) ) \ + return; \ + M_CALL_INIT_SET(oplist, *data, x); \ + } \ + , /* No INIT_SET */ ) \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _push_new)(array_t v) \ + { \ + type *data = M_C(name, _push_raw)(v); \ + if (M_UNLIKELY (data == NULL) ) \ + return NULL; \ + M_CALL_INIT(oplist, *data); \ + return data; \ + } \ + , /* No INIT */ ) \ + \ + M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ + static inline void \ + M_C(name, _push_move)(array_t v, type *x) \ + { \ + assert (x != NULL); \ + type *data = M_C(name, _push_raw)(v); \ + if (M_UNLIKELY (data == NULL) ) \ + return; \ + M_DO_INIT_MOVE (oplist, *data, *x); \ + } \ + , /* INIT_SET | INIT_MOVE */ ) \ + \ + M_IF_METHOD(INIT_SET, oplist)( \ + static inline void \ + M_C(name, _push_at)(array_t v, size_t key, type const x) \ + { \ + ARRAYI_CONTRACT(v); \ + M_ASSERT_INDEX(key, v->size+1); \ + if (M_UNLIKELY (v->size >= v->alloc) ) { \ + assert(v->size == v->alloc); \ + size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ + if (M_UNLIKELY (alloc <= v->alloc)) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return ; \ + } \ + assert (alloc > v->size); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return; \ + } \ + v->ptr = ptr; \ + v->alloc = alloc; \ + } \ + assert(v->ptr != NULL); \ + memmove(&v->ptr[key+1], &v->ptr[key], (v->size-key)*sizeof(type)); \ + v->size++; \ + M_CALL_INIT_SET(oplist, v->ptr[key], x); \ + ARRAYI_CONTRACT(v); \ + } \ + , /* No INIT_SET */ ) \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline void \ + M_C(name, _resize)(array_t v, size_t size) \ + { \ + ARRAYI_CONTRACT(v); \ + if (v->size > size) { \ + /* Decrease size of array */ \ + for(size_t i = size ; i < v->size; i++) \ + M_CALL_CLEAR(oplist, v->ptr[i]); \ + v->size = size; \ + } else if (v->size < size) { \ + /* Increase size of array */ \ + if (size > v->alloc) { \ + size_t alloc = size ; \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return; \ + } \ + v->ptr = ptr; \ + v->alloc = alloc; \ + } \ + for(size_t i = v->size ; i < size; i++) \ + M_CALL_INIT(oplist, v->ptr[i]); \ + v->size = size; \ + } \ + ARRAYI_CONTRACT(v); \ + } \ + , /* No INIT */ ) \ + \ + static inline void \ + M_C(name, _reserve)(array_t v, size_t alloc) \ + { \ + ARRAYI_CONTRACT(v); \ + /* NOTE: Reserve below needed size to perform a shrink to fit */ \ + if (v->size > alloc) { \ + alloc = v->size; \ + } \ + if (M_UNLIKELY (alloc == 0)) { \ + M_CALL_FREE(oplist, v->ptr); \ + v->size = v->alloc = 0; \ + v->ptr = NULL; \ + } else { \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return; \ + } \ + v->ptr = ptr; \ + v->alloc = alloc; \ + } \ + ARRAYI_CONTRACT(v); \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _get_at)(array_t v, size_t idx) \ + { \ + ARRAYI_CONTRACT(v); \ + const size_t size = idx + 1; \ + /* resize if needed */ \ + if (v->size <= size) { \ + /* Increase size of array */ \ + if (M_UNLIKELY (size > v->alloc) ) { \ + size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ + /* In case of overflow of size_t */ \ + if (M_UNLIKELY (alloc <= v->alloc)) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return NULL; \ + } \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return NULL; \ + } \ + v->ptr = ptr; \ + v->alloc = alloc; \ + } \ + for(size_t i = v->size ; i < size; i++) \ + M_CALL_INIT(oplist, v->ptr[i]); \ + v->size = size; \ + } \ + assert (idx < v->size); \ + ARRAYI_CONTRACT(v); \ + return &v->ptr[idx]; \ + } \ + , /* No INIT */) \ + \ + M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ + static inline void \ + M_C(name, _pop_back)(type *dest, array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (v->ptr != NULL); \ + M_ASSERT_INDEX(0, v->size); \ + v->size--; \ + if (dest) { \ + M_DO_MOVE (oplist, *dest, v->ptr[v->size]); \ + } else { \ + M_CALL_CLEAR(oplist, v->ptr[v->size]); \ + } \ + ARRAYI_CONTRACT(v); \ + } \ + , /* SET | INIT_MOVE */ ) \ + \ + M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ + static inline void \ + M_C(name, _pop_move)(type *dest, array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (v->ptr != NULL); \ + M_ASSERT_INDEX(0, v->size); \ + assert (dest != NULL); \ + v->size--; \ + M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \ + ARRAYI_CONTRACT(v); \ + } \ + , /* INIT_SET | INIT_MOVE */ ) \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline void \ + M_C(name, _pop_until)(array_t v, it_t pos) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (v == pos->array); \ + M_ASSERT_INDEX(pos->index, v->size+1); \ + M_C(name, _resize)(v, pos->index); \ + } \ + , /* No INIT */ ) \ + \ + static inline bool \ + M_C(name, _empty_p)(const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + return v->size == 0; \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + return v->size; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + return v->alloc; \ + } \ + \ + M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ + static inline void \ + M_C(name, _pop_at)(type *dest, array_t v, size_t i) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (v->size > 0 && v->ptr != NULL); \ + M_ASSERT_INDEX(i, v->size); \ + if (dest) \ + M_DO_MOVE (oplist, *dest, v->ptr[i]); \ + else \ + M_CALL_CLEAR(oplist, v->ptr[i]); \ + memmove(&v->ptr[i], &v->ptr[i+1], sizeof(type)*(v->size - i) ); \ + v->size--; \ + ARRAYI_CONTRACT(v); \ + } \ + \ + static inline bool \ + M_C(name, _erase)(array_t a, size_t i) \ + { \ + ARRAYI_CONTRACT(a); \ + if (i >= a->size) return false; \ + M_C(name, _pop_at)(NULL, a, i); \ + return true; \ + } \ + , /* SET | INIT_MOVE */ ) \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline void \ + M_C(name, _insert_v)(array_t v, size_t i, size_t num) \ + { \ + ARRAYI_CONTRACT(v); \ + M_ASSERT_INDEX(i, v->size+1); \ + size_t size = v->size + num; \ + /* Test for overflow of variable size */ \ + if (M_UNLIKELY (size <= v->size)) { \ + /* Unlikely case of nothing to do */ \ + if (num == 0) return; \ + M_MEMORY_FULL(sizeof (type) * v->size); \ + return ; \ + } \ + /* Test if alloc array is sufficient */ \ + if (size > v->alloc) { \ + size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ + if (M_UNLIKELY (alloc <= v->alloc)) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return ; \ + } \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * alloc); \ + return; \ + } \ + v->ptr = ptr; \ + v->alloc = alloc; \ + } \ + memmove(&v->ptr[i+num], &v->ptr[i], sizeof(type)*(v->size - i) ); \ + for(size_t k = i ; k < i+num; k++) \ + M_CALL_INIT(oplist, v->ptr[k]); \ + v->size = size; \ + ARRAYI_CONTRACT(v); \ + } \ + , /* No INIT */) \ + \ + static inline void \ + M_C(name, _remove_v)(array_t v, size_t i, size_t j) \ + { \ + ARRAYI_CONTRACT(v); \ + assert(i < j && v->ptr != NULL); \ + M_ASSERT_INDEX(i, v->size); \ + M_ASSERT_INDEX(j, v->size+1); \ + for(size_t k = i ; k < j; k++) \ + M_CALL_CLEAR(oplist, v->ptr[k]); \ + memmove(&v->ptr[i], &v->ptr[j], sizeof(type)*(v->size - j) ); \ + v->size -= (j-i); \ + ARRAYI_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _swap)(array_t v1, array_t v2) \ + { \ + ARRAYI_CONTRACT(v1); \ + ARRAYI_CONTRACT(v2); \ + size_t tmp = v1->size; \ + v1->size = v2->size; \ + v2->size = tmp; \ + tmp = v1->alloc; \ + v1->alloc = v2->alloc; \ + v2->alloc = tmp; \ + type *p = v1->ptr; \ + v1->ptr = v2->ptr; \ + v2->ptr = p; \ + ARRAYI_CONTRACT(v1); \ + ARRAYI_CONTRACT(v2); \ + } \ + \ + M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist) ( \ + static inline void \ + M_C(name, _swap_at)(array_t v, size_t i, size_t j) \ + { \ + ARRAYI_CONTRACT(v); \ + assert(v->ptr != NULL); \ + M_ASSERT_INDEX(i, v->size); \ + M_ASSERT_INDEX(j, v->size); \ + type tmp; \ + M_DO_INIT_MOVE(oplist, tmp, v->ptr[i]); \ + M_DO_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \ + M_DO_INIT_MOVE(oplist, v->ptr[j], tmp); \ + ARRAYI_CONTRACT(v); \ + } \ + , /* INIT_SET | INIT_MOVE */ ) \ + \ + static inline type * \ + M_C(name, _get)(const array_t v, size_t i) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (v->ptr != NULL); \ + M_ASSERT_INDEX(i, v->size); \ + return &v->ptr[i]; \ + } \ + \ + static inline type const * \ + M_C(name, _cget)(const array_t v, size_t i) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (v->ptr != NULL); \ + M_ASSERT_INDEX(i, v->size); \ + return M_CONST_CAST(type, &v->ptr[i]); \ + } \ + \ + static inline type const * \ + M_C(name, _front)(const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + M_ASSERT_INDEX(0, v->size); \ + return M_C(name, _cget)(v, 0); \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (it != NULL); \ + it->index = 0; \ + it->array = v; \ + } \ + \ + static inline void \ + M_C(name, _it_last)(it_t it, const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (it != NULL); \ + /* If size is 0, index is set -1U, so it is greater than end */ \ + it->index = v->size - 1; \ + it->array = v; \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it, const array_t v) \ + { \ + ARRAYI_CONTRACT(v); \ + assert (it != NULL); \ + it->index = v->size; \ + it->array = v; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t it, const it_t org) \ + { \ + assert (it != NULL && org != NULL); \ + it->index = org->index; \ + it->array = org->array; \ + ARRAYI_CONTRACT(it->array); \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const it_t it) \ + { \ + assert(it != NULL && it->array != NULL); \ + return it->index >= it->array->size; \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(const it_t it) \ + { \ + assert(it != NULL && it->array != NULL); \ + /* NOTE: Can not compute 'size-1' due to potential overflow \ + if size is 0 */ \ + return it->index + 1 >= it->array->size; \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const it_t it1, \ + const it_t it2) \ + { \ + assert(it1 != NULL && it2 != NULL); \ + return it1->array == it2->array && it1->index == it2->index; \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + assert(it != NULL && it->array != NULL); \ + it->index ++; \ + } \ + \ + static inline void \ + M_C(name, _previous)(it_t it) \ + { \ + assert(it != NULL && it->array != NULL); \ + /* NOTE: In the case index=0, it will be set to (unsigned) -1 \ + ==> it will be greater than size ==> end_p will return true */ \ + it->index --; \ + } \ + \ + static inline type * \ + M_C(name, _ref)(const it_t it) \ + { \ + assert(it != NULL); \ + return M_C(name, _get)(it->array, it->index); \ + } \ + \ + static inline type const * \ + M_C(name, _cref)(const it_t it) \ + { \ + assert(it != NULL); \ + return M_C(name, _cget)(it->array, it->index); \ + } \ + \ + M_IF_METHOD(INIT_SET, oplist)( \ + static inline void \ + M_C(name, _insert)(array_t a, it_t it, type const x) \ + { \ + assert (it != NULL && a == it->array); \ + M_C(name, _push_at)(a, it->index + 1, x); \ + it->index ++; \ + } \ + , /* End of INIT_SET */ ) \ + \ + M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ + static inline void \ + M_C(name, _remove)(array_t a, it_t it) \ + { \ + assert (it != NULL && a == it->array); \ + M_C(name, _pop_at)(NULL, a, it->index); \ + /* NOTE: it->index will naturaly point to the next element */ \ + } \ + , /* End of SET | INIT_SET */ ) \ + \ + M_IF_METHOD(CMP, oplist) \ + ( \ + static inline void M_C(name, _special_sort)(array_t l, \ + int (*func_type) (type const *a, type const *b)) \ + { \ + /* Using qsort is more compact but slower than a full templated \ + version which can be twice faster */ \ + int (*func_void)(const void*, const void*); \ + /* There is no way (?) to avoid the cast */ \ + func_void = (int (*)(const void*, const void*))func_type; \ + qsort (l->ptr, l->size, sizeof(type), func_void); \ + } \ + \ + M_IF_METHOD2(SWAP, SET, oplist)( \ + static inline void \ M_C(name, _special_stable_sort_noalloc) (type tab[], size_t size, type tmp[]) \ - { \ - size_t th = 4; \ - M_IF_DEBUG(type *org_tab = tab;) \ - assert (size > 1); \ - /* Let's select the threshold of the pass 1 to be sure \ - the final result is in tab.*/ \ - if (m_core_clz64(size-1) & 1) \ - th += th; \ - \ - /* Pass 1: insertion sort (stable) */ \ - for(size_t k = 0 ; k < size; ) { \ - size_t max = size - k < 2*th ? size - k : th; \ - M_ASSUME(max >= th); \ - for(size_t i = 1; i < max; i++) { \ - size_t j = i; \ - while (j > 0 && M_CALL_CMP(oplist, tab[k+j-1], tab[k+j]) > 0) { \ - M_CALL_SWAP(oplist, tab[k+j-1], tab[k+j]); \ - j = j - 1; \ - } \ - } \ - k += max; \ - } \ - \ - /* N Pass of merge sort (stable) */ \ - while (th < size) { \ - type *dest = tmp; \ - /* Pass n: Merge */ \ - for(size_t k = 0 ; k < size; ) { \ - type *el1 = &tab[k]; \ - type *el2 = &tab[k+th]; \ - size_t n1 = th; \ - size_t n2 = size-k <= 3*th ? size-k-th : th; \ - assert (size-k > th); \ - assert (0 < n1 && n1 <= size); \ - assert (0 < n2 && n2 <= size); \ - k += n1+n2; \ - for (;;) { \ - if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \ - M_CALL_SET(oplist, *dest, *el1); \ - dest++; \ - el1++; \ - if (-- n1 == 0) { \ - if (n2 > 0) { \ - memcpy (dest, el2, n2 * sizeof (type)); \ - dest += n2; \ - } \ - break; \ - } \ - } else { \ - M_CALL_SET(oplist, *dest, *el2); \ - dest++; \ - el2++; \ - if (-- n2 == 0) { \ - if (n1 > 0) { \ - memcpy (dest, el1, n1 * sizeof (type)); \ - dest += n1; \ - } \ - break; \ - } \ - } \ - } \ - } \ - /* Swap t & tab */ \ - M_SWAP(type *, tab, tmp); \ - /* Increase th for next pass */ \ - th += th; \ - } \ - assert (org_tab == tab); \ - } \ - \ - static inline void \ - M_C(name, _special_stable_sort)(array_t l) \ - { \ - if (M_UNLIKELY (l->size < 2)) \ - return; \ - /* NOTE: if size is <= 4, no need to perform an allocation */ \ - type *temp = M_CALL_REALLOC(oplist, type, NULL, l->size); \ - if (temp == NULL) { \ - M_MEMORY_FULL(sizeof (type) * l->size); \ - return ; \ - } \ - M_C(name, _special_stable_sort_noalloc)(l->ptr, l->size, temp); \ - M_CALL_FREE(oplist, temp); \ - } \ - ,) /* IF SWAP & SET methods */ \ - \ - ,) /* IF CMP oplist */ \ - \ - \ - M_IF_METHOD(GET_STR, oplist)( \ - static inline void \ - M_C(name, _get_str)(string_t str, array_t const array, \ - bool append) \ - { \ - STRINGI_CONTRACT(str); \ - ARRAYI_CONTRACT(array); \ - (append ? string_cat_str : string_set_str) (str, "["); \ - it_t it; \ - for (M_C(name, _it)(it, array) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - type const *item = M_C(name, _cref)(it); \ - M_CALL_GET_STR(oplist, str, *item, true); \ - if (!M_C(name, _last_p)(it)) \ - string_push_back (str, M_GET_SEPARATOR oplist); \ - } \ - string_push_back (str, ']'); \ - STRINGI_CONTRACT(str); \ - } \ - , /* no GET_STR */ ) \ - \ - M_IF_METHOD(OUT_STR, oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *file, const array_t array) \ - { \ - ARRAYI_CONTRACT(array); \ - assert (file != NULL); \ - fputc ('[', file); \ - for (size_t i = 0; i < array->size; i++) { \ - type const *item = M_C(name, _cget)(array, i); \ - M_CALL_OUT_STR(oplist, file, *item); \ - if (i != array->size-1) \ - fputc (M_GET_SEPARATOR oplist, file); \ - } \ - fputc (']', file); \ - } \ - , /* no OUT_STR */ ) \ - \ - M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ - static inline bool \ - M_C(name, _parse_str)(array_t array, const char str[], const char**endp) \ - { \ - ARRAYI_CONTRACT(array); \ - assert (str != NULL); \ - M_C(name,_clean)(array); \ - bool success = false; \ - int c = *str++; \ - if (M_UNLIKELY (c != '[')) goto exit; \ - c = *str++; \ - if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \ - if (M_UNLIKELY (c == 0)) goto exit; \ - str--; \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ - do { c = *str++; } while (isspace(c)); \ - if (b == false || c == 0) { goto exit_clear; } \ - M_C(name, _push_back)(array, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - ARRAYI_CONTRACT(array); \ - success = (c == ']'); \ - exit_clear: \ - M_CALL_CLEAR(oplist, item); \ - exit: \ - if (endp) *endp = str; \ - return success; \ - } \ - , /* no PARSE_STR & INIT */ ) \ - \ - M_IF_METHOD2(IN_STR, INIT, oplist)( \ - static inline bool \ - M_C(name, _in_str)(array_t array, FILE *file) \ - { \ - ARRAYI_CONTRACT(array); \ - assert (file != NULL); \ - M_C(name,_clean)(array); \ - int c = fgetc(file); \ - if (M_UNLIKELY (c != '[')) return false; \ - c = fgetc(file); \ - if (M_UNLIKELY (c == ']')) return true; \ - if (M_UNLIKELY (c == EOF)) return false; \ - ungetc(c, file); \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_IN_STR(oplist, item, file); \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false || c == EOF) { break; } \ - M_C(name, _push_back)(array, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - M_CALL_CLEAR(oplist, item); \ - ARRAYI_CONTRACT(array); \ - return c == ']'; \ - } \ - , /* no IN_STR & INIT */ ) \ - \ - M_IF_METHOD(OUT_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, const array_t array) \ - { \ - ARRAYI_CONTRACT(array); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_return_code_t ret; \ - m_serial_local_t local; \ - ret = f->m_interface->write_array_start(local, f, array->size); \ - for (size_t i = 0; i < array->size; i++) { \ - type const *item = M_C(name, _cget)(array, i); \ - if (i != 0) { \ - ret |= f->m_interface->write_array_next(local, f); \ - } \ - ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ - } \ - ret |= f->m_interface->write_array_end(local, f); \ - return ret & M_SERIAL_FAIL; \ - } \ - , /* no OUT_SERIAL */ ) \ - \ - M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(array_t array, m_serial_read_t f) \ - { \ - ARRAYI_CONTRACT(array); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_return_code_t ret; \ - m_serial_local_t local; \ - size_t estimated_size = 0; \ - M_C(name,_clean)(array); \ - ret = f->m_interface->read_array_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { \ - return ret; \ - } \ - if (estimated_size != 0) { \ - /* The format has given an estimation of the array size */ \ - M_C(name, _reserve)(array, estimated_size); \ - } \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - ret = M_CALL_IN_SERIAL(oplist, item, f); \ - if (ret != M_SERIAL_OK_DONE) { break; } \ - M_C(name, _push_back)(array, item); \ - ret = f->m_interface->read_array_next(local, f); \ - } while (ret == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(oplist, item); \ - ARRAYI_CONTRACT(array); \ - return ret; \ - } \ - , /* no IN_SERIAL & INIT */ ) \ - \ - M_IF_METHOD(EQUAL, oplist)( \ - static inline bool \ - M_C(name, _equal_p)(const array_t array1, \ - const array_t array2) \ - { \ - ARRAYI_CONTRACT(array1); \ - ARRAYI_CONTRACT(array2); \ - if (array1->size != array2->size) return false; \ - size_t i; \ - for(i = 0; i < array1->size; i++) { \ - type const *item1 = M_C(name, _cget)(array1, i); \ - type const *item2 = M_C(name, _cget)(array2, i); \ - bool b = M_CALL_EQUAL(oplist, *item1, *item2); \ - if (!b) return false; \ - } \ - return i == array1->size; \ - } \ - , /* no EQUAL */ ) \ - \ - M_IF_METHOD(HASH, oplist)( \ - static inline size_t \ - M_C(name, _hash)(const array_t array) \ - { \ - ARRAYI_CONTRACT(array); \ - M_HASH_DECL(hash); \ - for(size_t i = 0 ; i < array->size; i++) { \ - size_t hi = M_CALL_HASH(oplist, array->ptr[i]); \ - M_HASH_UP(hash, hi); \ - } \ - return M_HASH_FINAL (hash); \ - } \ - , /* no HASH */ ) \ - \ - static inline void \ - M_C(name, _splice)(array_t a1, array_t a2) \ - { \ - ARRAYI_CONTRACT(a1); \ - ARRAYI_CONTRACT(a2); \ - if (M_LIKELY (a2->size > 0)) { \ - size_t newSize = a1->size + a2->size; \ - if (newSize > a1->alloc) { \ - type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \ - if (M_UNLIKELY (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * newSize); \ - } \ - a1->ptr = ptr; \ - a1->alloc = newSize; \ - } \ - memcpy(&a1->ptr[a1->size], &a2->ptr[0], a2->size * sizeof (type)); \ - /* a2 is now empty */ \ - a2->size = 0; \ - /* a1 has been expanded with the items of a2 */ \ - a1->size = newSize; \ - } \ - } \ + { \ + size_t th = 4; \ + M_IF_DEBUG(type *org_tab = tab;) \ + assert (size > 1); \ + /* Let's select the threshold of the pass 1 to be sure \ + the final result is in tab.*/ \ + if (m_core_clz64(size-1) & 1) \ + th += th; \ + \ + /* Pass 1: insertion sort (stable) */ \ + for(size_t k = 0 ; k < size; ) { \ + size_t max = size - k < 2*th ? size - k : th; \ + M_ASSUME(max >= th); \ + for(size_t i = 1; i < max; i++) { \ + size_t j = i; \ + while (j > 0 && M_CALL_CMP(oplist, tab[k+j-1], tab[k+j]) > 0) { \ + M_CALL_SWAP(oplist, tab[k+j-1], tab[k+j]); \ + j = j - 1; \ + } \ + } \ + k += max; \ + } \ + \ + /* N Pass of merge sort (stable) */ \ + while (th < size) { \ + type *dest = tmp; \ + /* Pass n: Merge */ \ + for(size_t k = 0 ; k < size; ) { \ + type *el1 = &tab[k]; \ + type *el2 = &tab[k+th]; \ + size_t n1 = th; \ + size_t n2 = size-k <= 3*th ? size-k-th : th; \ + assert (size-k > th); \ + assert (0 < n1 && n1 <= size); \ + assert (0 < n2 && n2 <= size); \ + k += n1+n2; \ + for (;;) { \ + if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \ + M_CALL_SET(oplist, *dest, *el1); \ + dest++; \ + el1++; \ + if (-- n1 == 0) { \ + if (n2 > 0) { \ + memcpy (dest, el2, n2 * sizeof (type)); \ + dest += n2; \ + } \ + break; \ + } \ + } else { \ + M_CALL_SET(oplist, *dest, *el2); \ + dest++; \ + el2++; \ + if (-- n2 == 0) { \ + if (n1 > 0) { \ + memcpy (dest, el1, n1 * sizeof (type)); \ + dest += n1; \ + } \ + break; \ + } \ + } \ + } \ + } \ + /* Swap t & tab */ \ + M_SWAP(type *, tab, tmp); \ + /* Increase th for next pass */ \ + th += th; \ + } \ + assert (org_tab == tab); \ + } \ + \ + static inline void \ + M_C(name, _special_stable_sort)(array_t l) \ + { \ + if (M_UNLIKELY (l->size < 2)) \ + return; \ + /* NOTE: if size is <= 4, no need to perform an allocation */ \ + type *temp = M_CALL_REALLOC(oplist, type, NULL, l->size); \ + if (temp == NULL) { \ + M_MEMORY_FULL(sizeof (type) * l->size); \ + return ; \ + } \ + M_C(name, _special_stable_sort_noalloc)(l->ptr, l->size, temp); \ + M_CALL_FREE(oplist, temp); \ + } \ + ,) /* IF SWAP & SET methods */ \ + \ + ,) /* IF CMP oplist */ \ + \ + \ + M_IF_METHOD(GET_STR, oplist)( \ + static inline void \ + M_C(name, _get_str)(string_t str, array_t const array, \ + bool append) \ + { \ + STRINGI_CONTRACT(str); \ + ARRAYI_CONTRACT(array); \ + (append ? string_cat_str : string_set_str) (str, "["); \ + it_t it; \ + for (M_C(name, _it)(it, array) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + type const *item = M_C(name, _cref)(it); \ + M_CALL_GET_STR(oplist, str, *item, true); \ + if (!M_C(name, _last_p)(it)) \ + string_push_back (str, M_GET_SEPARATOR oplist); \ + } \ + string_push_back (str, ']'); \ + STRINGI_CONTRACT(str); \ + } \ + , /* no GET_STR */ ) \ + \ + M_IF_METHOD(OUT_STR, oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *file, const array_t array) \ + { \ + ARRAYI_CONTRACT(array); \ + assert (file != NULL); \ + fputc ('[', file); \ + for (size_t i = 0; i < array->size; i++) { \ + type const *item = M_C(name, _cget)(array, i); \ + M_CALL_OUT_STR(oplist, file, *item); \ + if (i != array->size-1) \ + fputc (M_GET_SEPARATOR oplist, file); \ + } \ + fputc (']', file); \ + } \ + , /* no OUT_STR */ ) \ + \ + M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ + static inline bool \ + M_C(name, _parse_str)(array_t array, const char str[], const char**endp) \ + { \ + ARRAYI_CONTRACT(array); \ + assert (str != NULL); \ + M_C(name,_clean)(array); \ + bool success = false; \ + int c = *str++; \ + if (M_UNLIKELY (c != '[')) goto exit; \ + c = *str++; \ + if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \ + if (M_UNLIKELY (c == 0)) goto exit; \ + str--; \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ + do { c = *str++; } while (isspace(c)); \ + if (b == false || c == 0) { goto exit_clear; } \ + M_C(name, _push_back)(array, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + ARRAYI_CONTRACT(array); \ + success = (c == ']'); \ + exit_clear: \ + M_CALL_CLEAR(oplist, item); \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } \ + , /* no PARSE_STR & INIT */ ) \ + \ + M_IF_METHOD2(IN_STR, INIT, oplist)( \ + static inline bool \ + M_C(name, _in_str)(array_t array, FILE *file) \ + { \ + ARRAYI_CONTRACT(array); \ + assert (file != NULL); \ + M_C(name,_clean)(array); \ + int c = fgetc(file); \ + if (M_UNLIKELY (c != '[')) return false; \ + c = fgetc(file); \ + if (M_UNLIKELY (c == ']')) return true; \ + if (M_UNLIKELY (c == EOF)) return false; \ + ungetc(c, file); \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_IN_STR(oplist, item, file); \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false || c == EOF) { break; } \ + M_C(name, _push_back)(array, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + M_CALL_CLEAR(oplist, item); \ + ARRAYI_CONTRACT(array); \ + return c == ']'; \ + } \ + , /* no IN_STR & INIT */ ) \ + \ + M_IF_METHOD(OUT_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, const array_t array) \ + { \ + ARRAYI_CONTRACT(array); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_return_code_t ret; \ + m_serial_local_t local; \ + ret = f->m_interface->write_array_start(local, f, array->size); \ + for (size_t i = 0; i < array->size; i++) { \ + type const *item = M_C(name, _cget)(array, i); \ + if (i != 0) { \ + ret |= f->m_interface->write_array_next(local, f); \ + } \ + ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ + } \ + ret |= f->m_interface->write_array_end(local, f); \ + return ret & M_SERIAL_FAIL; \ + } \ + , /* no OUT_SERIAL */ ) \ + \ + M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(array_t array, m_serial_read_t f) \ + { \ + ARRAYI_CONTRACT(array); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_return_code_t ret; \ + m_serial_local_t local; \ + size_t estimated_size = 0; \ + M_C(name,_clean)(array); \ + ret = f->m_interface->read_array_start(local, f, &estimated_size); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { \ + return ret; \ + } \ + if (estimated_size != 0) { \ + /* The format has given an estimation of the array size */ \ + M_C(name, _reserve)(array, estimated_size); \ + } \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + ret = M_CALL_IN_SERIAL(oplist, item, f); \ + if (ret != M_SERIAL_OK_DONE) { break; } \ + M_C(name, _push_back)(array, item); \ + ret = f->m_interface->read_array_next(local, f); \ + } while (ret == M_SERIAL_OK_CONTINUE); \ + M_CALL_CLEAR(oplist, item); \ + ARRAYI_CONTRACT(array); \ + return ret; \ + } \ + , /* no IN_SERIAL & INIT */ ) \ + \ + M_IF_METHOD(EQUAL, oplist)( \ + static inline bool \ + M_C(name, _equal_p)(const array_t array1, \ + const array_t array2) \ + { \ + ARRAYI_CONTRACT(array1); \ + ARRAYI_CONTRACT(array2); \ + if (array1->size != array2->size) return false; \ + size_t i; \ + for(i = 0; i < array1->size; i++) { \ + type const *item1 = M_C(name, _cget)(array1, i); \ + type const *item2 = M_C(name, _cget)(array2, i); \ + bool b = M_CALL_EQUAL(oplist, *item1, *item2); \ + if (!b) return false; \ + } \ + return i == array1->size; \ + } \ + , /* no EQUAL */ ) \ + \ + M_IF_METHOD(HASH, oplist)( \ + static inline size_t \ + M_C(name, _hash)(const array_t array) \ + { \ + ARRAYI_CONTRACT(array); \ + M_HASH_DECL(hash); \ + for(size_t i = 0 ; i < array->size; i++) { \ + size_t hi = M_CALL_HASH(oplist, array->ptr[i]); \ + M_HASH_UP(hash, hi); \ + } \ + return M_HASH_FINAL (hash); \ + } \ + , /* no HASH */ ) \ + \ + static inline void \ + M_C(name, _splice)(array_t a1, array_t a2) \ + { \ + ARRAYI_CONTRACT(a1); \ + ARRAYI_CONTRACT(a2); \ + if (M_LIKELY (a2->size > 0)) { \ + size_t newSize = a1->size + a2->size; \ + if (newSize > a1->alloc) { \ + type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \ + if (M_UNLIKELY (ptr == NULL) ) { \ + M_MEMORY_FULL(sizeof (type) * newSize); \ + } \ + a1->ptr = ptr; \ + a1->alloc = newSize; \ + } \ + memcpy(&a1->ptr[a1->size], &a2->ptr[0], a2->size * sizeof (type)); \ + /* a2 is now empty */ \ + a2->size = 0; \ + /* a1 has been expanded with the items of a2 */ \ + a1->size = newSize; \ + } \ + } \ #endif diff --git a/m-atomic.h b/m-atomic.h index 70e3392e..72d62060 100644 --- a/m-atomic.h +++ b/m-atomic.h @@ -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 @@ -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))) diff --git a/m-bitset.h b/m-bitset.h index 50937f9e..93bc9b01 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -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 */ diff --git a/m-bptree.h b/m-bptree.h index 53c38df6..bd96b0f6 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -34,9 +34,9 @@ OR BPTREE_DEF2(name, N, key_t, value_t) */ -#define BPTREE_DEF2(name, N, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_DEF2(name, N, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, N, key_type, __VA_ARGS__, 1, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -49,9 +49,9 @@ OR BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t) */ -#define BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \ (name, N, key_type, __VA_ARGS__, 1, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ))) \ M_END_PROTECTED_CODE @@ -60,9 +60,9 @@ /* Define a B+tree of a given type, of size N. with its associated functions USAGE: BPTREE_DEF(name, N, type, [, oplist_of_the_type]) */ -#define BPTREE_DEF(name, N, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_DEF(name, N, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, N, __VA_ARGS__, __VA_ARGS__, 0, 0, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -71,9 +71,9 @@ /* Define a B+tree of a given type, of size N. as the given name name_t with its associated functions USAGE: BPTREE_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */ -#define BPTREE_DEF_AS(name, name_t, it_t, N, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_DEF_AS(name, name_t, it_t, N, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \ (name, N, __VA_ARGS__, __VA_ARGS__, 0, 0, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ))) \ M_END_PROTECTED_CODE @@ -87,9 +87,9 @@ OR BPTREE_MULTI_DEF2(name, N, key_t, value_t) */ -#define BPTREE_MULTI_DEF2(name, N, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_MULTI_DEF2(name, N, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, N, key_type, __VA_ARGS__, 1, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -103,9 +103,9 @@ OR BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_t, value_t) */ -#define BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_MULTI_DEF2_AS(name, name_t, it_t, itref_t, N, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ), \ (name, N, key_type, __VA_ARGS__, 1, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, itref_t ))) \ M_END_PROTECTED_CODE @@ -115,9 +115,9 @@ allowing multiple equal keys to exist, with its associated functions USAGE: BPTREE_MULTI_DEF(name, N, type, [, oplist_of_the_type]) */ -#define BPTREE_MULTI_DEF(name, N, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_MULTI_DEF(name, N, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, N, __VA_ARGS__, __VA_ARGS__, 0, 1, M_C(name, _t), M_C(name, _node_ct), M_C(name, _pit_ct), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_BEGIN_PROTECTED_CODE @@ -127,9 +127,9 @@ allowing multiple equal keys to exist, as the given name name_t with its associated functions USAGE: BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, type, [, oplist_of_the_type]) */ -#define BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \ - M_BEGIN_PROTECTED_CODE \ - BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BPTREE_MULTI_DEF_AS(name, name_t, it_t, N, ...) \ + M_BEGIN_PROTECTED_CODE \ + BPTREEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, N, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ), \ (name, N, __VA_ARGS__, __VA_ARGS__, 0, 1, name_t, M_C(name, _node_ct), M_C(name, _pit_ct), it_t, M_C(name, _itref_ct) ))) \ M_BEGIN_PROTECTED_CODE @@ -137,9 +137,9 @@ /* Define the oplist of a B+TREE used as a set of type (from BPTREE_DEF). USAGE: BPTREE_OPLIST(name [, oplist_of_the_type]) */ -#define BPTREE_OPLIST(...) \ - BPTREEI_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST ), \ +#define BPTREE_OPLIST(...) \ + BPTREEI_KEY_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST ), \ (__VA_ARGS__ ))) @@ -148,9 +148,9 @@ NOTE: IT_REF is not exported so that the contained appears as not modifiable by algorithm. */ -#define BPTREE_OPLIST2(...) \ - BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \ +#define BPTREE_OPLIST2(...) \ + BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \ (__VA_ARGS__ ))) @@ -162,95 +162,95 @@ #define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg /* Validation of the given oplists */ -#define BPTREEI_KEY_OPLIST_P2(name, oplist) \ +#define BPTREEI_KEY_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(BPTREEI_KEY_OPLIST_P3, BPTREEI_KEY_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define BPTREEI_KEY_OPLIST_FAILURE(name, oplist) \ +#define BPTREEI_KEY_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a b+tree */ -#define BPTREEI_KEY_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)), \ - IT_TYPE(M_C(name, _it_ct)), \ - IT_FIRST(M_C(name,_it)), \ - IT_SET(M_C(name,_it_set)), \ - IT_END(M_C(name,_it_end)), \ - IT_END_P(M_C(name,_end_p)), \ - IT_EQUAL_P(M_C(name,_it_equal_p)), \ - IT_NEXT(M_C(name,_next)), \ - IT_REF(M_C(name,_ref)), \ - IT_CREF(M_C(name,_cref)), \ - CLEAN(M_C(name,_clean)), \ - PUSH(M_C(name,_push)), \ - GET_MIN(M_C(name,_min)), \ - GET_MAX(M_C(name,_max)), \ - M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),), \ - M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),), \ - M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),), \ - M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),), \ - M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \ - M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),), \ - M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \ - M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ - ,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 BPTREEI_KEY_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)), \ + IT_TYPE(M_C(name, _it_ct)), \ + IT_FIRST(M_C(name,_it)), \ + IT_SET(M_C(name,_it_set)), \ + IT_END(M_C(name,_it_end)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_EQUAL_P(M_C(name,_it_equal_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_REF(M_C(name,_ref)), \ + IT_CREF(M_C(name,_cref)), \ + CLEAN(M_C(name,_clean)), \ + PUSH(M_C(name,_push)), \ + GET_MIN(M_C(name,_min)), \ + GET_MAX(M_C(name,_max)), \ + M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),), \ + M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),), \ + M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),), \ + M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),), \ + M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \ + M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),), \ + M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \ + M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ + ,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 evaluation */ #define BPTREEI_OPLIST2_P1(arg) BPTREEI_OPLIST2_P2 arg /* Validation of the given oplists (first the key oplist, then the value oplist) */ -#define BPTREEI_OPLIST2_P2(name, key_oplist, value_oplist) \ +#define BPTREEI_OPLIST2_P2(name, key_oplist, value_oplist) \ M_IF_OPLIST(key_oplist)(BPTREEI_OPLIST2_P3, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist) -#define BPTREEI_OPLIST2_P3(name, key_oplist, value_oplist) \ +#define BPTREEI_OPLIST2_P3(name, key_oplist, value_oplist) \ M_IF_OPLIST(value_oplist)(BPTREEI_OPLIST2_P4, BPTREEI_OPLIST2_FAILURE)(name, key_oplist, value_oplist) /* Prepare a clean compilation failure */ -#define BPTREEI_OPLIST2_FAILURE(name, key_oplist, value_oplist) \ +#define BPTREEI_OPLIST2_FAILURE(name, key_oplist, value_oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist))) /* Final definition of the oplist */ -#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \ - (INIT(M_C(name, _init)), \ - INIT_SET(M_C(name, _init_set)), \ - INIT_WITH(API_1(M_INIT_KEY_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)), \ - TEST_EMPTY(M_C(name,_empty_p)), \ - IT_TYPE(M_C(name, _it_ct)), \ - IT_FIRST(M_C(name,_it)), \ - IT_SET(M_C(name,_it_set)), \ - IT_END(M_C(name,_it_end)), \ - IT_END_P(M_C(name,_end_p)), \ - IT_EQUAL_P(M_C(name,_it_equal_p)), \ - IT_NEXT(M_C(name,_next)), \ - IT_CREF(M_C(name,_cref)), \ - CLEAN(M_C(name,_clean)), \ - GET_MIN(M_C(name,_min)), \ - GET_MAX(M_C(name,_max)), \ - KEY_TYPE(M_C(name, _key_ct)), \ - VALUE_TYPE(M_C(name, _value_ct)), \ - SET_KEY(M_C(name, _set_at)), \ - GET_KEY(M_C(name, _get)), \ - ERASE_KEY(M_C(name, _erase)), \ - KEY_OPLIST(key_oplist), \ - VALUE_OPLIST(value_oplist), \ +#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \ + (INIT(M_C(name, _init)), \ + INIT_SET(M_C(name, _init_set)), \ + INIT_WITH(API_1(M_INIT_KEY_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)), \ + TEST_EMPTY(M_C(name,_empty_p)), \ + IT_TYPE(M_C(name, _it_ct)), \ + IT_FIRST(M_C(name,_it)), \ + IT_SET(M_C(name,_it_set)), \ + IT_END(M_C(name,_it_end)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_EQUAL_P(M_C(name,_it_equal_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_CREF(M_C(name,_cref)), \ + CLEAN(M_C(name,_clean)), \ + GET_MIN(M_C(name,_min)), \ + GET_MAX(M_C(name,_max)), \ + KEY_TYPE(M_C(name, _key_ct)), \ + VALUE_TYPE(M_C(name, _value_ct)), \ + SET_KEY(M_C(name, _set_at)), \ + GET_KEY(M_C(name, _get)), \ + ERASE_KEY(M_C(name, _erase)), \ + KEY_OPLIST(key_oplist), \ + VALUE_OPLIST(value_oplist), \ M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),), \ M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),), \ M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),), \ @@ -258,10 +258,10 @@ M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \ M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_C(name, _in_serial)),), \ M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_C(name, _equal_p)),), \ - M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_C(name, _hash)),) \ - ,M_IF_METHOD(NEW, key_oplist)(NEW(M_GET_NEW oplist),) \ - ,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \ - ,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \ + M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_C(name, _hash)),) \ + ,M_IF_METHOD(NEW, key_oplist)(NEW(M_GET_NEW oplist),) \ + ,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \ + ,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \ ) @@ -270,40 +270,40 @@ #ifdef NDEBUG # define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { } while (0) #else -# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { \ - assert ((node) != NULL); \ - assert ((root) != NULL); \ - int num2 = (node)->num; \ - bool is_leaf2 = num2 <= 0; \ - num2 = num2 < 0 ? -num2 : num2; \ - if ((node) == (root)) { \ - /* Contract of the root node. num can be 0 */ \ - assert( 0 <= num2 && num2 <= N); \ - if (num2 == 0) assert (is_leaf2); \ - } else { \ - /* Contract of a non-root node. num cannot be 0 */ \ - int c2 = N / 2; \ - assert (c2 > 0); \ - assert (c2 <= num2 && num2 <= N); \ - } \ - /* The node is sorted */ \ - for(int i2 = 1; i2 < num2 ; i2++) { \ +# define BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, node, root) do { \ + assert ((node) != NULL); \ + assert ((root) != NULL); \ + int num2 = (node)->num; \ + bool is_leaf2 = num2 <= 0; \ + num2 = num2 < 0 ? -num2 : num2; \ + if ((node) == (root)) { \ + /* Contract of the root node. num can be 0 */ \ + assert( 0 <= num2 && num2 <= N); \ + if (num2 == 0) assert (is_leaf2); \ + } else { \ + /* Contract of a non-root node. num cannot be 0 */ \ + int c2 = N / 2; \ + assert (c2 > 0); \ + assert (c2 <= num2 && num2 <= N); \ + } \ + /* The node is sorted */ \ + for(int i2 = 1; i2 < num2 ; i2++) { \ assert (M_CALL_CMP(key_oplist, (node)->key[i2-1], (node)->key[i2]) M_IF(isMulti)(<=, <) 0); \ - } \ - /* The chain node is also sorted */ \ - if ((node)->next != NULL) { \ - assert (num2 >= 1); \ + } \ + /* The chain node is also sorted */ \ + if ((node)->next != NULL) { \ + assert (num2 >= 1); \ assert (M_CALL_CMP(key_oplist, (node)->key[num2-1], (node)->next->key[0]) M_IF(isMulti)(<=, <) 0); \ - } \ + } \ } while (0) #endif /* Contract for a B+TREE of size N named 'b' */ -#define BPTREEI_CONTRACT(N, isMulti, key_oplist, b) do { \ - assert (N >= 3); /* TBC: 2 instead ? */ \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, (b)->root, (b)->root); \ - assert ((b)->root->next == NULL); \ - if ((b)->root->num <= 0) assert (-(b)->root->num == (int) (b)->size); \ +#define BPTREEI_CONTRACT(N, isMulti, key_oplist, b) do { \ + assert (N >= 3); /* TBC: 2 instead ? */ \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, (b)->root, (b)->root); \ + assert ((b)->root->next == NULL); \ + if ((b)->root->num <= 0) assert (-(b)->root->num == (int) (b)->size); \ } while (0) /* Max depth of any B+tree @@ -348,1122 +348,1122 @@ - subtype_t: alias for the type referenced by the iterator */ #define BPTREEI_DEF_P4(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ - \ - M_IF(isMap)( \ - /* Type returned by the iterator. Due to having key and value \ - separated in their own array in the node, it is pointers to \ - the objects, not a global pointer to both objects. */ \ - typedef struct M_C(name, _pair_s) { \ - key_t *key_ptr; \ - value_t *value_ptr; \ - } subtype_t; \ - , \ - typedef key_t subtype_t; \ - ) \ - \ - /* Define a Node of a B+TREE \ - * For a reason of simplicity, it allocates one more element than \ - * needed so that the code can push one more element in the node and \ - * then split the nodes (simplify the code) \ - */ \ - typedef struct M_C(name, _node_s) { \ - int num; /* Abs=Number of keys. Sign <0 is leaf */ \ - key_t key[N+1]; /* We can temporary push one more key */ \ - struct M_C(name, _node_s) *next; /* next node reference */ \ + \ + M_IF(isMap)( \ + /* Type returned by the iterator. Due to having key and value \ + separated in their own array in the node, it is pointers to \ + the objects, not a global pointer to both objects. */ \ + typedef struct M_C(name, _pair_s) { \ + key_t *key_ptr; \ + value_t *value_ptr; \ + } subtype_t; \ + , \ + typedef key_t subtype_t; \ + ) \ + \ + /* Define a Node of a B+TREE \ + * For a reason of simplicity, it allocates one more element than \ + * needed so that the code can push one more element in the node and \ + * then split the nodes (simplify the code) \ + */ \ + typedef struct M_C(name, _node_s) { \ + int num; /* Abs=Number of keys. Sign <0 is leaf */ \ + key_t key[N+1]; /* We can temporary push one more key */ \ + struct M_C(name, _node_s) *next; /* next node reference */ \ union M_C(name, _kind_s) { /* either value or pointer to other nodes */ \ - M_IF(isMap)(value_t value[N+1];,) \ - struct M_C(name, _node_s) *node[N+2]; \ - } kind; \ - } *node_t; \ - \ - /* A B+TREE is just a pointer to the root node */ \ - typedef struct M_C(name, _s) { \ - node_t root; \ - size_t size; \ - } tree_t[1]; \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - /* Definition of the alias used by the oplists */ \ - typedef subtype_t M_C(name, _subtype_ct); \ - typedef key_t M_C(name, _key_ct); \ - typedef value_t M_C(name, _value_ct); \ - typedef tree_t M_C(name, _ct); \ - \ - /* Define the Parent Tree Iterator */ \ - typedef struct M_C(name, _parent_it_s) { \ - int num; \ - node_t parent[BPTREEI_MAX_STACK]; \ - } pit_t[1]; \ - \ - /* Define the Iterator */ \ - typedef struct M_C(name, _it_s) { \ - M_IF(isMap)(struct M_C(name, _pair_s) pair;,) \ - node_t node; \ - int idx; \ - } it_t[1]; \ - typedef it_t M_C(name, _it_ct); \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, key_t, key_oplist) \ - M_CHECK_COMPATIBLE_OPLIST(name, 2, value_t, value_oplist) \ - \ - /* Allocate a new node */ \ - /* TODO: Can be specialized to alloc for leaf or for non leaf */ \ - static inline node_t M_C(name, _new_node)(void) \ - { \ - node_t n = M_CALL_NEW(key_oplist, struct M_C(name, _node_s)); \ - if (M_UNLIKELY (n == NULL)) { \ - M_MEMORY_FULL(sizeof (node_t)); \ - assert (0); \ - } \ - n->next = NULL; \ - n->num = 0; \ - return n; \ - } \ - \ - static inline void M_C(name, _init)(tree_t b) \ - { \ - b->root = M_C(name, _new_node)(); \ - b->size = 0; \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - } \ - \ - static inline bool M_C(name, _is_leaf)(const node_t n) \ - { \ - /* We consider the empty node as a leaf */ \ - /* Only the root node can be empty */ \ - return n->num <= 0; \ - } \ - \ - /* Return the number of keys of the node */ \ - static inline int M_C(name, _get_num)(const node_t n) \ - { \ - int num = n->num; \ - num = num < 0 ? -num : num; \ - assert (num <= N); \ - return num; \ - } \ - \ - static inline void M_C(name, _clean)(tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - node_t next, n = b->root; \ - pit_t pit; \ - /* np is the heigh of the tree */ \ - int np = 0; \ - /* Scan down the nodes to the left down node */ \ - while (!M_C(name, _is_leaf)(n)) { \ - pit->parent[np++] = n; \ - assert (np <= BPTREEI_MAX_STACK); \ - n = n->kind.node[0]; \ - } \ - pit->parent[np++] = n; \ - assert (np <= BPTREEI_MAX_STACK); \ - /* Clean & free non root */ \ - for(int i = 0; i < np; i++) { \ - n = pit->parent[i]; \ - while (n != NULL) { \ - /* Clear key (& value for leaf) */ \ - int num = M_C(name, _get_num)(n); \ - M_IF(isMap)(bool is_leaf = M_C(name, _is_leaf)(n);,) \ - for(int j = 0; j < num; j++) { \ - M_CALL_CLEAR(key_oplist, n->key[j]); \ - M_IF(isMap)(if (is_leaf) { \ - M_CALL_CLEAR(value_oplist, n->kind.value[j]); \ - },) \ - } \ - /* Next node of the same height */ \ - next = n->next; \ - if (i != 0) { \ - /* Free the node if non root */ \ - M_CALL_DEL(key_oplist, n); \ - } \ - n = next; \ - } \ - } \ - /* Clean root */ \ - b->root->num = 0; \ - b->size = 0; \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - } \ - \ - static inline void M_C(name, _clear)(tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - M_C(name, _clean)(b); \ - /* Once the tree is clean, only the root remains */ \ - M_CALL_DEL(key_oplist, b->root); \ - b->root = NULL; \ - } \ - \ - /* Copy recursively the node 'o' of root node 'root' */ \ + M_IF(isMap)(value_t value[N+1];,) \ + struct M_C(name, _node_s) *node[N+2]; \ + } kind; \ + } *node_t; \ + \ + /* A B+TREE is just a pointer to the root node */ \ + typedef struct M_C(name, _s) { \ + node_t root; \ + size_t size; \ + } tree_t[1]; \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + /* Definition of the alias used by the oplists */ \ + typedef subtype_t M_C(name, _subtype_ct); \ + typedef key_t M_C(name, _key_ct); \ + typedef value_t M_C(name, _value_ct); \ + typedef tree_t M_C(name, _ct); \ + \ + /* Define the Parent Tree Iterator */ \ + typedef struct M_C(name, _parent_it_s) { \ + int num; \ + node_t parent[BPTREEI_MAX_STACK]; \ + } pit_t[1]; \ + \ + /* Define the Iterator */ \ + typedef struct M_C(name, _it_s) { \ + M_IF(isMap)(struct M_C(name, _pair_s) pair;,) \ + node_t node; \ + int idx; \ + } it_t[1]; \ + typedef it_t M_C(name, _it_ct); \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, key_t, key_oplist) \ + M_CHECK_COMPATIBLE_OPLIST(name, 2, value_t, value_oplist) \ + \ + /* Allocate a new node */ \ + /* TODO: Can be specialized to alloc for leaf or for non leaf */ \ + static inline node_t M_C(name, _new_node)(void) \ + { \ + node_t n = M_CALL_NEW(key_oplist, struct M_C(name, _node_s)); \ + if (M_UNLIKELY (n == NULL)) { \ + M_MEMORY_FULL(sizeof (node_t)); \ + assert (0); \ + } \ + n->next = NULL; \ + n->num = 0; \ + return n; \ + } \ + \ + static inline void M_C(name, _init)(tree_t b) \ + { \ + b->root = M_C(name, _new_node)(); \ + b->size = 0; \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + } \ + \ + static inline bool M_C(name, _is_leaf)(const node_t n) \ + { \ + /* We consider the empty node as a leaf */ \ + /* Only the root node can be empty */ \ + return n->num <= 0; \ + } \ + \ + /* Return the number of keys of the node */ \ + static inline int M_C(name, _get_num)(const node_t n) \ + { \ + int num = n->num; \ + num = num < 0 ? -num : num; \ + assert (num <= N); \ + return num; \ + } \ + \ + static inline void M_C(name, _clean)(tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + node_t next, n = b->root; \ + pit_t pit; \ + /* np is the heigh of the tree */ \ + int np = 0; \ + /* Scan down the nodes to the left down node */ \ + while (!M_C(name, _is_leaf)(n)) { \ + pit->parent[np++] = n; \ + assert (np <= BPTREEI_MAX_STACK); \ + n = n->kind.node[0]; \ + } \ + pit->parent[np++] = n; \ + assert (np <= BPTREEI_MAX_STACK); \ + /* Clean & free non root */ \ + for(int i = 0; i < np; i++) { \ + n = pit->parent[i]; \ + while (n != NULL) { \ + /* Clear key (& value for leaf) */ \ + int num = M_C(name, _get_num)(n); \ + M_IF(isMap)(bool is_leaf = M_C(name, _is_leaf)(n);,) \ + for(int j = 0; j < num; j++) { \ + M_CALL_CLEAR(key_oplist, n->key[j]); \ + M_IF(isMap)(if (is_leaf) { \ + M_CALL_CLEAR(value_oplist, n->kind.value[j]); \ + },) \ + } \ + /* Next node of the same height */ \ + next = n->next; \ + if (i != 0) { \ + /* Free the node if non root */ \ + M_CALL_DEL(key_oplist, n); \ + } \ + n = next; \ + } \ + } \ + /* Clean root */ \ + b->root->num = 0; \ + b->size = 0; \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + } \ + \ + static inline void M_C(name, _clear)(tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + M_C(name, _clean)(b); \ + /* Once the tree is clean, only the root remains */ \ + M_CALL_DEL(key_oplist, b->root); \ + b->root = NULL; \ + } \ + \ + /* Copy recursively the node 'o' of root node 'root' */ \ static inline node_t M_C(name, _copy_node)(const node_t o, const node_t root) \ - { \ - node_t n = M_C(name, _new_node)(); \ - /* Set default number of keys and type to copy */ \ - n->num = o->num; \ - /* By default it is not linked to its brother. \ - Only the parent of this node can do it. It is fixed by it */ \ - n->next = NULL; \ - /* Get number of keys in the node and copy them */ \ - int num = M_C(name, _get_num)(o); \ - for(int i = 0; i < num; i++) { \ - M_CALL_INIT_SET(key_oplist, n->key[i], o->key[i]); \ - } \ - if (M_C(name, _is_leaf)(o)) { \ - /* Copy the associated values if it is a leaf and a MAP */ \ - M_IF(isMap)( \ - for(int i = 0; i < num; i++) { \ - M_CALL_INIT_SET(value_oplist, n->kind.value[i], o->kind.value[i]); \ - } \ - , /* End of isMap */) \ - } else { \ - /* Copy recursively the associated nodes if it is not a leaf */ \ - for(int i = 0; i <= num; i++) { \ - assert(o->kind.node[i] != root); \ - n->kind.node[i] = M_C(name, _copy_node)(o->kind.node[i], root); \ - } \ - /* The copied nodes don't have their next field correct */ \ - /* Fix the next field for the copied nodes */ \ - for(int i = 0; i < num; i++) { \ - node_t current = n->kind.node[i]; \ - node_t next = n->kind.node[i+1]; \ - current->next = next; \ - /* Go down the tree up to the leaf \ - and fix the final 'next' link with the copied node */ \ - while (!M_C(name, _is_leaf)(current)) { \ - assert(!M_C(name, _is_leaf)(next)); \ - current = current->kind.node[current->num]; \ - next = next->kind.node[0]; \ - current->next = next; \ - } \ - } \ - } \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \ - return n; \ - } \ - \ - static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, o); \ - assert (b != NULL); \ - /* Just copy recursively the root node */ \ - b->root = M_C(name, _copy_node)(o->root, o->root); \ - b->size = o->size; \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - } \ - \ - static inline void M_C(name, _set)(tree_t b, const tree_t o) \ - { \ - /* NOTE: We could reuse the already allocated nodes of 'b'. \ - Not sure if it worth the effort */ \ - M_C(name, _clear)(b); \ - M_C(name, _init_set)(b, o); \ - } \ - \ - static inline bool M_C(name, _empty_p)(const tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - /* root shall be an empty leaf */ \ - return b->size == 0; \ - } \ - \ - static inline size_t M_C(name, _size)(const tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - return b->size; \ - } \ - \ + { \ + node_t n = M_C(name, _new_node)(); \ + /* Set default number of keys and type to copy */ \ + n->num = o->num; \ + /* By default it is not linked to its brother. \ + Only the parent of this node can do it. It is fixed by it */ \ + n->next = NULL; \ + /* Get number of keys in the node and copy them */ \ + int num = M_C(name, _get_num)(o); \ + for(int i = 0; i < num; i++) { \ + M_CALL_INIT_SET(key_oplist, n->key[i], o->key[i]); \ + } \ + if (M_C(name, _is_leaf)(o)) { \ + /* Copy the associated values if it is a leaf and a MAP */ \ + M_IF(isMap)( \ + for(int i = 0; i < num; i++) { \ + M_CALL_INIT_SET(value_oplist, n->kind.value[i], o->kind.value[i]); \ + } \ + , /* End of isMap */) \ + } else { \ + /* Copy recursively the associated nodes if it is not a leaf */ \ + for(int i = 0; i <= num; i++) { \ + assert(o->kind.node[i] != root); \ + n->kind.node[i] = M_C(name, _copy_node)(o->kind.node[i], root); \ + } \ + /* The copied nodes don't have their next field correct */ \ + /* Fix the next field for the copied nodes */ \ + for(int i = 0; i < num; i++) { \ + node_t current = n->kind.node[i]; \ + node_t next = n->kind.node[i+1]; \ + current->next = next; \ + /* Go down the tree up to the leaf \ + and fix the final 'next' link with the copied node */ \ + while (!M_C(name, _is_leaf)(current)) { \ + assert(!M_C(name, _is_leaf)(next)); \ + current = current->kind.node[current->num]; \ + next = next->kind.node[0]; \ + current->next = next; \ + } \ + } \ + } \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, (o==root) ? n : root); \ + return n; \ + } \ + \ + static inline void M_C(name, _init_set)(tree_t b, const tree_t o) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, o); \ + assert (b != NULL); \ + /* Just copy recursively the root node */ \ + b->root = M_C(name, _copy_node)(o->root, o->root); \ + b->size = o->size; \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + } \ + \ + static inline void M_C(name, _set)(tree_t b, const tree_t o) \ + { \ + /* NOTE: We could reuse the already allocated nodes of 'b'. \ + Not sure if it worth the effort */ \ + M_C(name, _clear)(b); \ + M_C(name, _init_set)(b, o); \ + } \ + \ + static inline bool M_C(name, _empty_p)(const tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + /* root shall be an empty leaf */ \ + return b->size == 0; \ + } \ + \ + static inline size_t M_C(name, _size)(const tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + return b->size; \ + } \ + \ static inline node_t M_C(name, _search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \ - { \ - node_t n = b->root; \ - int np = 0; \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ - /* Go down the tree while searching for key */ \ - while (!M_C(name, _is_leaf)(n)) { \ - assert (np <= BPTREEI_MAX_STACK); \ - int i, hi = n->num; \ - assert (hi > 0); \ - /* Linear search is usually faster than binary search for \ - B+TREE (due to cache effect). If a binary tree is faster for \ - the choosen type and size , it probably means that the \ - size of B+TREE is too big and should be reduced. */ \ - for(i = 0; i < hi; i++) { \ - if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \ - break; \ - } \ - /* Update the Parent iterator */ \ - pit->parent[np++] = n; \ - /* Select the new node to go down to */ \ - n = n->kind.node[i]; \ - assert (n != NULL); \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ - } \ - pit->num = np; \ - return n; \ - } \ - \ - static inline value_t *M_C(name, _get)(const tree_t b, key_t const key) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - pit_t pit; \ - /* Get the leaf node where the key can be */ \ - node_t n = M_C(name, _search_for_leaf)(pit, b, key); \ - int cmp = 0; \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ - /* Search in the leaf for key */ \ - for(int i = 0; cmp >= 0 && i < -n->num; i++) { \ - cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ - if (cmp == 0) { \ - /* Return the value if MAP mode or the key if SET mode */ \ - return M_IF(isMap)(&n->kind.value[i],&n->key[i]); \ - } \ - } \ - /* Key not found */ \ - return NULL; \ - } \ - \ + { \ + node_t n = b->root; \ + int np = 0; \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ + /* Go down the tree while searching for key */ \ + while (!M_C(name, _is_leaf)(n)) { \ + assert (np <= BPTREEI_MAX_STACK); \ + int i, hi = n->num; \ + assert (hi > 0); \ + /* Linear search is usually faster than binary search for \ + B+TREE (due to cache effect). If a binary tree is faster for \ + the choosen type and size , it probably means that the \ + size of B+TREE is too big and should be reduced. */ \ + for(i = 0; i < hi; i++) { \ + if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \ + break; \ + } \ + /* Update the Parent iterator */ \ + pit->parent[np++] = n; \ + /* Select the new node to go down to */ \ + n = n->kind.node[i]; \ + assert (n != NULL); \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ + } \ + pit->num = np; \ + return n; \ + } \ + \ + static inline value_t *M_C(name, _get)(const tree_t b, key_t const key) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + pit_t pit; \ + /* Get the leaf node where the key can be */ \ + node_t n = M_C(name, _search_for_leaf)(pit, b, key); \ + int cmp = 0; \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ + /* Search in the leaf for key */ \ + for(int i = 0; cmp >= 0 && i < -n->num; i++) { \ + cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ + if (cmp == 0) { \ + /* Return the value if MAP mode or the key if SET mode */ \ + return M_IF(isMap)(&n->kind.value[i],&n->key[i]); \ + } \ + } \ + /* Key not found */ \ + return NULL; \ + } \ + \ static inline value_t const *M_C(name, _cget)(const tree_t b, key_t const key) \ - { \ - return M_CONST_CAST(value_t, M_C(name, _get)(b, key)); \ - } \ - \ - static inline int \ - M_C(name, _search_and_insert_in_leaf)(node_t n, key_t const key \ + { \ + return M_CONST_CAST(value_t, M_C(name, _get)(b, key)); \ + } \ + \ + static inline int \ + M_C(name, _search_and_insert_in_leaf)(node_t n, key_t const key \ M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \ - { \ - assert (M_C(name, _is_leaf)(n)); \ - int i, num = M_C(name, _get_num)(n); \ - assert (num <= N); \ - /* Search for the key in the node n (a leaf) for insertion */ \ - for(i = 0; i < num; i++) { \ - int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ - if (cmp <= 0) { \ - M_IF(isMulti)( /* Nothing to do : fallthrough */, \ - /* Update value if keys are equal */ \ - if (M_UNLIKELY (cmp == 0)) { \ - M_IF(isMap)(M_CALL_SET(value_oplist, n->kind.value[i], value);,) \ - return -1; \ - } \ - ) \ - /* Move tables to make space for insertion */ \ + { \ + assert (M_C(name, _is_leaf)(n)); \ + int i, num = M_C(name, _get_num)(n); \ + assert (num <= N); \ + /* Search for the key in the node n (a leaf) for insertion */ \ + for(i = 0; i < num; i++) { \ + int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ + if (cmp <= 0) { \ + M_IF(isMulti)( /* Nothing to do : fallthrough */, \ + /* Update value if keys are equal */ \ + if (M_UNLIKELY (cmp == 0)) { \ + M_IF(isMap)(M_CALL_SET(value_oplist, n->kind.value[i], value);,) \ + return -1; \ + } \ + ) \ + /* Move tables to make space for insertion */ \ memmove(&n->key[i+1], &n->key[i], sizeof(key_t)*(unsigned int)(num-i)); \ M_IF(isMap)(memmove(&n->kind.value[i+1], &n->kind.value[i], sizeof(value_t)*(unsigned int)(num-i));,) \ - break; \ - } \ - } \ - /* Insert key & value if MAP mode */ \ - M_CALL_INIT_SET(key_oplist, n->key[i], key); \ - M_IF(isMap)(M_CALL_INIT_SET(value_oplist, n->kind.value[i], value);,) \ - /* Increase the number of key in the node */ \ - n->num += -1; /* Increase num as num<0 for leaf */ \ - return i; \ - } \ - \ - static inline int \ - M_C(name, _search_and_insert_in_node)(node_t n, node_t l, key_t key) \ - { \ - assert (!M_C(name, _is_leaf)(n)); \ - int i, num = M_C(name, _get_num)(n); \ - assert (num <= N); \ - /* Search for the key in the node n (not a leaf) for insertion */ \ - for(i = 0; i < num; i++) { \ - if (n->kind.node[i] == l) { \ - /* Move tables to make space for insertion */ \ + break; \ + } \ + } \ + /* Insert key & value if MAP mode */ \ + M_CALL_INIT_SET(key_oplist, n->key[i], key); \ + M_IF(isMap)(M_CALL_INIT_SET(value_oplist, n->kind.value[i], value);,) \ + /* Increase the number of key in the node */ \ + n->num += -1; /* Increase num as num<0 for leaf */ \ + return i; \ + } \ + \ + static inline int \ + M_C(name, _search_and_insert_in_node)(node_t n, node_t l, key_t key) \ + { \ + assert (!M_C(name, _is_leaf)(n)); \ + int i, num = M_C(name, _get_num)(n); \ + assert (num <= N); \ + /* Search for the key in the node n (not a leaf) for insertion */ \ + for(i = 0; i < num; i++) { \ + if (n->kind.node[i] == l) { \ + /* Move tables to make space for insertion */ \ memmove(&n->key[i+1], &n->key[i], sizeof(key_t)*(unsigned int)(num-i)); \ memmove(&n->kind.node[i+1], &n->kind.node[i], sizeof(node_t)*(unsigned int)(num-i+1)); \ - break; \ - } \ - } \ - /* Insert key in node */ \ - /* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \ - M_CALL_INIT_SET(key_oplist, n->key[i], key); \ - /* Increase the number of key in the node */ \ - n->num += 1; \ - return i; \ - } \ - \ - static inline void \ - M_IF(isMap)(M_C(name, _set_at),M_C(name,_push))(tree_t b, key_t const key \ + break; \ + } \ + } \ + /* Insert key in node */ \ + /* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \ + M_CALL_INIT_SET(key_oplist, n->key[i], key); \ + /* Increase the number of key in the node */ \ + n->num += 1; \ + return i; \ + } \ + \ + static inline void \ + M_IF(isMap)(M_C(name, _set_at),M_C(name,_push))(tree_t b, key_t const key \ M_IF(isMap)(M_DEFERRED_COMMA value_t const value,)) \ - { \ - pit_t pit; \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \ - /* Insert key into the leaf.*/ \ - /* NOTE: Even if there is N elements, we can still add one more.*/ \ + { \ + pit_t pit; \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \ + /* Insert key into the leaf.*/ \ + /* NOTE: Even if there is N elements, we can still add one more.*/ \ int i = M_C(name, _search_and_insert_in_leaf)(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \ - if (i < 0) { \ - /* Nothing to do anymore. key already exists in the tree. \ - value has been updated if needed */ \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - return; \ - } \ - b->size ++; \ - /* Most likely case: leaf can accept key */ \ - int num = -leaf->num; \ - assert (num > 0); \ - if (M_LIKELY (num <= N)) { \ - /* nothing more to do */ \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - return; \ - } \ - assert (num == N+1); \ - \ - /* Needs to rebalance the B+TREE */ \ - /* leaf is full: need to slip the leaf in two */ \ - int nnum = (N + 1) / 2; \ - num = N + 1 - nnum; \ - node_t nleaf = M_C(name, _new_node)(); \ - /* Move half objects to the new node */ \ + if (i < 0) { \ + /* Nothing to do anymore. key already exists in the tree. \ + value has been updated if needed */ \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + return; \ + } \ + b->size ++; \ + /* Most likely case: leaf can accept key */ \ + int num = -leaf->num; \ + assert (num > 0); \ + if (M_LIKELY (num <= N)) { \ + /* nothing more to do */ \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + return; \ + } \ + assert (num == N+1); \ + \ + /* Needs to rebalance the B+TREE */ \ + /* leaf is full: need to slip the leaf in two */ \ + int nnum = (N + 1) / 2; \ + num = N + 1 - nnum; \ + node_t nleaf = M_C(name, _new_node)(); \ + /* Move half objects to the new node */ \ memmove(&nleaf->key[0], &leaf->key[num], sizeof(key_t)*(unsigned int)nnum); \ M_IF(isMap)(memmove(&nleaf->kind.value[0], &leaf->kind.value[num], sizeof(value_t)*(unsigned int)nnum);,) \ - leaf->num = -num; \ - nleaf->num = -nnum; \ - nleaf->next = leaf->next; \ - leaf->next = nleaf; \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, leaf, b->root); \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nleaf, b->root); \ - /* Update parent to inject *key_ptr that splits between (leaf, nleaf) */ \ - key_t *key_ptr = &leaf->key[num-1]; \ - while (true) { \ - if (pit->num == 0) { \ - /* We reach root ==> Need to increase the height of the tree.*/ \ - node_t parent = M_C(name, _new_node)(); \ - parent->num = 1; \ - /* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \ - M_CALL_INIT_SET(key_oplist, parent->key[0], *key_ptr); \ - parent->kind.node[0] = leaf; \ - parent->kind.node[1] = nleaf; \ - b->root = parent; \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - return; \ - } \ - /* Non root node. Get the parent node */ \ - node_t parent = pit->parent[--pit->num]; \ + leaf->num = -num; \ + nleaf->num = -nnum; \ + nleaf->next = leaf->next; \ + leaf->next = nleaf; \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, leaf, b->root); \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nleaf, b->root); \ + /* Update parent to inject *key_ptr that splits between (leaf, nleaf) */ \ + key_t *key_ptr = &leaf->key[num-1]; \ + while (true) { \ + if (pit->num == 0) { \ + /* We reach root ==> Need to increase the height of the tree.*/ \ + node_t parent = M_C(name, _new_node)(); \ + parent->num = 1; \ + /* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \ + M_CALL_INIT_SET(key_oplist, parent->key[0], *key_ptr); \ + parent->kind.node[0] = leaf; \ + parent->kind.node[1] = nleaf; \ + b->root = parent; \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + return; \ + } \ + /* Non root node. Get the parent node */ \ + node_t parent = pit->parent[--pit->num]; \ /* Insert into parent (It is big enough to receive temporary one more) */ \ - i = M_C(name, _search_and_insert_in_node)(parent, leaf, *key_ptr); \ - parent->kind.node[i] = leaf; \ - parent->kind.node[i+1] = nleaf; \ - /* Test if parent node is full? */ \ - if (M_LIKELY (parent->num <= N)) { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - return; /* No need to split parent.*/ \ - } \ - assert (parent->num == N+1); \ - /* Need to split parent in {np} {med} {nnp} */ \ - int nnp = N / 2; \ - int np = N - nnp; \ - assert (nnp > 0 && np > 0 && nnp+np+1 == N+1); \ - node_t nparent = M_C(name, _new_node)(); \ - /* Move half items to new node (Like a classic B-TREE) \ - and the median key to the grand-parent*/ \ + i = M_C(name, _search_and_insert_in_node)(parent, leaf, *key_ptr); \ + parent->kind.node[i] = leaf; \ + parent->kind.node[i+1] = nleaf; \ + /* Test if parent node is full? */ \ + if (M_LIKELY (parent->num <= N)) { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + return; /* No need to split parent.*/ \ + } \ + assert (parent->num == N+1); \ + /* Need to split parent in {np} {med} {nnp} */ \ + int nnp = N / 2; \ + int np = N - nnp; \ + assert (nnp > 0 && np > 0 && nnp+np+1 == N+1); \ + node_t nparent = M_C(name, _new_node)(); \ + /* Move half items to new node (Like a classic B-TREE) \ + and the median key to the grand-parent*/ \ memmove(&nparent->key[0], &parent->key[np+1], sizeof(key_t)*(unsigned int)nnp); \ memmove(&nparent->kind.node[0], &parent->kind.node[np+1], sizeof(node_t)*(unsigned int)(nnp+1)); \ - parent->num = np; \ - nparent->num = nnp; \ - nparent->next = parent->next; \ - parent->next = nparent; \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, parent, b->root); \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nparent, b->root); \ - /* Prepare for the next step */ \ - key_ptr = &parent->key[np]; \ - leaf = parent; \ - nleaf = nparent; \ - } \ - } \ - \ - static inline int \ - M_C(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \ - { \ - assert(M_C(name, _is_leaf)(n)); \ - const int num = M_C(name, _get_num)(n); \ - for(int i = 0; i < num; i++) { \ - const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ - if (cmp == 0) { \ - /* found key ==> delete it */ \ - M_CALL_CLEAR(key_oplist, n->key[i]); \ - M_IF(isMap)(M_CALL_CLEAR(value_oplist, n->kind.value[i]);,) \ + parent->num = np; \ + nparent->num = nnp; \ + nparent->next = parent->next; \ + parent->next = nparent; \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, parent, b->root); \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, nparent, b->root); \ + /* Prepare for the next step */ \ + key_ptr = &parent->key[np]; \ + leaf = parent; \ + nleaf = nparent; \ + } \ + } \ + \ + static inline int \ + M_C(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \ + { \ + assert(M_C(name, _is_leaf)(n)); \ + const int num = M_C(name, _get_num)(n); \ + for(int i = 0; i < num; i++) { \ + const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ + if (cmp == 0) { \ + /* found key ==> delete it */ \ + M_CALL_CLEAR(key_oplist, n->key[i]); \ + M_IF(isMap)(M_CALL_CLEAR(value_oplist, n->kind.value[i]);,) \ memmove(&n->key[i], &n->key[i+1], sizeof(key_t)*(unsigned int)(num-1-i)); \ M_IF(isMap)(memmove(&n->kind.value[i], &n->kind.value[i+1], sizeof(value_t)*(unsigned int)(num-1-i));,) \ - n->num -= -1; /* decrease number as num is < 0 */ \ - return i; \ - } \ - } \ - return -1; /* Not found */ \ - } \ - \ - static inline void M_C(name, _left_shift)(node_t parent, int k) \ - { \ - assert (parent != NULL && !M_C(name, _is_leaf)(parent)); \ - assert (0 <= k && k < M_C(name, _get_num)(parent)); \ - node_t left = parent->kind.node[k]; \ - node_t right = parent->kind.node[k+1]; \ - assert (left != NULL && right != NULL); \ - int num_left = M_C(name, _get_num)(left); \ - int num_right = M_C(name, _get_num)(right); \ - assert (num_left > N/2); \ - assert (num_right < N/2); \ - \ - /* Move one item from the left node to the right node */ \ + n->num -= -1; /* decrease number as num is < 0 */ \ + return i; \ + } \ + } \ + return -1; /* Not found */ \ + } \ + \ + static inline void M_C(name, _left_shift)(node_t parent, int k) \ + { \ + assert (parent != NULL && !M_C(name, _is_leaf)(parent)); \ + assert (0 <= k && k < M_C(name, _get_num)(parent)); \ + node_t left = parent->kind.node[k]; \ + node_t right = parent->kind.node[k+1]; \ + assert (left != NULL && right != NULL); \ + int num_left = M_C(name, _get_num)(left); \ + int num_right = M_C(name, _get_num)(right); \ + assert (num_left > N/2); \ + assert (num_right < N/2); \ + \ + /* Move one item from the left node to the right node */ \ memmove(&right->key[1], &right->key[0], sizeof(key_t)*(unsigned int)num_right); \ - if (M_C(name, _is_leaf)(left)) { \ + if (M_C(name, _is_leaf)(left)) { \ M_IF(isMap)(memmove (&right->kind.value[1], &right->kind.value[0], sizeof(value_t)*(unsigned int)num_right);,) \ - memmove (&right->key[0], &left->key[num_left-1], sizeof (key_t)); \ + memmove (&right->key[0], &left->key[num_left-1], sizeof (key_t)); \ M_IF(isMap)(memmove (&right->kind.value[0], &left->kind.value[num_left-1], sizeof (value_t));,) \ - right->num = -num_right - 1; \ - left->num = -num_left + 1; \ - M_CALL_SET(key_oplist, parent->key[k], left->key[num_left-2]); \ - } else { \ + right->num = -num_right - 1; \ + left->num = -num_left + 1; \ + M_CALL_SET(key_oplist, parent->key[k], left->key[num_left-2]); \ + } else { \ memmove(&right->kind.node[1], &right->kind.node[0], sizeof(node_t)*(unsigned int)(num_right+1)); \ /* parent[k] is moved to right[0] (clear). parent[k] is therefore clear */ \ - memmove(&right->key[0], &parent->key[k], sizeof(key_t)); \ - right->kind.node[0] = left->kind.node[num_left]; \ - right->num = num_right + 1; \ - left->num = num_left - 1; \ + memmove(&right->key[0], &parent->key[k], sizeof(key_t)); \ + right->kind.node[0] = left->kind.node[num_left]; \ + right->num = num_right + 1; \ + left->num = num_left - 1; \ /* left[n-1] is move to parent[k] (clear). left[n-1] is therefore clear */ \ - memmove(&parent->key[k], &left->key[num_left-1], sizeof (key_t)); \ - } \ - assert (right->num != 0); \ - assert (left->num != 0); \ - } \ - \ - static inline void M_C(name, _right_shift)(node_t parent, int k) \ - { \ - assert (parent != NULL && !M_C(name, _is_leaf)(parent)); \ - assert (0 <= k && k < M_C(name, _get_num)(parent)); \ - node_t left = parent->kind.node[k]; \ - node_t right = parent->kind.node[k+1]; \ - assert (left != NULL && right != NULL); \ - int num_left = M_C(name, _get_num)(left); \ - int num_right = M_C(name, _get_num)(right); \ - assert (num_left < N/2); \ - assert (num_right > N/2); \ - \ - /* Move one item from the right node to the left node. */ \ - if (M_C(name, _is_leaf)(right)) { \ - memmove (&left->key[num_left], &right->key[0], sizeof(key_t)); \ + memmove(&parent->key[k], &left->key[num_left-1], sizeof (key_t)); \ + } \ + assert (right->num != 0); \ + assert (left->num != 0); \ + } \ + \ + static inline void M_C(name, _right_shift)(node_t parent, int k) \ + { \ + assert (parent != NULL && !M_C(name, _is_leaf)(parent)); \ + assert (0 <= k && k < M_C(name, _get_num)(parent)); \ + node_t left = parent->kind.node[k]; \ + node_t right = parent->kind.node[k+1]; \ + assert (left != NULL && right != NULL); \ + int num_left = M_C(name, _get_num)(left); \ + int num_right = M_C(name, _get_num)(right); \ + assert (num_left < N/2); \ + assert (num_right > N/2); \ + \ + /* Move one item from the right node to the left node. */ \ + if (M_C(name, _is_leaf)(right)) { \ + memmove (&left->key[num_left], &right->key[0], sizeof(key_t)); \ memmove (&right->key[0], &right->key[1], sizeof(key_t)*(unsigned int)(num_right-1)); \ M_IF(isMap)(memmove (&left->kind.value[num_left], &right->kind.value[0], sizeof (value_t));,) \ M_IF(isMap)(memmove (&right->kind.value[0], &right->kind.value[1], sizeof(value_t)*(unsigned int)(num_right-1));,) \ - right->num = -num_right + 1; \ - left->num = -num_left - 1; \ - M_CALL_SET(key_oplist, parent->key[k], left->key[num_left]); \ - } else { \ - memmove (&left->key[num_left], &parent->key[k], sizeof (key_t)); \ - memmove (&parent->key[k], &right->key[0], sizeof (key_t)); \ + right->num = -num_right + 1; \ + left->num = -num_left - 1; \ + M_CALL_SET(key_oplist, parent->key[k], left->key[num_left]); \ + } else { \ + memmove (&left->key[num_left], &parent->key[k], sizeof (key_t)); \ + memmove (&parent->key[k], &right->key[0], sizeof (key_t)); \ memmove (&right->key[0], &right->key[1], sizeof(key_t)*(unsigned int)(num_right-1)); \ - left->kind.node[num_left+1] = right->kind.node[0]; \ + left->kind.node[num_left+1] = right->kind.node[0]; \ memmove (&right->kind.node[0], &right->kind.node[1], sizeof(node_t)*(unsigned int)num_right); \ - right->num = num_right - 1; \ - left->num = num_left + 1; \ - } \ - assert (right->num != 0); \ - assert (left->num != 0); \ - } \ - \ - static inline void M_C(name, _merge_node)(node_t parent, int k, bool leaf) \ - { \ - assert (parent != NULL && !M_C(name, _is_leaf)(parent)); \ - assert (0 <= k && k < M_C(name, _get_num(parent))); \ - node_t left = parent->kind.node[k]; \ - node_t right = parent->kind.node[k+1]; \ - assert (left != NULL && right != NULL); \ - int num_parent = M_C(name, _get_num)(parent); \ - int num_left = M_C(name, _get_num)(left); \ - int num_right = M_C(name, _get_num)(right); \ - \ - /* Merge node 'k' and 'k+1' into a single one */ \ - if (leaf) { \ - assert (num_left + num_right <= N); \ + right->num = num_right - 1; \ + left->num = num_left + 1; \ + } \ + assert (right->num != 0); \ + assert (left->num != 0); \ + } \ + \ + static inline void M_C(name, _merge_node)(node_t parent, int k, bool leaf) \ + { \ + assert (parent != NULL && !M_C(name, _is_leaf)(parent)); \ + assert (0 <= k && k < M_C(name, _get_num(parent))); \ + node_t left = parent->kind.node[k]; \ + node_t right = parent->kind.node[k+1]; \ + assert (left != NULL && right != NULL); \ + int num_parent = M_C(name, _get_num)(parent); \ + int num_left = M_C(name, _get_num)(left); \ + int num_right = M_C(name, _get_num)(right); \ + \ + /* Merge node 'k' and 'k+1' into a single one */ \ + if (leaf) { \ + assert (num_left + num_right <= N); \ memmove(&left->key[num_left], &right->key[0], sizeof(key_t)*(unsigned int)num_right); \ M_IF(isMap)(memmove(&left->kind.value[num_left], &right->kind.value[0], sizeof(value_t)*(unsigned int)num_right);,) \ - left->num = -num_left - num_right; \ - } else { \ - assert (num_left + num_right <= N -1); \ + left->num = -num_left - num_right; \ + } else { \ + assert (num_left + num_right <= N -1); \ memmove(&left->key[num_left+1], &right->key[0], sizeof(key_t)*(unsigned int)num_right); \ memmove(&left->kind.node[num_left+1], &right->kind.node[0], sizeof(node_t)*(unsigned int)(num_right+1)); \ - M_CALL_INIT_SET(key_oplist, left->key[num_left], parent->key[k]); \ - left->num = num_left + 1 + num_right; \ - } \ - left->next = right->next; \ - M_CALL_DEL(key_oplist, right); \ - /* remove k'th key from the parent */ \ - M_CALL_CLEAR(key_oplist, parent->key[k]); \ + M_CALL_INIT_SET(key_oplist, left->key[num_left], parent->key[k]); \ + left->num = num_left + 1 + num_right; \ + } \ + left->next = right->next; \ + M_CALL_DEL(key_oplist, right); \ + /* remove k'th key from the parent */ \ + M_CALL_CLEAR(key_oplist, parent->key[k]); \ memmove(&parent->key[k], &parent->key[k+1], sizeof(key_t)*(unsigned int)(num_parent - k - 1)); \ memmove(&parent->kind.node[k+1], &parent->kind.node[k+2], sizeof(node_t)*(unsigned int)(num_parent - k -1)); \ - parent->num --; \ - } \ - \ - /* We can also cache the index when we descend the tree. \ - TODO: Bench if this is worth the effort.*/ \ - static inline int \ - M_C(name, _search_for_node)(node_t parent, node_t child) \ - { \ - assert (!M_C(name, _is_leaf)(parent)); \ - const int num = M_C(name, _get_num)(parent); \ - for(int i = 0; i <= num; i++) { \ - if (parent->kind.node[i] == child) \ - return i; \ - } \ - assert(false); \ - return -1; /* unreachable */ \ - } \ - \ - static inline bool M_C(name, _erase)(tree_t b, key_t const key) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - pit_t pit; \ - node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \ - int k = M_C(name, _search_and_remove_in_leaf)(leaf, key); \ - /* If key is not found ==> erase failed */ \ - if (k < 0) return false; \ - /* Remove one item from the B+TREE */ \ - b->size --; \ - /* If number of keys greater than N>2 or root ==> Nothing more to do */ \ - if (M_LIKELY (M_C(name, _get_num)(leaf) >= N/2) || pit->num == 0) \ - return true; \ - /* Leaf is too small. Needs rebalancing */ \ - assert (M_C(name, _get_num)(leaf) == N/2-1); \ - bool pass1 = true; \ - while (true) { \ - assert (pit->num > 0); \ - /* Search for node 'leaf' in parent */ \ - node_t parent = pit->parent[--pit->num]; \ - assert (parent != NULL); \ - k = M_C(name, _search_for_node)(parent, leaf); \ - /* Look for the neighboor of the removed key. */ \ - /* if we can steal one key from them to keep our node balanced */ \ - if (k > 0 && M_C(name, _get_num)(parent->kind.node[k-1]) > N/2) { \ - M_C(name, _left_shift)(parent, k-1); \ - return true; \ - } else if (k < M_C(name, _get_num)(parent) \ - && M_C(name, _get_num)(parent->kind.node[k+1]) > N/2) { \ - M_C(name, _right_shift)(parent, k); \ - return true; \ - } \ - /* Merge both nodes, removing 'k' from parent */ \ - if (k == M_C(name, _get_num)(parent)) \ - k--; \ - assert(k >= 0 && k < M_C(name, _get_num)(parent)); \ - /* Merge 'k' & 'k+1' & remove 'k' from parent */ \ - M_C(name, _merge_node)(parent, k, pass1); \ - /* Check if we need to continue */ \ - if (M_C(name, _get_num)(parent) >= N/2) \ - return true; \ - if (pit->num == 0) { \ - /* We reach the root */ \ - if (M_C(name, _get_num)(parent) == 0) { \ - /* Update root (deleted) */ \ - b->root = parent->kind.node[0]; \ - M_CALL_DEL(key_oplist, parent); \ - } \ - return true; \ - } \ - /* Next iteration */ \ - leaf = parent; \ - pass1 = false; \ - } \ - } \ - \ + parent->num --; \ + } \ + \ + /* We can also cache the index when we descend the tree. \ + TODO: Bench if this is worth the effort.*/ \ + static inline int \ + M_C(name, _search_for_node)(node_t parent, node_t child) \ + { \ + assert (!M_C(name, _is_leaf)(parent)); \ + const int num = M_C(name, _get_num)(parent); \ + for(int i = 0; i <= num; i++) { \ + if (parent->kind.node[i] == child) \ + return i; \ + } \ + assert(false); \ + return -1; /* unreachable */ \ + } \ + \ + static inline bool M_C(name, _erase)(tree_t b, key_t const key) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + pit_t pit; \ + node_t leaf = M_C(name, _search_for_leaf)(pit, b, key); \ + int k = M_C(name, _search_and_remove_in_leaf)(leaf, key); \ + /* If key is not found ==> erase failed */ \ + if (k < 0) return false; \ + /* Remove one item from the B+TREE */ \ + b->size --; \ + /* If number of keys greater than N>2 or root ==> Nothing more to do */ \ + if (M_LIKELY (M_C(name, _get_num)(leaf) >= N/2) || pit->num == 0) \ + return true; \ + /* Leaf is too small. Needs rebalancing */ \ + assert (M_C(name, _get_num)(leaf) == N/2-1); \ + bool pass1 = true; \ + while (true) { \ + assert (pit->num > 0); \ + /* Search for node 'leaf' in parent */ \ + node_t parent = pit->parent[--pit->num]; \ + assert (parent != NULL); \ + k = M_C(name, _search_for_node)(parent, leaf); \ + /* Look for the neighboor of the removed key. */ \ + /* if we can steal one key from them to keep our node balanced */ \ + if (k > 0 && M_C(name, _get_num)(parent->kind.node[k-1]) > N/2) { \ + M_C(name, _left_shift)(parent, k-1); \ + return true; \ + } else if (k < M_C(name, _get_num)(parent) \ + && M_C(name, _get_num)(parent->kind.node[k+1]) > N/2) { \ + M_C(name, _right_shift)(parent, k); \ + return true; \ + } \ + /* Merge both nodes, removing 'k' from parent */ \ + if (k == M_C(name, _get_num)(parent)) \ + k--; \ + assert(k >= 0 && k < M_C(name, _get_num)(parent)); \ + /* Merge 'k' & 'k+1' & remove 'k' from parent */ \ + M_C(name, _merge_node)(parent, k, pass1); \ + /* Check if we need to continue */ \ + if (M_C(name, _get_num)(parent) >= N/2) \ + return true; \ + if (pit->num == 0) { \ + /* We reach the root */ \ + if (M_C(name, _get_num)(parent) == 0) { \ + /* Update root (deleted) */ \ + b->root = parent->kind.node[0]; \ + M_CALL_DEL(key_oplist, parent); \ + } \ + return true; \ + } \ + /* Next iteration */ \ + leaf = parent; \ + pass1 = false; \ + } \ + } \ + \ static inline bool M_C(name, _pop_at)(value_t *ptr, tree_t b, key_t const key) \ - { \ - if (ptr != NULL) { \ - value_t *ref = M_C(name, _get)(b, key); \ - if (ref == NULL) { \ - return false; \ - } \ - M_CALL_SET(value_oplist, *ptr, *ref); \ - } \ - return M_C(name, _erase)(b, key); \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - assert (it != NULL); \ - node_t n = b->root; \ - /* Scan down the nodes */ \ - while (!M_C(name, _is_leaf)(n)) { \ - n = n->kind.node[0]; \ - } \ - it->node = n; \ - it->idx = 0; \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it, const tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - assert (it != NULL); \ - node_t n = b->root; \ - /* Scan down the nodes */ \ - while (!M_C(name, _is_leaf)(n)) { \ - n = n->kind.node[n->num]; \ - } \ - it->node = n; \ - it->idx = -n->num; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t itd, const it_t its) \ - { \ - assert (itd != NULL && its != NULL); \ - itd->node = its->node; \ - itd->idx = its->idx; \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(it_t it) \ - { \ - assert (it != NULL && it->node != NULL); \ - assert (M_C(name, _is_leaf)(it->node)); \ - return it->node->next ==NULL && it->idx >= -it->node->num; \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ - { \ - return it1->node == it2->node && it1->idx == it2->idx; \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - assert (it != NULL && it->node != NULL); \ - it->idx ++; \ - if (it->idx >= -it->node->num && it->node->next != NULL) { \ - it->node = it->node->next; \ - it->idx = 0; \ - } \ - } \ - \ - static inline subtype_t * \ - M_C(name, _ref)(it_t it) \ - { \ - assert (it != NULL && it->node != NULL); \ - assert (it->idx <= -it->node->num); \ - M_IF(isMap)( \ - it->pair.key_ptr = &it->node->key[it->idx]; \ - it->pair.value_ptr = &it->node->kind.value[it->idx]; \ - return &it->pair \ - , \ - return &it->node->key[it->idx] \ - ); \ - } \ - \ - static inline subtype_t const * \ - M_C(name, _cref)(it_t it) \ - { \ - return M_CONST_CAST(subtype_t, M_C(name, _ref)(it)); \ - } \ - \ - \ - static inline void \ - M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - assert (it != NULL); \ - pit_t pit; \ - node_t n = M_C(name, _search_for_leaf)(pit, b, key); \ - it->node = n; \ - int i; \ - BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ - for(i = 0; i < -n->num; i++) { \ - if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \ - break; \ - } \ - if (i == -n->num && n->next != NULL) { \ - it->node = n->next; \ - i = 0; \ - } \ - it->idx = i; \ - } \ - \ - static inline bool \ - M_C(name, _it_until_p)(it_t it, key_t const key) \ - { \ - assert (it != NULL); \ - node_t n = it->node; \ - if (it->idx >= -n->num) return true; \ - int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \ - return (cmp >= 0); \ - } \ - \ - static inline bool \ - M_C(name, _it_while_p)(it_t it, key_t const key) \ - { \ - assert (it != NULL); \ - node_t n = it->node; \ - if (it->idx >= -n->num) return false; \ - int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \ - return (cmp <= 0); \ - } \ - \ - static inline bool M_ATTR_DEPRECATED \ - M_C(name, _it_to_p)(it_t it, key_t const key) \ - { \ - return M_C(name, _it_until_p)(it, key); \ - } \ - \ - static inline value_t * \ - M_C(name, _min)(const tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - assert (b->size > 0); \ - node_t n = b->root; \ - /* Scan down the nodes */ \ - while (!M_C(name, _is_leaf)(n)) { \ - n = n->kind.node[0]; \ - } \ - return &n->M_IF(isMap)(kind.value, key)[0]; \ - } \ - \ - static inline value_t * \ - M_C(name, _max)(const tree_t b) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - node_t n = b->root; \ - /* Scan down the nodes */ \ - while (!M_C(name, _is_leaf)(n)) { \ - n = n->kind.node[n->num]; \ - } \ - return &n->M_IF(isMap)(kind.value, key)[-n->num-1]; \ - } \ - \ - static inline value_t const * \ - M_C(name, _cmin)(const tree_t tree) \ - { \ - return M_CONST_CAST(value_t, M_C(name, _min)(tree)); \ - } \ - \ - static inline value_t const * \ - M_C(name, _cmax)(const tree_t tree) \ - { \ - return M_CONST_CAST(value_t, M_C(name, _max)(tree)); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(tree_t b, tree_t ref) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \ - assert (b != NULL && b != ref); \ - b->size = ref->size; \ - b->root = ref->root; \ - ref->root = NULL; \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - } \ - \ - static inline void \ - M_C(name, _move)(tree_t b, tree_t ref) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \ - assert (b != ref); \ - M_C(name,_clear)(b); \ - M_C(name,_init_move)(b, ref); \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ - } \ - \ - static inline void \ - M_C(name, _swap)(tree_t tree1, tree_t tree2) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \ - M_SWAP(size_t, tree1->size, tree2->size); \ - M_SWAP(node_t, tree1->root, tree2->root); \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \ - } \ - \ + { \ + if (ptr != NULL) { \ + value_t *ref = M_C(name, _get)(b, key); \ + if (ref == NULL) { \ + return false; \ + } \ + M_CALL_SET(value_oplist, *ptr, *ref); \ + } \ + return M_C(name, _erase)(b, key); \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + assert (it != NULL); \ + node_t n = b->root; \ + /* Scan down the nodes */ \ + while (!M_C(name, _is_leaf)(n)) { \ + n = n->kind.node[0]; \ + } \ + it->node = n; \ + it->idx = 0; \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it, const tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + assert (it != NULL); \ + node_t n = b->root; \ + /* Scan down the nodes */ \ + while (!M_C(name, _is_leaf)(n)) { \ + n = n->kind.node[n->num]; \ + } \ + it->node = n; \ + it->idx = -n->num; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t itd, const it_t its) \ + { \ + assert (itd != NULL && its != NULL); \ + itd->node = its->node; \ + itd->idx = its->idx; \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(it_t it) \ + { \ + assert (it != NULL && it->node != NULL); \ + assert (M_C(name, _is_leaf)(it->node)); \ + return it->node->next ==NULL && it->idx >= -it->node->num; \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ + { \ + return it1->node == it2->node && it1->idx == it2->idx; \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + assert (it != NULL && it->node != NULL); \ + it->idx ++; \ + if (it->idx >= -it->node->num && it->node->next != NULL) { \ + it->node = it->node->next; \ + it->idx = 0; \ + } \ + } \ + \ + static inline subtype_t * \ + M_C(name, _ref)(it_t it) \ + { \ + assert (it != NULL && it->node != NULL); \ + assert (it->idx <= -it->node->num); \ + M_IF(isMap)( \ + it->pair.key_ptr = &it->node->key[it->idx]; \ + it->pair.value_ptr = &it->node->kind.value[it->idx]; \ + return &it->pair \ + , \ + return &it->node->key[it->idx] \ + ); \ + } \ + \ + static inline subtype_t const * \ + M_C(name, _cref)(it_t it) \ + { \ + return M_CONST_CAST(subtype_t, M_C(name, _ref)(it)); \ + } \ + \ + \ + static inline void \ + M_C(name, _it_from)(it_t it, const tree_t b, key_t const key) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + assert (it != NULL); \ + pit_t pit; \ + node_t n = M_C(name, _search_for_leaf)(pit, b, key); \ + it->node = n; \ + int i; \ + BPTREEI_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ + for(i = 0; i < -n->num; i++) { \ + if (M_CALL_CMP(key_oplist, key, n->key[i]) <= 0) \ + break; \ + } \ + if (i == -n->num && n->next != NULL) { \ + it->node = n->next; \ + i = 0; \ + } \ + it->idx = i; \ + } \ + \ + static inline bool \ + M_C(name, _it_until_p)(it_t it, key_t const key) \ + { \ + assert (it != NULL); \ + node_t n = it->node; \ + if (it->idx >= -n->num) return true; \ + int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \ + return (cmp >= 0); \ + } \ + \ + static inline bool \ + M_C(name, _it_while_p)(it_t it, key_t const key) \ + { \ + assert (it != NULL); \ + node_t n = it->node; \ + if (it->idx >= -n->num) return false; \ + int cmp = M_CALL_CMP(key_oplist, n->key[it->idx], key); \ + return (cmp <= 0); \ + } \ + \ + static inline bool M_ATTR_DEPRECATED \ + M_C(name, _it_to_p)(it_t it, key_t const key) \ + { \ + return M_C(name, _it_until_p)(it, key); \ + } \ + \ + static inline value_t * \ + M_C(name, _min)(const tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + assert (b->size > 0); \ + node_t n = b->root; \ + /* Scan down the nodes */ \ + while (!M_C(name, _is_leaf)(n)) { \ + n = n->kind.node[0]; \ + } \ + return &n->M_IF(isMap)(kind.value, key)[0]; \ + } \ + \ + static inline value_t * \ + M_C(name, _max)(const tree_t b) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + node_t n = b->root; \ + /* Scan down the nodes */ \ + while (!M_C(name, _is_leaf)(n)) { \ + n = n->kind.node[n->num]; \ + } \ + return &n->M_IF(isMap)(kind.value, key)[-n->num-1]; \ + } \ + \ + static inline value_t const * \ + M_C(name, _cmin)(const tree_t tree) \ + { \ + return M_CONST_CAST(value_t, M_C(name, _min)(tree)); \ + } \ + \ + static inline value_t const * \ + M_C(name, _cmax)(const tree_t tree) \ + { \ + return M_CONST_CAST(value_t, M_C(name, _max)(tree)); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(tree_t b, tree_t ref) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \ + assert (b != NULL && b != ref); \ + b->size = ref->size; \ + b->root = ref->root; \ + ref->root = NULL; \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + } \ + \ + static inline void \ + M_C(name, _move)(tree_t b, tree_t ref) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, ref); \ + assert (b != ref); \ + M_C(name,_clear)(b); \ + M_C(name,_init_move)(b, ref); \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, b); \ + } \ + \ + static inline void \ + M_C(name, _swap)(tree_t tree1, tree_t tree2) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \ + M_SWAP(size_t, tree1->size, tree2->size); \ + M_SWAP(node_t, tree1->root, tree2->root); \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, tree1); \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, tree2); \ + } \ + \ BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) /* Define additional functions. Do not used any fields but the already defined methods */ #define BPTREEI_FUNC_ADDITIONAL_DEF2(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ - \ - M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)( \ - static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t2); \ - if (t1->size != t2->size) return false; \ - if (t1->size == 0) return true; \ - /* Slow comparaison */ \ - it_t it1; \ - it_t it2; \ - /* NOTE: We can't compare two trees directly as they can be \ - structuraly different but functionnaly equal (you get this by \ - constructing the tree in a different way). We have to \ - compare the ordered value within the tree. */ \ - M_C(name, _it)(it1, t1); \ - M_C(name, _it)(it2, t2); \ - while (!M_C(name, _end_p)(it1) \ - && !M_C(name, _end_p)(it2)) { \ - const subtype_t *ref1 = M_C(name, _cref)(it1); \ - const subtype_t *ref2 = M_C(name, _cref)(it2); \ - M_IF(isMap)( \ - if (!M_CALL_EQUAL(key_oplist, *ref1->key_ptr, *ref2->key_ptr)) \ - return false; \ - if (!M_CALL_EQUAL(value_oplist, *ref1->value_ptr, *ref2->value_ptr)) \ - return false; \ - , \ - if (!M_CALL_EQUAL(key_oplist, *ref1, *ref2)) \ - return false; \ - ) \ - M_C(name, _next)(it1); \ - M_C(name, _next)(it2); \ - } \ - return M_C(name, _end_p)(it1) \ - && M_C(name, _end_p)(it2); \ - } \ - , /* NO EQUAL METHOD */ ) \ - \ - M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)( \ - static inline size_t M_C(name,_hash)(const tree_t t1) { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - M_HASH_DECL(hash); \ - /* NOTE: We can't compute the hash directly for the same reason \ - than for EQUAL operator. */ \ - it_t it1; \ - M_C(name, _it)(it1, t1); \ - while (!M_C(name, _end_p)(it1)) { \ - subtype_t const *ref1 = M_C(name, _cref)(it1); \ - M_IF(isMap)( \ - M_HASH_UP(hash, M_CALL_HASH(key_oplist, *ref1->key_ptr)); \ + \ + M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)( \ + static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t2); \ + if (t1->size != t2->size) return false; \ + if (t1->size == 0) return true; \ + /* Slow comparaison */ \ + it_t it1; \ + it_t it2; \ + /* NOTE: We can't compare two trees directly as they can be \ + structuraly different but functionnaly equal (you get this by \ + constructing the tree in a different way). We have to \ + compare the ordered value within the tree. */ \ + M_C(name, _it)(it1, t1); \ + M_C(name, _it)(it2, t2); \ + while (!M_C(name, _end_p)(it1) \ + && !M_C(name, _end_p)(it2)) { \ + const subtype_t *ref1 = M_C(name, _cref)(it1); \ + const subtype_t *ref2 = M_C(name, _cref)(it2); \ + M_IF(isMap)( \ + if (!M_CALL_EQUAL(key_oplist, *ref1->key_ptr, *ref2->key_ptr)) \ + return false; \ + if (!M_CALL_EQUAL(value_oplist, *ref1->value_ptr, *ref2->value_ptr)) \ + return false; \ + , \ + if (!M_CALL_EQUAL(key_oplist, *ref1, *ref2)) \ + return false; \ + ) \ + M_C(name, _next)(it1); \ + M_C(name, _next)(it2); \ + } \ + return M_C(name, _end_p)(it1) \ + && M_C(name, _end_p)(it2); \ + } \ + , /* NO EQUAL METHOD */ ) \ + \ + M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)( \ + static inline size_t M_C(name,_hash)(const tree_t t1) { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + M_HASH_DECL(hash); \ + /* NOTE: We can't compute the hash directly for the same reason \ + than for EQUAL operator. */ \ + it_t it1; \ + M_C(name, _it)(it1, t1); \ + while (!M_C(name, _end_p)(it1)) { \ + subtype_t const *ref1 = M_C(name, _cref)(it1); \ + M_IF(isMap)( \ + M_HASH_UP(hash, M_CALL_HASH(key_oplist, *ref1->key_ptr)); \ M_HASH_UP(hash, M_CALL_HASH(value_oplist, *ref1->value_ptr)); \ - , \ - M_HASH_UP(hash, M_CALL_HASH(key_oplist, *ref1)); \ - ) \ - M_C(name, _next)(it1); \ - } \ - return M_HASH_FINAL (hash); \ - } \ - , /* NO HASH METHOD */ ) \ - \ - M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ - static inline void M_C(name, _get_str)(string_t str, \ - const tree_t t1, bool append) { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - assert(str != NULL); \ - (append ? string_cat_str : string_set_str) (str, "["); \ - /* NOTE: The print is really naive, and not really efficient */ \ - bool commaToPrint = false; \ - it_t it; \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)) { \ - if (commaToPrint) \ - string_push_back (str, M_GET_SEPARATOR key_oplist); \ - commaToPrint = true; \ - subtype_t const *ref1 = M_C(name, _cref)(it); \ - M_IF(isMap)( \ - M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \ - string_cat_str(str, ":"); \ - M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \ - , \ - M_CALL_GET_STR(key_oplist, str, *ref1, true); \ - ); \ - } \ - string_push_back (str, ']'); \ - } \ - , /* NO GET_STR */ ) \ - \ - M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *file, tree_t const t1) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - assert (file != NULL); \ - fputc ('[', file); \ - bool commaToPrint = false; \ - it_t it; \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - if (commaToPrint) \ - fputc (M_GET_SEPARATOR key_oplist, file); \ - commaToPrint = true; \ - subtype_t const *ref1 = M_C(name, _cref)(it); \ - M_IF(isMap)( \ - M_CALL_OUT_STR(key_oplist, file, *ref1->key_ptr); \ - fputc (':', file); \ - M_CALL_OUT_STR(value_oplist, file, *ref1->value_ptr) \ - , \ - M_CALL_OUT_STR(key_oplist, file, *ref1); \ - ); \ - } \ - fputc (']', file); \ - } \ - , /* no out_str */ ) \ - \ - M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ - static inline bool \ - M_C(name, _parse_str)(tree_t t1, const char str[], const char **endp) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - assert (str != NULL); \ - M_C(name,_clean)(t1); \ - bool success = false; \ - int c = *str++; \ - if (M_UNLIKELY (c != '[')) goto exit; \ - c = *str++; \ - if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \ - if (M_UNLIKELY (c == 0)) goto exit; \ - str--; \ - key_t key; \ - M_CALL_INIT(key_oplist, key); \ - M_IF(isMap)(value_t value; \ - M_CALL_INIT(value_oplist, value); \ - , /* No isMap */) \ - do { \ - bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \ - do { c = *str++; } while (isspace(c)); \ - if (b == false) goto exit_clear; \ - M_IF(isMap)(if (c != ':') goto exit_clear; \ - b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ - do { c = *str++; } while (isspace(c)); \ - if (b == false || c == 0) goto exit_clear; \ - M_C(name, _set_at)(t1, key, value); \ - , \ - M_C(name, _push)(t1, key); \ - ) \ - } while (c == M_GET_SEPARATOR key_oplist); \ - success = (c == ']'); \ - exit_clear: \ - M_CALL_CLEAR(key_oplist, key); \ - M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); , /* No isMap */ ) \ - exit: \ - if (endp) *endp = str; \ - return success; \ - } \ - , /* no parse_str */ ) \ - \ - M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ - static inline bool \ - M_C(name, _in_str)(tree_t t1, FILE *file) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - assert (file != NULL); \ - M_C(name,_clean)(t1); \ - int c = fgetc(file); \ - if (M_UNLIKELY (c != '[')) return false; \ - c = fgetc(file); \ - if (M_UNLIKELY (c == ']')) return true; \ - if (M_UNLIKELY (c == EOF)) return false; \ - ungetc(c, file); \ - key_t key; \ - M_CALL_INIT (key_oplist, key); \ - M_IF(isMap)(value_t value; \ - M_CALL_INIT (value_oplist, value); \ - ,) \ - do { \ - bool b = M_CALL_IN_STR(key_oplist, key, file); \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false) break; \ - M_IF(isMap)(if (c!=':') break; \ - b = M_CALL_IN_STR(value_oplist,value, file); \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false || c == EOF) break; \ - M_C(name, _set_at)(t1, key, value) \ - , \ - M_C(name, _push)(t1, key) \ - ); \ - } while (c == M_GET_SEPARATOR key_oplist); \ - M_CALL_CLEAR(key_oplist, key); \ - M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); \ - ,) \ - return c == ']'; \ - } \ - , /* no in_str */ ) \ - \ - M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_return_code_t ret; \ - m_serial_local_t local; \ - subtype_t const *item; \ - bool first_done = false; \ - it_t it; \ - /* Format is different between associative container \ - & set container */ \ - M_IF(isMap)( \ - ret = f->m_interface->write_map_start(local, f, t1->size); \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_map_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item->key_ptr); \ - ret |= f->m_interface->write_map_value(local, f); \ + , \ + M_HASH_UP(hash, M_CALL_HASH(key_oplist, *ref1)); \ + ) \ + M_C(name, _next)(it1); \ + } \ + return M_HASH_FINAL (hash); \ + } \ + , /* NO HASH METHOD */ ) \ + \ + M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ + static inline void M_C(name, _get_str)(string_t str, \ + const tree_t t1, bool append) { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + assert(str != NULL); \ + (append ? string_cat_str : string_set_str) (str, "["); \ + /* NOTE: The print is really naive, and not really efficient */ \ + bool commaToPrint = false; \ + it_t it; \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)) { \ + if (commaToPrint) \ + string_push_back (str, M_GET_SEPARATOR key_oplist); \ + commaToPrint = true; \ + subtype_t const *ref1 = M_C(name, _cref)(it); \ + M_IF(isMap)( \ + M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \ + string_cat_str(str, ":"); \ + M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \ + , \ + M_CALL_GET_STR(key_oplist, str, *ref1, true); \ + ); \ + } \ + string_push_back (str, ']'); \ + } \ + , /* NO GET_STR */ ) \ + \ + M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *file, tree_t const t1) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + assert (file != NULL); \ + fputc ('[', file); \ + bool commaToPrint = false; \ + it_t it; \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + if (commaToPrint) \ + fputc (M_GET_SEPARATOR key_oplist, file); \ + commaToPrint = true; \ + subtype_t const *ref1 = M_C(name, _cref)(it); \ + M_IF(isMap)( \ + M_CALL_OUT_STR(key_oplist, file, *ref1->key_ptr); \ + fputc (':', file); \ + M_CALL_OUT_STR(value_oplist, file, *ref1->value_ptr) \ + , \ + M_CALL_OUT_STR(key_oplist, file, *ref1); \ + ); \ + } \ + fputc (']', file); \ + } \ + , /* no out_str */ ) \ + \ + M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ + static inline bool \ + M_C(name, _parse_str)(tree_t t1, const char str[], const char **endp) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + assert (str != NULL); \ + M_C(name,_clean)(t1); \ + bool success = false; \ + int c = *str++; \ + if (M_UNLIKELY (c != '[')) goto exit; \ + c = *str++; \ + if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \ + if (M_UNLIKELY (c == 0)) goto exit; \ + str--; \ + key_t key; \ + M_CALL_INIT(key_oplist, key); \ + M_IF(isMap)(value_t value; \ + M_CALL_INIT(value_oplist, value); \ + , /* No isMap */) \ + do { \ + bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \ + do { c = *str++; } while (isspace(c)); \ + if (b == false) goto exit_clear; \ + M_IF(isMap)(if (c != ':') goto exit_clear; \ + b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ + do { c = *str++; } while (isspace(c)); \ + if (b == false || c == 0) goto exit_clear; \ + M_C(name, _set_at)(t1, key, value); \ + , \ + M_C(name, _push)(t1, key); \ + ) \ + } while (c == M_GET_SEPARATOR key_oplist); \ + success = (c == ']'); \ + exit_clear: \ + M_CALL_CLEAR(key_oplist, key); \ + M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); , /* No isMap */ ) \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } \ + , /* no parse_str */ ) \ + \ + M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ + static inline bool \ + M_C(name, _in_str)(tree_t t1, FILE *file) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + assert (file != NULL); \ + M_C(name,_clean)(t1); \ + int c = fgetc(file); \ + if (M_UNLIKELY (c != '[')) return false; \ + c = fgetc(file); \ + if (M_UNLIKELY (c == ']')) return true; \ + if (M_UNLIKELY (c == EOF)) return false; \ + ungetc(c, file); \ + key_t key; \ + M_CALL_INIT (key_oplist, key); \ + M_IF(isMap)(value_t value; \ + M_CALL_INIT (value_oplist, value); \ + ,) \ + do { \ + bool b = M_CALL_IN_STR(key_oplist, key, file); \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false) break; \ + M_IF(isMap)(if (c!=':') break; \ + b = M_CALL_IN_STR(value_oplist,value, file); \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false || c == EOF) break; \ + M_C(name, _set_at)(t1, key, value) \ + , \ + M_C(name, _push)(t1, key) \ + ); \ + } while (c == M_GET_SEPARATOR key_oplist); \ + M_CALL_CLEAR(key_oplist, key); \ + M_IF(isMap)(M_CALL_CLEAR(value_oplist, value); \ + ,) \ + return c == ']'; \ + } \ + , /* no in_str */ ) \ + \ + M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_return_code_t ret; \ + m_serial_local_t local; \ + subtype_t const *item; \ + bool first_done = false; \ + it_t it; \ + /* Format is different between associative container \ + & set container */ \ + M_IF(isMap)( \ + ret = f->m_interface->write_map_start(local, f, t1->size); \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_map_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item->key_ptr); \ + ret |= f->m_interface->write_map_value(local, f); \ ret |= M_CALL_OUT_SERIAL(value_oplist, f, *item->value_ptr); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_map_end(local, f); \ - , \ - ret = f->m_interface->write_array_start(local, f, t1->size); \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_array_end(local, f); \ - ) \ - return ret & M_SERIAL_FAIL; \ - } \ - , /* no OUT_SERIAL */ ) \ - \ - M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \ - { \ - BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - size_t estimated_size = 0; \ - key_t key; \ - M_C(name,_clean)(t1); \ - M_IF(isMap)( \ - value_t value; \ + first_done = true; \ + } \ + ret |= f->m_interface->write_map_end(local, f); \ + , \ + ret = f->m_interface->write_array_start(local, f, t1->size); \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_array_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \ + first_done = true; \ + } \ + ret |= f->m_interface->write_array_end(local, f); \ + ) \ + return ret & M_SERIAL_FAIL; \ + } \ + , /* no OUT_SERIAL */ ) \ + \ + M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \ + { \ + BPTREEI_CONTRACT(N, isMulti, key_oplist, t1); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + size_t estimated_size = 0; \ + key_t key; \ + M_C(name,_clean)(t1); \ + M_IF(isMap)( \ + value_t value; \ ret = f->m_interface->read_map_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - M_CALL_INIT(key_oplist, key); \ - M_CALL_INIT (value_oplist, value); \ - do { \ - ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ - if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ - ret = f->m_interface->read_map_value(local, f); \ - if (ret != M_SERIAL_OK_CONTINUE) return M_SERIAL_FAIL; \ - ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ - if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ - M_C(name, _set_at)(t1, key, value); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + M_CALL_INIT(key_oplist, key); \ + M_CALL_INIT (value_oplist, value); \ + do { \ + ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ + if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ + ret = f->m_interface->read_map_value(local, f); \ + if (ret != M_SERIAL_OK_CONTINUE) return M_SERIAL_FAIL; \ + ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ + if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ + M_C(name, _set_at)(t1, key, value); \ } while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(key_oplist, key); \ - M_CALL_CLEAR(value_oplist, value); \ - , \ + M_CALL_CLEAR(key_oplist, key); \ + M_CALL_CLEAR(value_oplist, value); \ + , \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - M_CALL_INIT(key_oplist, key); \ - do { \ - ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ - if (ret != M_SERIAL_OK_DONE) { break; } \ - M_C(name, _push)(t1, key); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + M_CALL_INIT(key_oplist, key); \ + do { \ + ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ + if (ret != M_SERIAL_OK_DONE) { break; } \ + M_C(name, _push)(t1, key); \ } while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(key_oplist, key); \ - ) /* End of IF isMap */ \ - return ret; \ - } \ - , /* no in_serial */ ) \ - \ + M_CALL_CLEAR(key_oplist, key); \ + ) /* End of IF isMap */ \ + return ret; \ + } \ + , /* no in_serial */ ) \ + \ #endif diff --git a/m-buffer.h b/m-buffer.h index 245b77d6..28256daa 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -53,9 +53,9 @@ typedef enum { /* Define a lock based buffer. USAGE: BUFFER_DEF(name, type, size_of_buffer_or_0, policy[, oplist]) */ -#define BUFFER_DEF(name, type, m_size, ... ) \ - M_BEGIN_PROTECTED_CODE \ - BUFFERI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BUFFER_DEF(name, type, m_size, ... ) \ + M_BEGIN_PROTECTED_CODE \ + BUFFERI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), M_C(name,_t)), \ (name, type, m_size,__VA_ARGS__, M_C(name,_t)))) \ M_END_PROTECTED_CODE @@ -64,9 +64,9 @@ typedef enum { /* Define a lock based buffer as the provided type name_t. USAGE: BUFFER_DEF_AS(name, name_t, type, size_of_buffer_or_0, policy[, oplist]) */ -#define BUFFER_DEF_AS(name, name_t, type, m_size, ... ) \ - M_BEGIN_PROTECTED_CODE \ - BUFFERI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define BUFFER_DEF_AS(name, name_t, type, m_size, ... ) \ + M_BEGIN_PROTECTED_CODE \ + BUFFERI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, type, m_size,__VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \ (name, type, m_size,__VA_ARGS__, name_t ))) \ M_END_PROTECTED_CODE @@ -74,9 +74,9 @@ typedef enum { /* Define the oplist of a lock based buffer given its name and its oplist. USAGE: BUFFER_OPLIST(name[, oplist of the type]) */ -#define BUFFER_OPLIST(...) \ - BUFFERI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST), \ +#define BUFFER_OPLIST(...) \ + BUFFERI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST), \ (__VA_ARGS__ ))) @@ -84,9 +84,9 @@ typedef enum { Much faster than queue of BUFFER_DEF in heavy communication scenario Size of created queue can only a power of 2. */ -#define QUEUE_MPMC_DEF(name, type, ...) \ - M_BEGIN_PROTECTED_CODE \ - QUEUEI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define QUEUE_MPMC_DEF(name, type, ...) \ + M_BEGIN_PROTECTED_CODE \ + QUEUEI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), M_C(name,_t)), \ (name, type, __VA_ARGS__, M_C(name,_t)))) \ M_END_PROTECTED_CODE @@ -97,9 +97,9 @@ typedef enum { Much faster than queue of BUFFER_DEF in heavy communication scenario Size of created queue can only a power of 2. */ -#define QUEUE_MPMC_DEF_AS(name, name_t, type, ...) \ - M_BEGIN_PROTECTED_CODE \ - QUEUEI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define QUEUE_MPMC_DEF_AS(name, name_t, type, ...) \ + M_BEGIN_PROTECTED_CODE \ + QUEUEI_MPMC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \ (name, type, __VA_ARGS__, name_t ))) \ M_END_PROTECTED_CODE @@ -109,9 +109,9 @@ typedef enum { Much faster than queue of BUFFER_DEF in heavy communication scenario Size of created queue can only a power of 2. */ -#define QUEUE_SPSC_DEF(name, type, ...) \ - M_BEGIN_PROTECTED_CODE \ - QUEUEI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define QUEUE_SPSC_DEF(name, type, ...) \ + M_BEGIN_PROTECTED_CODE \ + QUEUEI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), M_C(name,_t)), \ (name, type, __VA_ARGS__, M_C(name,_t)))) \ M_END_PROTECTED_CODE @@ -122,9 +122,9 @@ typedef enum { Much faster than queue of BUFFER_DEF in heavy communication scenario Size of created queue can only a power of 2. */ -#define QUEUE_SPSC_DEF_AS(name, name_t, type, ...) \ - M_BEGIN_PROTECTED_CODE \ - QUEUEI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define QUEUE_SPSC_DEF_AS(name, name_t, type, ...) \ + M_BEGIN_PROTECTED_CODE \ + QUEUEI_SPSC_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t ), \ (name, type, __VA_ARGS__, name_t ))) \ M_END_PROTECTED_CODE @@ -137,16 +137,16 @@ typedef enum { #define BUFFERI_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size)) #define BUFFERI_SIZE(m_size) BUFFERI_IF_CTE_SIZE(m_size) (m_size, v->size) -#define BUFFERI_POLICY_P(policy, val) \ +#define BUFFERI_POLICY_P(policy, val) \ (((policy) & (val)) != 0) -#define BUFFERI_CONTRACT(buffer, size) do { \ - assert (buffer != NULL); \ - assert (buffer->data != NULL); \ +#define BUFFERI_CONTRACT(buffer, size) do { \ + assert (buffer != NULL); \ + assert (buffer->data != NULL); \ }while (0) -#define BUFFERI_PROTECTED_CONTRACT(buffer, size) do { \ - assert (atomic_load(&buffer->number[0]) <= BUFFERI_SIZE(size)); \ +#define BUFFERI_PROTECTED_CONTRACT(buffer, size) do { \ + assert (atomic_load(&buffer->number[0]) <= BUFFERI_SIZE(size)); \ } while (0) /* Deferred evaluation for the definition, @@ -154,11 +154,11 @@ typedef enum { #define BUFFERI_DEF_P1(arg) BUFFERI_DEF_P2 arg /* Validate the value oplist before going further */ -#define BUFFERI_DEF_P2(name, type, m_size, policy, oplist, buffer_t) \ +#define BUFFERI_DEF_P2(name, type, m_size, policy, oplist, buffer_t) \ M_IF_OPLIST(oplist)(BUFFERI_DEF_P3, BUFFERI_DEF_FAILURE)(name, type, m_size, policy, oplist, buffer_t) /* Stop processing with a compilation failure */ -#define BUFFERI_DEF_FAILURE(name, type, m_size, policy, oplist, buffer_t) \ +#define BUFFERI_DEF_FAILURE(name, type, m_size, policy, oplist, buffer_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(BUFFER_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) /* Define the buffer type using mutex lock and its functions. @@ -169,473 +169,473 @@ typedef enum { - oplist: the oplist of the type of an element of the buffer - buffer_t: name of the buffer */ -#define BUFFERI_DEF_P3(name, type, m_size, policy, oplist, buffer_t) \ - \ - typedef struct M_C(name, _s) { \ - m_mutex_t mutexPush; /* MUTEX used for pushing elements */ \ - size_t idx_prod; /* Index of the production threads */ \ - size_t overwrite; /* Number of overwritten values */ \ - m_cond_t there_is_data; /* condition raised when there is data */ \ - m_cond_t there_is_room_for_data; /* Cond. raised when there is room */ \ - m_mutex_t mutexPop; /* MUTEX used for popping elements */ \ - size_t idx_cons; /* Index of the consumption threads */ \ - BUFFERI_IF_CTE_SIZE(m_size)( ,size_t size;) /* Size of the buffer */ \ - /* number[0] := Number of elements in the buffer */ \ +#define BUFFERI_DEF_P3(name, type, m_size, policy, oplist, buffer_t) \ + \ + typedef struct M_C(name, _s) { \ + m_mutex_t mutexPush; /* MUTEX used for pushing elements */ \ + size_t idx_prod; /* Index of the production threads */ \ + size_t overwrite; /* Number of overwritten values */ \ + m_cond_t there_is_data; /* condition raised when there is data */ \ + m_cond_t there_is_room_for_data; /* Cond. raised when there is room */ \ + m_mutex_t mutexPop; /* MUTEX used for popping elements */ \ + size_t idx_cons; /* Index of the consumption threads */ \ + BUFFERI_IF_CTE_SIZE(m_size)( ,size_t size;) /* Size of the buffer */ \ + /* number[0] := Number of elements in the buffer */ \ /* number[1] := [OPTION] Number of elements being deferred in the buffer */ \ - atomic_ulong number[1 + BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \ - /* If fixed size, array of elements, otherwise pointer to element */ \ - BUFFERI_IF_CTE_SIZE(m_size)(type data[m_size], type *data); \ - } buffer_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 used to unconst the buffer */ \ + atomic_ulong number[1 + BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)]; \ + /* If fixed size, array of elements, otherwise pointer to element */ \ + BUFFERI_IF_CTE_SIZE(m_size)(type data[m_size], type *data); \ + } buffer_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 used to unconst the buffer */ \ typedef union { M_C(name, _srcptr) cptr; M_C(name, _ptr) ptr; } M_C(name, _uptr_ct); \ - /* Internal types used by the oplist */ \ - typedef type M_C(name, _subtype_ct); \ - typedef buffer_t M_C(name, _ct); \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ -static inline void \ -M_C(name, _init)(buffer_t v, size_t size) \ -{ \ - BUFFERI_IF_CTE_SIZE(m_size)(assert(size == m_size), v->size = size); \ - v->idx_prod = v->idx_cons = v->overwrite = 0; \ - atomic_init (&v->number[0], 0UL); \ - if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ - atomic_init (&v->number[1], 0UL); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_init(v->mutexPush); \ - m_mutex_init(v->mutexPop); \ - m_cond_init(v->there_is_data); \ - m_cond_init(v->there_is_room_for_data); \ - } else { \ - assert(BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING)); \ - } \ - \ - BUFFERI_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \ - v->data = M_CALL_REALLOC(oplist, type, NULL, BUFFERI_SIZE(m_size)); \ - if (v->data == NULL) { \ - M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \ - return; \ - } \ - ) \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(size_t i = 0; i < size; i++) { \ - M_CALL_INIT(oplist, v->data[i]); \ - } \ - } \ - BUFFERI_CONTRACT(v,m_size); \ -} \ - \ - BUFFERI_IF_CTE_SIZE(m_size)( \ - static inline void \ - M_C(name, _int_init)(buffer_t v) \ - { \ - M_C(name, _init)(v, m_size); \ - } \ - , ) \ - \ - static inline void \ - M_C(name, _int_clear_obj)(buffer_t v) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \ - M_CALL_CLEAR(oplist, v->data[i]); \ - } \ - } else { \ - size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \ - while (i != v->idx_prod) { \ - M_CALL_CLEAR(oplist, v->data[i]); \ - i++; \ + /* Internal types used by the oplist */ \ + typedef type M_C(name, _subtype_ct); \ + typedef buffer_t M_C(name, _ct); \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ +static inline void \ +M_C(name, _init)(buffer_t v, size_t size) \ +{ \ + BUFFERI_IF_CTE_SIZE(m_size)(assert(size == m_size), v->size = size); \ + v->idx_prod = v->idx_cons = v->overwrite = 0; \ + atomic_init (&v->number[0], 0UL); \ + if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ + atomic_init (&v->number[1], 0UL); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_init(v->mutexPush); \ + m_mutex_init(v->mutexPop); \ + m_cond_init(v->there_is_data); \ + m_cond_init(v->there_is_room_for_data); \ + } else { \ + assert(BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING)); \ + } \ + \ + BUFFERI_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \ + v->data = M_CALL_REALLOC(oplist, type, NULL, BUFFERI_SIZE(m_size)); \ + if (v->data == NULL) { \ + M_MEMORY_FULL (BUFFERI_SIZE(m_size)*sizeof(type)); \ + return; \ + } \ + ) \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(size_t i = 0; i < size; i++) { \ + M_CALL_INIT(oplist, v->data[i]); \ + } \ + } \ + BUFFERI_CONTRACT(v,m_size); \ +} \ + \ + BUFFERI_IF_CTE_SIZE(m_size)( \ + static inline void \ + M_C(name, _int_init)(buffer_t v) \ + { \ + M_C(name, _init)(v, m_size); \ + } \ + , ) \ + \ + static inline void \ + M_C(name, _int_clear_obj)(buffer_t v) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \ + M_CALL_CLEAR(oplist, v->data[i]); \ + } \ + } else { \ + size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \ + while (i != v->idx_prod) { \ + M_CALL_CLEAR(oplist, v->data[i]); \ + i++; \ if (!BUFFERI_POLICY_P((policy), BUFFER_STACK) && i >= BUFFERI_SIZE(m_size)) \ - i = 0; \ - } \ - } \ - v->idx_prod = v->idx_cons = 0; \ - atomic_store_explicit (&v->number[0], 0UL, memory_order_relaxed); \ - if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ - atomic_store_explicit(&v->number[1], 0UL, memory_order_relaxed); \ - BUFFERI_CONTRACT(v,m_size); \ - } \ - \ - static inline void \ - M_C(name, _clear)(buffer_t v) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - M_C(name, _int_clear_obj)(v); \ - BUFFERI_IF_CTE_SIZE(m_size)( , \ - M_CALL_FREE(oplist, v->data); \ - v->data = NULL; \ - ) \ - v->overwrite = 0; \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_clear(v->mutexPush); \ - m_mutex_clear(v->mutexPop); \ - m_cond_clear(v->there_is_data); \ - m_cond_clear(v->there_is_room_for_data); \ - } \ - } \ - \ - static inline void \ - M_C(name, _clean)(buffer_t v) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - } \ - BUFFERI_PROTECTED_CONTRACT(v, m_size); \ - if (BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) \ - M_C(name, _int_clear_obj)(v); \ - v->idx_prod = v->idx_cons = 0; \ - atomic_store_explicit (&v->number[0], 0UL, memory_order_relaxed); \ - if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ - atomic_store_explicit(&v->number[1], 0UL, memory_order_relaxed); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - } \ - BUFFERI_CONTRACT(v,m_size); \ - } \ - \ - static inline void \ - M_C(name, _init_set)(buffer_t dest, const buffer_t src) \ - { \ - /* unconst 'src', so that we can lock it (semantically it is const) */ \ - M_C(name, _uptr_ct) vu; \ - vu.cptr = src; \ - M_C(name, _ptr) v = vu.ptr; \ - assert (dest != v); \ - BUFFERI_CONTRACT(v,m_size); \ - M_C(name, _init)(dest, BUFFERI_SIZE(m_size)); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - } \ - \ - BUFFERI_PROTECTED_CONTRACT(v, m_size); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \ - M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ - } \ - } else { \ - size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \ - while (i != v->idx_prod) { \ - M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ - i++; \ + i = 0; \ + } \ + } \ + v->idx_prod = v->idx_cons = 0; \ + atomic_store_explicit (&v->number[0], 0UL, memory_order_relaxed); \ + if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ + atomic_store_explicit(&v->number[1], 0UL, memory_order_relaxed); \ + BUFFERI_CONTRACT(v,m_size); \ + } \ + \ + static inline void \ + M_C(name, _clear)(buffer_t v) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + M_C(name, _int_clear_obj)(v); \ + BUFFERI_IF_CTE_SIZE(m_size)( , \ + M_CALL_FREE(oplist, v->data); \ + v->data = NULL; \ + ) \ + v->overwrite = 0; \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_clear(v->mutexPush); \ + m_mutex_clear(v->mutexPop); \ + m_cond_clear(v->there_is_data); \ + m_cond_clear(v->there_is_room_for_data); \ + } \ + } \ + \ + static inline void \ + M_C(name, _clean)(buffer_t v) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ + } \ + BUFFERI_PROTECTED_CONTRACT(v, m_size); \ + if (BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) \ + M_C(name, _int_clear_obj)(v); \ + v->idx_prod = v->idx_cons = 0; \ + atomic_store_explicit (&v->number[0], 0UL, memory_order_relaxed); \ + if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ + atomic_store_explicit(&v->number[1], 0UL, memory_order_relaxed); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ + } \ + BUFFERI_CONTRACT(v,m_size); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(buffer_t dest, const buffer_t src) \ + { \ + /* unconst 'src', so that we can lock it (semantically it is const) */ \ + M_C(name, _uptr_ct) vu; \ + vu.cptr = src; \ + M_C(name, _ptr) v = vu.ptr; \ + assert (dest != v); \ + BUFFERI_CONTRACT(v,m_size); \ + M_C(name, _init)(dest, BUFFERI_SIZE(m_size)); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ + } \ + \ + BUFFERI_PROTECTED_CONTRACT(v, m_size); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \ + M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ + } \ + } else { \ + size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \ + while (i != v->idx_prod) { \ + M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ + i++; \ if (!BUFFERI_POLICY_P((policy), BUFFER_STACK) && i >= BUFFERI_SIZE(m_size)) \ - i = 0; \ - } \ - } \ - \ - dest->idx_prod = v->idx_prod; \ - dest->idx_cons = v->idx_cons; \ + i = 0; \ + } \ + } \ + \ + dest->idx_prod = v->idx_prod; \ + dest->idx_cons = v->idx_cons; \ atomic_store_explicit (&dest->number[0], atomic_load(&v->number[0]), memory_order_relaxed); \ - if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ + if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ atomic_store_explicit(&dest->number[1], atomic_load(&v->number[1]), memory_order_relaxed); \ - \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - } \ - BUFFERI_CONTRACT(v,m_size); \ - BUFFERI_CONTRACT(dest, m_size); \ - } \ - \ - static inline void \ - M_C(name, _set)(buffer_t dest, const buffer_t src) \ - { \ - /* unconst 'src', so that we can lock it (semantically it is const) */ \ - M_C(name, _uptr_ct) vu; \ - vu.cptr = src; \ - M_C(name, _ptr) v = vu.ptr; \ - BUFFERI_CONTRACT(dest,m_size); \ - BUFFERI_CONTRACT(v,m_size); \ - \ - if (dest == v) return; \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - /* Case of deadlock: A := B, B:=C, C:=A (all in //) \ - Solution: order the lock by increasing memory */ \ - if (dest < v) { \ - m_mutex_lock(dest->mutexPush); \ - m_mutex_lock(dest->mutexPop); \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - } else { \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - m_mutex_lock(dest->mutexPush); \ - m_mutex_lock(dest->mutexPop); \ - } \ - } \ - \ - BUFFERI_PROTECTED_CONTRACT(v, m_size); \ - M_C(name, _int_clear_obj)(dest); \ - \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \ - M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ - } \ - } else { \ - size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \ - while (i != v->idx_prod) { \ - M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ - i++; \ + \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ + } \ + BUFFERI_CONTRACT(v,m_size); \ + BUFFERI_CONTRACT(dest, m_size); \ + } \ + \ + static inline void \ + M_C(name, _set)(buffer_t dest, const buffer_t src) \ + { \ + /* unconst 'src', so that we can lock it (semantically it is const) */ \ + M_C(name, _uptr_ct) vu; \ + vu.cptr = src; \ + M_C(name, _ptr) v = vu.ptr; \ + BUFFERI_CONTRACT(dest,m_size); \ + BUFFERI_CONTRACT(v,m_size); \ + \ + if (dest == v) return; \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + /* Case of deadlock: A := B, B:=C, C:=A (all in //) \ + Solution: order the lock by increasing memory */ \ + if (dest < v) { \ + m_mutex_lock(dest->mutexPush); \ + m_mutex_lock(dest->mutexPop); \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ + } else { \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ + m_mutex_lock(dest->mutexPush); \ + m_mutex_lock(dest->mutexPop); \ + } \ + } \ + \ + BUFFERI_PROTECTED_CONTRACT(v, m_size); \ + M_C(name, _int_clear_obj)(dest); \ + \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(size_t i = 0; i < BUFFERI_SIZE(m_size); i++) { \ + M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ + } \ + } else { \ + size_t i = BUFFERI_POLICY_P((policy), BUFFER_STACK) ? 0 : v->idx_cons; \ + while (i != v->idx_prod) { \ + M_CALL_INIT_SET(oplist, dest->data[i], v->data[i]); \ + i++; \ if (!BUFFERI_POLICY_P((policy), BUFFER_STACK) && i >= BUFFERI_SIZE(m_size)) \ - i = 0; \ - } \ - } \ - \ - dest->idx_prod = v->idx_prod; \ - dest->idx_cons = v->idx_cons; \ + i = 0; \ + } \ + } \ + \ + dest->idx_prod = v->idx_prod; \ + dest->idx_cons = v->idx_cons; \ atomic_store_explicit (&dest->number[0], atomic_load(&v->number[0]), memory_order_relaxed); \ - if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ + if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ atomic_store_explicit(&dest->number[1], atomic_load(&v->number[1]), memory_order_relaxed); \ - \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - /* It may be false, but it is not wrong! */ \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_cond_broadcast(v->there_is_data); \ - if (dest < v) { \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - m_mutex_unlock(dest->mutexPop); \ - m_mutex_unlock(dest->mutexPush); \ - } else { \ - m_mutex_unlock(dest->mutexPop); \ - m_mutex_unlock(dest->mutexPush); \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - } \ - } \ - BUFFERI_CONTRACT(v,m_size); \ - BUFFERI_CONTRACT(dest, m_size); \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(buffer_t v) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - /* If the buffer has been configured with deferred pop \ - we considered the queue as empty when the number of \ - deferred pop has reached 0, not the number of items in the \ - buffer is 0. */ \ - if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ - return atomic_load_explicit (&v->number[1], memory_order_relaxed) == 0; \ - else \ - return atomic_load_explicit (&v->number[0], memory_order_relaxed) == 0; \ - } \ - \ - static inline bool \ - M_C(name, _full_p)(buffer_t v) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - return atomic_load_explicit (&v->number[0], memory_order_relaxed) \ - == BUFFERI_SIZE(m_size); \ - } \ - \ - static inline size_t \ - M_C(name, _size)(buffer_t v) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - return atomic_load_explicit (&v->number[0], memory_order_relaxed); \ - } \ - \ - static inline bool \ - M_C(name, _push_blocking)(buffer_t v, type const data, bool blocking) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - \ - /* BUFFER lock */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPush); \ - while (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \ - && M_C(name, _full_p)(v)) { \ - if (!blocking) { \ - m_mutex_unlock(v->mutexPush); \ - return false; \ - } \ - m_cond_wait(v->there_is_room_for_data, v->mutexPush); \ - } \ - } else if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \ - && M_C(name, _full_p)(v)) \ - return false; \ - BUFFERI_PROTECTED_CONTRACT(v, m_size); \ - \ - size_t previousSize, idx = v->idx_prod; \ - /* INDEX computation if we have to overwrite the last element */ \ - if (M_UNLIKELY (BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \ - && M_C(name, _full_p)(v))) { \ - v->overwrite++; \ - /* Let's overwrite the last element */ \ - /* Compute the index of the last push element */ \ - idx--; \ - if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \ - idx = idx >= BUFFERI_SIZE(m_size) ? BUFFERI_SIZE(m_size)-1 : idx; \ - } \ - /* Update data in the buffer */ \ - M_CALL_SET(oplist, v->data[idx], data); \ - previousSize = BUFFERI_SIZE(m_size); \ - \ - } else { \ - \ - /* Add a new item in the buffer */ \ - /* PUSH data in the buffer */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, v->data[idx], data); \ - } else { \ - M_CALL_INIT_SET(oplist, v->data[idx], data); \ - } \ - \ - /* Increment production INDEX of the buffer */ \ - idx++; \ - if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \ - idx = (idx == BUFFERI_SIZE(m_size)) ? 0 : idx; \ - } \ - v->idx_prod = idx; \ - \ - /* number[] is the only variable which can be modified by both \ - the consummer thread which has the pop lock and the producer \ - thread which has the push lock. As such, it has to be handled \ - like an atomic variable. */ \ - /* Increment number of elements of the buffer */ \ - previousSize = atomic_fetch_add (&v->number[0], 1UL); \ - if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \ - previousSize = atomic_fetch_add (&v->number[1], 1UL); \ - } \ - } \ - \ - /* BUFFER unlock */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_unlock(v->mutexPush); \ - /* If the number of items in the buffer was 0, some consummer \ - may be waiting. Signal to them the availibility of the data \ - We cannot only signal one thread. */ \ - if (previousSize == 0) { \ - m_mutex_lock(v->mutexPop); \ - m_cond_broadcast(v->there_is_data); \ - m_mutex_unlock(v->mutexPop); \ - } \ - } \ - \ - BUFFERI_CONTRACT(v,m_size); \ - return true; \ - } \ - \ - static inline bool \ - M_C(name, _pop_blocking)(type *data, buffer_t v, bool blocking) \ - { \ - BUFFERI_CONTRACT(v,m_size); \ - assert (data != NULL); \ - \ - /* BUFFER lock */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPop); \ - while (M_C(name, _empty_p)(v)) { \ - if (!blocking) { \ - m_mutex_unlock(v->mutexPop); \ - return false; \ - } \ - m_cond_wait(v->there_is_data, v->mutexPop); \ - } \ - } else if (M_C(name, _empty_p)(v)) \ - return false; \ - BUFFERI_PROTECTED_CONTRACT(v, m_size); \ - \ - /* POP data from the buffer and update INDEX */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \ - /* FIFO queue */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, *data, v->data[v->idx_cons]); \ - } else { \ - M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons]); \ - } \ + \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + /* It may be false, but it is not wrong! */ \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_cond_broadcast(v->there_is_data); \ + if (dest < v) { \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ + m_mutex_unlock(dest->mutexPop); \ + m_mutex_unlock(dest->mutexPush); \ + } else { \ + m_mutex_unlock(dest->mutexPop); \ + m_mutex_unlock(dest->mutexPush); \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ + } \ + } \ + BUFFERI_CONTRACT(v,m_size); \ + BUFFERI_CONTRACT(dest, m_size); \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(buffer_t v) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + /* If the buffer has been configured with deferred pop \ + we considered the queue as empty when the number of \ + deferred pop has reached 0, not the number of items in the \ + buffer is 0. */ \ + if (BUFFERI_POLICY_P(policy, BUFFER_DEFERRED_POP)) \ + return atomic_load_explicit (&v->number[1], memory_order_relaxed) == 0; \ + else \ + return atomic_load_explicit (&v->number[0], memory_order_relaxed) == 0; \ + } \ + \ + static inline bool \ + M_C(name, _full_p)(buffer_t v) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + return atomic_load_explicit (&v->number[0], memory_order_relaxed) \ + == BUFFERI_SIZE(m_size); \ + } \ + \ + static inline size_t \ + M_C(name, _size)(buffer_t v) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + return atomic_load_explicit (&v->number[0], memory_order_relaxed); \ + } \ + \ + static inline bool \ + M_C(name, _push_blocking)(buffer_t v, type const data, bool blocking) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + \ + /* BUFFER lock */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_lock(v->mutexPush); \ + while (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \ + && M_C(name, _full_p)(v)) { \ + if (!blocking) { \ + m_mutex_unlock(v->mutexPush); \ + return false; \ + } \ + m_cond_wait(v->there_is_room_for_data, v->mutexPush); \ + } \ + } else if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \ + && M_C(name, _full_p)(v)) \ + return false; \ + BUFFERI_PROTECTED_CONTRACT(v, m_size); \ + \ + size_t previousSize, idx = v->idx_prod; \ + /* INDEX computation if we have to overwrite the last element */ \ + if (M_UNLIKELY (BUFFERI_POLICY_P((policy), BUFFER_PUSH_OVERWRITE) \ + && M_C(name, _full_p)(v))) { \ + v->overwrite++; \ + /* Let's overwrite the last element */ \ + /* Compute the index of the last push element */ \ + idx--; \ + if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \ + idx = idx >= BUFFERI_SIZE(m_size) ? BUFFERI_SIZE(m_size)-1 : idx; \ + } \ + /* Update data in the buffer */ \ + M_CALL_SET(oplist, v->data[idx], data); \ + previousSize = BUFFERI_SIZE(m_size); \ + \ + } else { \ + \ + /* Add a new item in the buffer */ \ + /* PUSH data in the buffer */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, v->data[idx], data); \ + } else { \ + M_CALL_INIT_SET(oplist, v->data[idx], data); \ + } \ + \ + /* Increment production INDEX of the buffer */ \ + idx++; \ + if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \ + idx = (idx == BUFFERI_SIZE(m_size)) ? 0 : idx; \ + } \ + v->idx_prod = idx; \ + \ + /* number[] is the only variable which can be modified by both \ + the consummer thread which has the pop lock and the producer \ + thread which has the push lock. As such, it has to be handled \ + like an atomic variable. */ \ + /* Increment number of elements of the buffer */ \ + previousSize = atomic_fetch_add (&v->number[0], 1UL); \ + if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \ + previousSize = atomic_fetch_add (&v->number[1], 1UL); \ + } \ + } \ + \ + /* BUFFER unlock */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_unlock(v->mutexPush); \ + /* If the number of items in the buffer was 0, some consummer \ + may be waiting. Signal to them the availibility of the data \ + We cannot only signal one thread. */ \ + if (previousSize == 0) { \ + m_mutex_lock(v->mutexPop); \ + m_cond_broadcast(v->there_is_data); \ + m_mutex_unlock(v->mutexPop); \ + } \ + } \ + \ + BUFFERI_CONTRACT(v,m_size); \ + return true; \ + } \ + \ + static inline bool \ + M_C(name, _pop_blocking)(type *data, buffer_t v, bool blocking) \ + { \ + BUFFERI_CONTRACT(v,m_size); \ + assert (data != NULL); \ + \ + /* BUFFER lock */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_lock(v->mutexPop); \ + while (M_C(name, _empty_p)(v)) { \ + if (!blocking) { \ + m_mutex_unlock(v->mutexPop); \ + return false; \ + } \ + m_cond_wait(v->there_is_data, v->mutexPop); \ + } \ + } else if (M_C(name, _empty_p)(v)) \ + return false; \ + BUFFERI_PROTECTED_CONTRACT(v, m_size); \ + \ + /* POP data from the buffer and update INDEX */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_STACK)) { \ + /* FIFO queue */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, *data, v->data[v->idx_cons]); \ + } else { \ + M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons]); \ + } \ v->idx_cons = (v->idx_cons == BUFFERI_SIZE(m_size)-1) ? 0 : (v->idx_cons + 1); \ - } else { \ - /* STACK queue */ \ - v->idx_prod --; \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, *data, v->data[v->idx_prod]); \ - } else { \ - M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod]); \ - } \ - } \ - \ - /* number[] is the only variable which can be modified by both \ - the consummer thread which has the pop lock and the producer \ - thread which has the push lock. As such, it has to be handled \ - like an atomic variable. */ \ - /* Decrement number of elements in the buffer */ \ - size_t previousSize; \ - if (!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \ - previousSize = atomic_fetch_sub (&v->number[0], 1UL); \ - } else { \ - atomic_fetch_sub (&v->number[1], 1UL); \ - } \ - \ - /* BUFFER unlock */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ - m_mutex_unlock(v->mutexPop); \ - /* If the number of items in the buffer was the max, some producer \ - may be waiting. Signal to them the availibility of the free room \ - We cannot only signal one thread. */ \ - if ((!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \ - && previousSize == BUFFERI_SIZE(m_size)) { \ - m_mutex_lock(v->mutexPush); \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_mutex_unlock(v->mutexPush); \ - } \ - } \ - \ - BUFFERI_CONTRACT(v,m_size); \ - return true; \ - } \ - \ - \ - static inline bool \ - M_C(name, _push)(buffer_t v, type const data) \ - { \ - return M_C(name, _push_blocking)(v, data, \ + } else { \ + /* STACK queue */ \ + v->idx_prod --; \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, *data, v->data[v->idx_prod]); \ + } else { \ + M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod]); \ + } \ + } \ + \ + /* number[] is the only variable which can be modified by both \ + the consummer thread which has the pop lock and the producer \ + thread which has the push lock. As such, it has to be handled \ + like an atomic variable. */ \ + /* Decrement number of elements in the buffer */ \ + size_t previousSize; \ + if (!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \ + previousSize = atomic_fetch_sub (&v->number[0], 1UL); \ + } else { \ + atomic_fetch_sub (&v->number[1], 1UL); \ + } \ + \ + /* BUFFER unlock */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_THREAD_UNSAFE)) { \ + m_mutex_unlock(v->mutexPop); \ + /* If the number of items in the buffer was the max, some producer \ + may be waiting. Signal to them the availibility of the free room \ + We cannot only signal one thread. */ \ + if ((!BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) \ + && previousSize == BUFFERI_SIZE(m_size)) { \ + m_mutex_lock(v->mutexPush); \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_mutex_unlock(v->mutexPush); \ + } \ + } \ + \ + BUFFERI_CONTRACT(v,m_size); \ + return true; \ + } \ + \ + \ + static inline bool \ + M_C(name, _push)(buffer_t v, type const data) \ + { \ + return M_C(name, _push_blocking)(v, data, \ !BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_PUSH)); \ - } \ - \ - static inline bool \ - M_C(name, _pop)(type *data, buffer_t v) \ - { \ - return M_C(name, _pop_blocking)(data, v, \ + } \ + \ + static inline bool \ + M_C(name, _pop)(type *data, buffer_t v) \ + { \ + return M_C(name, _pop_blocking)(data, v, \ !BUFFERI_POLICY_P((policy), BUFFER_UNBLOCKING_POP)); \ - } \ - \ - static inline size_t \ - M_C(name, _overwrite)(const buffer_t v) \ - { \ - return v->overwrite; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity)(const buffer_t v) \ - { \ - (void) v; /* may be unused */ \ - return BUFFERI_SIZE(m_size); \ - } \ - \ - static inline void \ - M_C(name, _pop_release)(buffer_t v) \ - { \ - /* Decrement the effective number of elements in the buffer */ \ - if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \ - size_t previousSize = atomic_fetch_sub (&v->number[0], 1UL); \ - if (previousSize == BUFFERI_SIZE(m_size)) { \ - m_mutex_lock(v->mutexPush); \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_mutex_unlock(v->mutexPush); \ - } \ - } \ - } \ + } \ + \ + static inline size_t \ + M_C(name, _overwrite)(const buffer_t v) \ + { \ + return v->overwrite; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(const buffer_t v) \ + { \ + (void) v; /* may be unused */ \ + return BUFFERI_SIZE(m_size); \ + } \ + \ + static inline void \ + M_C(name, _pop_release)(buffer_t v) \ + { \ + /* Decrement the effective number of elements in the buffer */ \ + if (BUFFERI_POLICY_P((policy), BUFFER_DEFERRED_POP)) { \ + size_t previousSize = atomic_fetch_sub (&v->number[0], 1UL); \ + if (previousSize == BUFFERI_SIZE(m_size)) { \ + m_mutex_lock(v->mutexPush); \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_mutex_unlock(v->mutexPush); \ + } \ + } \ + } \ @@ -654,24 +654,24 @@ M_C(name, _init)(buffer_t v, size_t size) \ #define QUEUEI_MPMC_DEF_P1(arg) QUEUEI_MPMC_DEF_P2 arg /* Validate the value oplist before going further */ -#define QUEUEI_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \ +#define QUEUEI_MPMC_DEF_P2(name, type, policy, oplist, buffer_t) \ M_IF_OPLIST(oplist)(QUEUEI_MPMC_DEF_P3, QUEUEI_MPMC_DEF_FAILURE)(name, type, policy, oplist, buffer_t) /* Stop processing with a compilation failure */ -#define QUEUEI_MPMC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \ +#define QUEUEI_MPMC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(QUEUE_MPMC_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) #ifdef NDEBUG # define QUEUEI_MPMC_CONTRACT(v) /* nothing */ #else -# define QUEUEI_MPMC_CONTRACT(v) do { \ - assert (v != 0); \ - assert (v->Tab != NULL); \ - unsigned int _r = atomic_load(&v->ConsoIdx); \ - unsigned int _w = atomic_load(&v->ProdIdx); \ - _r = atomic_load(&v->ConsoIdx); \ - assert (_r > _w || _w-_r <= v->size); \ - assert (M_POWEROF2_P(v->size)); \ +# define QUEUEI_MPMC_CONTRACT(v) do { \ + assert (v != 0); \ + assert (v->Tab != NULL); \ + unsigned int _r = atomic_load(&v->ConsoIdx); \ + unsigned int _w = atomic_load(&v->ProdIdx); \ + _r = atomic_load(&v->ConsoIdx); \ + assert (_r > _w || _w-_r <= v->size); \ + assert (M_POWEROF2_P(v->size)); \ } while (0) #endif @@ -683,180 +683,180 @@ M_C(name, _init)(buffer_t v, size_t size) \ - oplist: the oplist of the type of an element of the buffer - buffer_t: name of the buffer */ -#define QUEUEI_MPMC_DEF_P3(name, type, policy, oplist, buffer_t) \ - \ - /* The sequence number of an element will be equal to either \ - - 2* the index of the production which creates it, \ - - 1 + 2* the index of the consumption which consummes it \ - In case of wrapping, as there is no order comparison but only \ - equal comparison, there is no special issue. \ - Each element is put in a separate cache line to avoid false \ - sharing. \ - */ \ - typedef struct M_C(name, _el_s) { \ - atomic_uint seq; /* Can only increase until wrapping */ \ - type x; \ - M_CACHELINE_ALIGN(align, atomic_uint, type); \ - } M_C(name, _el_t); \ - \ - /* If there is only one producer and one consummer, then they won't \ - typically use the same cache line, increasing performance. */ \ - typedef struct M_C(name, _s) { \ - atomic_uint ProdIdx; /* Can only increase until wrapping */ \ - M_CACHELINE_ALIGN(align1, atomic_uint); \ - atomic_uint ConsoIdx; /* Can only increase until wrapping */ \ - M_CACHELINE_ALIGN(align2, atomic_uint); \ - M_C(name, _el_t) *Tab; \ - unsigned int size; \ - } buffer_t[1]; \ - \ - typedef type M_C(name, _subtype_ct); \ - typedef buffer_t M_C(name, _ct); \ - \ - static inline bool \ - M_C(name, _push)(buffer_t table, type const x) \ - { \ - QUEUEI_MPMC_CONTRACT(table); \ - unsigned int idx = atomic_load_explicit(&table->ProdIdx, \ - memory_order_relaxed); \ - const unsigned int i = idx & (table->size -1); \ - const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \ - memory_order_acquire); \ - if (M_UNLIKELY (2*(idx - table->size) + 1 != seq)) { \ - /* Buffer full (or unlikely preemption). Can not push */ \ - return false; \ - } \ +#define QUEUEI_MPMC_DEF_P3(name, type, policy, oplist, buffer_t) \ + \ + /* The sequence number of an element will be equal to either \ + - 2* the index of the production which creates it, \ + - 1 + 2* the index of the consumption which consummes it \ + In case of wrapping, as there is no order comparison but only \ + equal comparison, there is no special issue. \ + Each element is put in a separate cache line to avoid false \ + sharing. \ + */ \ + typedef struct M_C(name, _el_s) { \ + atomic_uint seq; /* Can only increase until wrapping */ \ + type x; \ + M_CACHELINE_ALIGN(align, atomic_uint, type); \ + } M_C(name, _el_t); \ + \ + /* If there is only one producer and one consummer, then they won't \ + typically use the same cache line, increasing performance. */ \ + typedef struct M_C(name, _s) { \ + atomic_uint ProdIdx; /* Can only increase until wrapping */ \ + M_CACHELINE_ALIGN(align1, atomic_uint); \ + atomic_uint ConsoIdx; /* Can only increase until wrapping */ \ + M_CACHELINE_ALIGN(align2, atomic_uint); \ + M_C(name, _el_t) *Tab; \ + unsigned int size; \ + } buffer_t[1]; \ + \ + typedef type M_C(name, _subtype_ct); \ + typedef buffer_t M_C(name, _ct); \ + \ + static inline bool \ + M_C(name, _push)(buffer_t table, type const x) \ + { \ + QUEUEI_MPMC_CONTRACT(table); \ + unsigned int idx = atomic_load_explicit(&table->ProdIdx, \ + memory_order_relaxed); \ + const unsigned int i = idx & (table->size -1); \ + const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \ + memory_order_acquire); \ + if (M_UNLIKELY (2*(idx - table->size) + 1 != seq)) { \ + /* Buffer full (or unlikely preemption). Can not push */ \ + return false; \ + } \ if (M_UNLIKELY (!atomic_compare_exchange_strong_explicit(&table->ProdIdx, \ - &idx, idx+1, memory_order_relaxed, memory_order_relaxed))) { \ - /* Thread has been preempted by another one. */ \ - return false; \ - } \ - /* If it is interrupted here, it may block pop method (not push) */ \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, table->Tab[i].x, x); \ - } else { \ - M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \ - } \ - /* Finish transaction */ \ - atomic_store_explicit(&table->Tab[i].seq, 2*idx, memory_order_release); \ - QUEUEI_MPMC_CONTRACT(table); \ - return true; \ - } \ - \ - static inline bool \ - M_C(name, _pop)(type *ptr, buffer_t table) \ - { \ - QUEUEI_MPMC_CONTRACT(table); \ - assert (ptr != NULL); \ - unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \ - memory_order_relaxed); \ - const unsigned int i = (iC & (table->size -1)); \ - const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \ - memory_order_acquire); \ - if (seq != 2 * iC) { \ - /* Nothing in buffer to consumme (or unlikely preemption) */ \ - return false; \ - } \ + &idx, idx+1, memory_order_relaxed, memory_order_relaxed))) { \ + /* Thread has been preempted by another one. */ \ + return false; \ + } \ + /* If it is interrupted here, it may block pop method (not push) */ \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, table->Tab[i].x, x); \ + } else { \ + M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \ + } \ + /* Finish transaction */ \ + atomic_store_explicit(&table->Tab[i].seq, 2*idx, memory_order_release); \ + QUEUEI_MPMC_CONTRACT(table); \ + return true; \ + } \ + \ + static inline bool \ + M_C(name, _pop)(type *ptr, buffer_t table) \ + { \ + QUEUEI_MPMC_CONTRACT(table); \ + assert (ptr != NULL); \ + unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \ + memory_order_relaxed); \ + const unsigned int i = (iC & (table->size -1)); \ + const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \ + memory_order_acquire); \ + if (seq != 2 * iC) { \ + /* Nothing in buffer to consumme (or unlikely preemption) */ \ + return false; \ + } \ if (M_UNLIKELY (!atomic_compare_exchange_strong_explicit(&table->ConsoIdx, \ - &iC, iC+1, memory_order_relaxed, memory_order_relaxed))) { \ - /* Thread has been preempted by another one */ \ - return false; \ - } \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, *ptr, table->Tab[i].x); \ - } else { \ - M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ - } \ + &iC, iC+1, memory_order_relaxed, memory_order_relaxed))) { \ + /* Thread has been preempted by another one */ \ + return false; \ + } \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, *ptr, table->Tab[i].x); \ + } else { \ + M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ + } \ atomic_store_explicit(&table->Tab[i].seq, 2*iC + 1, memory_order_release); \ - QUEUEI_MPMC_CONTRACT(table); \ - return true; \ - } \ - \ - static inline void \ - M_C(name, _init)(buffer_t buffer, size_t size) \ - { \ - assert (buffer != NULL); \ - assert( M_POWEROF2_P(size)); \ - assert (0 < size && size <= UINT_MAX); \ + QUEUEI_MPMC_CONTRACT(table); \ + return true; \ + } \ + \ + static inline void \ + M_C(name, _init)(buffer_t buffer, size_t size) \ + { \ + assert (buffer != NULL); \ + assert( M_POWEROF2_P(size)); \ + assert (0 < size && size <= UINT_MAX); \ assert(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \ - atomic_init(&buffer->ProdIdx, (unsigned int) size); \ - atomic_init(&buffer->ConsoIdx, (unsigned int) size); \ - buffer->size = (unsigned int) size; \ - buffer->Tab = M_CALL_REALLOC(oplist, M_C(name, _el_t), NULL, size); \ - if (buffer->Tab == NULL) { \ - M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \ - return; \ - } \ - for(unsigned int j = 0; j < (unsigned int) size; j++) { \ - atomic_init(&buffer->Tab[j].seq, 2*j+1U); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_INIT(oplist, buffer->Tab[j].x); \ - } \ - } \ - QUEUEI_MPMC_CONTRACT(buffer); \ - } \ - \ - static inline void \ - M_C(name, _clear)(buffer_t buffer) \ - { \ - QUEUEI_MPMC_CONTRACT(buffer); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(unsigned int j = 0; j < buffer->size; j++) { \ - M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ - } \ - } else { \ + atomic_init(&buffer->ProdIdx, (unsigned int) size); \ + atomic_init(&buffer->ConsoIdx, (unsigned int) size); \ + buffer->size = (unsigned int) size; \ + buffer->Tab = M_CALL_REALLOC(oplist, M_C(name, _el_t), NULL, size); \ + if (buffer->Tab == NULL) { \ + M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \ + return; \ + } \ + for(unsigned int j = 0; j < (unsigned int) size; j++) { \ + atomic_init(&buffer->Tab[j].seq, 2*j+1U); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_INIT(oplist, buffer->Tab[j].x); \ + } \ + } \ + QUEUEI_MPMC_CONTRACT(buffer); \ + } \ + \ + static inline void \ + M_C(name, _clear)(buffer_t buffer) \ + { \ + QUEUEI_MPMC_CONTRACT(buffer); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(unsigned int j = 0; j < buffer->size; j++) { \ + M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ + } \ + } else { \ unsigned int iP = atomic_load_explicit(&buffer->ProdIdx, memory_order_relaxed); \ - unsigned int i = iP & (buffer->size -1); \ + unsigned int i = iP & (buffer->size -1); \ unsigned int iC = atomic_load_explicit(&buffer->ConsoIdx, memory_order_relaxed); \ - unsigned int j = iC & (buffer->size -1); \ - while (i != j) { \ - M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ - j++; \ - if (j >= buffer->size) \ - j = 0; \ - } \ - } \ - M_CALL_FREE(oplist, buffer->Tab); \ - buffer->Tab = NULL; /* safer */ \ - } \ - \ - static inline size_t \ - M_C(name, _size)(buffer_t table) \ - { \ - QUEUEI_MPMC_CONTRACT(table); \ + unsigned int j = iC & (buffer->size -1); \ + while (i != j) { \ + M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ + j++; \ + if (j >= buffer->size) \ + j = 0; \ + } \ + } \ + M_CALL_FREE(oplist, buffer->Tab); \ + buffer->Tab = NULL; /* safer */ \ + } \ + \ + static inline size_t \ + M_C(name, _size)(buffer_t table) \ + { \ + QUEUEI_MPMC_CONTRACT(table); \ const unsigned int iC = atomic_load_explicit(&table->ConsoIdx, memory_order_relaxed); \ const unsigned int iP = atomic_load_explicit(&table->ProdIdx, memory_order_acquire); \ - /* We return an approximation as we can't read both iC & iP atomically \ - As we read producer index after consummer index, \ - and they are atomic variables without reordering \ - producer index is always greater or equal than consumer index \ - (or on overflow occurs, in which case as we compute with modulo \ - arithmetic, the right result is computed). \ - We may return a result which is greater than the size of the queue \ - if the function is interrupted a long time between reading iC & \ - iP. the function is not protected against it. \ - */ \ - return iP-iC; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity)(buffer_t v) \ - { \ - QUEUEI_MPMC_CONTRACT(v); \ - return v->size; \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(buffer_t v) \ - { \ - return M_C(name, _size) (v) == 0; \ - } \ - \ - static inline bool \ - M_C(name, _full_p)(buffer_t v) \ - { \ - return M_C(name, _size)(v) >= v->size; \ - } \ + /* We return an approximation as we can't read both iC & iP atomically \ + As we read producer index after consummer index, \ + and they are atomic variables without reordering \ + producer index is always greater or equal than consumer index \ + (or on overflow occurs, in which case as we compute with modulo \ + arithmetic, the right result is computed). \ + We may return a result which is greater than the size of the queue \ + if the function is interrupted a long time between reading iC & \ + iP. the function is not protected against it. \ + */ \ + return iP-iC; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(buffer_t v) \ + { \ + QUEUEI_MPMC_CONTRACT(v); \ + return v->size; \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(buffer_t v) \ + { \ + return M_C(name, _size) (v) == 0; \ + } \ + \ + static inline bool \ + M_C(name, _full_p)(buffer_t v) \ + { \ + return M_C(name, _size)(v) >= v->size; \ + } \ @@ -875,24 +875,24 @@ M_C(name, _init)(buffer_t v, size_t size) \ #define QUEUEI_SPSC_DEF_P1(arg) QUEUEI_SPSC_DEF_P2 arg /* Validate the value oplist before going further */ -#define QUEUEI_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \ +#define QUEUEI_SPSC_DEF_P2(name, type, policy, oplist, buffer_t) \ M_IF_OPLIST(oplist)(QUEUEI_SPSC_DEF_P3, QUEUEI_SPSC_DEF_FAILURE)(name, type, policy, oplist, buffer_t) /* Stop processing with a compilation failure */ -#define QUEUEI_SPSC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \ +#define QUEUEI_SPSC_DEF_FAILURE(name, type, policy, oplist, buffer_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(QUEUE_SPSC_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) #ifdef NDEBUG #define QUEUEI_SPSC_CONTRACT(table) do { } while (0) #else -#define QUEUEI_SPSC_CONTRACT(table) do { \ - assert (table != NULL); \ - unsigned int _r = atomic_load(&table->consoIdx); \ - unsigned int _w = atomic_load(&table->prodIdx); \ - /* Due to overflow we don't have assert (_r <= _w); */ \ - _r = atomic_load(&table->consoIdx); \ - assert (_r > _w || _w-_r <= table->size); \ - assert (M_POWEROF2_P(table->size)); \ +#define QUEUEI_SPSC_CONTRACT(table) do { \ + assert (table != NULL); \ + unsigned int _r = atomic_load(&table->consoIdx); \ + unsigned int _w = atomic_load(&table->prodIdx); \ + /* Due to overflow we don't have assert (_r <= _w); */ \ + _r = atomic_load(&table->consoIdx); \ + assert (_r > _w || _w-_r <= table->size); \ + assert (M_POWEROF2_P(table->size)); \ } while (0) #endif @@ -903,275 +903,275 @@ M_C(name, _init)(buffer_t v, size_t size) \ - oplist: the oplist of the type of an element of the buffer - buffer_t: name of the buffer */ -#define QUEUEI_SPSC_DEF_P3(name, type, policy, oplist, buffer_t) \ - \ - typedef struct M_C(name, _el_s) { \ - type x; \ - } M_C(name, _el_t); \ - \ - typedef struct M_C(name, _s) { \ - atomic_uint consoIdx; /* Can only increase until overflow */ \ - unsigned int size; \ - M_C(name, _el_t) *Tab; \ - M_CACHELINE_ALIGN(align, atomic_uint, size_t, M_C(name, _el_t) *); \ - atomic_uint prodIdx; /* Can only increase until overflow */ \ - } buffer_t[1]; \ - \ - typedef type M_C(name, _subtype_ct); \ - typedef buffer_t M_C(name, _ct); \ - \ - static inline bool \ - M_C(name, _push)(buffer_t table, type const x) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_relaxed); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_acquire); \ - if (w-r >= table->size) \ - return false; \ - unsigned int i = w & (table->size -1); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, table->Tab[i].x, x); \ - } else { \ - M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \ - } \ - atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ - QUEUEI_SPSC_CONTRACT(table); \ - return true; \ - } \ - \ - static inline bool \ - M_C(name, _push_move)(buffer_t table, type x) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_relaxed); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_acquire); \ - if (w-r >= table->size) \ - return false; \ - unsigned int i = w & (table->size -1); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_DO_MOVE(oplist, table->Tab[i].x, x); \ - } else { \ - M_DO_INIT_MOVE(oplist, table->Tab[i].x, x); \ - } \ - atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ - QUEUEI_SPSC_CONTRACT(table); \ - return true; \ - } \ - \ - static inline bool \ - M_C(name, _pop)(type *ptr, buffer_t table) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - assert (ptr != NULL); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_relaxed); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_acquire); \ - if (w-r == 0) \ - return false; \ - unsigned int i = r & (table->size -1); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, *ptr , table->Tab[i].x); \ - } else { \ - M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ - } \ - atomic_store_explicit(&table->consoIdx, r+1, memory_order_release); \ - QUEUEI_SPSC_CONTRACT(table); \ - return true; \ - } \ - \ - static inline unsigned \ - M_C(name, _push_bulk)(buffer_t table, unsigned n, type const x[]) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - assert (x != NULL); \ - assert (n <= table->size); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_relaxed); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_acquire); \ - unsigned int max = M_MIN(n, table->size - (w-r) ); \ - if (max == 0) \ - return 0; \ - for(unsigned int k = 0; k < max; k++) { \ - unsigned int i = (w+k) & (table->size -1); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, table->Tab[i].x, x[k]); \ - } else { \ - M_CALL_INIT_SET(oplist, table->Tab[i].x, x[k]); \ - } \ - } \ - atomic_store_explicit(&table->prodIdx, w+max, memory_order_release); \ - QUEUEI_SPSC_CONTRACT(table); \ - return max; \ - } \ - \ - static inline unsigned \ - M_C(name, _pop_bulk)(unsigned int n, type ptr[], buffer_t table) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - assert (ptr != NULL); \ - assert (n <= table->size); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_relaxed); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_acquire); \ - if (w-r == 0) \ - return 0; \ - unsigned int max = M_MIN(w-r, n); \ - for(unsigned int k = 0; k < max; k++) { \ - unsigned int i = (r+k) & (table->size -1); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, ptr[k], table->Tab[i].x); \ - } else { \ - M_DO_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \ - } \ - } \ - atomic_store_explicit(&table->consoIdx, r+max, memory_order_release); \ - QUEUEI_SPSC_CONTRACT(table); \ - return max; \ - } \ - \ - static inline void \ - M_C(name, _push_force)(buffer_t table, type const x) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_relaxed); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_acquire); \ - /* If no place in queue, try to skip the last one */ \ - while (w-r >= table->size) { \ - bool b = atomic_compare_exchange_strong(&table->consoIdx, &r, r+1); \ - r += b; \ - } \ - unsigned int i = w & (table->size -1); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - M_CALL_SET(oplist, table->Tab[i].x, x); \ - } else { \ - M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \ - } \ - atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ - QUEUEI_SPSC_CONTRACT(table); \ - } \ - \ - static inline size_t \ - M_C(name, _size)(buffer_t table) \ - { \ - QUEUEI_SPSC_CONTRACT(table); \ - unsigned int r = atomic_load_explicit(&table->consoIdx, \ - memory_order_relaxed); \ - unsigned int w = atomic_load_explicit(&table->prodIdx, \ - memory_order_acquire); \ - /* We return an approximation as we can't read both r & w atomically \ - As we read producer index after consummer index, \ - and they are atomic variables without reordering \ - producer index is always greater or equal than consumer index \ - (or on overflow occurs, in which case as we compute with modulo \ - arithmetic, the right result is computed). \ - We may return a result which is greater than the size of the queue \ - if the function is interrupted a long time between reading the \ - indexs. The function is not protected against it. \ - */ \ - return w-r; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity)(buffer_t v) \ - { \ - return v->size; \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(buffer_t v) \ - { \ - return M_C(name, _size) (v) == 0; \ - } \ - \ - static inline bool \ - M_C(name, _full_p)(buffer_t v) \ - { \ - return M_C(name, _size)(v) >= v->size; \ - } \ - \ - static inline void \ - M_C(name, _init)(buffer_t buffer, size_t size) \ - { \ - assert (buffer != NULL); \ - assert( M_POWEROF2_P(size)); \ - assert (0 < size && size <= UINT_MAX); \ +#define QUEUEI_SPSC_DEF_P3(name, type, policy, oplist, buffer_t) \ + \ + typedef struct M_C(name, _el_s) { \ + type x; \ + } M_C(name, _el_t); \ + \ + typedef struct M_C(name, _s) { \ + atomic_uint consoIdx; /* Can only increase until overflow */ \ + unsigned int size; \ + M_C(name, _el_t) *Tab; \ + M_CACHELINE_ALIGN(align, atomic_uint, size_t, M_C(name, _el_t) *); \ + atomic_uint prodIdx; /* Can only increase until overflow */ \ + } buffer_t[1]; \ + \ + typedef type M_C(name, _subtype_ct); \ + typedef buffer_t M_C(name, _ct); \ + \ + static inline bool \ + M_C(name, _push)(buffer_t table, type const x) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_relaxed); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_acquire); \ + if (w-r >= table->size) \ + return false; \ + unsigned int i = w & (table->size -1); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, table->Tab[i].x, x); \ + } else { \ + M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \ + } \ + atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ + QUEUEI_SPSC_CONTRACT(table); \ + return true; \ + } \ + \ + static inline bool \ + M_C(name, _push_move)(buffer_t table, type x) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_relaxed); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_acquire); \ + if (w-r >= table->size) \ + return false; \ + unsigned int i = w & (table->size -1); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_DO_MOVE(oplist, table->Tab[i].x, x); \ + } else { \ + M_DO_INIT_MOVE(oplist, table->Tab[i].x, x); \ + } \ + atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ + QUEUEI_SPSC_CONTRACT(table); \ + return true; \ + } \ + \ + static inline bool \ + M_C(name, _pop)(type *ptr, buffer_t table) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + assert (ptr != NULL); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_relaxed); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_acquire); \ + if (w-r == 0) \ + return false; \ + unsigned int i = r & (table->size -1); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, *ptr , table->Tab[i].x); \ + } else { \ + M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ + } \ + atomic_store_explicit(&table->consoIdx, r+1, memory_order_release); \ + QUEUEI_SPSC_CONTRACT(table); \ + return true; \ + } \ + \ + static inline unsigned \ + M_C(name, _push_bulk)(buffer_t table, unsigned n, type const x[]) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + assert (x != NULL); \ + assert (n <= table->size); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_relaxed); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_acquire); \ + unsigned int max = M_MIN(n, table->size - (w-r) ); \ + if (max == 0) \ + return 0; \ + for(unsigned int k = 0; k < max; k++) { \ + unsigned int i = (w+k) & (table->size -1); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, table->Tab[i].x, x[k]); \ + } else { \ + M_CALL_INIT_SET(oplist, table->Tab[i].x, x[k]); \ + } \ + } \ + atomic_store_explicit(&table->prodIdx, w+max, memory_order_release); \ + QUEUEI_SPSC_CONTRACT(table); \ + return max; \ + } \ + \ + static inline unsigned \ + M_C(name, _pop_bulk)(unsigned int n, type ptr[], buffer_t table) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + assert (ptr != NULL); \ + assert (n <= table->size); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_relaxed); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_acquire); \ + if (w-r == 0) \ + return 0; \ + unsigned int max = M_MIN(w-r, n); \ + for(unsigned int k = 0; k < max; k++) { \ + unsigned int i = (r+k) & (table->size -1); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, ptr[k], table->Tab[i].x); \ + } else { \ + M_DO_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \ + } \ + } \ + atomic_store_explicit(&table->consoIdx, r+max, memory_order_release); \ + QUEUEI_SPSC_CONTRACT(table); \ + return max; \ + } \ + \ + static inline void \ + M_C(name, _push_force)(buffer_t table, type const x) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_relaxed); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_acquire); \ + /* If no place in queue, try to skip the last one */ \ + while (w-r >= table->size) { \ + bool b = atomic_compare_exchange_strong(&table->consoIdx, &r, r+1); \ + r += b; \ + } \ + unsigned int i = w & (table->size -1); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + M_CALL_SET(oplist, table->Tab[i].x, x); \ + } else { \ + M_CALL_INIT_SET(oplist, table->Tab[i].x, x); \ + } \ + atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ + QUEUEI_SPSC_CONTRACT(table); \ + } \ + \ + static inline size_t \ + M_C(name, _size)(buffer_t table) \ + { \ + QUEUEI_SPSC_CONTRACT(table); \ + unsigned int r = atomic_load_explicit(&table->consoIdx, \ + memory_order_relaxed); \ + unsigned int w = atomic_load_explicit(&table->prodIdx, \ + memory_order_acquire); \ + /* We return an approximation as we can't read both r & w atomically \ + As we read producer index after consummer index, \ + and they are atomic variables without reordering \ + producer index is always greater or equal than consumer index \ + (or on overflow occurs, in which case as we compute with modulo \ + arithmetic, the right result is computed). \ + We may return a result which is greater than the size of the queue \ + if the function is interrupted a long time between reading the \ + indexs. The function is not protected against it. \ + */ \ + return w-r; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(buffer_t v) \ + { \ + return v->size; \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(buffer_t v) \ + { \ + return M_C(name, _size) (v) == 0; \ + } \ + \ + static inline bool \ + M_C(name, _full_p)(buffer_t v) \ + { \ + return M_C(name, _size)(v) >= v->size; \ + } \ + \ + static inline void \ + M_C(name, _init)(buffer_t buffer, size_t size) \ + { \ + assert (buffer != NULL); \ + assert( M_POWEROF2_P(size)); \ + assert (0 < size && size <= UINT_MAX); \ assert(((policy) & (BUFFER_STACK|BUFFER_THREAD_UNSAFE|BUFFER_PUSH_OVERWRITE)) == 0); \ - atomic_init(&buffer->prodIdx, (unsigned int) size); \ - atomic_init(&buffer->consoIdx, (unsigned int) size); \ - buffer->size = (unsigned int) size; \ - buffer->Tab = M_CALL_REALLOC(oplist, M_C(name, _el_t), NULL, size); \ - if (buffer->Tab == NULL) { \ - M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \ - return; \ - } \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(unsigned int j = 0; j < (unsigned int) size; j++) { \ - M_CALL_INIT(oplist, buffer->Tab[j].x); \ - } \ - } \ - QUEUEI_SPSC_CONTRACT(buffer); \ - } \ - \ - static inline void \ - M_C(name, _clear)(buffer_t buffer) \ - { \ - QUEUEI_SPSC_CONTRACT(buffer); \ - if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ - for(unsigned int j = 0; j < buffer->size; j++) { \ - M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ - } \ - } else { \ + atomic_init(&buffer->prodIdx, (unsigned int) size); \ + atomic_init(&buffer->consoIdx, (unsigned int) size); \ + buffer->size = (unsigned int) size; \ + buffer->Tab = M_CALL_REALLOC(oplist, M_C(name, _el_t), NULL, size); \ + if (buffer->Tab == NULL) { \ + M_MEMORY_FULL (size*sizeof(M_C(name, _el_t) )); \ + return; \ + } \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(unsigned int j = 0; j < (unsigned int) size; j++) { \ + M_CALL_INIT(oplist, buffer->Tab[j].x); \ + } \ + } \ + QUEUEI_SPSC_CONTRACT(buffer); \ + } \ + \ + static inline void \ + M_C(name, _clear)(buffer_t buffer) \ + { \ + QUEUEI_SPSC_CONTRACT(buffer); \ + if (!BUFFERI_POLICY_P((policy), BUFFER_PUSH_INIT_POP_MOVE)) { \ + for(unsigned int j = 0; j < buffer->size; j++) { \ + M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ + } \ + } else { \ unsigned int iP = atomic_load_explicit(&buffer->prodIdx, memory_order_relaxed); \ - unsigned int i = iP & (buffer->size -1); \ + unsigned int i = iP & (buffer->size -1); \ unsigned int iC = atomic_load_explicit(&buffer->consoIdx, memory_order_relaxed); \ - unsigned int j = iC & (buffer->size -1); \ - while (i != j) { \ - M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ - j++; \ - if (j >= buffer->size) \ - j = 0; \ - } \ - } \ - M_CALL_FREE(oplist, buffer->Tab); \ - buffer->Tab = NULL; /* safer */ \ - } \ - \ + unsigned int j = iC & (buffer->size -1); \ + while (i != j) { \ + M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ + j++; \ + if (j >= buffer->size) \ + j = 0; \ + } \ + } \ + M_CALL_FREE(oplist, buffer->Tab); \ + buffer->Tab = NULL; /* safer */ \ + } \ + \ /* Deferred evaluation for the definition, so that all arguments are evaluated before further expansion */ #define BUFFERI_OPLIST_P1(arg) BUFFERI_OPLIST_P2 arg /* Validation of the given oplist */ -#define BUFFERI_OPLIST_P2(name, oplist) \ +#define BUFFERI_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(BUFFERI_OPLIST_P3, BUFFERI_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define BUFFERI_OPLIST_FAILURE(name, oplist) \ +#define BUFFERI_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_BUFFER_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a buffer */ -#define BUFFERI_OPLIST_P3(name, oplist) \ - (INIT(M_C(name, _int_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)) \ - ,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)) \ +#define BUFFERI_OPLIST_P3(name, oplist) \ + (INIT(M_C(name, _int_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)) \ + ,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)) \ ) diff --git a/m-c-mempool.h b/m-c-mempool.h index ed2802df..c88dea8d 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -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); \ + } \ /***********************************************************************/ diff --git a/m-concurrent.h b/m-concurrent.h index b0f277e8..ecb05130 100644 --- a/m-concurrent.h +++ b/m-concurrent.h @@ -32,9 +32,9 @@ /* Define a protected concurrent container and its associated functions based on the given container. USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */ -#define CONCURRENT_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - CONCURRENTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define CONCURRENT_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + CONCURRENTI_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 @@ -43,9 +43,9 @@ /* Define a protected concurrent container and its associated functions based on the given container as the given name name_t USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */ -#define CONCURRENT_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - CONCURRENTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define CONCURRENT_DEF_AS(name, name_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + CONCURRENTI_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 @@ -53,9 +53,9 @@ /* Define the oplist of a protected concurrent container given its name and its oplist. USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */ -#define CONCURRENT_OPLIST(...) \ - CONCURRENTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST), \ +#define CONCURRENT_OPLIST(...) \ + CONCURRENTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST), \ (__VA_ARGS__ ))) @@ -63,9 +63,9 @@ based on its given container. Operations that perform only read of the container can be done in parallel. USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */ -#define CONCURRENT_RP_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - CONCURRENTI_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define CONCURRENT_RP_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + CONCURRENTI_RP_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 @@ -76,9 +76,9 @@ based on its given container. Operations that perform only read of the container can be done in parallel. USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */ -#define CONCURRENT_RP_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - CONCURRENTI_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define CONCURRENT_RP_DEF_AS(name, name_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + CONCURRENTI_RP_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 @@ -95,7 +95,7 @@ M_IF_OPLIST(oplist)(CONCURRENTI_OPLIST_P3, CONCURRENTI_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \ +#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition @@ -103,48 +103,48 @@ container (_get returns a pointer to an internal data, data that may be destroyed by another thread). */ -#define CONCURRENTI_OPLIST_P3(name, oplist) \ - (M_IF_METHOD(INIT, oplist)(INIT(M_C(name, _init)),) \ - ,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_C(name, _init_set)),) \ - ,M_IF_METHOD(SET, oplist)(SET(M_C(name, _set)),) \ - ,M_IF_METHOD(CLEAR, oplist)(CLEAR(M_C(name, _clear)),) \ - ,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \ - ,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \ - ,M_IF_METHOD(SWAP,oplist)(SWAP(M_C(name, _swap)),) \ - ,TYPE(M_C(name,_ct)) \ - ,SUBTYPE(M_C(name, _subtype_ct)) \ - ,OPLIST(oplist) \ - ,M_IF_METHOD(TEST_EMPTY, oplist)(TEST_EMPTY(M_C(name,_empty_p)),) \ - ,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_C(name,_size)),) \ - ,M_IF_METHOD(CLEAN, oplist)(CLEAN(M_C(name,_clean)),) \ - ,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \ - ,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \ - ,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \ +#define CONCURRENTI_OPLIST_P3(name, oplist) \ + (M_IF_METHOD(INIT, oplist)(INIT(M_C(name, _init)),) \ + ,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_C(name, _init_set)),) \ + ,M_IF_METHOD(SET, oplist)(SET(M_C(name, _set)),) \ + ,M_IF_METHOD(CLEAR, oplist)(CLEAR(M_C(name, _clear)),) \ + ,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_C(name, _init_move)),) \ + ,M_IF_METHOD(MOVE, oplist)(MOVE(M_C(name, _move)),) \ + ,M_IF_METHOD(SWAP,oplist)(SWAP(M_C(name, _swap)),) \ + ,TYPE(M_C(name,_ct)) \ + ,SUBTYPE(M_C(name, _subtype_ct)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(TEST_EMPTY, oplist)(TEST_EMPTY(M_C(name,_empty_p)),) \ + ,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_C(name,_size)),) \ + ,M_IF_METHOD(CLEAN, oplist)(CLEAN(M_C(name,_clean)),) \ + ,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \ + ,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \ + ,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \ ,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_OPLIST(M_GET_VALUE_OPLIST oplist), ) \ - ,M_IF_METHOD(SET_KEY, oplist)(SET_KEY(M_C(name, _set_at)),) \ - ,M_IF_METHOD(ERASE_KEY, oplist)(ERASE_KEY(M_C(name, _erase)),) \ - ,M_IF_METHOD(PUSH, oplist)(PUSH(M_C(name,_push)),) \ - ,M_IF_METHOD(POP, oplist)(POP(M_C(name,_pop)),) \ - ,M_IF_METHOD(PUSH_MOVE, oplist)(PUSH_MOVE(M_C(name,_push_move)),) \ - ,M_IF_METHOD(POP_MOVE, oplist)(POP_MOVE(M_C(name,_pop_move)),) \ - ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ - ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ - ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ - ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ - ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ - ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ - ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \ - ,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ - ,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),) \ + ,M_IF_METHOD(SET_KEY, oplist)(SET_KEY(M_C(name, _set_at)),) \ + ,M_IF_METHOD(ERASE_KEY, oplist)(ERASE_KEY(M_C(name, _erase)),) \ + ,M_IF_METHOD(PUSH, oplist)(PUSH(M_C(name,_push)),) \ + ,M_IF_METHOD(POP, oplist)(POP(M_C(name,_pop)),) \ + ,M_IF_METHOD(PUSH_MOVE, oplist)(PUSH_MOVE(M_C(name,_push_move)),) \ + ,M_IF_METHOD(POP_MOVE, oplist)(POP_MOVE(M_C(name,_pop_move)),) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ + ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \ + ,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ + ,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),) \ ) /* Internal contract Nothing notable. Can't check too much without locking the structure itself */ -#define CONCURRENTI_CONTRACT(c) do { \ - assert ((c) != NULL); \ +#define CONCURRENTI_CONTRACT(c) do { \ + assert ((c) != NULL); \ } while (0) /* Deferred evaluation for the concurrent definition, @@ -152,11 +152,11 @@ #define CONCURRENTI_DEF_P1(arg) CONCURRENTI_DEF_P2 arg /* Validate the value oplist before going further */ -#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \ +#define CONCURRENTI_DEF_P2(name, type, oplist, concurrent_t) \ M_IF_OPLIST(oplist)(CONCURRENTI_DEF_P3, CONCURRENTI_DEF_FAILURE)(name, type, oplist, concurrent_t) /* Stop processing with a compilation failure */ -#define CONCURRENTI_DEF_FAILURE(name, type, oplist, concurrent_t) \ +#define CONCURRENTI_DEF_FAILURE(name, type, oplist, concurrent_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) /* Internal concurrent definition @@ -165,90 +165,90 @@ - oplist: oplist of the type of the sub container - concurrent_t: alias for M_C(name, _t) [ type of the container ] */ -#define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \ - \ - /* Define a concurrent container using a lock */ \ - typedef struct M_C(name, _s) { \ - struct M_C(name, _s) *self; \ - m_mutex_t lock; \ - m_cond_t there_is_data; /* condition raised when there is data */ \ - type data; \ - } concurrent_t[1]; \ - \ - /* Define alias for pointer types */ \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - /* Internal types for oplist */ \ - typedef concurrent_t M_C(name, _ct); \ - typedef type M_C(name, _subtype_ct); \ - \ - /* Don't define iterator as it cannot be reliable in a concurrent type */ \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ - /* Define the lock strategy (global & shared lock) */ \ - static inline void \ - M_C(name, _internal_init)(concurrent_t out) \ - { \ - m_mutex_init(out->lock); \ - m_cond_init(out->there_is_data); \ - out->self = out; \ - } \ - \ - static inline void \ - M_C(name, _internal_clear)(concurrent_t out) \ - { \ - assert (out->self == out); \ - m_mutex_clear(out->lock); \ - m_cond_clear(out->there_is_data); \ - out->self = NULL; \ - } \ - \ - static inline void \ - M_C(name, _read_lock)(const concurrent_t out) \ - { \ - assert (out->self == out); \ - m_mutex_lock (out->self->lock); \ - } \ - \ - static inline void \ - M_C(name, _read_unlock)(const concurrent_t out) \ - { \ - assert (out->self == out); \ - m_mutex_unlock (out->self->lock); \ - } \ - \ - static inline void \ - M_C(name, _read_wait)(const concurrent_t out) \ - { \ - assert (out->self == out); \ - m_cond_wait(out->self->there_is_data, out->self->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_lock)(concurrent_t out) \ - { \ - m_mutex_lock (out->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_unlock)(concurrent_t out) \ - { \ - m_mutex_unlock (out->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_wait)(const concurrent_t out) \ - { \ - m_cond_wait(out->self->there_is_data, out->self->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_signal)(concurrent_t out) \ - { \ - m_cond_broadcast(out->there_is_data); \ - } \ - \ +#define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \ + \ + /* Define a concurrent container using a lock */ \ + typedef struct M_C(name, _s) { \ + struct M_C(name, _s) *self; \ + m_mutex_t lock; \ + m_cond_t there_is_data; /* condition raised when there is data */ \ + type data; \ + } concurrent_t[1]; \ + \ + /* Define alias for pointer types */ \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + /* Internal types for oplist */ \ + typedef concurrent_t M_C(name, _ct); \ + typedef type M_C(name, _subtype_ct); \ + \ + /* Don't define iterator as it cannot be reliable in a concurrent type */ \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ + /* Define the lock strategy (global & shared lock) */ \ + static inline void \ + M_C(name, _internal_init)(concurrent_t out) \ + { \ + m_mutex_init(out->lock); \ + m_cond_init(out->there_is_data); \ + out->self = out; \ + } \ + \ + static inline void \ + M_C(name, _internal_clear)(concurrent_t out) \ + { \ + assert (out->self == out); \ + m_mutex_clear(out->lock); \ + m_cond_clear(out->there_is_data); \ + out->self = NULL; \ + } \ + \ + static inline void \ + M_C(name, _read_lock)(const concurrent_t out) \ + { \ + assert (out->self == out); \ + m_mutex_lock (out->self->lock); \ + } \ + \ + static inline void \ + M_C(name, _read_unlock)(const concurrent_t out) \ + { \ + assert (out->self == out); \ + m_mutex_unlock (out->self->lock); \ + } \ + \ + static inline void \ + M_C(name, _read_wait)(const concurrent_t out) \ + { \ + assert (out->self == out); \ + m_cond_wait(out->self->there_is_data, out->self->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_lock)(concurrent_t out) \ + { \ + m_mutex_lock (out->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_unlock)(concurrent_t out) \ + { \ + m_mutex_unlock (out->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_wait)(const concurrent_t out) \ + { \ + m_cond_wait(out->self->there_is_data, out->self->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_signal)(concurrent_t out) \ + { \ + m_cond_broadcast(out->there_is_data); \ + } \ + \ CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t) @@ -258,433 +258,433 @@ - oplist: oplist of the type of the sub container - concurrent_t: alias for M_C(name, _t) [ type of the container ] */ -#define CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t) \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline void \ - M_C(name, _init)(concurrent_t out) \ - { \ - M_C(name, _internal_init)(out); \ - M_CALL_INIT(oplist, out->data); \ - CONCURRENTI_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(INIT_SET, oplist)( \ - static inline void \ - M_C(name, _init_set)(concurrent_t out, concurrent_t const src) \ - { \ - CONCURRENTI_CONTRACT(src); \ - assert (out != src); \ - M_C(name, _internal_init)(out); \ - M_C(name, _read_lock)(src); \ - M_CALL_INIT_SET(oplist, out->data, src->data); \ - M_C(name, _read_unlock)(src); \ - CONCURRENTI_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(SET, oplist)( \ - static inline void \ - M_C(name, _set)(concurrent_t out, concurrent_t const src) \ - { \ - CONCURRENTI_CONTRACT(out); \ - if (out == src) return; \ - if (out < src) { \ - M_C(name, _write_lock)(out); \ - M_C(name, _read_lock)(src); \ - } else { \ - M_C(name, _read_lock)(src); \ - M_C(name, _write_lock)(out); \ - } \ - M_CALL_SET(oplist, out->data, src->data); \ - if (out < src) { \ - M_C(name, _read_lock)(src); \ - M_C(name, _write_unlock)(out); \ - } else { \ - M_C(name, _write_unlock)(out); \ - M_C(name, _read_unlock)(src); \ - } \ - CONCURRENTI_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(CLEAR, oplist)( \ - static inline void \ - M_C(name, _clear)(concurrent_t out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - /* No need to lock */ \ - M_CALL_CLEAR(oplist, out->data); \ - M_C(name, _internal_clear)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(INIT_MOVE, oplist)( \ - static inline void \ - M_C(name, _init_move)(concurrent_t out, concurrent_t src) \ - { \ - CONCURRENTI_CONTRACT(src); \ - assert (out != src); \ - /* No need to lock 'src' ? */ \ - M_C(name, _internal_init)(out); \ - M_CALL_INIT_MOVE(oplist, out->data, src->data); \ - M_C(name, _internal_clear)(src); \ - CONCURRENTI_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(MOVE, oplist)( \ - static inline void \ - M_C(name, _move)(concurrent_t out, concurrent_t src) \ - { \ - CONCURRENTI_CONTRACT(out); \ - CONCURRENTI_CONTRACT(src); \ - /* No need to lock 'src' ? */ \ - M_C(name, _write_lock)(out); \ - M_CALL_MOVE(oplist, out->data, src->data); \ - M_C(name, _write_unlock)(out); \ - M_C(name, _internal_clear)(src); \ - CONCURRENTI_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(SWAP, oplist)( \ - static inline void \ - M_C(name, _swap)(concurrent_t out, concurrent_t src) \ - { \ - CONCURRENTI_CONTRACT(out); \ - CONCURRENTI_CONTRACT(src); \ - if (out < src) { \ - M_C(name, _write_lock)(out); \ - M_C(name, _write_lock)(src); \ - } else { \ - M_C(name, _write_lock)(src); \ - M_C(name, _write_lock)(out); \ - } \ - M_CALL_SWAP(oplist, out->data, src->data); \ - if (out < src) { \ - M_C(name, _write_unlock)(src); \ - M_C(name, _write_unlock)(out); \ - } else { \ - M_C(name, _write_unlock)(out); \ - M_C(name, _write_unlock)(src); \ - } \ - } \ - ,) \ - \ - M_IF_METHOD(CLEAN, oplist)( \ - static inline void \ - M_C(name, _clean)(concurrent_t out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - M_CALL_CLEAN(oplist, out->data); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(TEST_EMPTY, oplist)( \ - static inline bool \ - M_C(name, _empty_p)(concurrent_t const out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _read_lock)(out); \ - bool b = M_CALL_TEST_EMPTY(oplist, out->data); \ - M_C(name, _read_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(GET_SIZE, oplist)( \ - static inline size_t \ - M_C(name, _size)(concurrent_t const out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _read_lock)(out); \ - size_t r = M_CALL_GET_SIZE(oplist, out->data); \ - M_C(name, _read_unlock)(out); \ - return r; \ - } \ - ,) \ - \ - M_IF_METHOD(SET_KEY, oplist)( \ - static inline void \ +#define CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t) \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline void \ + M_C(name, _init)(concurrent_t out) \ + { \ + M_C(name, _internal_init)(out); \ + M_CALL_INIT(oplist, out->data); \ + CONCURRENTI_CONTRACT(out); \ + } \ + ,) \ + \ + M_IF_METHOD(INIT_SET, oplist)( \ + static inline void \ + M_C(name, _init_set)(concurrent_t out, concurrent_t const src) \ + { \ + CONCURRENTI_CONTRACT(src); \ + assert (out != src); \ + M_C(name, _internal_init)(out); \ + M_C(name, _read_lock)(src); \ + M_CALL_INIT_SET(oplist, out->data, src->data); \ + M_C(name, _read_unlock)(src); \ + CONCURRENTI_CONTRACT(out); \ + } \ + ,) \ + \ + M_IF_METHOD(SET, oplist)( \ + static inline void \ + M_C(name, _set)(concurrent_t out, concurrent_t const src) \ + { \ + CONCURRENTI_CONTRACT(out); \ + if (out == src) return; \ + if (out < src) { \ + M_C(name, _write_lock)(out); \ + M_C(name, _read_lock)(src); \ + } else { \ + M_C(name, _read_lock)(src); \ + M_C(name, _write_lock)(out); \ + } \ + M_CALL_SET(oplist, out->data, src->data); \ + if (out < src) { \ + M_C(name, _read_lock)(src); \ + M_C(name, _write_unlock)(out); \ + } else { \ + M_C(name, _write_unlock)(out); \ + M_C(name, _read_unlock)(src); \ + } \ + CONCURRENTI_CONTRACT(out); \ + } \ + ,) \ + \ + M_IF_METHOD(CLEAR, oplist)( \ + static inline void \ + M_C(name, _clear)(concurrent_t out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + /* No need to lock */ \ + M_CALL_CLEAR(oplist, out->data); \ + M_C(name, _internal_clear)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(INIT_MOVE, oplist)( \ + static inline void \ + M_C(name, _init_move)(concurrent_t out, concurrent_t src) \ + { \ + CONCURRENTI_CONTRACT(src); \ + assert (out != src); \ + /* No need to lock 'src' ? */ \ + M_C(name, _internal_init)(out); \ + M_CALL_INIT_MOVE(oplist, out->data, src->data); \ + M_C(name, _internal_clear)(src); \ + CONCURRENTI_CONTRACT(out); \ + } \ + ,) \ + \ + M_IF_METHOD(MOVE, oplist)( \ + static inline void \ + M_C(name, _move)(concurrent_t out, concurrent_t src) \ + { \ + CONCURRENTI_CONTRACT(out); \ + CONCURRENTI_CONTRACT(src); \ + /* No need to lock 'src' ? */ \ + M_C(name, _write_lock)(out); \ + M_CALL_MOVE(oplist, out->data, src->data); \ + M_C(name, _write_unlock)(out); \ + M_C(name, _internal_clear)(src); \ + CONCURRENTI_CONTRACT(out); \ + } \ + ,) \ + \ + M_IF_METHOD(SWAP, oplist)( \ + static inline void \ + M_C(name, _swap)(concurrent_t out, concurrent_t src) \ + { \ + CONCURRENTI_CONTRACT(out); \ + CONCURRENTI_CONTRACT(src); \ + if (out < src) { \ + M_C(name, _write_lock)(out); \ + M_C(name, _write_lock)(src); \ + } else { \ + M_C(name, _write_lock)(src); \ + M_C(name, _write_lock)(out); \ + } \ + M_CALL_SWAP(oplist, out->data, src->data); \ + if (out < src) { \ + M_C(name, _write_unlock)(src); \ + M_C(name, _write_unlock)(out); \ + } else { \ + M_C(name, _write_unlock)(out); \ + M_C(name, _write_unlock)(src); \ + } \ + } \ + ,) \ + \ + M_IF_METHOD(CLEAN, oplist)( \ + static inline void \ + M_C(name, _clean)(concurrent_t out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + M_CALL_CLEAN(oplist, out->data); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(TEST_EMPTY, oplist)( \ + static inline bool \ + M_C(name, _empty_p)(concurrent_t const out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _read_lock)(out); \ + bool b = M_CALL_TEST_EMPTY(oplist, out->data); \ + M_C(name, _read_unlock)(out); \ + return b; \ + } \ + ,) \ + \ + M_IF_METHOD(GET_SIZE, oplist)( \ + static inline size_t \ + M_C(name, _size)(concurrent_t const out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _read_lock)(out); \ + size_t r = M_CALL_GET_SIZE(oplist, out->data); \ + M_C(name, _read_unlock)(out); \ + return r; \ + } \ + ,) \ + \ + M_IF_METHOD(SET_KEY, oplist)( \ + static inline void \ M_C(name, _set_at)(concurrent_t out, M_GET_KEY_TYPE oplist const key, M_GET_VALUE_TYPE oplist const data) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - M_CALL_SET_KEY(oplist, out->data, key, data); \ - M_C(name, _write_signal)(out); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(GET_KEY, oplist)( \ - static inline bool \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + M_CALL_SET_KEY(oplist, out->data, key, data); \ + M_C(name, _write_signal)(out); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(GET_KEY, oplist)( \ + static inline bool \ M_C(name, _get_copy)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key) \ - { \ - CONCURRENTI_CONTRACT(out); \ - assert (out_data != NULL); \ - M_C(name, _read_lock)(out); \ - M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \ - if (p != NULL) { \ - M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ - } \ - M_C(name, _read_unlock)(out); \ - return p != NULL; \ - } \ - ,) \ - \ - M_IF_METHOD(GET_SET_KEY, oplist)( \ - static inline void \ + { \ + CONCURRENTI_CONTRACT(out); \ + assert (out_data != NULL); \ + M_C(name, _read_lock)(out); \ + M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \ + if (p != NULL) { \ + M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ + } \ + M_C(name, _read_unlock)(out); \ + return p != NULL; \ + } \ + ,) \ + \ + M_IF_METHOD(GET_SET_KEY, oplist)( \ + static inline void \ M_C(name, _get_at_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \ - { \ - CONCURRENTI_CONTRACT(out); \ - assert (out_data != NULL); \ - M_C(name, _write_lock)(out); \ - M_GET_VALUE_TYPE oplist *p = M_CALL_GET_SET_KEY(oplist, out->data, key); \ - assert (p != NULL); \ - M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(ERASE_KEY, oplist)( \ - static inline bool \ - M_C(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \ - M_C(name, _write_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(PUSH, oplist)( \ - static inline void \ - M_C(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - M_CALL_PUSH(oplist, out->data, data); \ - M_C(name, _write_signal)(out); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(POP, oplist)( \ - static inline void \ - M_C(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - M_CALL_POP(oplist, p, out->data); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(PUSH_MOVE, oplist)( \ - static inline void \ - M_C(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - M_CALL_PUSH_MOVE(oplist, out->data, data); \ - M_C(name, _write_signal)(out); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(POP_MOVE, oplist)( \ - static inline void \ - M_C(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - M_CALL_POP_MOVE(oplist, p, out->data); \ - M_C(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(GET_STR, oplist)( \ - static inline void \ - M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _read_lock)(out); \ - M_CALL_GET_STR(oplist, str, out->data, a); \ - M_C(name, _read_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(OUT_STR, oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *f, concurrent_t const out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _read_lock)(out); \ - M_CALL_OUT_STR(oplist, f, out->data); \ - M_C(name, _read_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(PARSE_STR, oplist)( \ - static inline bool \ - M_C(name, _parse_str)(concurrent_t out, const char str[], const char **e) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \ - M_C(name, _write_signal)(out); \ - M_C(name, _write_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(IN_STR, oplist)( \ - static inline bool \ - M_C(name, _in_str)(concurrent_t out, FILE *f) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - bool b = M_CALL_IN_STR(oplist, out->data, f); \ - M_C(name, _write_signal)(out); \ - M_C(name, _write_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(OUT_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, concurrent_t const out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _read_lock)(out); \ - m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, f, out->data); \ - M_C(name, _read_unlock)(out); \ - return r; \ - } \ - ,) \ - \ - M_IF_METHOD(IN_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(concurrent_t out, m_serial_read_t f) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _write_lock)(out); \ - m_serial_return_code_t r = M_CALL_IN_SERIAL(oplist, out->data, f); \ - M_C(name, _write_signal)(out); \ - M_C(name, _write_unlock)(out); \ - return r; \ - } \ - ,) \ - \ - M_IF_METHOD(EQUAL, oplist)( \ - static inline bool \ - M_C(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \ - { \ - CONCURRENTI_CONTRACT(out1); \ - CONCURRENTI_CONTRACT(out2); \ - if (out1 == out2) return true; \ - if (out1 < out2) { \ - M_C(name, _read_lock)(out1); \ - M_C(name, _read_lock)(out2); \ - } else { \ - M_C(name, _read_lock)(out2); \ - M_C(name, _read_lock)(out1); \ - } \ - bool b = M_CALL_EQUAL(oplist, out1->data, out2->data); \ - if (out1 < out2) { \ - M_C(name, _read_unlock)(out2); \ - M_C(name, _read_unlock)(out1); \ - } else { \ - M_C(name, _read_unlock)(out1); \ - M_C(name, _read_unlock)(out2); \ - } \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(GET_KEY, oplist)( \ - static inline bool \ + { \ + CONCURRENTI_CONTRACT(out); \ + assert (out_data != NULL); \ + M_C(name, _write_lock)(out); \ + M_GET_VALUE_TYPE oplist *p = M_CALL_GET_SET_KEY(oplist, out->data, key); \ + assert (p != NULL); \ + M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(ERASE_KEY, oplist)( \ + static inline bool \ + M_C(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \ + M_C(name, _write_unlock)(out); \ + return b; \ + } \ + ,) \ + \ + M_IF_METHOD(PUSH, oplist)( \ + static inline void \ + M_C(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + M_CALL_PUSH(oplist, out->data, data); \ + M_C(name, _write_signal)(out); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(POP, oplist)( \ + static inline void \ + M_C(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + M_CALL_POP(oplist, p, out->data); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(PUSH_MOVE, oplist)( \ + static inline void \ + M_C(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + M_CALL_PUSH_MOVE(oplist, out->data, data); \ + M_C(name, _write_signal)(out); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(POP_MOVE, oplist)( \ + static inline void \ + M_C(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + M_CALL_POP_MOVE(oplist, p, out->data); \ + M_C(name, _write_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(GET_STR, oplist)( \ + static inline void \ + M_C(name, _get_str)(string_t str, concurrent_t const out, bool a) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _read_lock)(out); \ + M_CALL_GET_STR(oplist, str, out->data, a); \ + M_C(name, _read_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(OUT_STR, oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *f, concurrent_t const out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _read_lock)(out); \ + M_CALL_OUT_STR(oplist, f, out->data); \ + M_C(name, _read_unlock)(out); \ + } \ + ,) \ + \ + M_IF_METHOD(PARSE_STR, oplist)( \ + static inline bool \ + M_C(name, _parse_str)(concurrent_t out, const char str[], const char **e) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \ + M_C(name, _write_signal)(out); \ + M_C(name, _write_unlock)(out); \ + return b; \ + } \ + ,) \ + \ + M_IF_METHOD(IN_STR, oplist)( \ + static inline bool \ + M_C(name, _in_str)(concurrent_t out, FILE *f) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + bool b = M_CALL_IN_STR(oplist, out->data, f); \ + M_C(name, _write_signal)(out); \ + M_C(name, _write_unlock)(out); \ + return b; \ + } \ + ,) \ + \ + M_IF_METHOD(OUT_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, concurrent_t const out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _read_lock)(out); \ + m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, f, out->data); \ + M_C(name, _read_unlock)(out); \ + return r; \ + } \ + ,) \ + \ + M_IF_METHOD(IN_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(concurrent_t out, m_serial_read_t f) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _write_lock)(out); \ + m_serial_return_code_t r = M_CALL_IN_SERIAL(oplist, out->data, f); \ + M_C(name, _write_signal)(out); \ + M_C(name, _write_unlock)(out); \ + return r; \ + } \ + ,) \ + \ + M_IF_METHOD(EQUAL, oplist)( \ + static inline bool \ + M_C(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \ + { \ + CONCURRENTI_CONTRACT(out1); \ + CONCURRENTI_CONTRACT(out2); \ + if (out1 == out2) return true; \ + if (out1 < out2) { \ + M_C(name, _read_lock)(out1); \ + M_C(name, _read_lock)(out2); \ + } else { \ + M_C(name, _read_lock)(out2); \ + M_C(name, _read_lock)(out1); \ + } \ + bool b = M_CALL_EQUAL(oplist, out1->data, out2->data); \ + if (out1 < out2) { \ + M_C(name, _read_unlock)(out2); \ + M_C(name, _read_unlock)(out1); \ + } else { \ + M_C(name, _read_unlock)(out1); \ + M_C(name, _read_unlock)(out2); \ + } \ + return b; \ + } \ + ,) \ + \ + M_IF_METHOD(GET_KEY, oplist)( \ + static inline bool \ M_C(name, _get_blocking)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key, bool blocking) \ - { \ - CONCURRENTI_CONTRACT(out); \ - assert (out_data != NULL); \ - bool ret = false; \ - M_C(name, _read_lock)(out); \ - while (true) { \ - M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \ - if (p != NULL) { \ - M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ - ret = true; \ - break; \ - } \ - if (blocking == false) break; \ - M_C(name, _read_wait)(out); \ - } \ - M_C(name, _read_unlock)(out); \ - return ret; \ - } \ - ,) \ - \ - M_IF_METHOD2(POP, TEST_EMPTY, oplist)( \ - static inline bool \ + { \ + CONCURRENTI_CONTRACT(out); \ + assert (out_data != NULL); \ + bool ret = false; \ + M_C(name, _read_lock)(out); \ + while (true) { \ + M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \ + if (p != NULL) { \ + M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ + ret = true; \ + break; \ + } \ + if (blocking == false) break; \ + M_C(name, _read_wait)(out); \ + } \ + M_C(name, _read_unlock)(out); \ + return ret; \ + } \ + ,) \ + \ + M_IF_METHOD2(POP, TEST_EMPTY, oplist)( \ + static inline bool \ M_C(name, _pop_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \ - { \ - CONCURRENTI_CONTRACT(out); \ - assert (p != NULL); \ - bool ret = false; \ - M_C(name, _write_lock)(out); \ - while (true) { \ - if (!M_CALL_TEST_EMPTY(oplist, out->data)) { \ - M_CALL_POP(oplist, p, out->data); \ - ret = true; \ - break; \ - } \ - if (blocking == false) break; \ - M_C(name, _write_wait)(out); \ - } \ - M_C(name, _write_unlock)(out); \ - return ret; \ - } \ - ,) \ - \ - M_IF_METHOD2(POP_MOVE, TEST_EMPTY, oplist)( \ - static inline bool \ + { \ + CONCURRENTI_CONTRACT(out); \ + assert (p != NULL); \ + bool ret = false; \ + M_C(name, _write_lock)(out); \ + while (true) { \ + if (!M_CALL_TEST_EMPTY(oplist, out->data)) { \ + M_CALL_POP(oplist, p, out->data); \ + ret = true; \ + break; \ + } \ + if (blocking == false) break; \ + M_C(name, _write_wait)(out); \ + } \ + M_C(name, _write_unlock)(out); \ + return ret; \ + } \ + ,) \ + \ + M_IF_METHOD2(POP_MOVE, TEST_EMPTY, oplist)( \ + static inline bool \ M_C(name, _pop_move_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \ - { \ - CONCURRENTI_CONTRACT(out); \ - assert (p != NULL); \ - bool ret = false; \ - M_C(name, _write_lock)(out); \ - while (true) { \ - if (!M_CALL_TEST_EMPTY(oplist, out->data)) { \ - M_CALL_POP_MOVE(oplist, p, out->data); \ - ret = true; \ - break; \ - } \ - if (blocking == false) break; \ - M_C(name, _write_wait)(out); \ - } \ - M_C(name, _write_unlock)(out); \ - return ret; \ - } \ - ,) \ - \ - M_IF_METHOD(HASH, oplist)( \ - static inline size_t \ - M_C(name, _hash)(concurrent_t const out) \ - { \ - CONCURRENTI_CONTRACT(out); \ - M_C(name, _read_lock)(out); \ - size_t h = M_CALL_HASH(oplist, out->data); \ - M_C(name, _read_unlock)(out); \ - return h; \ - } \ - ,) \ + { \ + CONCURRENTI_CONTRACT(out); \ + assert (p != NULL); \ + bool ret = false; \ + M_C(name, _write_lock)(out); \ + while (true) { \ + if (!M_CALL_TEST_EMPTY(oplist, out->data)) { \ + M_CALL_POP_MOVE(oplist, p, out->data); \ + ret = true; \ + break; \ + } \ + if (blocking == false) break; \ + M_C(name, _write_wait)(out); \ + } \ + M_C(name, _write_unlock)(out); \ + return ret; \ + } \ + ,) \ + \ + M_IF_METHOD(HASH, oplist)( \ + static inline size_t \ + M_C(name, _hash)(concurrent_t const out) \ + { \ + CONCURRENTI_CONTRACT(out); \ + M_C(name, _read_lock)(out); \ + size_t h = M_CALL_HASH(oplist, out->data); \ + M_C(name, _read_unlock)(out); \ + return h; \ + } \ + ,) \ @@ -693,11 +693,11 @@ #define CONCURRENTI_RP_DEF_P1(arg) CONCURRENTI_RP_DEF_P2 arg /* Validate the value oplist before going further */ -#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \ +#define CONCURRENTI_RP_DEF_P2(name, type, oplist, concurrent_t) \ M_IF_OPLIST(oplist)(CONCURRENTI_RP_DEF_P3, CONCURRENTI_RP_DEF_FAILURE)(name, type, oplist, concurrent_t) /* Stop processing with a compilation failure */ -#define CONCURRENTI_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \ +#define CONCURRENTI_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_RP_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) /* Internal RP concurrent definition @@ -706,137 +706,137 @@ - oplist: oplist of the type of the sub container - concurrent_t: alias for M_C(name, _t) [ type of the container ] */ -#define CONCURRENTI_RP_DEF_P3(name, type, oplist, concurrent_t) \ - \ - typedef struct M_C(name, _s) { \ - struct M_C(name, _s) *self; \ - m_mutex_t lock; \ - m_cond_t rw_done; \ - size_t read_count; \ - bool writer_waiting; \ - m_cond_t there_is_data; /* condition raised when there is data */ \ - type data; \ - } concurrent_t[1]; \ - \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - typedef type M_C(name, _subtype_ct); \ - \ - /* Define the lock strategy (multi lock) */ \ - static inline void \ - M_C(name, _internal_init)(concurrent_t out) \ - { \ - m_mutex_init(out->lock); \ - m_cond_init(out->rw_done); \ - m_cond_init(out->there_is_data); \ - out->self = out; \ - out->read_count = 0; \ - out->writer_waiting = false; \ - } \ - \ - static inline void \ - M_C(name, _internal_clear)(concurrent_t out) \ - { \ - assert (out->self == out); \ - m_mutex_clear(out->lock); \ - m_cond_clear(out->rw_done); \ - m_cond_clear(out->there_is_data); \ - out->self = NULL; \ - } \ - \ - static inline void \ - M_C(name, _read_lock)(const concurrent_t out) \ - { \ - struct M_C(name, _s) *self = out->self; \ - assert (self == out); \ - m_mutex_lock (self->lock); \ - while (self->writer_waiting == true) { \ - m_cond_wait(self->rw_done, self->lock); \ - } \ - self->read_count ++; \ - m_mutex_unlock (self->lock); \ - } \ - \ - static inline void \ - M_C(name, _read_unlock)(const concurrent_t out) \ - { \ - struct M_C(name, _s) *self = out->self; \ - assert (self == out); \ - m_mutex_lock (self->lock); \ - self->read_count --; \ - if (self->read_count == 0) { \ - m_cond_broadcast (self->rw_done); \ - } \ - m_mutex_unlock (self->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_lock)(concurrent_t out) \ - { \ - m_mutex_lock (out->lock); \ - while (out->writer_waiting == true) { \ - m_cond_wait(out->rw_done, out->lock); \ - } \ - out->writer_waiting = true; \ - while (out->read_count > 0) { \ - m_cond_wait(out->rw_done, out->lock); \ - } \ - m_mutex_unlock (out->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_unlock)(concurrent_t out) \ - { \ - m_mutex_lock (out->lock); \ - out->writer_waiting = false; \ - m_cond_broadcast (out->rw_done); \ - m_mutex_unlock (out->lock); \ - } \ - \ - static inline void \ - M_C(name, _read_wait)(const concurrent_t out) \ - { \ - struct M_C(name, _s) *self = out->self; \ - assert (self == out); \ - m_mutex_lock (out->self->lock); \ - self->read_count --; \ - if (self->read_count == 0) { \ - m_cond_broadcast (self->rw_done); \ - } \ - m_cond_wait(self->there_is_data, self->lock); \ - while (self->writer_waiting == true) { \ - m_cond_wait(self->rw_done, self->lock); \ - } \ - self->read_count ++; \ - m_mutex_unlock (out->self->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_wait)(concurrent_t out) \ - { \ - m_mutex_lock (out->lock); \ - out->writer_waiting = false; \ - m_cond_broadcast (out->rw_done); \ - m_cond_wait(out->there_is_data, out->lock); \ - while (out->writer_waiting == true) { \ - m_cond_wait(out->rw_done, out->lock); \ - } \ - out->writer_waiting = true; \ - while (out->read_count > 0) { \ - m_cond_wait(out->rw_done, out->lock); \ - } \ - m_mutex_unlock (out->lock); \ - } \ - \ - static inline void \ - M_C(name, _write_signal)(concurrent_t out) \ - { \ - m_mutex_lock (out->lock); \ - m_cond_broadcast(out->there_is_data); \ - m_mutex_unlock (out->lock); \ - } \ - \ +#define CONCURRENTI_RP_DEF_P3(name, type, oplist, concurrent_t) \ + \ + typedef struct M_C(name, _s) { \ + struct M_C(name, _s) *self; \ + m_mutex_t lock; \ + m_cond_t rw_done; \ + size_t read_count; \ + bool writer_waiting; \ + m_cond_t there_is_data; /* condition raised when there is data */ \ + type data; \ + } concurrent_t[1]; \ + \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + typedef type M_C(name, _subtype_ct); \ + \ + /* Define the lock strategy (multi lock) */ \ + static inline void \ + M_C(name, _internal_init)(concurrent_t out) \ + { \ + m_mutex_init(out->lock); \ + m_cond_init(out->rw_done); \ + m_cond_init(out->there_is_data); \ + out->self = out; \ + out->read_count = 0; \ + out->writer_waiting = false; \ + } \ + \ + static inline void \ + M_C(name, _internal_clear)(concurrent_t out) \ + { \ + assert (out->self == out); \ + m_mutex_clear(out->lock); \ + m_cond_clear(out->rw_done); \ + m_cond_clear(out->there_is_data); \ + out->self = NULL; \ + } \ + \ + static inline void \ + M_C(name, _read_lock)(const concurrent_t out) \ + { \ + struct M_C(name, _s) *self = out->self; \ + assert (self == out); \ + m_mutex_lock (self->lock); \ + while (self->writer_waiting == true) { \ + m_cond_wait(self->rw_done, self->lock); \ + } \ + self->read_count ++; \ + m_mutex_unlock (self->lock); \ + } \ + \ + static inline void \ + M_C(name, _read_unlock)(const concurrent_t out) \ + { \ + struct M_C(name, _s) *self = out->self; \ + assert (self == out); \ + m_mutex_lock (self->lock); \ + self->read_count --; \ + if (self->read_count == 0) { \ + m_cond_broadcast (self->rw_done); \ + } \ + m_mutex_unlock (self->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_lock)(concurrent_t out) \ + { \ + m_mutex_lock (out->lock); \ + while (out->writer_waiting == true) { \ + m_cond_wait(out->rw_done, out->lock); \ + } \ + out->writer_waiting = true; \ + while (out->read_count > 0) { \ + m_cond_wait(out->rw_done, out->lock); \ + } \ + m_mutex_unlock (out->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_unlock)(concurrent_t out) \ + { \ + m_mutex_lock (out->lock); \ + out->writer_waiting = false; \ + m_cond_broadcast (out->rw_done); \ + m_mutex_unlock (out->lock); \ + } \ + \ + static inline void \ + M_C(name, _read_wait)(const concurrent_t out) \ + { \ + struct M_C(name, _s) *self = out->self; \ + assert (self == out); \ + m_mutex_lock (out->self->lock); \ + self->read_count --; \ + if (self->read_count == 0) { \ + m_cond_broadcast (self->rw_done); \ + } \ + m_cond_wait(self->there_is_data, self->lock); \ + while (self->writer_waiting == true) { \ + m_cond_wait(self->rw_done, self->lock); \ + } \ + self->read_count ++; \ + m_mutex_unlock (out->self->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_wait)(concurrent_t out) \ + { \ + m_mutex_lock (out->lock); \ + out->writer_waiting = false; \ + m_cond_broadcast (out->rw_done); \ + m_cond_wait(out->there_is_data, out->lock); \ + while (out->writer_waiting == true) { \ + m_cond_wait(out->rw_done, out->lock); \ + } \ + out->writer_waiting = true; \ + while (out->read_count > 0) { \ + m_cond_wait(out->rw_done, out->lock); \ + } \ + m_mutex_unlock (out->lock); \ + } \ + \ + static inline void \ + M_C(name, _write_signal)(concurrent_t out) \ + { \ + m_mutex_lock (out->lock); \ + m_cond_broadcast(out->there_is_data); \ + m_mutex_unlock (out->lock); \ + } \ + \ CONCURRENTI_DEF_FUNC_P3(name, type, oplist, concurrent_t) diff --git a/m-core.h b/m-core.h index e7221d3f..69b458e6 100644 --- a/m-core.h +++ b/m-core.h @@ -59,10 +59,10 @@ Not sure if it is worth it however. */ #if !defined(NDEBUG) # define M_ASSUME(x) assert(x) -#elif defined(__GNUC__) \ +#elif defined(__GNUC__) \ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 -# define M_ASSUME(x) \ - (! __builtin_constant_p (!!(x) || !(x)) || (x) ? \ +# define M_ASSUME(x) \ + (! __builtin_constant_p (!!(x) || !(x)) || (x) ? \ (void) 0 : __builtin_unreachable()) #elif defined(_MSC_VER) # define M_ASSUME(x) __assume(x) @@ -123,21 +123,21 @@ /* Warnings disabled for CLANG in C++ mode */ #if __clang_major__ >= 6 -#define M_BEGIN_PROTECTED_CODE \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - _Pragma("clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \ - _Pragma("clang diagnostic ignored \"-Wunused-function\"") \ +#define M_BEGIN_PROTECTED_CODE \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + _Pragma("clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \ + _Pragma("clang diagnostic ignored \"-Wunused-function\"") \ _Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"") #else -#define M_BEGIN_PROTECTED_CODE \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ - _Pragma("clang diagnostic ignored \"-Wunused-function\"") \ +#define M_BEGIN_PROTECTED_CODE \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + _Pragma("clang diagnostic ignored \"-Wunused-function\"") \ _Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"") #endif -#define M_END_PROTECTED_CODE \ +#define M_END_PROTECTED_CODE \ _Pragma("clang diagnostic pop") #elif defined(__GNUC__) && defined(__cplusplus) @@ -146,34 +146,34 @@ * However, G++ doesn't support well disabling temporary warnings. * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431 */ -#define M_BEGIN_PROTECTED_CODE \ - _Pragma("GCC diagnostic push") \ - _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") \ - _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \ +#define M_BEGIN_PROTECTED_CODE \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"") \ + _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \ _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") -#define M_END_PROTECTED_CODE \ +#define M_END_PROTECTED_CODE \ _Pragma("GCC diagnostic pop") #elif defined(__clang__) /* Warnings disabled for CLANG in C mode */ -#define M_BEGIN_PROTECTED_CODE \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Wunused-function\"") \ +#define M_BEGIN_PROTECTED_CODE \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wunused-function\"") \ _Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"") -#define M_END_PROTECTED_CODE \ +#define M_END_PROTECTED_CODE \ _Pragma("clang diagnostic pop") #elif defined(__GNUC__) /* Warnings disabled for GNU C in C mode */ -#define M_BEGIN_PROTECTED_CODE \ - _Pragma("GCC diagnostic push") \ +#define M_BEGIN_PROTECTED_CODE \ + _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") -#define M_END_PROTECTED_CODE \ +#define M_END_PROTECTED_CODE \ _Pragma("GCC diagnostic pop") #else @@ -897,7 +897,7 @@ M_BEGIN_PROTECTED_CODE */ #define M_PARENTHESISI_DETECT1(...) , #define M_PARENTHESISI_DETECT2(...) -#define M_PARENTHESIS_P(...) \ +#define M_PARENTHESIS_P(...) \ M_AND(M_AND(M_COMMA_P(M_PARENTHESISI_DETECT1 __VA_ARGS__), M_INV(M_COMMA_P(__VA_ARGS__))), \ M_EMPTY_P(M_PARENTHESISI_DETECT2 __VA_ARGS__)) @@ -907,7 +907,7 @@ M_BEGIN_PROTECTED_CODE It shall be either 'and', 'or', 'sum' (equivalent to 'add'), 'bool' - testedFunc is the tested keyword. It cannot start with a special character */ -#define M_KEYWORD_P(refFunc, testedFunc) \ +#define M_KEYWORD_P(refFunc, testedFunc) \ M_COMMA_P(M_C4(M_PATTERN_, refFunc, _, testedFunc)) /* The different special recognized patterns: */ #define M_PATTERN_and_and , @@ -1336,12 +1336,12 @@ M_BEGIN_PROTECTED_CODE /* M_NARGS: Return number of argument. (don't work for empty arg) */ -#define M_NARGS(...) \ - M_RET_ARG76(__VA_ARGS__, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, \ - 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, \ - 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, \ - 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, \ - 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \ +#define M_NARGS(...) \ + M_RET_ARG76(__VA_ARGS__, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, \ + 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, \ + 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, \ + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, \ + 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, \ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, useless) /* If the number of arguments is 1 */ @@ -1374,7 +1374,7 @@ M_BEGIN_PROTECTED_CODE #define f(...) M_APPLY(f, M_IF_DEFAULT1(0, __VA_ARGS__)) This need to be called within a M_APPLY macro. */ -#define M_IF_DEFAULT1(value, ...) \ +#define M_IF_DEFAULT1(value, ...) \ __VA_ARGS__ M_IF_NARGS_EQ1(__VA_ARGS__)(M_DEFERRED_COMMA value, ) /* Helper macro to redefine a function with a default values: @@ -1385,7 +1385,7 @@ M_BEGIN_PROTECTED_CODE Example: #define f(...) f(M_DEFAULT_ARGS(4, (0, 1, NULL), __VA_ARGS__)) */ -#define M_DEFAULT_ARGS2(expected, value, ...) \ +#define M_DEFAULT_ARGS2(expected, value, ...) \ __VA_ARGS__ M_IF(M_NOTEQUAL(M_NARGS(__VA_ARGS__), expected))(M_DEFERRED_COMMA, ) \ M_ID M_INVERT(M_KEEP_ARGS(M_SUB(expected, M_NARGS(__VA_ARGS__)), M_ID M_INVERT value)) #define M_DEFAULT_ARGS_EVAL(...) __VA_ARGS__ @@ -1531,26 +1531,26 @@ M_BEGIN_PROTECTED_CODE #endif /* Return the string format of a variable */ -#define M_PRINTF_FORMAT(x) \ - _Generic(((void)0,(x)), \ - char: "%c", \ - bool: "%d", \ - signed char: "%hhd", \ - unsigned char: "%hhu", \ - signed short: "%hd", \ - unsigned short: "%hu", \ - signed int: "%d", \ - unsigned int: "%u", \ - long int: "%ld", \ - unsigned long int: "%lu", \ - long long int: "%lld", \ - unsigned long long int: "%llu", \ - float: "%f", \ - double: "%f", \ - long double: "%Lf", \ - const char *: "%s", \ - char *: "%s", \ - const void *: "%p", \ +#define M_PRINTF_FORMAT(x) \ + _Generic(((void)0,(x)), \ + char: "%c", \ + bool: "%d", \ + signed char: "%hhd", \ + unsigned char: "%hhu", \ + signed short: "%hd", \ + unsigned short: "%hu", \ + signed int: "%d", \ + unsigned int: "%u", \ + long int: "%ld", \ + unsigned long int: "%lu", \ + long long int: "%lld", \ + unsigned long long int: "%llu", \ + float: "%f", \ + double: "%f", \ + long double: "%Lf", \ + const char *: "%s", \ + char *: "%s", \ + const void *: "%p", \ void *: "%p") /* IF FILE is supported */ @@ -1621,26 +1621,26 @@ m_core_fopen(const char filename[], const char opt[]) #define M_FPRINT_ARG(f, x) fprintf(f, M_PRINTF_FORMAT(x), x) /* Get a C variable if it is a standard type from the given file 'f'.*/ -#define M_FSCAN_ARG(xptr, f) \ - _Generic(((void)0,*(xptr)), \ - bool: m_core_fscan_bool(M_AS_TYPE(bool*,xptr), f), \ - char: m_core_fscan_char(M_AS_TYPE(char*,xptr), f), \ - signed char: m_core_fscan_schar(M_AS_TYPE(signed char*,xptr),f), \ +#define M_FSCAN_ARG(xptr, f) \ + _Generic(((void)0,*(xptr)), \ + bool: m_core_fscan_bool(M_AS_TYPE(bool*,xptr), f), \ + char: m_core_fscan_char(M_AS_TYPE(char*,xptr), f), \ + signed char: m_core_fscan_schar(M_AS_TYPE(signed char*,xptr),f), \ unsigned char: m_core_fscan_uchar(M_AS_TYPE(unsigned char*,xptr),f), \ signed short: m_core_fscan_sshort(M_AS_TYPE(signed short*,xptr),f), \ unsigned short: m_core_fscan_ushort(M_AS_TYPE(unsigned short*,xptr), f), \ - signed int: m_core_fscan_sint(M_AS_TYPE(signed int*,xptr), f), \ + signed int: m_core_fscan_sint(M_AS_TYPE(signed int*,xptr), f), \ unsigned int: m_core_fscan_uint(M_AS_TYPE(unsigned int*,xptr), f), \ - long int: m_core_fscan_slong(M_AS_TYPE(long*,xptr), f), \ + long int: m_core_fscan_slong(M_AS_TYPE(long*,xptr), f), \ unsigned long int: m_core_fscan_ulong(M_AS_TYPE(unsigned long*,xptr), f), \ long long int: m_core_fscan_sllong(M_AS_TYPE(long long*,xptr), f), \ unsigned long long int: m_core_fscan_ullong(M_AS_TYPE(unsigned long long*,xptr),f), \ - float: m_core_fscan_float(M_AS_TYPE(float*,xptr), f), \ - double: m_core_fscan_double(M_AS_TYPE(double*,xptr), f), \ + float: m_core_fscan_float(M_AS_TYPE(float*,xptr), f), \ + double: m_core_fscan_double(M_AS_TYPE(double*,xptr), f), \ long double: m_core_fscan_ldouble(M_AS_TYPE(long double*,xptr),f), \ - const char *: false /* unsupported */, \ - char *: false /* unsupported */, \ - const void *: false /* unsupported */, \ + const char *: false /* unsupported */, \ + char *: false /* unsupported */, \ + const void *: false /* unsupported */, \ void *: false /* unsupported */) static inline bool @@ -1659,11 +1659,11 @@ m_core_fscan_char (char *ptr, FILE *f) return c != EOF; } -#define M_FSCAN_DEFAULT_TYPE_DEF(name, type, format) \ - static inline bool \ - name (type *ptr, FILE *f) \ - { \ - return m_core_fscanf(f, format, ptr) == 1; \ +#define M_FSCAN_DEFAULT_TYPE_DEF(name, type, format) \ + static inline bool \ + name (type *ptr, FILE *f) \ + { \ + return m_core_fscanf(f, format, ptr) == 1; \ } M_FSCAN_DEFAULT_TYPE_DEF(m_core_fscan_schar, signed char, "%hhd") M_FSCAN_DEFAULT_TYPE_DEF(m_core_fscan_uchar, unsigned char, "%hhu") @@ -1682,17 +1682,17 @@ M_FSCAN_DEFAULT_TYPE_DEF(m_core_fscan_ldouble, long double, "%Lf") #endif /* Transform a C variable into a string_t (needs m-string.h) */ -#define M_GET_STRING_ARG(string, x, append) \ +#define M_GET_STRING_ARG(string, x, append) \ (append ? string_cat_printf : string_printf) (str, M_PRINTF_FORMAT(x), x) /* No use of GET_STR if no inclusion of m-string */ #define M_GET_STR_METHOD_FOR_DEFAULT_TYPE /* */ /* Parse string of default type */ -#define M_PARSE_DEFAULT_TYPE(x, str, endptr) \ - _Generic(((void)0,*(x)), \ - char: m_core_parse_char(M_AS_TYPE(char*,x),str,endptr), \ - bool: m_core_parse_bool(M_AS_TYPE(bool*,x),str,endptr), \ +#define M_PARSE_DEFAULT_TYPE(x, str, endptr) \ + _Generic(((void)0,*(x)), \ + char: m_core_parse_char(M_AS_TYPE(char*,x),str,endptr), \ + bool: m_core_parse_bool(M_AS_TYPE(bool*,x),str,endptr), \ signed char: m_core_parse_schar(M_AS_TYPE(signed char*,x),str,endptr), \ unsigned char: m_core_parse_uchar(M_AS_TYPE(unsigned char*,x),str,endptr), \ signed short: m_core_parse_sshort(M_AS_TYPE(signed short*,x),str,endptr), \ @@ -1703,12 +1703,12 @@ M_FSCAN_DEFAULT_TYPE_DEF(m_core_fscan_ldouble, long double, "%Lf") unsigned long: m_core_parse_ulong(M_AS_TYPE(unsigned long*,x),str,endptr), \ signed long long: m_core_parse_sllong(M_AS_TYPE(signed long long*,x),str,endptr), \ unsigned long long: m_core_parse_ullong(M_AS_TYPE(unsigned long long*,x),str,endptr), \ - float: m_core_parse_float(M_AS_TYPE(float*,x),str,endptr), \ - double: m_core_parse_double(M_AS_TYPE(double*,x),str,endptr), \ + float: m_core_parse_float(M_AS_TYPE(float*,x),str,endptr), \ + double: m_core_parse_double(M_AS_TYPE(double*,x),str,endptr), \ long double: m_core_parse_ldouble(M_AS_TYPE(long double*,x),str,endptr), \ - const char *: false /* not supported */, \ - char *: false /* not supported */, \ - const void *: false /* not supported */, \ + const char *: false /* not supported */, \ + char *: false /* not supported */, \ + const void *: false /* not supported */, \ void *: false /* not supported */) static inline bool @@ -1728,14 +1728,14 @@ m_core_parse_bool (bool *ptr, const char str[], const char **endptr) return (c == '0' || c == '1'); } -#define M_PARSE_DEFAULT_TYPE_DEF(name, type, parse_func, extra_arg) \ - static inline bool \ - name (type *ptr, const char str[], const char **endptr) \ - { \ - char *end; \ - *ptr = (type) parse_func (str, &end extra_arg); \ - if (endptr != NULL) *endptr = end; \ - return end != str; \ +#define M_PARSE_DEFAULT_TYPE_DEF(name, type, parse_func, extra_arg) \ + static inline bool \ + name (type *ptr, const char str[], const char **endptr) \ + { \ + char *end; \ + *ptr = (type) parse_func (str, &end extra_arg); \ + if (endptr != NULL) *endptr = end; \ + return end != str; \ } M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_schar, signed char, strtol, M_DEFERRED_COMMA 10) @@ -1785,10 +1785,10 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, ) #define M_POWEROF2_P(n) (!((n)&((n)-1))) /* Swap two types */ -#define M_SWAP(type, x, y) do { \ - type _tmp = (x); \ - (x) = (y); \ - (y) = _tmp; \ +#define M_SWAP(type, x, y) do { \ + type _tmp = (x); \ + (x) = (y); \ + (y) = _tmp; \ } while (0) @@ -1816,7 +1816,7 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, ) alignment requirements." */ #ifndef __cplusplus -# define M_CONST_CAST(type, n) \ +# define M_CONST_CAST(type, n) \ (((union { type *ptr; type const *cptr; }){n}).cptr) #else # define M_CONST_CAST(type, n) const_cast(n) @@ -1829,10 +1829,10 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, ) * Used to handle intrusive structure. * NOTE: Use an ASSIGN_CAST to make the cast a little bit safer. */ -#define M_TYPE_FROM_FIELD(type, ptr, field_type, field) \ +#define M_TYPE_FROM_FIELD(type, ptr, field_type, field) \ ((type *)(void*)( (char *)M_ASSIGN_CAST(field_type*, (ptr)) - offsetof(type, field) )) -#define M_CTYPE_FROM_FIELD(type, ptr, field_type, field) \ +#define M_CTYPE_FROM_FIELD(type, ptr, field_type, field) \ ((type const *)(const void*)( (const char *)M_ASSIGN_CAST(field_type const *, (ptr)) - offsetof(type const, field) )) @@ -1841,7 +1841,7 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, ) */ #define M_APPLY_SIZEOF(id) sizeof (id) #define M_ADD_SIZE(a,b) a + b -#define M_CACHELINE_ALIGN(name, ...) \ +#define M_CACHELINE_ALIGN(name, ...) \ char name[M_ALIGN_FOR_CACHELINE_EXCLUSION > M_REDUCE(M_APPLY_SIZEOF, M_ADD_SIZE, __VA_ARGS__) \ ? M_ALIGN_FOR_CACHELINE_EXCLUSION - M_REDUCE(M_APPLY_SIZEOF, M_ADD_SIZE, __VA_ARGS__) : 1] @@ -2098,12 +2098,12 @@ m_core_hash (const void *str, size_t length) #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define M_HASH_INT32(a) ( (a) ^ ((a) << 11) ^ M_HASH_SEED ) #define M_HASH_INT64(a) ( ( (a) >> 33 ) ^ (a) ^ ((a) << 11) ^ M_HASH_SEED ) -#define M_HASH_DEFAULT(a) \ - (size_t) _Generic((a)+0, \ - int32_t: M_HASH_INT32((uint32_t) M_AS_TYPE(int32_t, a)), \ - uint32_t: M_HASH_INT32(M_AS_TYPE(uint32_t, a)), \ - int64_t: M_HASH_INT64((uint64_t) M_AS_TYPE(int64_t, a)), \ - uint64_t: M_HASH_INT64(M_AS_TYPE(uint64_t, a)), \ +#define M_HASH_DEFAULT(a) \ + (size_t) _Generic((a)+0, \ + int32_t: M_HASH_INT32((uint32_t) M_AS_TYPE(int32_t, a)), \ + uint32_t: M_HASH_INT32(M_AS_TYPE(uint32_t, a)), \ + int64_t: M_HASH_INT64((uint64_t) M_AS_TYPE(int64_t, a)), \ + uint64_t: M_HASH_INT64(M_AS_TYPE(uint64_t, a)), \ default: M_HASH_POD_DEFAULT(a) ) #else #define M_HASH_DEFAULT(a) M_HASH_POD_DEFAULT(a) @@ -2195,7 +2195,7 @@ m_core_hash (const void *str, size_t length) Example: M_GET_METHOD(INIT, my_default, INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)) --> mpz_init M_GET_METHOD(INIT, my_default, CLEAR(mpz_clear),SET(mpz_set)) --> my_default */ -#define M_GET_METHOD(method, method_default, ...) \ +#define M_GET_METHOD(method, method_default, ...) \ M_RET_ARG2 (M_MAP2B(M_C, M_C3(M_, method, _), __VA_ARGS__), method_default,) /* Get the given method */ @@ -2343,7 +2343,7 @@ m_core_hash (const void *str, size_t length) /* API transformation support: transform the call to the method into the supported API by the method. Example of usage in oplist: ( INIT_WITH(API_1(method)) ) */ -#define M_APPLY_API(method, oplist, ...) \ +#define M_APPLY_API(method, oplist, ...) \ M_RET_ARG2(M_C(M_OPLAPI_INDIRECT_, method)(M_C(M_OPLAPI_EXTRACT_,method),oplist,__VA_ARGS__), method(__VA_ARGS__),) /* API Transformation : @@ -2385,33 +2385,33 @@ m_core_hash (const void *str, size_t length) /* Define the no default function that generates a compiler error if the method is expanded. */ -#define M_NO_DEFAULT(...) \ - M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ +#define M_NO_DEFAULT(...) \ + M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ "The requested operator has no method registered in the given OPLIST. ") -#define M_NO_DEF_TYPE \ - M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ +#define M_NO_DEF_TYPE \ + M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ "The requested operator has no type/subtype/suboplist registered in the given OPLIST. ") /* Test if the given variable is a basic C variable: int, float, enum, bool or compatible. NOTE: Not perfect, but catch some errors */ -#define M_CHECK_DEFAULT_TYPE(a) \ - M_STATIC_ASSERT(sizeof (a) <= M_MAX(sizeof(long long), \ - M_MAX(sizeof (long double), \ - sizeof (uintmax_t))), \ - M_LIB_NOT_A_DEFAULT_TYPE, \ - "The given variable is too big to be a default type," \ - "but the used macro can only be used with such one." \ +#define M_CHECK_DEFAULT_TYPE(a) \ + M_STATIC_ASSERT(sizeof (a) <= M_MAX(sizeof(long long), \ + M_MAX(sizeof (long double), \ + sizeof (uintmax_t))), \ + M_LIB_NOT_A_DEFAULT_TYPE, \ + "The given variable is too big to be a default type," \ + "but the used macro can only be used with such one." \ "It is likely the given oplist is not right.") /* Check if both variables are of the same type. The test compare their size. NOTE: Not perfect but catch some errors */ -#define M_CHECK_SAME(a, b) \ - M_STATIC_ASSERT(sizeof(a) == sizeof(b), \ - M_LIB_NOT_SAME_TYPE, \ - "The variable " M_AS_STR(a) " and " M_AS_STR(b) \ +#define M_CHECK_SAME(a, b) \ + M_STATIC_ASSERT(sizeof(a) == sizeof(b), \ + M_LIB_NOT_SAME_TYPE, \ + "The variable " M_AS_STR(a) " and " M_AS_STR(b) \ " are not of same type.") /* Check if the oplist is compatible with the type. @@ -2425,33 +2425,33 @@ m_core_hash (const void *str, size_t length) - oplist of the oplist to test to. */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \ - M_IF_METHOD(TYPE, oplist) \ - ( \ - static inline void M_C3(name, _int_control_type, inst)(void) \ - { \ - type x; \ - M_STATIC_ASSERT(_Generic(&x, \ - M_GET_TYPE oplist *: 1 /* Ok, type matches */, \ - default: 0 /* NOK, type doesn't match */ ), \ - M_LIB_TYPE_MISTMACH, \ - "The given type " M_AS_STR(type) \ - " and the type of the oplist does not match: " \ - M_AS_STR(oplist) ); \ - } \ +#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \ + M_IF_METHOD(TYPE, oplist) \ + ( \ + static inline void M_C3(name, _int_control_type, inst)(void) \ + { \ + type x; \ + M_STATIC_ASSERT(_Generic(&x, \ + M_GET_TYPE oplist *: 1 /* Ok, type matches */, \ + default: 0 /* NOK, type doesn't match */ ), \ + M_LIB_TYPE_MISTMACH, \ + "The given type " M_AS_STR(type) \ + " and the type of the oplist does not match: " \ + M_AS_STR(oplist) ); \ + } \ , /* End of TYPE */) #else -#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \ - M_IF_METHOD(TYPE, oplist) \ - ( \ - static inline void M_C3(name, _int_control_type, inst)(void) \ - { \ - M_STATIC_ASSERT(sizeof (type) == sizeof (M_GET_TYPE oplist), \ - M_LIB_TYPE_MISTMACH, \ - "The given type " M_AS_STR(type) \ - " and the type of the oplist does not match: " \ - M_AS_STR(oplist) ); \ - } \ +#define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \ + M_IF_METHOD(TYPE, oplist) \ + ( \ + static inline void M_C3(name, _int_control_type, inst)(void) \ + { \ + M_STATIC_ASSERT(sizeof (type) == sizeof (M_GET_TYPE oplist), \ + M_LIB_TYPE_MISTMACH, \ + "The given type " M_AS_STR(type) \ + " and the type of the oplist does not match: " \ + M_AS_STR(oplist) ); \ + } \ , /* End of TYPE */) #endif @@ -2488,12 +2488,12 @@ m_core_hash (const void *str, size_t length) #define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a))) #define M_MEMCMP1_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)) == 0) #define M_MEMCMP2_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a))) -#define M_SWAP_DEFAULT(el1, el2) do { \ - char _tmp[sizeof (el1)]; \ - M_CHECK_SAME(el1, el2); \ - memcpy(&_tmp, &(el1), sizeof (el1)); \ - memcpy(&(el1), &(el2), sizeof (el1)); \ - memcpy(&(el2), &_tmp, sizeof (el1)); \ +#define M_SWAP_DEFAULT(el1, el2) do { \ + char _tmp[sizeof (el1)]; \ + M_CHECK_SAME(el1, el2); \ + memcpy(&_tmp, &(el1), sizeof (el1)); \ + memcpy(&(el1), &(el2), sizeof (el1)); \ + memcpy(&(el2), &_tmp, sizeof (el1)); \ } while (0) /* NOTE: Theses operators are to be used with the '[1]' tricks @@ -2508,27 +2508,27 @@ m_core_hash (const void *str, size_t length) /* Default oplist for plain structure */ -#define M_POD_OPLIST \ +#define M_POD_OPLIST \ (INIT(M_MEMSET_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT), SET(M_MEMCPY_DEFAULT), \ CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), \ HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT)) /* Default oplist for a structure defined with an array of size 1 */ -#define M_A1_OPLIST \ +#define M_A1_OPLIST \ (INIT(M_MEMSET_A1_DEFAULT), INIT_SET(M_MEMCPY_A1_DEFAULT), SET(M_MEMCPY_A1_DEFAULT), \ CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_A1_DEFAULT), CMP(M_MEMCMP2_A1_DEFAULT), \ HASH(M_HASH_A1_DEFAULT)) /* Oplist for a type that does nothing and shall not be instanciated */ -#define M_EMPTY_OPLIST \ - (INIT(M_EMPTY_DEFAULT), INIT_SET(M_EMPTY_DEFAULT), \ - SET(M_EMPTY_DEFAULT), CLEAR(M_EMPTY_DEFAULT), \ - INIT_MOVE(M_EMPTY_DEFAULT), MOVE(M_EMPTY_DEFAULT), \ - EQUAL(M_TRUE_DEFAULT), GET_STR(M_EMPTY_DEFAULT), \ - OUT_STR(M_EMPTY_DEFAULT), IN_STR(M_TRUE_DEFAULT), \ - OUT_SERIAL(M_EMPTY_DEFAULT), IN_SERIAL(M_TRUE_DEFAULT), \ +#define M_EMPTY_OPLIST \ + (INIT(M_EMPTY_DEFAULT), INIT_SET(M_EMPTY_DEFAULT), \ + SET(M_EMPTY_DEFAULT), CLEAR(M_EMPTY_DEFAULT), \ + INIT_MOVE(M_EMPTY_DEFAULT), MOVE(M_EMPTY_DEFAULT), \ + EQUAL(M_TRUE_DEFAULT), GET_STR(M_EMPTY_DEFAULT), \ + OUT_STR(M_EMPTY_DEFAULT), IN_STR(M_TRUE_DEFAULT), \ + OUT_SERIAL(M_EMPTY_DEFAULT), IN_SERIAL(M_TRUE_DEFAULT), \ PARSE_STR(M_TRUE_DEFAULT)) @@ -2540,36 +2540,36 @@ m_core_hash (const void *str, size_t length) # if M_USE_STDIO /* C11 + FILE support */ -# define M_DEFAULT_OPLIST \ - (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ - ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ - MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ - HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \ - IN_STR(M_FSCAN_ARG M_IPTR), OUT_STR(M_FPRINT_ARG), \ +# define M_DEFAULT_OPLIST \ + (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ + CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ + INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ + MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ + HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \ + IN_STR(M_FSCAN_ARG M_IPTR), OUT_STR(M_FPRINT_ARG), \ IN_SERIAL(M_IN_SERIAL_DEFAULT_ARG M_IPTR), OUT_SERIAL(M_OUT_SERIAL_DEFAULT_ARG), \ PARSE_STR(M_PARSE_DEFAULT_TYPE M_IPTR), M_GET_STR_METHOD_FOR_DEFAULT_TYPE) # else /* C11 + No FILE support */ -# define M_DEFAULT_OPLIST \ - (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ - ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ - MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ - HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \ +# define M_DEFAULT_OPLIST \ + (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ + CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ + INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ + MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ + HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) , \ IN_SERIAL(M_IN_SERIAL_DEFAULT_ARG M_IPTR), OUT_SERIAL(M_OUT_SERIAL_DEFAULT_ARG), \ PARSE_STR(M_PARSE_DEFAULT_TYPE M_IPTR), M_GET_STR_METHOD_FOR_DEFAULT_TYPE) # endif #else /* C99 */ -# define M_DEFAULT_OPLIST \ - (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ - ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ - MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ +# define M_DEFAULT_OPLIST \ + (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ + CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ + INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ + MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ HASH(M_HASH_DEFAULT), SWAP(M_SWAP_DEFAULT) ) #endif @@ -2578,8 +2578,8 @@ m_core_hash (const void *str, size_t length) * M_DEFAULT_OPLIST is nearly ok, except for ADD/SUB/MUL/DIV * that generates warnings with boolean. */ -#define M_BOOL_OPLIST \ - M_OPEXTEND(M_DEFAULT_OPLIST, ADD(M_OR_DEFAULT), MUL(M_AND_DEFAULT), \ +#define M_BOOL_OPLIST \ + M_OPEXTEND(M_DEFAULT_OPLIST, ADD(M_OR_DEFAULT), MUL(M_AND_DEFAULT), \ SUB(0), DIV(0)) @@ -2591,28 +2591,28 @@ m_core_hash (const void *str, size_t length) */ #if M_USE_STDIO /* FILE support */ -#define M_ENUM_OPLIST(type, init) \ - (INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \ - SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ - EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ - HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ - TYPE(type), OPLIST(init), \ - IN_STR(API_1(M_ENUM_FSCAN)), OUT_STR(M_ENUM_FPRINT), \ - IN_SERIAL(API_1(M_ENUM_IN_SERIAL)), OUT_SERIAL(M_ENUM_OUT_SERIAL), \ - PARSE_STR(API_1(M_ENUM_PARSE)), M_GET_STR_METHOD_FOR_ENUM_TYPE \ +#define M_ENUM_OPLIST(type, init) \ + (INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \ + SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ + INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ + TYPE(type), OPLIST(init), \ + IN_STR(API_1(M_ENUM_FSCAN)), OUT_STR(M_ENUM_FPRINT), \ + IN_SERIAL(API_1(M_ENUM_IN_SERIAL)), OUT_SERIAL(M_ENUM_OUT_SERIAL), \ + PARSE_STR(API_1(M_ENUM_PARSE)), M_GET_STR_METHOD_FOR_ENUM_TYPE \ ) #else /* No File support */ -#define M_ENUM_OPLIST(type, init) \ - (INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \ - SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ - EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ - HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ - TYPE(type), OPLIST(init), \ - IN_SERIAL(API_1(M_ENUM_IN_SERIAL)), OUT_SERIAL(M_ENUM_OUT_SERIAL), \ - PARSE_STR(API_1(M_ENUM_PARSE)), M_GET_STR_METHOD_FOR_ENUM_TYPE \ +#define M_ENUM_OPLIST(type, init) \ + (INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \ + SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ + INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ + TYPE(type), OPLIST(init), \ + IN_SERIAL(API_1(M_ENUM_IN_SERIAL)), OUT_SERIAL(M_ENUM_OUT_SERIAL), \ + PARSE_STR(API_1(M_ENUM_PARSE)), M_GET_STR_METHOD_FOR_ENUM_TYPE \ ) #endif /* M_USE_STDIO */ @@ -2620,7 +2620,7 @@ m_core_hash (const void *str, size_t length) #define M_GET_STR_METHOD_FOR_ENUM_TYPE /* Initialize an enum to its init value */ -#define M_ENUM_INIT(oplist, var) \ +#define M_ENUM_INIT(oplist, var) \ ((var) = M_GET_OPLIST oplist ) /* Define helper functions for enum oplist */ @@ -2638,7 +2638,7 @@ m_core_fscan_enum (FILE *f) return ret; } #define M_ENUM_FPRINT(f, var) fprintf( (f), "%lld", (long long) (var)) -#define M_ENUM_FSCAN(oplist, var, f) \ +#define M_ENUM_FSCAN(oplist, var, f) \ ( var = (M_GET_TYPE oplist) (true ? m_core_fscan_enum(f) : 0), fgetc(f)) #endif /* M_USE_STDIO */ @@ -2658,32 +2658,32 @@ m_core_parse2_enum (const char str[], const char **endptr) return end != str; } -#define M_ENUM_OUT_SERIAL(serial, var) \ +#define M_ENUM_OUT_SERIAL(serial, var) \ ((serial)->m_interface->write_integer(serial, (long long) (var), sizeof (var))) -#define M_ENUM_IN_SERIAL(oplist, var, serial) \ +#define M_ENUM_IN_SERIAL(oplist, var, serial) \ ( var = (M_GET_TYPE oplist)(true ? m_core_in_serial_enum(serial) : 0), (serial)->tmp.r) -#define M_ENUM_GET_STR(str, var, append) \ +#define M_ENUM_GET_STR(str, var, append) \ ((append ? string_cat_printf : string_printf) (str, "%lld", (long long) (var) )) -#define M_ENUM_PARSE(oplist, var, str, endptr) \ +#define M_ENUM_PARSE(oplist, var, str, endptr) \ ( var = (M_GET_TYPE oplist) (true ? m_core_parse1_enum(str) : 0), m_core_parse2_enum(str, endptr)) /* Default oplist for standard types of pointers. */ -#define M_PTR_OPLIST \ - (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ +#define M_PTR_OPLIST \ + (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ + CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), \ + INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ SWAP(M_SWAP_DEFAULT) ) /* Default oplist for complex objects with "classic" names for methods. */ -#define M_CLASSIC_OPLIST(name) ( \ - INIT(M_C(name, _init)), \ - INIT_SET(M_C(name, _init_set)), \ - SET(M_C(name, _set)), \ - CLEAR(M_C(name, _clear)), \ +#define M_CLASSIC_OPLIST(name) ( \ + 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, _t)) ) @@ -2694,10 +2694,10 @@ m_core_parse2_enum (const char str[], const char **endptr) #define M_CSTR_HASH(s) (m_core_hash((s), strlen(s))) #define M_CSTR_EQUAL(a,b) (strcmp((a),(b)) == 0) #define M_CSTR_OUT_STR(file, str) fprintf(file, "%s", str) -#define M_CSTR_OPLIST (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), \ - SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ - HASH(M_CSTR_HASH), EQUAL(M_CSTR_EQUAL), \ - CMP(strcmp), TYPE(const char *), \ +#define M_CSTR_OPLIST (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), \ + SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + HASH(M_CSTR_HASH), EQUAL(M_CSTR_EQUAL), \ + CMP(strcmp), TYPE(const char *), \ OUT_STR(M_CSTR_OUT_STR) ) @@ -2717,7 +2717,7 @@ m_core_parse2_enum (const char str[], const char **endptr) Return 0 (method is absent or disabled) or 1 (method is present and not disabled). NOTE: Does not work if method is OPLIST, KEY_OPLIST or VALUE_OPLIST. */ -#define M_TEST_METHOD_P(method, oplist) \ +#define M_TEST_METHOD_P(method, oplist) \ M_BOOL(M_GET_METHOD (method, 0, M_OPFLAT oplist)) /* Test if a method is disabled in an oplist. @@ -2725,7 +2725,7 @@ m_core_parse2_enum (const char str[], const char **endptr) Example: (INIT(0), CLEAR(clear)) Here INIT is disabled, whereas CLEAR is not. Return 1 (method is disabled) or 0 (method is not disabled - absent or present) */ -#define M_TEST_DISABLED_METHOD_P(method, oplist) \ +#define M_TEST_DISABLED_METHOD_P(method, oplist) \ M_INV(M_BOOL(M_GET_METHOD (method, 1, M_OPFLAT oplist))) /* Perfom a preprocessing M_IF, if the method is present in the oplist. @@ -2738,7 +2738,7 @@ m_core_parse2_enum (const char str[], const char **endptr) /* Perform a preprocessing M_IF if the method exists in both oplist. Example: M_IF_METHOD_BOTH(HASH, oplist1, oplist2) (define function with HASH method, ) */ -#define M_IF_METHOD_BOTH(method, oplist1, oplist2) \ +#define M_IF_METHOD_BOTH(method, oplist1, oplist2) \ M_IF(M_AND(M_TEST_METHOD_P(method, oplist1), M_TEST_METHOD_P(method, oplist2))) /* Perform a preprocessing M_IF if both methods exist in the oplist. @@ -2753,20 +2753,20 @@ m_core_parse2_enum (const char str[], const char **endptr) /* Perform a preprocessing M_IF if both methods exists in both oplist. Example: M_IF_METHOD2_BOTH(HASH, INIT, oplist1, oplist2) (define function with HASH & INIT method, ) */ -#define M_IF_METHOD2_BOTH(method1, method2, oplist1, oplist2) \ +#define M_IF_METHOD2_BOTH(method1, method2, oplist1, oplist2) \ M_IF(M_AND(M_AND(M_TEST_METHOD_P(method1, oplist1), M_TEST_METHOD_P(method1, oplist2)), \ M_AND(M_TEST_METHOD_P(method2, oplist1), M_TEST_METHOD_P(method2, oplist2)))) /* Perform a preprocessing M_IF if the method exists for all oplist. Example: M_IF_METHOD_ALL(HASH, oplist1, oplist2) (define function with HASH method, ) */ -#define M_IF_METHOD_ALL(method, ...) \ +#define M_IF_METHOD_ALL(method, ...) \ M_IF(M_REDUCE2(M_TEST_METHOD_P, M_AND, method, __VA_ARGS__)) /* Perform a preprocessing M_IF if both methods exist for all oplist. Example: M_IF_METHOD2_ALL(HASH, INIT, oplist1, oplist2) (define function with HASH & INIT methods, ) */ -#define M_IF_METHOD2_ALL(method1, method2, ...) \ +#define M_IF_METHOD2_ALL(method1, method2, ...) \ M_IF(M_REDUCE2(M_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__)) -#define M_TEST_METHOD2_P(method_pair, oplist) \ +#define M_TEST_METHOD2_P(method_pair, oplist) \ M_AND(M_TEST_METHOD_P(M_PAIR_1 method_pair, oplist), M_TEST_METHOD_P(M_PAIR_2 method_pair, oplist)) /* By putting this after a method in an oplist, we transform the argument list @@ -2774,27 +2774,27 @@ m_core_parse2_enum (const char str[], const char **endptr) #define M_IPTR(...) ( & __VA_ARGS__ ) /* Perform an INIT_MOVE if present, or emulate it using INIT_SET/CLEAR */ -#define M_DO_INIT_MOVE(oplist, dest, src) do { \ - M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_INIT_MOVE(oplist, (dest), (src)), \ - M_CALL_INIT_SET(oplist, (dest), (src)) ; \ - M_CALL_CLEAR(oplist, (src) )); \ +#define M_DO_INIT_MOVE(oplist, dest, src) do { \ + M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_INIT_MOVE(oplist, (dest), (src)), \ + M_CALL_INIT_SET(oplist, (dest), (src)) ; \ + M_CALL_CLEAR(oplist, (src) )); \ } while (0) /* Perform a MOVE if present, or emulate it using CLEAR/INIT_MOVE if possible, or with SET/CLEAR otherwise */ -#define M_DO_MOVE(oplist, dest, src) do { \ - M_IF_METHOD(MOVE, oplist) (M_CALL_MOVE(oplist, (dest), (src)), \ - M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_CLEAR(oplist, (dest)); \ - M_CALL_INIT_MOVE(oplist, (dest), (src)), \ - M_CALL_SET(oplist, (dest), (src)); \ - M_CALL_CLEAR(oplist, (src)) \ - )); \ +#define M_DO_MOVE(oplist, dest, src) do { \ + M_IF_METHOD(MOVE, oplist) (M_CALL_MOVE(oplist, (dest), (src)), \ + M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_CLEAR(oplist, (dest)); \ + M_CALL_INIT_MOVE(oplist, (dest), (src)), \ + M_CALL_SET(oplist, (dest), (src)); \ + M_CALL_CLEAR(oplist, (src)) \ + )); \ } while (0) /* Test if the argument is a valid oplist. NOTE: Incomplete test. */ -#define M_OPLIST_P(a) \ +#define M_OPLIST_P(a) \ M_AND(M_PARENTHESIS_P(a), M_INV(M_PARENTHESIS_P (M_OPFLAT a))) #define M_IF_OPLIST(a) M_IF(M_OPLIST_P(a)) @@ -2806,13 +2806,13 @@ m_core_parse2_enum (const char str[], const char **endptr) otherwise it returns the argument. Global oplist is limited to typedef types. */ -#define M_GLOBAL_OPLIST(a) \ +#define M_GLOBAL_OPLIST(a) \ M_IF( M_OPLIST_P(a))(M_GLOBALI_ID, M_GLOBALI_OPLIST_ELSE)(a) #define M_GLOBALI_ID(a) a #define M_GLOBALI_OPLIST_ELSE(a) M_GLOBALI_OPLIST_ELSE2(a, M_C(M_OPL_, a)()) #define M_GLOBALI_OPLIST_ELSE2(a, op) M_IF( M_OPLIST_P (op))(op, a) -#define M_GLOBAL_TYPE(a) \ +#define M_GLOBAL_TYPE(a) \ M_IF( M_OPLIST_P(a))(M_GLOBALI_TYPE_GET, M_GLOBALI_ID)(a) #define M_GLOBALI_TYPE_GET(a) M_GET_TYPE a @@ -2825,7 +2825,7 @@ m_core_parse2_enum (const char str[], const char **endptr) but rather than if it starts with parenthesis: this is to allow M_OPL_a() to expand into an invalid oplist ((M_LIB_ERRROR())) */ -#define M_GLOBAL_OPLIST_OR_DEF(a) \ +#define M_GLOBAL_OPLIST_OR_DEF(a) \ M_IF( M_PARENTHESIS_P(a))(M_GLOBALI_OPLIST_DEFAULT1, M_GLOBALI_OPLIST_OR_DEF_ELSE)(a) #define M_GLOBALI_OPLIST_DEFAULT1(a) M_GLOBALI_OPLIST_DEFAULT2 #define M_GLOBALI_OPLIST_DEFAULT2() M_DEFAULT_OPLIST @@ -2851,7 +2851,7 @@ m_core_parse2_enum (const char str[], const char **endptr) * Shall define a NAME base method * All INIT_WITH methods shall be named as name ## _init_with_ ## NARGS */ -#define M_INIT_WITH_NVAR(oplist, ...) \ +#define M_INIT_WITH_NVAR(oplist, ...) \ M_SUFFIX_FUNCTION_BY_NARGS(M_C(M_GET_NAME oplist, _init_with), __VA_ARGS__)(__VA_ARGS__) @@ -2866,33 +2866,33 @@ m_core_parse2_enum (const char str[], const char **endptr) oplist has been recorded. USAGE: for M_EACH(item, list, LIST_OPLIST) { M_LETaction; } */ -#define M_EACH(item, container, oplist) \ +#define M_EACH(item, container, oplist) \ M_EACHI_OPLIST(item, container, M_GLOBAL_OPLIST(oplist)) /* Internal for M_EACH */ -#define M_EACHI_OPLIST(item, container, oplist) \ - M_IF_METHOD(IT_REF, oplist)(M_EACHI, M_EACHI_CONST) \ - (item, container, oplist, M_C(local_iterator_, __LINE__), \ +#define M_EACHI_OPLIST(item, container, oplist) \ + M_IF_METHOD(IT_REF, oplist)(M_EACHI, M_EACHI_CONST) \ + (item, container, oplist, M_C(local_iterator_, __LINE__), \ M_C(local_cont_, __LINE__)) /* Internal for M_EACH with M_GET_IT_REF operator */ -#define M_EACHI(item,container,oplist, iterator, cont) \ - (bool cont = true; cont; cont = false) \ - for(M_GET_SUBTYPE oplist *item; cont ; cont = false) \ - for(M_GET_IT_TYPE oplist iterator; cont ; cont = false) \ - for(M_GET_IT_FIRST oplist (iterator, container) ; \ - !M_GET_IT_END_P oplist (iterator) \ - && (item = M_GET_IT_REF oplist (iterator), true) ; \ +#define M_EACHI(item,container,oplist, iterator, cont) \ + (bool cont = true; cont; cont = false) \ + for(M_GET_SUBTYPE oplist *item; cont ; cont = false) \ + for(M_GET_IT_TYPE oplist iterator; cont ; cont = false) \ + for(M_GET_IT_FIRST oplist (iterator, container) ; \ + !M_GET_IT_END_P oplist (iterator) \ + && (item = M_GET_IT_REF oplist (iterator), true) ; \ M_GET_IT_NEXT oplist (iterator)) /* Internal for M_EACH with M_GET_IT_CREF operator */ -#define M_EACHI_CONST(item,container,oplist, iterator, cont) \ - (bool cont = true; cont; cont = false) \ - for(const M_GET_SUBTYPE oplist *item; cont ; cont = false) \ - for(M_GET_IT_TYPE oplist iterator; cont ; cont = false) \ - for(M_GET_IT_FIRST oplist (iterator, container) ; \ - !M_GET_IT_END_P oplist (iterator) \ - && (item = M_GET_IT_CREF oplist (iterator), true) ; \ +#define M_EACHI_CONST(item,container,oplist, iterator, cont) \ + (bool cont = true; cont; cont = false) \ + for(const M_GET_SUBTYPE oplist *item; cont ; cont = false) \ + for(M_GET_IT_TYPE oplist iterator; cont ; cont = false) \ + for(M_GET_IT_FIRST oplist (iterator, container) ; \ + !M_GET_IT_END_P oplist (iterator) \ + && (item = M_GET_IT_CREF oplist (iterator), true) ; \ M_GET_IT_NEXT oplist (iterator)) @@ -2908,45 +2908,45 @@ m_core_parse2_enum (const char str[], const char **endptr) Last argument can be the oplist or the type itself if a global oplist has been recorded for this type. */ -#define M_LET(a, ...) \ - M_ID(M_LETI1 M_INVERT(a, __VA_ARGS__, \ - M_IF(M_PARENTHESIS_P(a))(M_LETI_VAR_NAME_A, \ +#define M_LET(a, ...) \ + M_ID(M_LETI1 M_INVERT(a, __VA_ARGS__, \ + M_IF(M_PARENTHESIS_P(a))(M_LETI_VAR_NAME_A, \ M_LETI_VAR_NAME_B)(a) )) // 1b. Generate a unique name based on the first variable and the line number #define M_LETI_VAR_NAME_A(var) M_C3(_local_cont_, M_RET_ARG1 var, __LINE__) #define M_LETI_VAR_NAME_B(var) M_C3(_local_cont_, var, __LINE__) // 2. Evaluate with or without and inject oplist -#define M_LETI1(cont, oplist, ...) \ +#define M_LETI1(cont, oplist, ...) \ M_LETI2(cont, M_GLOBAL_OPLIST(oplist), __VA_ARGS__) // 3. Validate oplist before going any further -#define M_LETI2(cont, oplist, ...) \ +#define M_LETI2(cont, oplist, ...) \ M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__) // Stop with a failure (invalid oplist) -#define M_LETI2_FAILURE(cont, oplist, ...) \ +#define M_LETI2_FAILURE(cont, oplist, ...) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist)) // 4. Map all variables to their own LET -#define M_LETI3(cont, oplist, ...) \ - for(bool cont = true; cont ; /* unused */) \ +#define M_LETI3(cont, oplist, ...) \ + for(bool cont = true; cont ; /* unused */) \ M_MAP2(M_LETI_SINGLE, (cont, oplist), __VA_ARGS__) // 5. Dispatch the right LET in function of having or not arguments -#define M_LETI_SINGLE(data, name) \ - M_IF(M_PARENTHESIS_P(name))( \ +#define M_LETI_SINGLE(data, name) \ + M_IF(M_PARENTHESIS_P(name))( \ M_LETI_SINGLE2_SET(M_PAIR_1 data, M_PAIR_2 data, M_RET_ARG1 name, M_SKIPI_1 name), \ M_LETI_SINGLE2(M_PAIR_1 data, M_PAIR_2 data, name)) // 6a. Define without argument ==> use INIT -#define M_LETI_SINGLE2(cont, oplist, name) \ - for(M_GET_TYPE oplist name; \ - cont && (M_GET_INIT oplist (name), true); \ - (M_GET_CLEAR oplist (name), cont = false)) \ +#define M_LETI_SINGLE2(cont, oplist, name) \ + for(M_GET_TYPE oplist name; \ + cont && (M_GET_INIT oplist (name), true); \ + (M_GET_CLEAR oplist (name), cont = false)) \ for(;cont;cont = false) // 6b. Define with arguments ==> use INIT_SET (or INIT_WITH support pending) -#define M_LETI_SINGLE2_SET(cont, oplist, name, ...) \ - for(M_GET_TYPE oplist name; \ - cont && (M_LETI_SINGLE2_INIT(oplist, name, __VA_ARGS__), true); \ - (M_GET_CLEAR oplist (name), cont = false)) \ +#define M_LETI_SINGLE2_SET(cont, oplist, name, ...) \ + for(M_GET_TYPE oplist name; \ + cont && (M_LETI_SINGLE2_INIT(oplist, name, __VA_ARGS__), true); \ + (M_GET_CLEAR oplist (name), cont = false)) \ for(;cont;cont = false) -#define M_LETI_SINGLE2_INIT(oplist, name, ...) \ +#define M_LETI_SINGLE2_INIT(oplist, name, ...) \ M_IF_METHOD(INIT_WITH,oplist)(M_CALL_INIT_WITH(oplist, name, __VA_ARGS__), M_GET_INIT_SET oplist (name, __VA_ARGS__)) @@ -2961,20 +2961,20 @@ m_core_parse2_enum (const char str[], const char **endptr) NOTE: If the REVERSE operator exists, it is a list, so reverse the final order. */ -#define M_INIT_VAI(oplist, dest, ...) \ - (void)(M_GET_INIT oplist (dest) , \ - M_MAP2_C(M_INIT_VAI_FUNC, (dest, M_GET_PUSH oplist) , __VA_ARGS__) \ +#define M_INIT_VAI(oplist, dest, ...) \ + (void)(M_GET_INIT oplist (dest) , \ + M_MAP2_C(M_INIT_VAI_FUNC, (dest, M_GET_PUSH oplist) , __VA_ARGS__) \ M_IF_METHOD(REVERSE, oplist)(M_DEFERRED_COMMA M_GET_REVERSE oplist (dest), ) \ ) -#define M_INIT_VAI_FUNC(d, a) \ +#define M_INIT_VAI_FUNC(d, a) \ M_PAIR_2 d (M_PAIR_1 d, a) /* Initialize the container 'dest' as per 'oplist' and fill it with the given VA arguments which are pair of (key,value) */ -#define M_INIT_KEY_VAI(oplist, dest, ...) \ - (void)(M_GET_INIT oplist (dest) , \ +#define M_INIT_KEY_VAI(oplist, dest, ...) \ + (void)(M_GET_INIT oplist (dest) , \ M_MAP2_C(M_INIT_KEY_VAI_FUNC, (dest, M_GET_SET_KEY oplist) , __VA_ARGS__)) -#define M_INIT_KEY_VAI_FUNC(d, a) \ +#define M_INIT_KEY_VAI_FUNC(d, a) \ M_PAIR_2 d (M_PAIR_1 d, M_PAIR_1 a, M_PAIR_2 a) @@ -3018,7 +3018,7 @@ m_core_parse2_enum (const char str[], const char **endptr) #ifndef M_MEMORY_REALLOC #ifdef __cplusplus # include -# define M_MEMORY_REALLOC(type, ptr, n) \ +# define M_MEMORY_REALLOC(type, ptr, n) \ ((type*) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : std::realloc ((ptr), (n)*sizeof (type)))) # define M_MEMORY_FREE(ptr) std::free(ptr) #else @@ -3032,10 +3032,10 @@ m_core_parse2_enum (const char str[], const char **endptr) * NOTE: Can be overloaded by user code. */ #ifndef M_MEMORY_FULL -#define M_MEMORY_FULL(size) do { \ +#define M_MEMORY_FULL(size) do { \ fprintf(stderr, "ERROR(M*LIB): Cannot allocate %zu bytes of memory at (%s:%s:%d).\n", \ - (size_t) (size), __FILE__, __func__, __LINE__); \ - abort(); \ + (size_t) (size), __FILE__, __func__, __LINE__); \ + abort(); \ } while (0) #endif @@ -3046,11 +3046,11 @@ m_core_parse2_enum (const char str[], const char **endptr) /* Always perform a runtime check of the given condition */ #ifndef M_ASSERT_INIT -#define M_ASSERT_INIT(expr, object) { \ - if (!(expr)) { \ +#define M_ASSERT_INIT(expr, object) { \ + if (!(expr)) { \ fprintf(stderr, "ERROR(M*LIB): Cannot initialize %s at (%s:%s:%d): %s\n", \ - (object), __FILE__, __func__, __LINE__, #expr); \ - abort(); \ + (object), __FILE__, __func__, __LINE__, #expr); \ + abort(); \ } } while (0) #endif @@ -3060,8 +3060,8 @@ m_core_parse2_enum (const char str[], const char **endptr) * NOTE: Can be overiden by user if it needs to keep access under control * even on release mode */ #ifndef M_ASSERT_INDEX -#define M_ASSERT_INDEX(index, max) do { \ - assert(index < max); \ +#define M_ASSERT_INDEX(index, max) do { \ + assert(index < max); \ } while (0) #endif @@ -3092,13 +3092,13 @@ m_core_parse2_enum (const char str[], const char **endptr) an expression. */ #if defined(__cplusplus) -# define M_STATIC_ASSERT(cond, error, msg) \ +# define M_STATIC_ASSERT(cond, error, msg) \ ([] { static_assert(cond, #error ": " msg); } ()) #elif defined(__GNUC__) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -# define M_STATIC_ASSERT(cond, error, msg) \ +# define M_STATIC_ASSERT(cond, error, msg) \ M_ATTR_EXTENSION ({ static_assert(cond, #error ": " msg); }) #else -# define M_STATIC_ASSERT(cond, error, msg) \ +# define M_STATIC_ASSERT(cond, error, msg) \ ((void) sizeof(struct { int error : !!(cond);})) #endif @@ -3305,8 +3305,8 @@ typedef struct m_serial_write_interface_s { * by calling the serializer interface associated to the type of the object. * NOTE: Supports only C11. */ -#define M_OUT_SERIAL_DEFAULT_ARG(serial, x) \ - _Generic(((void)0,(x)), \ +#define M_OUT_SERIAL_DEFAULT_ARG(serial, x) \ + _Generic(((void)0,(x)), \ bool: (serial)->m_interface->write_boolean(serial, M_AS_TYPE(bool, (x))), \ char: (serial)->m_interface->write_integer(serial, M_AS_TYPE(char,(x)), sizeof (x)), \ signed char: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed char,(x)), sizeof (x)), \ @@ -3324,46 +3324,46 @@ typedef struct m_serial_write_interface_s { long double: (serial)->m_interface->write_float(serial, M_AS_TYPE(long double,(x)), sizeof (x)), \ const char *: (serial)->m_interface->write_string(serial, M_AS_TYPE(const char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \ char *: (serial)->m_interface->write_string(serial, M_AS_TYPE(char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \ - const void *: M_SERIAL_FAIL /* unsupported */, \ + const void *: M_SERIAL_FAIL /* unsupported */, \ void *: M_SERIAL_FAIL /* unsupported */) /* Convert a Serialized data to a C default variale (bool, integer, float) * by calling the serializer interface associated to the type of the object. * NOTE: Supports only C11. */ -#define M_IN_SERIAL_DEFAULT_ARG(xptr, serial) \ - _Generic(((void)0,*(xptr)), \ +#define M_IN_SERIAL_DEFAULT_ARG(xptr, serial) \ + _Generic(((void)0,*(xptr)), \ bool: (serial)->m_interface->read_boolean(serial, M_AS_TYPE(bool *, xptr)), \ - char: m_core_in_serial_char(serial, M_AS_TYPE(char*,xptr)), \ + char: m_core_in_serial_char(serial, M_AS_TYPE(char*,xptr)), \ signed char: m_core_in_serial_schar(serial, M_AS_TYPE(signed char*,xptr)), \ unsigned char: m_core_in_serial_uchar(serial, M_AS_TYPE(unsigned char*,xptr)), \ signed short: m_core_in_serial_sshort(serial, M_AS_TYPE(signed short*,xptr)), \ unsigned short: m_core_in_serial_ushort(serial, M_AS_TYPE(unsigned short*,xptr)), \ signed int: m_core_in_serial_sint(serial, M_AS_TYPE(signed int*,xptr)), \ unsigned int: m_core_in_serial_uint(serial, M_AS_TYPE(unsigned int*,xptr)), \ - long int: m_core_in_serial_slong(serial, M_AS_TYPE(long*,xptr)), \ + long int: m_core_in_serial_slong(serial, M_AS_TYPE(long*,xptr)), \ unsigned long int: m_core_in_serial_ulong(serial, M_AS_TYPE(unsigned long*,xptr)), \ long long int: m_core_in_serial_sllong(serial, M_AS_TYPE(long long*,xptr)), \ unsigned long long int: m_core_in_serial_ullong(serial, M_AS_TYPE(unsigned long long*,xptr)), \ - float: m_core_in_serial_float(serial, M_AS_TYPE(float*,xptr)), \ - double: m_core_in_serial_double(serial, M_AS_TYPE(double*,xptr)), \ + float: m_core_in_serial_float(serial, M_AS_TYPE(float*,xptr)), \ + double: m_core_in_serial_double(serial, M_AS_TYPE(double*,xptr)), \ long double: m_core_in_serial_ldouble(serial, M_AS_TYPE(long double*,xptr)), \ - const char *: M_SERIAL_FAIL /* unsupported (size unknown) */, \ - char *: M_SERIAL_FAIL /* unsupported (size unknown) */, \ - const void *: M_SERIAL_FAIL /* unsupported */, \ + const char *: M_SERIAL_FAIL /* unsupported (size unknown) */, \ + char *: M_SERIAL_FAIL /* unsupported (size unknown) */, \ + const void *: M_SERIAL_FAIL /* unsupported */, \ void *: M_SERIAL_FAIL /* unsupported */) /* Helper functions for M_IN_SERIAL_DEFAULT_ARG as we need to define a function per supported type in the generic expression */ -#define M_IN_SERIAL_DEFAULT_TYPE_DEF(name, type, func, promoted_type) \ - static inline m_serial_return_code_t \ - name (m_serial_read_t serial, type *ptr) \ - { \ - promoted_type i; \ - m_serial_return_code_t r; \ - r = serial->m_interface->func(serial, &i, sizeof (type)); \ - *ptr = (type) i; \ - return r; \ +#define M_IN_SERIAL_DEFAULT_TYPE_DEF(name, type, func, promoted_type) \ + static inline m_serial_return_code_t \ + name (m_serial_read_t serial, type *ptr) \ + { \ + promoted_type i; \ + m_serial_return_code_t r; \ + r = serial->m_interface->func(serial, &i, sizeof (type)); \ + *ptr = (type) i; \ + return r; \ } M_IN_SERIAL_DEFAULT_TYPE_DEF(m_core_in_serial_char, char, read_integer, long long) diff --git a/m-deque.h b/m-deque.h index 78dda982..1626a8be 100644 --- a/m-deque.h +++ b/m-deque.h @@ -29,9 +29,9 @@ /* Define a deque of a given type and its associated functions. USAGE: DEQUE_DEF(name, type [, oplist_of_the_type]) */ -#define DEQUE_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - DEQUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DEQUE_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + DEQUEI_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), M_C(name, _node_ct) ), \ (name, __VA_ARGS__, M_C(name,_t), M_C(name,_it_t), M_C(name, _node_ct)))) \ M_END_PROTECTED_CODE @@ -40,9 +40,9 @@ /* Define a deque of a given type and its associated functions. as the provided type name_t with the iterator named it_t. USAGE: DEQUE_DEF(name, name_t, it_t, type [, oplist_of_the_type]) */ -#define DEQUE_DEF_AS(name, name_t, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - DEQUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DEQUE_DEF_AS(name, name_t, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + DEQUEI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, M_C(name, _node_ct) ), \ (name, __VA_ARGS__, name_t, it_t, M_C(name, _node_ct)))) \ M_END_PROTECTED_CODE @@ -50,9 +50,9 @@ /* Define the oplist of a deque of a type. USAGE: DEQUE_OPLIST(name[, oplist of the type]) */ -#define DEQUE_OPLIST(...) \ - DEQUEI_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST), \ +#define DEQUE_OPLIST(...) \ + DEQUEI_OPLIST_P1 (M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST), \ (__VA_ARGS__ ))) /********************************** INTERNAL ************************************/ @@ -63,17 +63,17 @@ #endif /* Define the internal contract of a deque */ -#define DEQUEI_CONTRACT(d) do { \ - assert ((d) != NULL); \ - assert ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \ - assert ((d)->front->node != NULL); \ - assert ((d)->front->index <= (d)->front->node->size); \ - assert ((d)->back->node != NULL); \ - assert ((d)->back->index <= (d)->back->node->size); \ - assert ((d)->front->node != (d)->back->node || \ - (d)->front->index <= (d)->back->index); \ - assert ((d)->front->node != (d)->back->node || \ - (d)->back->index - (d)->front->index == (d)->count); \ +#define DEQUEI_CONTRACT(d) do { \ + assert ((d) != NULL); \ + assert ((d)->default_size >= DEQUEUI_DEFAULT_SIZE); \ + assert ((d)->front->node != NULL); \ + assert ((d)->front->index <= (d)->front->node->size); \ + assert ((d)->back->node != NULL); \ + assert ((d)->back->index <= (d)->back->node->size); \ + assert ((d)->front->node != (d)->back->node || \ + (d)->front->index <= (d)->back->index); \ + assert ((d)->front->node != (d)->back->node || \ + (d)->back->index - (d)->front->index == (d)->count); \ } while (0) /* Deferred evaluation for the deque definition, @@ -81,11 +81,11 @@ #define DEQUEI_DEF_P1(arg) DEQUEI_DEF_P2 arg /* Validate the oplist before going further */ -#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \ +#define DEQUEI_DEF_P2(name, type, oplist, deque_t, it_t, node_t) \ M_IF_OPLIST(oplist)(DEQUEI_DEF_P3, DEQUEI_DEF_FAILURE)(name, type, oplist, deque_t, it_t, node_t) /* Stop processing with a compilation failure */ -#define DEQUEI_DEF_FAILURE(name, type, oplist, deque_t, it_t, node_t) \ +#define DEQUEI_DEF_FAILURE(name, type, oplist, deque_t, it_t, node_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DEQUE_DEF): the given argument is not a valid oplist: " #oplist) /* Internal deque definition @@ -96,880 +96,880 @@ - it_t: alias for M_C(name, _it_t) [ iterator of the container ] - node_t: alias for node_t [ node ] */ -#define DEQUEI_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \ - \ - /* It is a linked list of buckets of the types, \ - each new created bucket size grows compared to the previous one \ - resulting in: \ - strict O(1) for push/pop \ - O(ln(n)) for random access. \ - No insert / delete operations are planned. \ - [Could be done in O(n) complexity if needed] \ - Define the bucket (aka node) structure. \ - */ \ - typedef struct M_C(name, _node_s) { \ - ILIST_INTERFACE(M_C(name, _node_list), struct M_C(name, _node_s)); \ - size_t size; \ - type data[M_MIN_FLEX_ARRAY_SIZE]; \ - } node_t; \ - \ - /* Each node is allocated with a variable size bucket (so we use \ - M_GET_REALLOC for the allocation). But we want to delete the nodes \ - automatically with the intrusive list used for storing the nodes: \ - so we register as a DEL operator the FREE operator of the oplist. \ - The interfaces are compatible. \ - */ \ - ILIST_DEF(M_C(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \ - \ - /* Define an internal iterator */ \ - typedef struct M_C(name, _it2_s) { \ - node_t *node; \ - size_t index; \ - } M_C(name, _it2_ct)[1]; \ - \ - /* Define the deque type: \ - - 'list' if the list of buckets containing the objects. \ - - 'front' and 'back' are iterators to the first and last elements. \ - - 'default_size' is the size used for the creation of a new bucket \ - - 'count' is the number of elements in the container. \ - */ \ - typedef struct M_C(name, _s) { \ - M_C(name, _node_list_t) list; \ - M_C(name, _it2_ct) front; \ - M_C(name, _it2_ct) back; \ - size_t default_size; \ - size_t count; \ - } deque_t[1]; \ - \ - /* Define pointer alias */ \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - /* Define the iterator object */ \ - typedef struct M_C(name, _it_s) { \ - node_t *node; \ - size_t index; \ - const struct M_C(name, _s) *deque; \ - } it_t[1]; \ - \ - /* Define internal types for oplist */ \ - typedef deque_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 node_t* \ - M_C(name, _int_new_node)(deque_t d) \ - { \ - size_t def = d->default_size; \ - /* Test for overflow of the size computation */ \ - if (M_UNLIKELY (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \ - M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ - return NULL; \ - } \ - /* Alloc a new node */ \ - node_t*n = (node_t*) (void*) \ - M_CALL_REALLOC(oplist, char, NULL, \ - sizeof(node_t) + def * sizeof(type) ); \ - if (n==NULL) { \ - M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ - return NULL; \ - } \ - /* Initialize the node */ \ - n->size = def; \ - M_C(name, _node_list_init_field)(n); \ - /* Increase the next bucket allocation */ \ - /* Do not increase it too much if there are few items */ \ - def = M_MIN(def, d->count); \ - d->default_size = M_CALL_INC_ALLOC(oplist, def); \ - /* FIXME: Check for overflow? */ \ - return n; \ - } \ - \ - static inline void \ - M_C(name, _init)(deque_t d) \ - { \ - M_C(name, _node_list_init)(d->list); \ - d->default_size = DEQUEUI_DEFAULT_SIZE; \ - d->count = 0; \ - node_t *n = M_C(name, _int_new_node)(d); \ - if (n == NULL) return; \ - M_C(name, _node_list_push_back)(d->list, n); \ - d->front->node = n; \ - d->front->index = DEQUEUI_DEFAULT_SIZE/2; \ - d->back->node = n; \ - d->back->index = DEQUEUI_DEFAULT_SIZE/2; \ - DEQUEI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _clean)(deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - node_t *min_node = NULL; \ - for(node_t *n = d->front->node; \ - n != NULL ; \ - n = (n == d->back->node) ? NULL : \ - M_C(name, _node_list_next_obj)(d->list, n) ){ \ - size_t min = n == d->front->node ? d->front->index : 0; \ - size_t max = n == d->back->node ? d->back->index : n->size; \ - for(size_t i = min; i < max; i++) { \ - M_CALL_CLEAR(oplist, n->data[i]); \ - } \ +#define DEQUEI_DEF_P3(name, type, oplist, deque_t, it_t, node_t) \ + \ + /* It is a linked list of buckets of the types, \ + each new created bucket size grows compared to the previous one \ + resulting in: \ + strict O(1) for push/pop \ + O(ln(n)) for random access. \ + No insert / delete operations are planned. \ + [Could be done in O(n) complexity if needed] \ + Define the bucket (aka node) structure. \ + */ \ + typedef struct M_C(name, _node_s) { \ + ILIST_INTERFACE(M_C(name, _node_list), struct M_C(name, _node_s)); \ + size_t size; \ + type data[M_MIN_FLEX_ARRAY_SIZE]; \ + } node_t; \ + \ + /* Each node is allocated with a variable size bucket (so we use \ + M_GET_REALLOC for the allocation). But we want to delete the nodes \ + automatically with the intrusive list used for storing the nodes: \ + so we register as a DEL operator the FREE operator of the oplist. \ + The interfaces are compatible. \ + */ \ + ILIST_DEF(M_C(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \ + \ + /* Define an internal iterator */ \ + typedef struct M_C(name, _it2_s) { \ + node_t *node; \ + size_t index; \ + } M_C(name, _it2_ct)[1]; \ + \ + /* Define the deque type: \ + - 'list' if the list of buckets containing the objects. \ + - 'front' and 'back' are iterators to the first and last elements. \ + - 'default_size' is the size used for the creation of a new bucket \ + - 'count' is the number of elements in the container. \ + */ \ + typedef struct M_C(name, _s) { \ + M_C(name, _node_list_t) list; \ + M_C(name, _it2_ct) front; \ + M_C(name, _it2_ct) back; \ + size_t default_size; \ + size_t count; \ + } deque_t[1]; \ + \ + /* Define pointer alias */ \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + /* Define the iterator object */ \ + typedef struct M_C(name, _it_s) { \ + node_t *node; \ + size_t index; \ + const struct M_C(name, _s) *deque; \ + } it_t[1]; \ + \ + /* Define internal types for oplist */ \ + typedef deque_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 node_t* \ + M_C(name, _int_new_node)(deque_t d) \ + { \ + size_t def = d->default_size; \ + /* Test for overflow of the size computation */ \ + if (M_UNLIKELY (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \ + M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ + return NULL; \ + } \ + /* Alloc a new node */ \ + node_t*n = (node_t*) (void*) \ + M_CALL_REALLOC(oplist, char, NULL, \ + sizeof(node_t) + def * sizeof(type) ); \ + if (n==NULL) { \ + M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ + return NULL; \ + } \ + /* Initialize the node */ \ + n->size = def; \ + M_C(name, _node_list_init_field)(n); \ + /* Increase the next bucket allocation */ \ + /* Do not increase it too much if there are few items */ \ + def = M_MIN(def, d->count); \ + d->default_size = M_CALL_INC_ALLOC(oplist, def); \ + /* FIXME: Check for overflow? */ \ + return n; \ + } \ + \ + static inline void \ + M_C(name, _init)(deque_t d) \ + { \ + M_C(name, _node_list_init)(d->list); \ + d->default_size = DEQUEUI_DEFAULT_SIZE; \ + d->count = 0; \ + node_t *n = M_C(name, _int_new_node)(d); \ + if (n == NULL) return; \ + M_C(name, _node_list_push_back)(d->list, n); \ + d->front->node = n; \ + d->front->index = DEQUEUI_DEFAULT_SIZE/2; \ + d->back->node = n; \ + d->back->index = DEQUEUI_DEFAULT_SIZE/2; \ + DEQUEI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _clean)(deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + node_t *min_node = NULL; \ + for(node_t *n = d->front->node; \ + n != NULL ; \ + n = (n == d->back->node) ? NULL : \ + M_C(name, _node_list_next_obj)(d->list, n) ){ \ + size_t min = n == d->front->node ? d->front->index : 0; \ + size_t max = n == d->back->node ? d->back->index : n->size; \ + for(size_t i = min; i < max; i++) { \ + M_CALL_CLEAR(oplist, n->data[i]); \ + } \ min_node = (min_node == NULL || min_node->size > n->size) ? n : min_node; \ - } \ - assert (min_node != NULL); \ - d->front->node = min_node; \ - d->front->index = min_node->size / 2; \ - d->back->node = min_node; \ - d->back->index = min_node->size / 2; \ - d->count = 0; \ - DEQUEI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _clear)(deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - M_C(name, _clean)(d); \ - /* We have registered the delete operator to clear all objects */ \ - M_C(name, _node_list_clear)(d->list); \ - /* It is safer to clean some variables */ \ - d->front->node = NULL; \ - d->back->node = NULL; \ - d->count = 0; \ - } \ - \ - static inline type * \ - M_C(name, _push_back_raw)(deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - node_t *n = d->back->node; \ - size_t index = d->back->index; \ - if (M_UNLIKELY (n->size <= index)) { \ - /* try to get an already allocated node */ \ - n = M_C(name, _node_list_next_obj)(d->list, n); \ - if (n == NULL) { \ - /* No node exists, allocate a new one */ \ - n = M_C(name, _int_new_node)(d); \ - if (M_UNLIKELY (n == NULL)) return NULL; \ - M_C(name, _node_list_push_back)(d->list, n); \ - } \ - d->back->node = n; \ - index = 0; \ - } \ - type *ret = &n->data[index]; \ - index++; \ - d->count ++; \ - d->back->index = index; \ - DEQUEI_CONTRACT(d); \ - return ret; \ - } \ - \ - static inline void \ - M_C(name, _push_back)(deque_t d, type const x) \ - { \ - type *p = M_C(name, _push_back_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ - M_CALL_INIT_SET(oplist, *p, x); \ - } \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _push_back_new)(deque_t d) \ - { \ - type *p = M_C(name, _push_back_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ - M_CALL_INIT(oplist, *p); \ - } \ - return p; \ - } \ - , ) \ - \ - static inline void \ - M_C(name, _push_back_move)(deque_t d, type *x) \ - { \ - assert (x != NULL); \ - type *p = M_C(name, _push_back_raw)(d); \ - if (M_UNLIKELY(p == NULL)) \ - return; \ - M_DO_INIT_MOVE (oplist, *p, *x); \ - } \ - \ - static inline type* \ - M_C(name, _push_front_raw)(deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - node_t *n = d->front->node; \ - size_t index = d->front->index; \ - index --; \ - /* If overflow */ \ - if (M_UNLIKELY (n->size <= index)) { \ - n = M_C(name, _node_list_previous_obj)(d->list, n); \ - if (n == NULL) { \ - n = M_C(name, _int_new_node)(d); \ - if (M_UNLIKELY (n == NULL)) return NULL; \ - M_C(name, _node_list_push_front)(d->list, n); \ - } \ - d->front->node = n; \ - index = n->size -1; \ - } \ - type *ret = &n->data[index]; \ - d->count ++; \ - d->front->index = index; \ - DEQUEI_CONTRACT(d); \ - return ret; \ - } \ - \ - static inline void \ - M_C(name, _push_front)(deque_t d, type const x) \ - { \ - type *p = M_C(name, _push_front_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ - M_CALL_INIT_SET(oplist, *p, x); \ - } \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _push_front_new)(deque_t d) \ - { \ - type *p = M_C(name, _push_front_raw)(d); \ - if (M_LIKELY(p != NULL)) { \ - M_CALL_INIT(oplist, *p); \ - } \ - return p; \ - } \ - ,) \ - \ - static inline void \ - M_C(name, _push_front_move)(deque_t d, type *x) \ - { \ - assert (x != NULL); \ - type *p = M_C(name, _push_front_raw)(d); \ - if (M_UNLIKELY(p == NULL)) \ - return; \ - M_DO_INIT_MOVE (oplist, *p, *x); \ - } \ - \ - static inline void \ - M_C(name, _pop_back)(type *ptr, deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert(d->count > 0); \ - node_t *n = d->back->node; \ - size_t index = d->back->index; \ - index --; \ - if (M_UNLIKELY (n->size <= index)) { \ - /* If there is a next node, \ - pop the back node and push it back to the front. This \ - reduce the used memory if the deque is used as a FIFO queue.*/ \ - node_t *next = M_C(name, _node_list_next_obj)(d->list, n); \ - if (next != NULL) { \ - next = M_C(name, _node_list_pop_back)(d->list); \ - assert (next != n); \ - M_C(name, _node_list_push_front)(d->list, next); \ - } \ - n = M_C(name, _node_list_previous_obj)(d->list, n); \ - assert (n != NULL); \ - d->back->node = n; \ - index = n->size-1; \ - } \ - if (ptr != NULL) \ - M_IF_METHOD(MOVE, oplist) ( \ - M_CALL_MOVE(oplist, *ptr, n->data[index]); else \ - , \ - M_CALL_SET(oplist, *ptr, n->data[index]); \ - ) \ - M_CALL_CLEAR(oplist, n->data[index]); \ - d->count --; \ - d->back->index = index; \ - DEQUEI_CONTRACT(d); \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline void \ - M_C(name, _pop_back_move)(type *ptr, deque_t d) \ - { \ - assert(ptr != NULL); \ - /* Note: Lazy implementation. Can be improved if needed */ \ - M_CALL_INIT(oplist, *ptr); \ - M_C(name, _pop_back)(ptr, d); \ - } \ - , ) \ - \ - static inline void \ - M_C(name, _pop_front)(type *ptr, deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert(d->count > 0); \ - node_t *n = d->front->node; \ - size_t index = d->front->index; \ - if (M_UNLIKELY (n->size <= index)) { \ - /* If there is a previous node, \ - pop the front node and push it back to the back. This \ - reduce the used memory if the deque is used as a FIFO queue.*/ \ - node_t *prev = M_C(name, _node_list_previous_obj)(d->list, n); \ - if (prev != NULL) { \ - prev = M_C(name, _node_list_pop_front)(d->list); \ - assert (prev != n); \ - M_C(name, _node_list_push_back)(d->list, prev); \ - } \ - n = M_C(name, _node_list_next_obj)(d->list, n); \ - assert (n != NULL); \ - d->front->node = n; \ - index = 0; \ - } \ - if (ptr != NULL) \ - M_IF_METHOD(MOVE, oplist) ( \ - M_CALL_MOVE(oplist, *ptr, n->data[index]); else \ - , \ - M_CALL_SET(oplist, *ptr, n->data[index]); \ - ) \ - M_CALL_CLEAR(oplist, n->data[index]); \ - index++; \ - d->count --; \ - d->front->index = index; \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline void \ - M_C(name, _pop_front_move)(type *ptr, deque_t d) \ - { \ - assert(ptr != NULL); \ - /* Note: Lazy implementation */ \ - M_CALL_INIT(oplist, *ptr); \ - M_C(name, _pop_front)(ptr, d); \ - } \ - ,) \ - \ - static inline type * \ - M_C(name, _back)(const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (d->count > 0); \ - size_t i = d->back->index; \ - node_t *n = d->back->node; \ - if (M_UNLIKELY (i == 0)) { \ - n = M_C(name, _node_list_previous_obj)(d->list, n); \ - assert (n != NULL); \ - i = n->size; \ - } \ - return &n->data[i-1]; \ - } \ - \ - static inline type * \ - M_C(name, _front)(const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (d->count > 0); \ - size_t i = d->front->index; \ - node_t *n = d->front->node; \ - if (M_UNLIKELY (n->size <= i)) { \ - n = M_C(name, _node_list_next_obj)(d->list, n); \ - assert (n != NULL); \ - i = 0; \ - } \ - return &n->data[i]; \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - return d->count; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity_back)(const deque_t v) \ - { \ - DEQUEI_CONTRACT(v); \ - size_t s = 0; \ - for(node_t *n = M_C(name, _node_list_back)(v->list); \ - n != NULL ; \ - n = (n == v->back->node) ? NULL : \ - M_C(name, _node_list_previous_obj)(v->list, n) ){ \ - s += (n == v->back->node ? v->back->index : n->size); \ - } \ - return s; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity_front)(const deque_t v) \ - { \ - DEQUEI_CONTRACT(v); \ - size_t s = 0; \ - for(node_t *n = M_C(name, _node_list_front)(v->list); \ - n != NULL ; \ - n = (n == v->front->node) ? NULL : \ - M_C(name, _node_list_next_obj)(v->list, n) ){ \ - s += n->size - (n == v->front->node ? v->front->index : 0); \ - } \ - return s; \ - } \ - \ - static inline size_t \ - M_C(name, _capacity)(const deque_t v) \ - { \ - return M_C(name, _capacity_back)(v)+M_C(name, _capacity_front)(v); \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - return d->count == 0; \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (it != NULL); \ - it->node = d->front->node; \ - it->index = d->front->index; \ - it->deque = d; \ - } \ - \ - static inline void \ - M_C(name, _it_last)(it_t it, const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (it != NULL); \ - it->node = d->back->node; \ - it->index = d->back->index - 1; \ - it->deque = d; \ - if (M_UNLIKELY (it->index >= it->node->size)) { \ - it->node = M_C(name, _node_list_previous_obj)(d->list, it->node); \ - assert (it->node != NULL); \ - it->index = it->node->size-1; \ - } \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it, const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (it != NULL); \ - it->node = d->back->node; \ - it->index = d->back->index; \ - it->deque = d; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t it1, const it_t it2) \ - { \ - assert (it1 != NULL); \ - assert (it2 != NULL); \ - it1->node = it2->node; \ - it1->index = it2->index; \ - it1->deque = it2->deque; \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(it_t it) \ - { \ - assert (it != NULL); \ - return (it->node == it->deque->back->node \ - && it->index >= it->deque->back->index) \ - || (it->node == it->deque->front->node \ - && it->index < it->deque->front->index); \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - assert (it != NULL); \ - node_t *n = it->node; \ - it->index ++; \ - if (M_UNLIKELY (it->index >= n->size)) { \ - n = M_C(name, _node_list_next_obj)(it->deque->list, n); \ - if (M_UNLIKELY (n == NULL)) { \ - /* Point to 'end' (can't undo it) */ \ - it->node = it->deque->back->node; \ - it->index = it->deque->back->node->size; \ - return; \ - } \ - it->node = n; \ - it->index = 0; \ - } \ - } \ - \ - static inline void \ - M_C(name, _previous)(it_t it) \ - { \ - assert (it != NULL); \ - node_t *n = it->node; \ - it->index --; \ - if (M_UNLIKELY (it->index >= n->size)) { \ - n = M_C(name, _node_list_previous_obj)(it->deque->list, n); \ - if (M_UNLIKELY (n == NULL)) { \ - /* Point to 'end' (can't undo it) */ \ - it->node = it->deque->back->node; \ - it->index = it->deque->back->node->size; \ - return; \ - } \ - it->node = n; \ - it->index = 0; \ - } \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(it_t it) \ - { \ - assert (it != NULL); \ - it_t it2; \ - M_C(name, _it_set)(it2, it); \ - M_C(name, _next)(it2); \ - return M_C(name, _end_p)(it2); \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(it_t it1, const it_t it2) \ - { \ - assert (it1 != NULL); \ - assert (it2 != NULL); \ - return it1->deque == it2->deque \ - && it1->node == it2->node \ - && it1->index == it2->index; \ - } \ - \ - static inline type * \ - M_C(name, _ref)(it_t it) \ - { \ - assert (it != NULL); \ - assert (it->index < it->node->size); \ - return &it->node->data[it->index]; \ - } \ - \ - static inline type const * \ - M_C(name, _cref)(it_t it) \ - { \ - assert (it != NULL); \ - assert (it->index < it->node->size); \ - return M_CONST_CAST(type, &it->node->data[it->index]); \ - } \ - \ - static inline void \ - M_C(name, _init_set)(deque_t d, const deque_t src) \ - { \ - DEQUEI_CONTRACT(src); \ - assert (d != NULL); \ - M_C(name, _node_list_init)(d->list); \ - d->default_size = DEQUEUI_DEFAULT_SIZE + src->count; \ - d->count = src->count; \ - node_t *n = M_C(name, _int_new_node)(d); \ - if (n == NULL) return; \ - d->default_size /= 2; \ - M_C(name, _node_list_push_back)(d->list, n); \ - d->front->node = n; \ - d->front->index = DEQUEUI_DEFAULT_SIZE/2; \ - d->back->node = n; \ - d->back->index = DEQUEUI_DEFAULT_SIZE/2 + src->count; \ - it_t it; \ - size_t i = DEQUEUI_DEFAULT_SIZE/2; \ + } \ + assert (min_node != NULL); \ + d->front->node = min_node; \ + d->front->index = min_node->size / 2; \ + d->back->node = min_node; \ + d->back->index = min_node->size / 2; \ + d->count = 0; \ + DEQUEI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _clear)(deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + M_C(name, _clean)(d); \ + /* We have registered the delete operator to clear all objects */ \ + M_C(name, _node_list_clear)(d->list); \ + /* It is safer to clean some variables */ \ + d->front->node = NULL; \ + d->back->node = NULL; \ + d->count = 0; \ + } \ + \ + static inline type * \ + M_C(name, _push_back_raw)(deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + node_t *n = d->back->node; \ + size_t index = d->back->index; \ + if (M_UNLIKELY (n->size <= index)) { \ + /* try to get an already allocated node */ \ + n = M_C(name, _node_list_next_obj)(d->list, n); \ + if (n == NULL) { \ + /* No node exists, allocate a new one */ \ + n = M_C(name, _int_new_node)(d); \ + if (M_UNLIKELY (n == NULL)) return NULL; \ + M_C(name, _node_list_push_back)(d->list, n); \ + } \ + d->back->node = n; \ + index = 0; \ + } \ + type *ret = &n->data[index]; \ + index++; \ + d->count ++; \ + d->back->index = index; \ + DEQUEI_CONTRACT(d); \ + return ret; \ + } \ + \ + static inline void \ + M_C(name, _push_back)(deque_t d, type const x) \ + { \ + type *p = M_C(name, _push_back_raw)(d); \ + if (M_LIKELY(p != NULL)) { \ + M_CALL_INIT_SET(oplist, *p, x); \ + } \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _push_back_new)(deque_t d) \ + { \ + type *p = M_C(name, _push_back_raw)(d); \ + if (M_LIKELY(p != NULL)) { \ + M_CALL_INIT(oplist, *p); \ + } \ + return p; \ + } \ + , ) \ + \ + static inline void \ + M_C(name, _push_back_move)(deque_t d, type *x) \ + { \ + assert (x != NULL); \ + type *p = M_C(name, _push_back_raw)(d); \ + if (M_UNLIKELY(p == NULL)) \ + return; \ + M_DO_INIT_MOVE (oplist, *p, *x); \ + } \ + \ + static inline type* \ + M_C(name, _push_front_raw)(deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + node_t *n = d->front->node; \ + size_t index = d->front->index; \ + index --; \ + /* If overflow */ \ + if (M_UNLIKELY (n->size <= index)) { \ + n = M_C(name, _node_list_previous_obj)(d->list, n); \ + if (n == NULL) { \ + n = M_C(name, _int_new_node)(d); \ + if (M_UNLIKELY (n == NULL)) return NULL; \ + M_C(name, _node_list_push_front)(d->list, n); \ + } \ + d->front->node = n; \ + index = n->size -1; \ + } \ + type *ret = &n->data[index]; \ + d->count ++; \ + d->front->index = index; \ + DEQUEI_CONTRACT(d); \ + return ret; \ + } \ + \ + static inline void \ + M_C(name, _push_front)(deque_t d, type const x) \ + { \ + type *p = M_C(name, _push_front_raw)(d); \ + if (M_LIKELY(p != NULL)) { \ + M_CALL_INIT_SET(oplist, *p, x); \ + } \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _push_front_new)(deque_t d) \ + { \ + type *p = M_C(name, _push_front_raw)(d); \ + if (M_LIKELY(p != NULL)) { \ + M_CALL_INIT(oplist, *p); \ + } \ + return p; \ + } \ + ,) \ + \ + static inline void \ + M_C(name, _push_front_move)(deque_t d, type *x) \ + { \ + assert (x != NULL); \ + type *p = M_C(name, _push_front_raw)(d); \ + if (M_UNLIKELY(p == NULL)) \ + return; \ + M_DO_INIT_MOVE (oplist, *p, *x); \ + } \ + \ + static inline void \ + M_C(name, _pop_back)(type *ptr, deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert(d->count > 0); \ + node_t *n = d->back->node; \ + size_t index = d->back->index; \ + index --; \ + if (M_UNLIKELY (n->size <= index)) { \ + /* If there is a next node, \ + pop the back node and push it back to the front. This \ + reduce the used memory if the deque is used as a FIFO queue.*/ \ + node_t *next = M_C(name, _node_list_next_obj)(d->list, n); \ + if (next != NULL) { \ + next = M_C(name, _node_list_pop_back)(d->list); \ + assert (next != n); \ + M_C(name, _node_list_push_front)(d->list, next); \ + } \ + n = M_C(name, _node_list_previous_obj)(d->list, n); \ + assert (n != NULL); \ + d->back->node = n; \ + index = n->size-1; \ + } \ + if (ptr != NULL) \ + M_IF_METHOD(MOVE, oplist) ( \ + M_CALL_MOVE(oplist, *ptr, n->data[index]); else \ + , \ + M_CALL_SET(oplist, *ptr, n->data[index]); \ + ) \ + M_CALL_CLEAR(oplist, n->data[index]); \ + d->count --; \ + d->back->index = index; \ + DEQUEI_CONTRACT(d); \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline void \ + M_C(name, _pop_back_move)(type *ptr, deque_t d) \ + { \ + assert(ptr != NULL); \ + /* Note: Lazy implementation. Can be improved if needed */ \ + M_CALL_INIT(oplist, *ptr); \ + M_C(name, _pop_back)(ptr, d); \ + } \ + , ) \ + \ + static inline void \ + M_C(name, _pop_front)(type *ptr, deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert(d->count > 0); \ + node_t *n = d->front->node; \ + size_t index = d->front->index; \ + if (M_UNLIKELY (n->size <= index)) { \ + /* If there is a previous node, \ + pop the front node and push it back to the back. This \ + reduce the used memory if the deque is used as a FIFO queue.*/ \ + node_t *prev = M_C(name, _node_list_previous_obj)(d->list, n); \ + if (prev != NULL) { \ + prev = M_C(name, _node_list_pop_front)(d->list); \ + assert (prev != n); \ + M_C(name, _node_list_push_back)(d->list, prev); \ + } \ + n = M_C(name, _node_list_next_obj)(d->list, n); \ + assert (n != NULL); \ + d->front->node = n; \ + index = 0; \ + } \ + if (ptr != NULL) \ + M_IF_METHOD(MOVE, oplist) ( \ + M_CALL_MOVE(oplist, *ptr, n->data[index]); else \ + , \ + M_CALL_SET(oplist, *ptr, n->data[index]); \ + ) \ + M_CALL_CLEAR(oplist, n->data[index]); \ + index++; \ + d->count --; \ + d->front->index = index; \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline void \ + M_C(name, _pop_front_move)(type *ptr, deque_t d) \ + { \ + assert(ptr != NULL); \ + /* Note: Lazy implementation */ \ + M_CALL_INIT(oplist, *ptr); \ + M_C(name, _pop_front)(ptr, d); \ + } \ + ,) \ + \ + static inline type * \ + M_C(name, _back)(const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (d->count > 0); \ + size_t i = d->back->index; \ + node_t *n = d->back->node; \ + if (M_UNLIKELY (i == 0)) { \ + n = M_C(name, _node_list_previous_obj)(d->list, n); \ + assert (n != NULL); \ + i = n->size; \ + } \ + return &n->data[i-1]; \ + } \ + \ + static inline type * \ + M_C(name, _front)(const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (d->count > 0); \ + size_t i = d->front->index; \ + node_t *n = d->front->node; \ + if (M_UNLIKELY (n->size <= i)) { \ + n = M_C(name, _node_list_next_obj)(d->list, n); \ + assert (n != NULL); \ + i = 0; \ + } \ + return &n->data[i]; \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + return d->count; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity_back)(const deque_t v) \ + { \ + DEQUEI_CONTRACT(v); \ + size_t s = 0; \ + for(node_t *n = M_C(name, _node_list_back)(v->list); \ + n != NULL ; \ + n = (n == v->back->node) ? NULL : \ + M_C(name, _node_list_previous_obj)(v->list, n) ){ \ + s += (n == v->back->node ? v->back->index : n->size); \ + } \ + return s; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity_front)(const deque_t v) \ + { \ + DEQUEI_CONTRACT(v); \ + size_t s = 0; \ + for(node_t *n = M_C(name, _node_list_front)(v->list); \ + n != NULL ; \ + n = (n == v->front->node) ? NULL : \ + M_C(name, _node_list_next_obj)(v->list, n) ){ \ + s += n->size - (n == v->front->node ? v->front->index : 0); \ + } \ + return s; \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(const deque_t v) \ + { \ + return M_C(name, _capacity_back)(v)+M_C(name, _capacity_front)(v); \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + return d->count == 0; \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (it != NULL); \ + it->node = d->front->node; \ + it->index = d->front->index; \ + it->deque = d; \ + } \ + \ + static inline void \ + M_C(name, _it_last)(it_t it, const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (it != NULL); \ + it->node = d->back->node; \ + it->index = d->back->index - 1; \ + it->deque = d; \ + if (M_UNLIKELY (it->index >= it->node->size)) { \ + it->node = M_C(name, _node_list_previous_obj)(d->list, it->node); \ + assert (it->node != NULL); \ + it->index = it->node->size-1; \ + } \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it, const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (it != NULL); \ + it->node = d->back->node; \ + it->index = d->back->index; \ + it->deque = d; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t it1, const it_t it2) \ + { \ + assert (it1 != NULL); \ + assert (it2 != NULL); \ + it1->node = it2->node; \ + it1->index = it2->index; \ + it1->deque = it2->deque; \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(it_t it) \ + { \ + assert (it != NULL); \ + return (it->node == it->deque->back->node \ + && it->index >= it->deque->back->index) \ + || (it->node == it->deque->front->node \ + && it->index < it->deque->front->index); \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + assert (it != NULL); \ + node_t *n = it->node; \ + it->index ++; \ + if (M_UNLIKELY (it->index >= n->size)) { \ + n = M_C(name, _node_list_next_obj)(it->deque->list, n); \ + if (M_UNLIKELY (n == NULL)) { \ + /* Point to 'end' (can't undo it) */ \ + it->node = it->deque->back->node; \ + it->index = it->deque->back->node->size; \ + return; \ + } \ + it->node = n; \ + it->index = 0; \ + } \ + } \ + \ + static inline void \ + M_C(name, _previous)(it_t it) \ + { \ + assert (it != NULL); \ + node_t *n = it->node; \ + it->index --; \ + if (M_UNLIKELY (it->index >= n->size)) { \ + n = M_C(name, _node_list_previous_obj)(it->deque->list, n); \ + if (M_UNLIKELY (n == NULL)) { \ + /* Point to 'end' (can't undo it) */ \ + it->node = it->deque->back->node; \ + it->index = it->deque->back->node->size; \ + return; \ + } \ + it->node = n; \ + it->index = 0; \ + } \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(it_t it) \ + { \ + assert (it != NULL); \ + it_t it2; \ + M_C(name, _it_set)(it2, it); \ + M_C(name, _next)(it2); \ + return M_C(name, _end_p)(it2); \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(it_t it1, const it_t it2) \ + { \ + assert (it1 != NULL); \ + assert (it2 != NULL); \ + return it1->deque == it2->deque \ + && it1->node == it2->node \ + && it1->index == it2->index; \ + } \ + \ + static inline type * \ + M_C(name, _ref)(it_t it) \ + { \ + assert (it != NULL); \ + assert (it->index < it->node->size); \ + return &it->node->data[it->index]; \ + } \ + \ + static inline type const * \ + M_C(name, _cref)(it_t it) \ + { \ + assert (it != NULL); \ + assert (it->index < it->node->size); \ + return M_CONST_CAST(type, &it->node->data[it->index]); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(deque_t d, const deque_t src) \ + { \ + DEQUEI_CONTRACT(src); \ + assert (d != NULL); \ + M_C(name, _node_list_init)(d->list); \ + d->default_size = DEQUEUI_DEFAULT_SIZE + src->count; \ + d->count = src->count; \ + node_t *n = M_C(name, _int_new_node)(d); \ + if (n == NULL) return; \ + d->default_size /= 2; \ + M_C(name, _node_list_push_back)(d->list, n); \ + d->front->node = n; \ + d->front->index = DEQUEUI_DEFAULT_SIZE/2; \ + d->back->node = n; \ + d->back->index = DEQUEUI_DEFAULT_SIZE/2 + src->count; \ + it_t it; \ + size_t i = DEQUEUI_DEFAULT_SIZE/2; \ for(M_C(name, _it)(it, src); !M_C(name, _end_p)(it) ; M_C(name, _next)(it)) { \ - type const *obj = M_C(name, _cref)(it); \ - M_CALL_INIT_SET(oplist, n->data[i], *obj); \ - i++; \ - assert (i <= d->back->index); \ - } \ - DEQUEI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _set)(deque_t d, deque_t const src) \ - { \ - if (M_UNLIKELY (src == d)) \ - return; \ - /* TODO: Reuse memory of d! */ \ - M_C(name, _clear)(d); \ - M_C(name, _init_set)(d, src); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(deque_t d, deque_t src) \ - { \ - DEQUEI_CONTRACT(src); \ - assert (d!= NULL); \ - M_C(name,_node_list_init_move)(d->list, src->list); \ - d->front->node = src->front->node; \ - d->front->index = src->front->index; \ - d->back->node = src->back->node; \ - d->back->index = src->back->index; \ - d->default_size = src->default_size; \ - d->count = src->count; \ - memset(src, 0, sizeof(deque_t)); \ - DEQUEI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _move)(deque_t d, deque_t src) \ - { \ - DEQUEI_CONTRACT(d); \ - DEQUEI_CONTRACT(src); \ - M_C(name, _clear)(d); \ - M_C(name, _init_move)(d, src); \ - DEQUEI_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _swap)(deque_t d, deque_t e) \ - { \ - DEQUEI_CONTRACT(d); \ - DEQUEI_CONTRACT(e); \ - M_C(name, _node_list_swap) (d->list, e->list); \ - M_SWAP(node_t *, d->front->node, e->front->node); \ - M_SWAP(node_t *, d->back->node, e->back->node); \ - M_SWAP(size_t, d->front->index, e->front->index); \ - M_SWAP(size_t, d->back->index, e->back->index); \ - M_SWAP(size_t, d->default_size, e->default_size); \ - M_SWAP(size_t, d->count, e->count); \ - DEQUEI_CONTRACT(d); \ - DEQUEI_CONTRACT(e); \ - } \ - \ - static inline type* \ - M_C(name, _get)(deque_t d, size_t key) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (key < d->count); \ - const size_t index0 = d->front->index; \ - size_t count = 0; \ - /* This loop is in log(N) since the size increase exponentially.*/ \ - for(node_t *n = d->front->node; \ - n != NULL ; \ - n = (n == d->back->node) ? NULL : \ - M_C(name, _node_list_next_obj)(d->list, n) ){ \ - if (index0 + key < count + n->size) { \ - return &n->data[index0 + key - count]; \ - } \ - count += n->size; \ - } \ - assert(false); \ - return NULL; \ - } \ - \ - static inline type const * \ - M_C(name, _cget)(deque_t d, size_t key) \ - { \ - return M_CONST_CAST(type, M_C(name, _get)(d, key)); \ - } \ - \ - static inline void \ - M_C(name, _set_at)(deque_t d, size_t key, type const x) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (key < d->count); \ - type *p = M_C(name, _get)(d, key); \ - M_CALL_SET(oplist, *p, x); \ - DEQUEI_CONTRACT(d); \ - } \ - \ - M_IF_METHOD(EQUAL, oplist)( \ - static inline bool \ - M_C(name, _equal_p)(const deque_t d1, const deque_t d2) \ - { \ - DEQUEI_CONTRACT(d1); \ - DEQUEI_CONTRACT(d2); \ - if (d1->count != d2->count) \ - return false; \ - it_t it1; \ - it_t it2; \ - for(M_C(name, _it)(it1, d1), M_C(name,_it)(it2, d2); \ - !M_C(name, _end_p)(it1) ; \ - M_C(name, _next)(it1), M_C(name, _next)(it2)) { \ - type const *obj1 = M_C(name, _cref)(it1); \ - type const *obj2 = M_C(name, _cref)(it2); \ - if (M_CALL_EQUAL(oplist, *obj1, *obj2) == false) \ - return false; \ - } \ - assert (M_C(name, _end_p)(it2)); \ - return true; \ - } \ - , /* NO EQUAL */) \ - \ - M_IF_METHOD(HASH, oplist)( \ - static inline size_t \ - M_C(name, _hash)(const deque_t d) \ - { \ - DEQUEI_CONTRACT(d); \ - M_HASH_DECL(hash); \ - it_t it; \ + type const *obj = M_C(name, _cref)(it); \ + M_CALL_INIT_SET(oplist, n->data[i], *obj); \ + i++; \ + assert (i <= d->back->index); \ + } \ + DEQUEI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _set)(deque_t d, deque_t const src) \ + { \ + if (M_UNLIKELY (src == d)) \ + return; \ + /* TODO: Reuse memory of d! */ \ + M_C(name, _clear)(d); \ + M_C(name, _init_set)(d, src); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(deque_t d, deque_t src) \ + { \ + DEQUEI_CONTRACT(src); \ + assert (d!= NULL); \ + M_C(name,_node_list_init_move)(d->list, src->list); \ + d->front->node = src->front->node; \ + d->front->index = src->front->index; \ + d->back->node = src->back->node; \ + d->back->index = src->back->index; \ + d->default_size = src->default_size; \ + d->count = src->count; \ + memset(src, 0, sizeof(deque_t)); \ + DEQUEI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _move)(deque_t d, deque_t src) \ + { \ + DEQUEI_CONTRACT(d); \ + DEQUEI_CONTRACT(src); \ + M_C(name, _clear)(d); \ + M_C(name, _init_move)(d, src); \ + DEQUEI_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _swap)(deque_t d, deque_t e) \ + { \ + DEQUEI_CONTRACT(d); \ + DEQUEI_CONTRACT(e); \ + M_C(name, _node_list_swap) (d->list, e->list); \ + M_SWAP(node_t *, d->front->node, e->front->node); \ + M_SWAP(node_t *, d->back->node, e->back->node); \ + M_SWAP(size_t, d->front->index, e->front->index); \ + M_SWAP(size_t, d->back->index, e->back->index); \ + M_SWAP(size_t, d->default_size, e->default_size); \ + M_SWAP(size_t, d->count, e->count); \ + DEQUEI_CONTRACT(d); \ + DEQUEI_CONTRACT(e); \ + } \ + \ + static inline type* \ + M_C(name, _get)(deque_t d, size_t key) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (key < d->count); \ + const size_t index0 = d->front->index; \ + size_t count = 0; \ + /* This loop is in log(N) since the size increase exponentially.*/ \ + for(node_t *n = d->front->node; \ + n != NULL ; \ + n = (n == d->back->node) ? NULL : \ + M_C(name, _node_list_next_obj)(d->list, n) ){ \ + if (index0 + key < count + n->size) { \ + return &n->data[index0 + key - count]; \ + } \ + count += n->size; \ + } \ + assert(false); \ + return NULL; \ + } \ + \ + static inline type const * \ + M_C(name, _cget)(deque_t d, size_t key) \ + { \ + return M_CONST_CAST(type, M_C(name, _get)(d, key)); \ + } \ + \ + static inline void \ + M_C(name, _set_at)(deque_t d, size_t key, type const x) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (key < d->count); \ + type *p = M_C(name, _get)(d, key); \ + M_CALL_SET(oplist, *p, x); \ + DEQUEI_CONTRACT(d); \ + } \ + \ + M_IF_METHOD(EQUAL, oplist)( \ + static inline bool \ + M_C(name, _equal_p)(const deque_t d1, const deque_t d2) \ + { \ + DEQUEI_CONTRACT(d1); \ + DEQUEI_CONTRACT(d2); \ + if (d1->count != d2->count) \ + return false; \ + it_t it1; \ + it_t it2; \ + for(M_C(name, _it)(it1, d1), M_C(name,_it)(it2, d2); \ + !M_C(name, _end_p)(it1) ; \ + M_C(name, _next)(it1), M_C(name, _next)(it2)) { \ + type const *obj1 = M_C(name, _cref)(it1); \ + type const *obj2 = M_C(name, _cref)(it2); \ + if (M_CALL_EQUAL(oplist, *obj1, *obj2) == false) \ + return false; \ + } \ + assert (M_C(name, _end_p)(it2)); \ + return true; \ + } \ + , /* NO EQUAL */) \ + \ + M_IF_METHOD(HASH, oplist)( \ + static inline size_t \ + M_C(name, _hash)(const deque_t d) \ + { \ + DEQUEI_CONTRACT(d); \ + M_HASH_DECL(hash); \ + it_t it; \ for(M_C(name, _it)(it, d); !M_C(name, _end_p)(it); M_C(name, _next)(it)) { \ - type const *obj = M_C(name, _cref)(it); \ - M_HASH_UP (hash, M_CALL_HASH(oplist, *obj)); \ - } \ - return M_HASH_FINAL(hash); \ - } \ - , /* NO HASH */) \ - \ - M_IF_METHOD(SWAP, oplist)( \ - static inline void \ - M_C(name, _swap_at)(deque_t d, size_t i, size_t j) \ - { \ - DEQUEI_CONTRACT(d); \ - assert (i < d->count); \ - assert (j < d->count); \ - type *obj1 = M_C(name, _get)(d, i); \ - type *obj2 = M_C(name, _get)(d, j); \ - M_CALL_SWAP(oplist, *obj1, *obj2); \ - DEQUEI_CONTRACT(d); \ - } \ - , /* NO SWAP */) \ - \ - M_IF_METHOD(GET_STR, oplist)( \ - static inline void \ - M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \ - { \ - STRINGI_CONTRACT(str); \ - DEQUEI_CONTRACT(deque); \ - (append ? string_cat_str : string_set_str) (str, "["); \ - it_t it; \ - for (M_C(name, _it)(it, deque) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - type const *item = M_C(name, _cref)(it); \ - M_CALL_GET_STR(oplist, str, *item, true); \ - if (!M_C(name, _last_p)(it)) \ - string_push_back (str, M_GET_SEPARATOR oplist); \ - } \ - string_push_back (str, ']'); \ - STRINGI_CONTRACT(str); \ - } \ - , /* no GET_STR */ ) \ - \ - M_IF_METHOD(OUT_STR, oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *file, const deque_t deque) \ - { \ - DEQUEI_CONTRACT(deque); \ - assert (file != NULL); \ - fputc ('[', file); \ - it_t it; \ - for (M_C(name, _it)(it, deque) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)) { \ - type const *item = M_C(name, _cref)(it); \ - M_CALL_OUT_STR(oplist, file, *item); \ - if (!M_C(name, _last_p)(it)) \ - fputc (M_GET_SEPARATOR oplist, file); \ - } \ - fputc (']', file); \ - } \ - , /* no OUT_STR */ ) \ - \ - M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ - static inline bool \ - M_C(name, _parse_str)(deque_t deque, const char str[], const char **endp) \ - { \ - DEQUEI_CONTRACT(deque); \ - assert (str != NULL); \ - M_C(name,_clean)(deque); \ - bool success = false; \ - int c = *str++; \ - if (M_UNLIKELY (c != '[')) goto exit; \ - c = *str++; \ - if (M_UNLIKELY (c == ']')) {success = true; goto exit;} \ - if (M_UNLIKELY (c == 0)) goto exit; \ - str--; \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ - do { c = *str++; } while (isspace(c)); \ - if (b == false || c == 0) { goto exit_clear; } \ - M_C(name, _push_back)(deque, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - DEQUEI_CONTRACT(deque); \ - success = (c == ']'); \ - exit_clear: \ - M_CALL_CLEAR(oplist, item); \ - exit: \ - if (endp) *endp = str; \ - return success; \ - } \ - , /* no PARSE_STR */ ) \ - \ - M_IF_METHOD2(IN_STR, INIT, oplist)( \ - static inline bool \ - M_C(name, _in_str)(deque_t deque, FILE *file) \ - { \ - DEQUEI_CONTRACT(deque); \ - assert (file != NULL); \ - M_C(name,_clean)(deque); \ - int c = fgetc(file); \ - if (M_UNLIKELY (c != '[')) return false; \ - c = fgetc(file); \ - if (M_UNLIKELY (c == ']')) return true; \ - if (M_UNLIKELY (c == EOF)) return false; \ - ungetc(c, file); \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_IN_STR(oplist, item, file); \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false || c == EOF) { break; } \ - M_C(name, _push_back)(deque, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - M_CALL_CLEAR(oplist, item); \ - DEQUEI_CONTRACT(deque); \ - return c == ']'; \ - } \ - , /* no IN_STR */ ) \ - \ - M_IF_METHOD(OUT_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, const deque_t deque) \ - { \ - DEQUEI_CONTRACT(deque); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - bool first_done = false; \ - ret = f->m_interface->write_array_start(local, f, deque->count); \ - M_C(name, _it_ct) it; \ - for (M_C(name, _it)(it, deque) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - type const *item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_array_end(local, f); \ - return ret & M_SERIAL_FAIL; \ - } \ - , /* no OUT_SERIAL */ ) \ - \ - M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(deque_t deque, m_serial_read_t f) \ - { \ - DEQUEI_CONTRACT(deque); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - size_t estimated_size = 0; \ - M_C(name,_clean)(deque); \ - ret = f->m_interface->read_array_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - ret = M_CALL_IN_SERIAL(oplist, item, f); \ - if (ret != M_SERIAL_OK_DONE) { break; } \ - M_C(name, _push_back)(deque, item); \ - ret = f->m_interface->read_array_next(local, f); \ - } while (ret == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(oplist, item); \ - return ret; \ - } \ - , /* no IN_SERIAL & INIT */ ) \ - \ + type const *obj = M_C(name, _cref)(it); \ + M_HASH_UP (hash, M_CALL_HASH(oplist, *obj)); \ + } \ + return M_HASH_FINAL(hash); \ + } \ + , /* NO HASH */) \ + \ + M_IF_METHOD(SWAP, oplist)( \ + static inline void \ + M_C(name, _swap_at)(deque_t d, size_t i, size_t j) \ + { \ + DEQUEI_CONTRACT(d); \ + assert (i < d->count); \ + assert (j < d->count); \ + type *obj1 = M_C(name, _get)(d, i); \ + type *obj2 = M_C(name, _get)(d, j); \ + M_CALL_SWAP(oplist, *obj1, *obj2); \ + DEQUEI_CONTRACT(d); \ + } \ + , /* NO SWAP */) \ + \ + M_IF_METHOD(GET_STR, oplist)( \ + static inline void \ + M_C(name, _get_str)(string_t str, deque_t const deque, bool append) \ + { \ + STRINGI_CONTRACT(str); \ + DEQUEI_CONTRACT(deque); \ + (append ? string_cat_str : string_set_str) (str, "["); \ + it_t it; \ + for (M_C(name, _it)(it, deque) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + type const *item = M_C(name, _cref)(it); \ + M_CALL_GET_STR(oplist, str, *item, true); \ + if (!M_C(name, _last_p)(it)) \ + string_push_back (str, M_GET_SEPARATOR oplist); \ + } \ + string_push_back (str, ']'); \ + STRINGI_CONTRACT(str); \ + } \ + , /* no GET_STR */ ) \ + \ + M_IF_METHOD(OUT_STR, oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *file, const deque_t deque) \ + { \ + DEQUEI_CONTRACT(deque); \ + assert (file != NULL); \ + fputc ('[', file); \ + it_t it; \ + for (M_C(name, _it)(it, deque) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)) { \ + type const *item = M_C(name, _cref)(it); \ + M_CALL_OUT_STR(oplist, file, *item); \ + if (!M_C(name, _last_p)(it)) \ + fputc (M_GET_SEPARATOR oplist, file); \ + } \ + fputc (']', file); \ + } \ + , /* no OUT_STR */ ) \ + \ + M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ + static inline bool \ + M_C(name, _parse_str)(deque_t deque, const char str[], const char **endp) \ + { \ + DEQUEI_CONTRACT(deque); \ + assert (str != NULL); \ + M_C(name,_clean)(deque); \ + bool success = false; \ + int c = *str++; \ + if (M_UNLIKELY (c != '[')) goto exit; \ + c = *str++; \ + if (M_UNLIKELY (c == ']')) {success = true; goto exit;} \ + if (M_UNLIKELY (c == 0)) goto exit; \ + str--; \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ + do { c = *str++; } while (isspace(c)); \ + if (b == false || c == 0) { goto exit_clear; } \ + M_C(name, _push_back)(deque, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + DEQUEI_CONTRACT(deque); \ + success = (c == ']'); \ + exit_clear: \ + M_CALL_CLEAR(oplist, item); \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } \ + , /* no PARSE_STR */ ) \ + \ + M_IF_METHOD2(IN_STR, INIT, oplist)( \ + static inline bool \ + M_C(name, _in_str)(deque_t deque, FILE *file) \ + { \ + DEQUEI_CONTRACT(deque); \ + assert (file != NULL); \ + M_C(name,_clean)(deque); \ + int c = fgetc(file); \ + if (M_UNLIKELY (c != '[')) return false; \ + c = fgetc(file); \ + if (M_UNLIKELY (c == ']')) return true; \ + if (M_UNLIKELY (c == EOF)) return false; \ + ungetc(c, file); \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_IN_STR(oplist, item, file); \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false || c == EOF) { break; } \ + M_C(name, _push_back)(deque, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + M_CALL_CLEAR(oplist, item); \ + DEQUEI_CONTRACT(deque); \ + return c == ']'; \ + } \ + , /* no IN_STR */ ) \ + \ + M_IF_METHOD(OUT_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, const deque_t deque) \ + { \ + DEQUEI_CONTRACT(deque); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + bool first_done = false; \ + ret = f->m_interface->write_array_start(local, f, deque->count); \ + M_C(name, _it_ct) it; \ + for (M_C(name, _it)(it, deque) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + type const *item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_array_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ + first_done = true; \ + } \ + ret |= f->m_interface->write_array_end(local, f); \ + return ret & M_SERIAL_FAIL; \ + } \ + , /* no OUT_SERIAL */ ) \ + \ + M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(deque_t deque, m_serial_read_t f) \ + { \ + DEQUEI_CONTRACT(deque); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + size_t estimated_size = 0; \ + M_C(name,_clean)(deque); \ + ret = f->m_interface->read_array_start(local, f, &estimated_size); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + ret = M_CALL_IN_SERIAL(oplist, item, f); \ + if (ret != M_SERIAL_OK_DONE) { break; } \ + M_C(name, _push_back)(deque, item); \ + ret = f->m_interface->read_array_next(local, f); \ + } while (ret == M_SERIAL_OK_CONTINUE); \ + M_CALL_CLEAR(oplist, item); \ + return ret; \ + } \ + , /* no IN_SERIAL & INIT */ ) \ + \ /* Deferred evaluation for the oplist definition, so that all arguments are evaluated before further expansion */ @@ -984,46 +984,46 @@ ((M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a deque */ -#define DEQUEI_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)) \ - ,TEST_EMPTY(M_C(name,_empty_p)) \ - ,IT_TYPE(M_C(name,_it_ct)) \ - ,IT_FIRST(M_C(name,_it)) \ - ,IT_LAST(M_C(name,_it_last)) \ - ,IT_END(M_C(name,_it_end)) \ - ,IT_SET(M_C(name,_it_set)) \ - ,IT_END_P(M_C(name,_end_p)) \ - ,IT_LAST_P(M_C(name,_last_p)) \ - ,IT_EQUAL_P(M_C(name,_it_equal_p)) \ - ,IT_NEXT(M_C(name,_next)) \ - ,IT_PREVIOUS(M_C(name,_previous)) \ - ,IT_REF(M_C(name,_ref)) \ - ,IT_CREF(M_C(name,_cref)) \ - ,CLEAN(M_C(name,_clean)) \ - ,GET_SIZE(M_C(name, _size)) \ - ,PUSH(M_C(name,_push_back)) \ - ,POP(M_C(name,_pop_back)) \ - ,OPLIST(oplist) \ - ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ - ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ - ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ - ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ - ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ - ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ - ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \ - ,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ - ,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 DEQUEI_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)) \ + ,TEST_EMPTY(M_C(name,_empty_p)) \ + ,IT_TYPE(M_C(name,_it_ct)) \ + ,IT_FIRST(M_C(name,_it)) \ + ,IT_LAST(M_C(name,_it_last)) \ + ,IT_END(M_C(name,_it_end)) \ + ,IT_SET(M_C(name,_it_set)) \ + ,IT_END_P(M_C(name,_end_p)) \ + ,IT_LAST_P(M_C(name,_last_p)) \ + ,IT_EQUAL_P(M_C(name,_it_equal_p)) \ + ,IT_NEXT(M_C(name,_next)) \ + ,IT_PREVIOUS(M_C(name,_previous)) \ + ,IT_REF(M_C(name,_ref)) \ + ,IT_CREF(M_C(name,_cref)) \ + ,CLEAN(M_C(name,_clean)) \ + ,GET_SIZE(M_C(name, _size)) \ + ,PUSH(M_C(name,_push_back)) \ + ,POP(M_C(name,_pop_back)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ + ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \ + ,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ + ,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),) \ ) #endif diff --git a/m-dict.h b/m-dict.h index cbe0c71b..be8a41e3 100644 --- a/m-dict.h +++ b/m-dict.h @@ -36,9 +36,9 @@ OR DICT_DEF2(name, key_type, value_type) */ -#define DICT_DEF2(name, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_DEF2(name, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(),M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, key_type, __VA_ARGS__,M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -52,8 +52,8 @@ DICT_DEF2_AS(name, name_t, it_t, itref_t, key_type, value_type) */ #define DICT_DEF2_AS(name, name_it, it_t, itref_t, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t, itref_t ), \ (name, key_type, __VA_ARGS__, name_t, it_t, itref_t ) )) \ M_END_PROTECTED_CODE @@ -67,9 +67,9 @@ OR DICT_STOREHASH_DEF2(name, key_type[, key_oplist], value_type[, value_oplist]) */ -#define DICT_STOREHASH_DEF2(name, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_SHASH_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_STOREHASH_DEF2(name, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_SHASH_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(),M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, key_type, __VA_ARGS__,M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -85,8 +85,8 @@ DICT_STOREHASH_DEF2_AS(name, name_it, it_t, itref_t, key_type[, key_oplist], value_type[, value_oplist]) */ #define DICT_STOREHASH_DEF2_AS(name, name_it, it_t, itref_t, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_SHASH_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_SHASH_DEF2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_it, it_t, itref_t ), \ (name, key_type, __VA_ARGS__, name_it, it_t, itref_t ))) \ M_END_PROTECTED_CODE @@ -100,9 +100,9 @@ OR DICT_OA_DEF2(name, key_type, value_type) */ -#define DICT_OA_DEF2(name, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_OA_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_OA_DEF2(name, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_OA_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(),M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ), \ (name, key_type, __VA_ARGS__,M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -117,11 +117,11 @@ OR DICT_OA_DEF2_AS(name, name_it, it_t, itref_t, key_type, value_type) */ -#define DICT_OA_DEF2_AS(name, name_it, it_t, itref_t, key_type, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_OA_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_OA_DEF2_AS(name, name_it, it_t, itref_t, key_type, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_OA_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, key_type, M_GLOBAL_OPLIST_OR_DEF(key_type)(), __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_it, it_t, itref_t ), \ - (name, key_type, __VA_ARGS__, name_it, it_t, itref_t ))) \ + (name, key_type, __VA_ARGS__, name_it, it_t, itref_t ))) \ M_END_PROTECTED_CODE @@ -129,9 +129,9 @@ The set is unordered. USAGE: DICT_SET_DEF(name, key_type[, key_oplist]) */ -#define DICT_SET_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_SET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_SET_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_SET_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), M_C(name, _itref_t)), \ (name, __VA_ARGS__,M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t)))) \ M_END_PROTECTED_CODE @@ -142,9 +142,9 @@ The set is unordered. USAGE: DICT_SET_DEF_AS(name, name_it, it_t, key_type[, key_oplist]) */ -#define DICT_SET_DEF_AS(name, name_it, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_SET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_SET_DEF_AS(name, name_it, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_SET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_it, it_t, M_C(name, _itref_ct) ), \ (name, __VA_ARGS__, name_it, it_t, M_C(name, _itref_ct) ))) \ M_END_PROTECTED_CODE @@ -155,9 +155,9 @@ The set is unordered. USAGE: DICT_OASET_DEF(name, key_type[, key_oplist]) */ -#define DICT_OASET_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_OASET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_OASET_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_OASET_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), M_C(name, _itref_t) ), \ (name, __VA_ARGS__,M_C(name, _t), M_C(name, _it_t), M_C(name, _itref_t) ))) \ M_END_PROTECTED_CODE @@ -169,9 +169,9 @@ The set is unordered. USAGE: DICT_OASET_DEF_AS(name, name_it, it_t, key_type[, key_oplist]) */ -#define DICT_OASET_DEF_AS(name, name_it, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - DICTI_OASET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define DICT_OASET_DEF_AS(name, name_it, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + DICTI_OASET_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_it, it_t, M_C(name, _itref_ct) ), \ (name, __VA_ARGS__, name_it, it_t, M_C(name, _itref_ct) ))) \ M_END_PROTECTED_CODE @@ -183,17 +183,17 @@ OR DICT_OPLIST(name) */ -#define DICT_OPLIST(...) \ - M_IF_NARGS_EQ1(__VA_ARGS__) \ - (DICTI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST )), \ +#define DICT_OPLIST(...) \ + M_IF_NARGS_EQ1(__VA_ARGS__) \ + (DICTI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST )), \ DICTI_OPLIST_P1((__VA_ARGS__ ))) /* Define the oplist of a dictionnary (DICT_SET_DEF). USAGE: DICT_SET_OPLIST(name[, oplist of the key type]) */ -#define DICT_SET_OPLIST(...) \ - M_IF_NARGS_EQ1(__VA_ARGS__) \ - (DICTI_SET_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \ +#define DICT_SET_OPLIST(...) \ + M_IF_NARGS_EQ1(__VA_ARGS__) \ + (DICTI_SET_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \ DICTI_SET_OPLIST_P1((__VA_ARGS__ ))) @@ -221,13 +221,13 @@ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) ) #define DICTI_DEF2_P4(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ - M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \ - \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ + M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \ + \ TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist), (value, value_type, value_oplist)) \ - \ - DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, \ + \ + DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, \ M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), key_oplist, value_oplist), 0, 0, \ dict_t, dict_it_t, it_deref_t ) @@ -253,13 +253,13 @@ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_STOREHASH_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) ) #define DICTI_SHASH_DEF2_P4(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ - M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \ - \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ + M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \ + \ TUPLE_DEF2(M_C(name, _pair), (hash, size_t, M_DEFAULT_OPLIST), (key, key_type, key_oplist), (value, value_type, value_oplist)) \ - \ - DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, \ + \ + DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, \ M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), M_DEFAULT_OPLIST, key_oplist, value_oplist), 0, 1, \ dict_t, dict_it_t, it_deref_t ) @@ -279,13 +279,13 @@ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_SET_DEF): the given argument is not a valid oplist: " M_AS_STR(key_oplist) ) #define DICTI_SET_DEF_P4(name, key_type, key_oplist, dict_t, dict_it_t, it_deref_t) \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ - \ - TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist)) \ - \ - DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, \ - M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), key_oplist), 1, 0, \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ + \ + TUPLE_DEF2(M_C(name, _pair), (key, key_type, key_oplist)) \ + \ + DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, \ + M_C(name, _pair_ct), TUPLE_OPLIST(M_C(name, _pair), key_oplist), 1, 0, \ dict_t, dict_it_t, it_deref_t) @@ -305,743 +305,743 @@ * it_deref_t: name of the type returned by an iterator */ #define DICTI_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, pair_type, pair_oplist, isSet, isStoreHash, dict_t, dict_it_t, it_deref_t) \ - \ - /* NOTE: \ - if isSet is true, all methods of value_oplist are NOP methods */ \ - \ - /* Define the list of buckets */ \ - /* Use memory allocator for bucket if needed */ \ - M_IF_METHOD(MEMPOOL, key_oplist) \ - ( \ - LIST_DEF(M_C(name, _list_pair), pair_type, \ + \ + /* NOTE: \ + if isSet is true, all methods of value_oplist are NOP methods */ \ + \ + /* Define the list of buckets */ \ + /* Use memory allocator for bucket if needed */ \ + M_IF_METHOD(MEMPOOL, key_oplist) \ + ( \ + LIST_DEF(M_C(name, _list_pair), pair_type, \ M_OPEXTEND(pair_oplist, MEMPOOL(M_GET_MEMPOOL key_oplist), MEMPOOL_LINKAGE(M_GET_MEMPOOL_LINKAGE key_oplist))) \ - , \ - LIST_DEF(M_C(name, _list_pair), pair_type, pair_oplist) \ - ) \ - \ - /* Define the array of list of buckets */ \ - ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_ct), \ - LIST_OPLIST(M_C(name, _list_pair), pair_oplist)) \ - \ - /* Define chained dict type */ \ - typedef struct M_C(name, _s) { \ - size_t used, lower_limit, upper_limit; \ - M_C(name, _array_list_pair_ct) table; \ - } dict_t[1]; \ - \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - /* Define iterator type */ \ - typedef struct M_C(name, _it_s) { \ - M_C(name, _array_list_pair_it_ct) array_it; \ - M_C(name, _list_pair_it_ct) list_it; \ - } dict_it_t[1]; \ - \ - /* Define type returned by the _ref method of an iterator */ \ - M_IF(isSet)( \ - typedef key_type it_deref_t; \ - , \ - typedef struct M_C(name, _pair_s) it_deref_t; \ - ) \ - \ - /* Define internal types for oplist */ \ - typedef dict_t M_C(name, _ct); \ - typedef it_deref_t M_C(name, _subtype_ct); \ - typedef key_type M_C(name, _key_ct); \ - typedef value_type M_C(name, _value_ct); \ - typedef dict_it_t M_C(name, _it_ct); \ - \ - static inline void \ - M_C(name, _init)(dict_t map) \ - { \ - assert (map != NULL); \ - map->used = 0; \ - M_C(name, _array_list_pair_init)(map->table); \ - M_C(name, _array_list_pair_resize)(map->table, DICTI_INITIAL_SIZE); \ - map->lower_limit = DICTI_LOWER_BOUND(DICTI_INITIAL_SIZE); \ - map->upper_limit = DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE); \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline void \ - M_C(name, _init_set)(dict_t map, const dict_t org) \ - { \ - DICTI_CONTRACT(name, org); \ - assert (map != org); \ - map->used = org->used; \ - map->lower_limit = org->lower_limit; \ - map->upper_limit = org->upper_limit; \ - M_C(name, _array_list_pair_init_set)(map->table, org->table); \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline void \ - M_C(name, _set)(dict_t map, const dict_t org) \ - { \ - DICTI_CONTRACT(name, map); \ - DICTI_CONTRACT(name, org); \ - map->used = org->used; \ - map->lower_limit = org->lower_limit; \ - map->upper_limit = org->upper_limit; \ - M_C(name, _array_list_pair_set)(map->table, org->table); \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline void \ - M_C(name,_clear)(dict_t map) \ - { \ - DICTI_CONTRACT(name, map); \ - M_C(name, _array_list_pair_clear)(map->table); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(dict_t map, dict_t org) \ - { \ - DICTI_CONTRACT(name, org); \ - map->used = org->used; \ - map->lower_limit = org->lower_limit; \ - map->upper_limit = org->upper_limit; \ - M_C(name, _array_list_pair_init_move)(map->table, org->table); \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline void \ - M_C(name, _swap)(dict_t d1, dict_t d2) \ - { \ - DICTI_CONTRACT(name, d1); \ - DICTI_CONTRACT(name, d2); \ - M_SWAP (size_t, d1->used, d2->used); \ - M_SWAP (size_t, d1->lower_limit, d2->lower_limit); \ - M_SWAP (size_t, d1->upper_limit, d2->upper_limit); \ - M_C(name, _array_list_pair_swap)(d1->table, d2->table); \ - DICTI_CONTRACT(name, d1); \ - DICTI_CONTRACT(name, d2); \ - } \ - \ - static inline void \ - M_C(name, _move)(dict_t map, dict_t org) \ - { \ - DICTI_CONTRACT(name, map); \ - DICTI_CONTRACT(name, org); \ - assert (map != org); \ - M_C(name,_clear)(map); \ - M_C(name,_init_move)(map, org); \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline void \ - M_C(name,_clean)(dict_t map) \ - { \ - M_C(name, _array_list_pair_clean)(map->table); \ - M_C(name, _array_list_pair_resize)(map->table, DICTI_INITIAL_SIZE); \ - map->lower_limit = DICTI_LOWER_BOUND(DICTI_INITIAL_SIZE); \ - map->upper_limit = DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE); \ - map->used = 0; \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline bool \ - M_C(name,_empty_p)(const dict_t map) \ - { \ - DICTI_CONTRACT(name, map); \ - return map->used == 0; \ - } \ - \ - static inline size_t \ - M_C(name,_size)(const dict_t map) \ - { \ - DICTI_CONTRACT(name, map); \ - return map->used; \ - } \ - \ - static inline value_type * \ - M_C(name, _get)(const dict_t map, key_type const key) \ - { \ - DICTI_CONTRACT(name, map); \ - size_t hash = M_CALL_HASH(key_oplist, key); \ - size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ - const M_C(name, _list_pair_ct) *list_ptr = \ - M_C(name, _array_list_pair_cget)(map->table, i); \ - M_C(name, _list_pair_it_ct) it; \ - for(M_C(name, _list_pair_it)(it, *list_ptr); \ - !M_C(name, _list_pair_end_p)(it); \ - M_C(name, _list_pair_next)(it)) { \ - pair_type *ref = M_C(name, _list_pair_ref)(it); \ - M_IF(isStoreHash)(if ((*ref)->hash != hash) { continue; }, ) \ - if (M_CALL_EQUAL(key_oplist, (*ref)->key, key)) \ - return &(*ref)->M_IF(isSet)(key, value); \ - } \ - return NULL; \ - } \ - \ - static inline value_type const * \ - M_C(name, _cget)(const dict_t map, key_type const key) \ - { \ - return M_CONST_CAST(value_type, M_C(name,_get)(map,key)); \ - } \ - \ - static inline void \ - M_C(name, _int_resize_up)(dict_t map) \ - { \ - /* NOTE: Contract may not be fullfilled here */ \ - size_t old_size = M_C(name, _array_list_pair_size)(map->table); \ - size_t new_size = old_size * 2; \ - if (M_UNLIKELY (new_size <= old_size)) { \ - M_MEMORY_FULL((size_t)-1); \ - } \ - /* Resize the table of the dictionnary */ \ - M_C(name, _array_list_pair_resize)(map->table, new_size); \ - /* Move the items to the new upper part */ \ - for(size_t i = 0; i < old_size; i++) { \ - M_C(name, _list_pair_ct) *list = \ - M_C(name, _array_list_pair_get)(map->table, i); \ - if (M_C(name, _list_pair_empty_p)(*list)) \ - continue; \ - /* We need to scan each item and recompute its hash to know \ - if it remains inplace or shall be moved to the upper part.*/ \ - M_C(name, _list_pair_it_ct) it; \ - M_C(name, _list_pair_it)(it, *list); \ - while (!M_C(name, _list_pair_end_p)(it)) { \ - M_C(name, _pair_ptr) pair = *M_C(name, _list_pair_ref)(it); \ + , \ + LIST_DEF(M_C(name, _list_pair), pair_type, pair_oplist) \ + ) \ + \ + /* Define the array of list of buckets */ \ + ARRAY_DEF(M_C(name, _array_list_pair), M_C(name, _list_pair_ct), \ + LIST_OPLIST(M_C(name, _list_pair), pair_oplist)) \ + \ + /* Define chained dict type */ \ + typedef struct M_C(name, _s) { \ + size_t used, lower_limit, upper_limit; \ + M_C(name, _array_list_pair_ct) table; \ + } dict_t[1]; \ + \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + /* Define iterator type */ \ + typedef struct M_C(name, _it_s) { \ + M_C(name, _array_list_pair_it_ct) array_it; \ + M_C(name, _list_pair_it_ct) list_it; \ + } dict_it_t[1]; \ + \ + /* Define type returned by the _ref method of an iterator */ \ + M_IF(isSet)( \ + typedef key_type it_deref_t; \ + , \ + typedef struct M_C(name, _pair_s) it_deref_t; \ + ) \ + \ + /* Define internal types for oplist */ \ + typedef dict_t M_C(name, _ct); \ + typedef it_deref_t M_C(name, _subtype_ct); \ + typedef key_type M_C(name, _key_ct); \ + typedef value_type M_C(name, _value_ct); \ + typedef dict_it_t M_C(name, _it_ct); \ + \ + static inline void \ + M_C(name, _init)(dict_t map) \ + { \ + assert (map != NULL); \ + map->used = 0; \ + M_C(name, _array_list_pair_init)(map->table); \ + M_C(name, _array_list_pair_resize)(map->table, DICTI_INITIAL_SIZE); \ + map->lower_limit = DICTI_LOWER_BOUND(DICTI_INITIAL_SIZE); \ + map->upper_limit = DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE); \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(dict_t map, const dict_t org) \ + { \ + DICTI_CONTRACT(name, org); \ + assert (map != org); \ + map->used = org->used; \ + map->lower_limit = org->lower_limit; \ + map->upper_limit = org->upper_limit; \ + M_C(name, _array_list_pair_init_set)(map->table, org->table); \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline void \ + M_C(name, _set)(dict_t map, const dict_t org) \ + { \ + DICTI_CONTRACT(name, map); \ + DICTI_CONTRACT(name, org); \ + map->used = org->used; \ + map->lower_limit = org->lower_limit; \ + map->upper_limit = org->upper_limit; \ + M_C(name, _array_list_pair_set)(map->table, org->table); \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline void \ + M_C(name,_clear)(dict_t map) \ + { \ + DICTI_CONTRACT(name, map); \ + M_C(name, _array_list_pair_clear)(map->table); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(dict_t map, dict_t org) \ + { \ + DICTI_CONTRACT(name, org); \ + map->used = org->used; \ + map->lower_limit = org->lower_limit; \ + map->upper_limit = org->upper_limit; \ + M_C(name, _array_list_pair_init_move)(map->table, org->table); \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline void \ + M_C(name, _swap)(dict_t d1, dict_t d2) \ + { \ + DICTI_CONTRACT(name, d1); \ + DICTI_CONTRACT(name, d2); \ + M_SWAP (size_t, d1->used, d2->used); \ + M_SWAP (size_t, d1->lower_limit, d2->lower_limit); \ + M_SWAP (size_t, d1->upper_limit, d2->upper_limit); \ + M_C(name, _array_list_pair_swap)(d1->table, d2->table); \ + DICTI_CONTRACT(name, d1); \ + DICTI_CONTRACT(name, d2); \ + } \ + \ + static inline void \ + M_C(name, _move)(dict_t map, dict_t org) \ + { \ + DICTI_CONTRACT(name, map); \ + DICTI_CONTRACT(name, org); \ + assert (map != org); \ + M_C(name,_clear)(map); \ + M_C(name,_init_move)(map, org); \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline void \ + M_C(name,_clean)(dict_t map) \ + { \ + M_C(name, _array_list_pair_clean)(map->table); \ + M_C(name, _array_list_pair_resize)(map->table, DICTI_INITIAL_SIZE); \ + map->lower_limit = DICTI_LOWER_BOUND(DICTI_INITIAL_SIZE); \ + map->upper_limit = DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE); \ + map->used = 0; \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline bool \ + M_C(name,_empty_p)(const dict_t map) \ + { \ + DICTI_CONTRACT(name, map); \ + return map->used == 0; \ + } \ + \ + static inline size_t \ + M_C(name,_size)(const dict_t map) \ + { \ + DICTI_CONTRACT(name, map); \ + return map->used; \ + } \ + \ + static inline value_type * \ + M_C(name, _get)(const dict_t map, key_type const key) \ + { \ + DICTI_CONTRACT(name, map); \ + size_t hash = M_CALL_HASH(key_oplist, key); \ + size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ + const M_C(name, _list_pair_ct) *list_ptr = \ + M_C(name, _array_list_pair_cget)(map->table, i); \ + M_C(name, _list_pair_it_ct) it; \ + for(M_C(name, _list_pair_it)(it, *list_ptr); \ + !M_C(name, _list_pair_end_p)(it); \ + M_C(name, _list_pair_next)(it)) { \ + pair_type *ref = M_C(name, _list_pair_ref)(it); \ + M_IF(isStoreHash)(if ((*ref)->hash != hash) { continue; }, ) \ + if (M_CALL_EQUAL(key_oplist, (*ref)->key, key)) \ + return &(*ref)->M_IF(isSet)(key, value); \ + } \ + return NULL; \ + } \ + \ + static inline value_type const * \ + M_C(name, _cget)(const dict_t map, key_type const key) \ + { \ + return M_CONST_CAST(value_type, M_C(name,_get)(map,key)); \ + } \ + \ + static inline void \ + M_C(name, _int_resize_up)(dict_t map) \ + { \ + /* NOTE: Contract may not be fullfilled here */ \ + size_t old_size = M_C(name, _array_list_pair_size)(map->table); \ + size_t new_size = old_size * 2; \ + if (M_UNLIKELY (new_size <= old_size)) { \ + M_MEMORY_FULL((size_t)-1); \ + } \ + /* Resize the table of the dictionnary */ \ + M_C(name, _array_list_pair_resize)(map->table, new_size); \ + /* Move the items to the new upper part */ \ + for(size_t i = 0; i < old_size; i++) { \ + M_C(name, _list_pair_ct) *list = \ + M_C(name, _array_list_pair_get)(map->table, i); \ + if (M_C(name, _list_pair_empty_p)(*list)) \ + continue; \ + /* We need to scan each item and recompute its hash to know \ + if it remains inplace or shall be moved to the upper part.*/ \ + M_C(name, _list_pair_it_ct) it; \ + M_C(name, _list_pair_it)(it, *list); \ + while (!M_C(name, _list_pair_end_p)(it)) { \ + M_C(name, _pair_ptr) pair = *M_C(name, _list_pair_ref)(it); \ size_t hash = M_IF(isStoreHash)(pair->hash, M_CALL_HASH(key_oplist, pair->key)); \ - if ((hash & (new_size-1)) >= old_size) { \ - assert( (hash & (new_size-1)) == (i + old_size)); \ - M_C(name, _list_pair_ct) *new_list = \ - M_C(name, _array_list_pair_get)(map->table, i + old_size); \ - M_C(name, _list_pair_splice_back)(*new_list, *list, it); \ - /* Splice_back has updated the iterator to the next one */ \ - } else { \ - M_C(name, _list_pair_next)(it); \ - } \ - } \ - } \ - map->upper_limit = DICTI_UPPER_BOUND(new_size); \ - map->lower_limit = DICTI_LOWER_BOUND(new_size); \ - } \ - \ - static inline void \ - M_C(name, _int_resize_down)(dict_t map) \ - { \ - /* NOTE: Contract may not be fullfilled here */ \ - size_t old_size = M_C(name, _array_list_pair_size)(map->table); \ - assert ((old_size % 2) == 0); \ - size_t new_size = old_size / 2; \ - assert (new_size >= DICTI_INITIAL_SIZE); \ - /* Move all items from the upper part to the lower part of the table */ \ - /* NOTE: We don't need to recompute the hash to move them! */ \ - for(size_t i = new_size; i < old_size; i++) { \ - M_C(name, _list_pair_ct) *list = \ - M_C(name, _array_list_pair_get)(map->table, i); \ - if (M_C(name, _list_pair_empty_p)(*list)) \ - continue; \ - M_C(name, _list_pair_ct) *new_list = \ - M_C(name, _array_list_pair_get)(map->table, i - new_size); \ - M_C(name, _list_pair_splice)(*new_list, *list); \ - } \ - /* Resize the table of the dictionary */ \ - M_C(name, _array_list_pair_resize)(map->table, new_size); \ - map->upper_limit = DICTI_UPPER_BOUND(new_size); \ - map->lower_limit = DICTI_LOWER_BOUND(new_size); \ - } \ - \ - static inline void \ - M_IF(isSet)(M_C(name, _push), M_C(name, _set_at)) \ - (dict_t map, key_type const key \ - M_IF(isSet)(, M_DEFERRED_COMMA value_type const value)) \ - { \ - DICTI_CONTRACT(name, map); \ - \ - size_t hash = M_CALL_HASH(key_oplist, key); \ - size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ - M_C(name, _list_pair_ct) *list_ptr = \ - M_C(name, _array_list_pair_get)(map->table, i); \ - M_C(name, _list_pair_it_ct) it; \ - for(M_C(name, _list_pair_it)(it, *list_ptr); \ - !M_C(name, _list_pair_end_p)(it); \ - M_C(name, _list_pair_next)(it)) { \ - M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ - M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ - if (M_CALL_EQUAL(key_oplist,ref->key, key)) { \ - M_CALL_SET(value_oplist, ref->value, value); \ - return; \ - } \ - } \ - M_C(name, _pair_init_set2)(*M_C(name, _list_pair_push_raw)(*list_ptr), \ - M_IF(isStoreHash)(hash M_DEFERRED_COMMA,) \ - key \ - M_IF(isSet)(, M_DEFERRED_COMMA value)); \ - map->used ++; \ - if (M_UNLIKELY (map->used > map->upper_limit) ) \ - M_C(name,_int_resize_up)(map); \ - DICTI_CONTRACT(name, map); \ - } \ - \ - static inline value_type * \ - M_C(name, _get_at)(dict_t map, key_type const key) \ - { \ - DICTI_CONTRACT(name, map); \ - \ - size_t hash = M_CALL_HASH(key_oplist, key); \ - size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ - M_C(name, _list_pair_ct) *list_ptr = \ - M_C(name, _array_list_pair_get)(map->table, i); \ - M_C(name, _list_pair_it_ct) it; \ - for(M_C(name, _list_pair_it)(it, *list_ptr); \ - !M_C(name, _list_pair_end_p)(it); \ - M_C(name, _list_pair_next)(it)) { \ - M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ - M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ - if (M_CALL_EQUAL(key_oplist, ref->key, key)) { \ - return &ref->M_IF(isSet)(key, value); \ - } \ - } \ - pair_type *ref = M_C(name, _list_pair_push_new)(*list_ptr); \ - M_IF(isStoreHash)(M_C(name, _pair_set_hash)(*ref, hash);,) \ - M_C(name, _pair_set_key)(*ref, key); \ - map->used ++; \ - if (M_UNLIKELY (map->used > map->upper_limit) ) { \ - M_C(name,_int_resize_up)(map); \ - /* Even if the array is being resized, the pointer 'ref' \ - shall still point to the same item in the bucket (it may still \ - be in a different bucket) */ \ - } \ - DICTI_CONTRACT(name, map); \ - return &(*ref)->M_IF(isSet)(key, value); \ - } \ - \ - static inline bool \ - M_C(name, _erase)(dict_t map, key_type const key) \ - { \ - DICTI_CONTRACT(name, map); \ - \ - bool ret = false; \ - size_t hash = M_CALL_HASH(key_oplist, key); \ - size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ - M_C(name, _list_pair_ct) *list_ptr = \ - M_C(name, _array_list_pair_get)(map->table, i); \ - M_C(name, _list_pair_it_ct) it; \ - for(M_C(name, _list_pair_it)(it, *list_ptr); \ - !M_C(name, _list_pair_end_p)(it); \ - M_C(name, _list_pair_next)(it)) { \ - M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ - M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ - if (M_CALL_EQUAL(key_oplist, ref->key, key)) { \ - M_C(name, _list_pair_remove)(*list_ptr, it); \ - map->used --; \ - ret = true; \ - break; \ - } \ - } \ - if (M_UNLIKELY (map->used < map->lower_limit) ) \ - M_C(name, _int_resize_down)(map); \ - return ret; \ - } \ - \ - static inline void \ - M_C(name, _it)(dict_it_t it, const dict_t d) \ - { \ - DICTI_CONTRACT(name, d); \ - M_C(name, _array_list_pair_it)(it->array_it, d->table); \ - M_C(name, _list_pair_ct) *ref = \ - M_C(name, _array_list_pair_ref)(it->array_it); \ - M_C(name, _list_pair_it)(it->list_it, *ref); \ - while (M_C(name, _list_pair_end_p)(it->list_it)) { \ - M_C(name, _array_list_pair_next)(it->array_it); \ - if (M_UNLIKELY (M_C(name, _array_list_pair_end_p)(it->array_it))) \ - break; \ - ref = M_C(name, _array_list_pair_ref)(it->array_it); \ - M_C(name, _list_pair_it)(it->list_it, *ref); \ - } \ - } \ - \ - static inline void \ - M_C(name, _it_set)(dict_it_t it, const dict_it_t ref) \ - { \ - assert (it != NULL && ref != NULL); \ - M_C(name, _array_list_pair_it_set)(it->array_it, \ - ref->array_it); \ - M_C(name, _list_pair_it_set)(it->list_it, ref->list_it); \ - } \ - \ - static inline void \ - M_C(name, _it_end)(dict_it_t it, const dict_t d) \ - { \ - DICTI_CONTRACT(name, d); \ - M_C(name, _array_list_pair_it_end)(it->array_it, d->table); \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const dict_it_t it) \ - { \ - assert (it != NULL); \ - return M_C(name, _list_pair_end_p)(it->list_it); \ - } \ - \ - static inline void \ - M_C(name, _next)(dict_it_t it) \ - { \ - assert(it != NULL); \ - M_C(name, _list_pair_next)(it->list_it); \ - M_C(name, _list_pair_ct) *ref; \ - while (M_C(name, _list_pair_end_p)(it->list_it)) { \ - M_C(name, _array_list_pair_next)(it->array_it); \ - if (M_C(name, _array_list_pair_end_p)(it->array_it)) \ - break; \ - ref = M_C(name, _array_list_pair_ref)(it->array_it); \ - M_C(name, _list_pair_it)(it->list_it, *ref); \ - } \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(const dict_it_t it) \ - { \ - assert (it != NULL); \ - dict_it_t it2; \ - M_C(name,_it_set)(it2, it); \ - M_C(name, _next)(it2); \ - return M_C(name, _end_p)(it2); \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const dict_it_t it1, const dict_it_t it2) \ - { \ - assert (it1 != NULL && it2 != NULL); \ - return M_C(name, _list_pair_it_equal_p)(it1->list_it, \ - it2->list_it); \ - } \ - \ - static inline it_deref_t * \ - M_C(name, _ref)(const dict_it_t it) \ - { \ - assert(it != NULL); \ - /* NOTE: partially unsafe if the user modify the 'key' \ - in a non equivalent way */ \ - M_IF(isSet)( \ - return &(*M_C(name, _list_pair_ref)(it->list_it))->key; \ - , \ - return *M_C(name, _list_pair_ref)(it->list_it); \ - ) \ - } \ - \ - static inline const it_deref_t * \ - M_C(name, _cref)(const dict_it_t it) \ - { \ - assert(it != NULL); \ - M_IF(isSet)( \ - return &(*M_C(name, _list_pair_cref)(it->list_it))->key; \ - , \ - return *M_C(name, _list_pair_cref)(it->list_it); \ - ) \ - } \ - \ - M_IF_METHOD(EQUAL, value_oplist)( \ - static inline bool \ - M_C(name, _equal_p)(const dict_t dict1, const dict_t dict2) \ - { \ - assert (dict1 != NULL && dict2 != NULL); \ - /* NOTE: Key type has mandatory equal operator */ \ - /* First the easy cases */ \ - if (M_LIKELY (dict1->used != dict2->used)) \ - return false; \ - if (M_UNLIKELY (dict1->used == 0)) \ - return true; \ - /* Otherwise this is the slow path : \ - both dictionary may not have arrays with the same size, but \ - still the dictionnaries shall be equal as they contain the same \ - items. */ \ - dict_it_t it; \ - for(M_C(name, _it)(it, dict1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)) { \ - const it_deref_t *item = M_C(name, _cref)(it); \ + if ((hash & (new_size-1)) >= old_size) { \ + assert( (hash & (new_size-1)) == (i + old_size)); \ + M_C(name, _list_pair_ct) *new_list = \ + M_C(name, _array_list_pair_get)(map->table, i + old_size); \ + M_C(name, _list_pair_splice_back)(*new_list, *list, it); \ + /* Splice_back has updated the iterator to the next one */ \ + } else { \ + M_C(name, _list_pair_next)(it); \ + } \ + } \ + } \ + map->upper_limit = DICTI_UPPER_BOUND(new_size); \ + map->lower_limit = DICTI_LOWER_BOUND(new_size); \ + } \ + \ + static inline void \ + M_C(name, _int_resize_down)(dict_t map) \ + { \ + /* NOTE: Contract may not be fullfilled here */ \ + size_t old_size = M_C(name, _array_list_pair_size)(map->table); \ + assert ((old_size % 2) == 0); \ + size_t new_size = old_size / 2; \ + assert (new_size >= DICTI_INITIAL_SIZE); \ + /* Move all items from the upper part to the lower part of the table */ \ + /* NOTE: We don't need to recompute the hash to move them! */ \ + for(size_t i = new_size; i < old_size; i++) { \ + M_C(name, _list_pair_ct) *list = \ + M_C(name, _array_list_pair_get)(map->table, i); \ + if (M_C(name, _list_pair_empty_p)(*list)) \ + continue; \ + M_C(name, _list_pair_ct) *new_list = \ + M_C(name, _array_list_pair_get)(map->table, i - new_size); \ + M_C(name, _list_pair_splice)(*new_list, *list); \ + } \ + /* Resize the table of the dictionary */ \ + M_C(name, _array_list_pair_resize)(map->table, new_size); \ + map->upper_limit = DICTI_UPPER_BOUND(new_size); \ + map->lower_limit = DICTI_LOWER_BOUND(new_size); \ + } \ + \ + static inline void \ + M_IF(isSet)(M_C(name, _push), M_C(name, _set_at)) \ + (dict_t map, key_type const key \ + M_IF(isSet)(, M_DEFERRED_COMMA value_type const value)) \ + { \ + DICTI_CONTRACT(name, map); \ + \ + size_t hash = M_CALL_HASH(key_oplist, key); \ + size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ + M_C(name, _list_pair_ct) *list_ptr = \ + M_C(name, _array_list_pair_get)(map->table, i); \ + M_C(name, _list_pair_it_ct) it; \ + for(M_C(name, _list_pair_it)(it, *list_ptr); \ + !M_C(name, _list_pair_end_p)(it); \ + M_C(name, _list_pair_next)(it)) { \ + M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ + M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ + if (M_CALL_EQUAL(key_oplist,ref->key, key)) { \ + M_CALL_SET(value_oplist, ref->value, value); \ + return; \ + } \ + } \ + M_C(name, _pair_init_set2)(*M_C(name, _list_pair_push_raw)(*list_ptr), \ + M_IF(isStoreHash)(hash M_DEFERRED_COMMA,) \ + key \ + M_IF(isSet)(, M_DEFERRED_COMMA value)); \ + map->used ++; \ + if (M_UNLIKELY (map->used > map->upper_limit) ) \ + M_C(name,_int_resize_up)(map); \ + DICTI_CONTRACT(name, map); \ + } \ + \ + static inline value_type * \ + M_C(name, _get_at)(dict_t map, key_type const key) \ + { \ + DICTI_CONTRACT(name, map); \ + \ + size_t hash = M_CALL_HASH(key_oplist, key); \ + size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ + M_C(name, _list_pair_ct) *list_ptr = \ + M_C(name, _array_list_pair_get)(map->table, i); \ + M_C(name, _list_pair_it_ct) it; \ + for(M_C(name, _list_pair_it)(it, *list_ptr); \ + !M_C(name, _list_pair_end_p)(it); \ + M_C(name, _list_pair_next)(it)) { \ + M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ + M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ + if (M_CALL_EQUAL(key_oplist, ref->key, key)) { \ + return &ref->M_IF(isSet)(key, value); \ + } \ + } \ + pair_type *ref = M_C(name, _list_pair_push_new)(*list_ptr); \ + M_IF(isStoreHash)(M_C(name, _pair_set_hash)(*ref, hash);,) \ + M_C(name, _pair_set_key)(*ref, key); \ + map->used ++; \ + if (M_UNLIKELY (map->used > map->upper_limit) ) { \ + M_C(name,_int_resize_up)(map); \ + /* Even if the array is being resized, the pointer 'ref' \ + shall still point to the same item in the bucket (it may still \ + be in a different bucket) */ \ + } \ + DICTI_CONTRACT(name, map); \ + return &(*ref)->M_IF(isSet)(key, value); \ + } \ + \ + static inline bool \ + M_C(name, _erase)(dict_t map, key_type const key) \ + { \ + DICTI_CONTRACT(name, map); \ + \ + bool ret = false; \ + size_t hash = M_CALL_HASH(key_oplist, key); \ + size_t i = hash & (M_C(name, _array_list_pair_size)(map->table) - 1); \ + M_C(name, _list_pair_ct) *list_ptr = \ + M_C(name, _array_list_pair_get)(map->table, i); \ + M_C(name, _list_pair_it_ct) it; \ + for(M_C(name, _list_pair_it)(it, *list_ptr); \ + !M_C(name, _list_pair_end_p)(it); \ + M_C(name, _list_pair_next)(it)) { \ + M_C(name, _pair_ptr) ref = *M_C(name, _list_pair_ref)(it); \ + M_IF(isStoreHash)(if (ref->hash != hash) continue;, ) \ + if (M_CALL_EQUAL(key_oplist, ref->key, key)) { \ + M_C(name, _list_pair_remove)(*list_ptr, it); \ + map->used --; \ + ret = true; \ + break; \ + } \ + } \ + if (M_UNLIKELY (map->used < map->lower_limit) ) \ + M_C(name, _int_resize_down)(map); \ + return ret; \ + } \ + \ + static inline void \ + M_C(name, _it)(dict_it_t it, const dict_t d) \ + { \ + DICTI_CONTRACT(name, d); \ + M_C(name, _array_list_pair_it)(it->array_it, d->table); \ + M_C(name, _list_pair_ct) *ref = \ + M_C(name, _array_list_pair_ref)(it->array_it); \ + M_C(name, _list_pair_it)(it->list_it, *ref); \ + while (M_C(name, _list_pair_end_p)(it->list_it)) { \ + M_C(name, _array_list_pair_next)(it->array_it); \ + if (M_UNLIKELY (M_C(name, _array_list_pair_end_p)(it->array_it))) \ + break; \ + ref = M_C(name, _array_list_pair_ref)(it->array_it); \ + M_C(name, _list_pair_it)(it->list_it, *ref); \ + } \ + } \ + \ + static inline void \ + M_C(name, _it_set)(dict_it_t it, const dict_it_t ref) \ + { \ + assert (it != NULL && ref != NULL); \ + M_C(name, _array_list_pair_it_set)(it->array_it, \ + ref->array_it); \ + M_C(name, _list_pair_it_set)(it->list_it, ref->list_it); \ + } \ + \ + static inline void \ + M_C(name, _it_end)(dict_it_t it, const dict_t d) \ + { \ + DICTI_CONTRACT(name, d); \ + M_C(name, _array_list_pair_it_end)(it->array_it, d->table); \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const dict_it_t it) \ + { \ + assert (it != NULL); \ + return M_C(name, _list_pair_end_p)(it->list_it); \ + } \ + \ + static inline void \ + M_C(name, _next)(dict_it_t it) \ + { \ + assert(it != NULL); \ + M_C(name, _list_pair_next)(it->list_it); \ + M_C(name, _list_pair_ct) *ref; \ + while (M_C(name, _list_pair_end_p)(it->list_it)) { \ + M_C(name, _array_list_pair_next)(it->array_it); \ + if (M_C(name, _array_list_pair_end_p)(it->array_it)) \ + break; \ + ref = M_C(name, _array_list_pair_ref)(it->array_it); \ + M_C(name, _list_pair_it)(it->list_it, *ref); \ + } \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(const dict_it_t it) \ + { \ + assert (it != NULL); \ + dict_it_t it2; \ + M_C(name,_it_set)(it2, it); \ + M_C(name, _next)(it2); \ + return M_C(name, _end_p)(it2); \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const dict_it_t it1, const dict_it_t it2) \ + { \ + assert (it1 != NULL && it2 != NULL); \ + return M_C(name, _list_pair_it_equal_p)(it1->list_it, \ + it2->list_it); \ + } \ + \ + static inline it_deref_t * \ + M_C(name, _ref)(const dict_it_t it) \ + { \ + assert(it != NULL); \ + /* NOTE: partially unsafe if the user modify the 'key' \ + in a non equivalent way */ \ + M_IF(isSet)( \ + return &(*M_C(name, _list_pair_ref)(it->list_it))->key; \ + , \ + return *M_C(name, _list_pair_ref)(it->list_it); \ + ) \ + } \ + \ + static inline const it_deref_t * \ + M_C(name, _cref)(const dict_it_t it) \ + { \ + assert(it != NULL); \ + M_IF(isSet)( \ + return &(*M_C(name, _list_pair_cref)(it->list_it))->key; \ + , \ + return *M_C(name, _list_pair_cref)(it->list_it); \ + ) \ + } \ + \ + M_IF_METHOD(EQUAL, value_oplist)( \ + static inline bool \ + M_C(name, _equal_p)(const dict_t dict1, const dict_t dict2) \ + { \ + assert (dict1 != NULL && dict2 != NULL); \ + /* NOTE: Key type has mandatory equal operator */ \ + /* First the easy cases */ \ + if (M_LIKELY (dict1->used != dict2->used)) \ + return false; \ + if (M_UNLIKELY (dict1->used == 0)) \ + return true; \ + /* Otherwise this is the slow path : \ + both dictionary may not have arrays with the same size, but \ + still the dictionnaries shall be equal as they contain the same \ + items. */ \ + dict_it_t it; \ + for(M_C(name, _it)(it, dict1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)) { \ + const it_deref_t *item = M_C(name, _cref)(it); \ value_type *ptr = M_C(name, _get)(dict2, M_IF(isSet)(*item, item->key)); \ - if (ptr == NULL) \ - return false; \ - if (M_CALL_EQUAL(value_oplist, item->value, *ptr) == false) \ - return false; \ - } \ - return true; \ - } \ - , /* no value equal */ ) \ - \ + if (ptr == NULL) \ + return false; \ + if (M_CALL_EQUAL(value_oplist, item->value, *ptr) == false) \ + return false; \ + } \ + return true; \ + } \ + , /* no value equal */ ) \ + \ DICTI_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) /* Define additional functions for dictionnary (Common for all kinds of dictionnary). Do not used any fields of the dictionnary but the public API */ #define DICTI_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) \ - \ - M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ - static inline void \ - M_C(name, _get_str)(string_t str, const dict_t dict, const bool append) \ - { \ - STRINGI_CONTRACT (str); \ - (append ? string_cat_str : string_set_str) (str, "{"); \ - dict_it_t it; \ - bool print_comma = false; \ - for (M_C(name, _it)(it, dict) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - if (print_comma) \ - string_push_back (str, ','); \ - const it_deref_t *item = M_C(name, _cref)(it); \ - M_IF(isSet)( \ - M_CALL_GET_STR(key_oplist, str, *item, true); \ - , \ - M_CALL_GET_STR(key_oplist, str, item->key, true); \ - string_push_back (str, ':'); \ - M_CALL_GET_STR(value_oplist, str, item->value, true); \ - ) \ - print_comma = true; \ - } \ - string_push_back (str, '}'); \ - STRINGI_CONTRACT(str); \ - } \ - , /* no GET_STR */ ) \ - \ - M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *file, const dict_t dict) \ - { \ - assert (file != NULL); \ - fputc ('{', file); \ - dict_it_t it; \ - bool print_comma = false; \ - for (M_C(name, _it)(it, dict) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - if (print_comma) \ - fputc (',', file); \ - const it_deref_t *item = M_C(name, _cref)(it); \ - M_IF(isSet)( \ - M_CALL_OUT_STR(key_oplist, file, *item); \ - , \ - M_CALL_OUT_STR(key_oplist, file, item->key); \ - fputc (':', file); \ - M_CALL_OUT_STR(value_oplist, file, item->value); \ - ) \ - print_comma = true; \ - } \ - fputc ('}', file); \ - } \ - , /* no OUT_STR */ ) \ - \ - M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ - static inline bool \ - M_C(name, _parse_str)(dict_t dict, const char str[], const char **endp) \ - { \ - assert (str != NULL); \ - M_C(name, _clean)(dict); \ - bool success = false; \ - int c = *str++; \ - if (M_UNLIKELY (c != '{')) goto exit; \ - c = *str++; \ - if (M_UNLIKELY (c == '}')) { success = true; goto exit;} \ - if (M_UNLIKELY (c == 0)) goto exit; \ - str--; \ - key_type key; \ - M_IF(isSet)( ,value_type value); \ - M_CALL_INIT(key_oplist, key); \ - M_CALL_INIT(value_oplist, value); \ - do { \ - while (isspace((int) *str)) str++; \ - bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \ - M_IF(isSet)( \ - if (b == false) { goto exit_clear; } \ - M_C(name, _push)(dict, key); \ - , \ - do { c = *str++; } while (isspace(c)); \ - if (b == false || c != ':') { goto exit_clear; } \ - b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ - if (b == false) { goto exit_clear; } \ - M_C(name, _set_at)(dict, key, value); \ - ) \ - do { c = *str++; } while (isspace(c)); \ - } while (c == ','); \ - success = (c == '}'); \ - exit_clear: \ - M_CALL_CLEAR(key_oplist, key); \ - M_CALL_CLEAR(value_oplist, value); \ - exit: \ - if (endp) *endp = str; \ - return success; \ - } \ - , /* no PARSE_STR */ ) \ - \ - M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ - static inline bool \ - M_C(name, _in_str)(dict_t dict, FILE *file) \ - { \ - assert (file != NULL); \ - M_C(name, _clean)(dict); \ - int c = fgetc(file); \ - if (M_UNLIKELY (c != '{')) return false; \ - c = fgetc(file); \ - if (M_UNLIKELY (c == '}')) return true; \ - if (M_UNLIKELY (c == EOF)) return true; \ - ungetc(c, file); \ - key_type key; \ - M_CALL_INIT(key_oplist, key); \ - M_IF(isSet)(, \ - value_type value; \ - M_CALL_INIT(value_oplist, value); \ - ) \ - do { \ - do { c = fgetc(file); } while (isspace(c)); \ - ungetc(c, file); \ - bool b = M_CALL_IN_STR(key_oplist, key, file); \ - M_IF(isSet)( \ - if (b == false) { break; } \ - M_C(name, _push)(dict, key); \ - , \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false || c == EOF) { break; } \ - if (c != ':') { c = 0; break; } \ - b = M_CALL_IN_STR(value_oplist, value, file); \ - if (b == false) { c = 0; break; } \ - M_C(name, _set_at)(dict, key, value); \ - ) \ - do { c = fgetc(file); } while (isspace(c)); \ - } while (c == ','); \ - M_CALL_CLEAR(key_oplist, key); \ - M_IF(isSet)(, \ - M_CALL_CLEAR(value_oplist, value); \ - ) \ - return c == '}'; \ - } \ - , /* no IN_STR */ ) \ - \ - M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, dict_t const t1) \ - { \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - const it_deref_t *item; \ - bool first_done = false; \ - dict_it_t it; \ - /* Format is different between associative container \ - & set container */ \ - M_IF(isSet)( \ + \ + M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ + static inline void \ + M_C(name, _get_str)(string_t str, const dict_t dict, const bool append) \ + { \ + STRINGI_CONTRACT (str); \ + (append ? string_cat_str : string_set_str) (str, "{"); \ + dict_it_t it; \ + bool print_comma = false; \ + for (M_C(name, _it)(it, dict) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + if (print_comma) \ + string_push_back (str, ','); \ + const it_deref_t *item = M_C(name, _cref)(it); \ + M_IF(isSet)( \ + M_CALL_GET_STR(key_oplist, str, *item, true); \ + , \ + M_CALL_GET_STR(key_oplist, str, item->key, true); \ + string_push_back (str, ':'); \ + M_CALL_GET_STR(value_oplist, str, item->value, true); \ + ) \ + print_comma = true; \ + } \ + string_push_back (str, '}'); \ + STRINGI_CONTRACT(str); \ + } \ + , /* no GET_STR */ ) \ + \ + M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *file, const dict_t dict) \ + { \ + assert (file != NULL); \ + fputc ('{', file); \ + dict_it_t it; \ + bool print_comma = false; \ + for (M_C(name, _it)(it, dict) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + if (print_comma) \ + fputc (',', file); \ + const it_deref_t *item = M_C(name, _cref)(it); \ + M_IF(isSet)( \ + M_CALL_OUT_STR(key_oplist, file, *item); \ + , \ + M_CALL_OUT_STR(key_oplist, file, item->key); \ + fputc (':', file); \ + M_CALL_OUT_STR(value_oplist, file, item->value); \ + ) \ + print_comma = true; \ + } \ + fputc ('}', file); \ + } \ + , /* no OUT_STR */ ) \ + \ + M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ + static inline bool \ + M_C(name, _parse_str)(dict_t dict, const char str[], const char **endp) \ + { \ + assert (str != NULL); \ + M_C(name, _clean)(dict); \ + bool success = false; \ + int c = *str++; \ + if (M_UNLIKELY (c != '{')) goto exit; \ + c = *str++; \ + if (M_UNLIKELY (c == '}')) { success = true; goto exit;} \ + if (M_UNLIKELY (c == 0)) goto exit; \ + str--; \ + key_type key; \ + M_IF(isSet)( ,value_type value); \ + M_CALL_INIT(key_oplist, key); \ + M_CALL_INIT(value_oplist, value); \ + do { \ + while (isspace((int) *str)) str++; \ + bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \ + M_IF(isSet)( \ + if (b == false) { goto exit_clear; } \ + M_C(name, _push)(dict, key); \ + , \ + do { c = *str++; } while (isspace(c)); \ + if (b == false || c != ':') { goto exit_clear; } \ + b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ + if (b == false) { goto exit_clear; } \ + M_C(name, _set_at)(dict, key, value); \ + ) \ + do { c = *str++; } while (isspace(c)); \ + } while (c == ','); \ + success = (c == '}'); \ + exit_clear: \ + M_CALL_CLEAR(key_oplist, key); \ + M_CALL_CLEAR(value_oplist, value); \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } \ + , /* no PARSE_STR */ ) \ + \ + M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ + static inline bool \ + M_C(name, _in_str)(dict_t dict, FILE *file) \ + { \ + assert (file != NULL); \ + M_C(name, _clean)(dict); \ + int c = fgetc(file); \ + if (M_UNLIKELY (c != '{')) return false; \ + c = fgetc(file); \ + if (M_UNLIKELY (c == '}')) return true; \ + if (M_UNLIKELY (c == EOF)) return true; \ + ungetc(c, file); \ + key_type key; \ + M_CALL_INIT(key_oplist, key); \ + M_IF(isSet)(, \ + value_type value; \ + M_CALL_INIT(value_oplist, value); \ + ) \ + do { \ + do { c = fgetc(file); } while (isspace(c)); \ + ungetc(c, file); \ + bool b = M_CALL_IN_STR(key_oplist, key, file); \ + M_IF(isSet)( \ + if (b == false) { break; } \ + M_C(name, _push)(dict, key); \ + , \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false || c == EOF) { break; } \ + if (c != ':') { c = 0; break; } \ + b = M_CALL_IN_STR(value_oplist, value, file); \ + if (b == false) { c = 0; break; } \ + M_C(name, _set_at)(dict, key, value); \ + ) \ + do { c = fgetc(file); } while (isspace(c)); \ + } while (c == ','); \ + M_CALL_CLEAR(key_oplist, key); \ + M_IF(isSet)(, \ + M_CALL_CLEAR(value_oplist, value); \ + ) \ + return c == '}'; \ + } \ + , /* no IN_STR */ ) \ + \ + M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, dict_t const t1) \ + { \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + const it_deref_t *item; \ + bool first_done = false; \ + dict_it_t it; \ + /* Format is different between associative container \ + & set container */ \ + M_IF(isSet)( \ ret = f->m_interface->write_array_start(local, f, M_C(name, _size)(t1)); \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_array_end(local, f); \ - , \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_array_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \ + first_done = true; \ + } \ + ret |= f->m_interface->write_array_end(local, f); \ + , \ ret = f->m_interface->write_map_start(local, f, M_C(name, _size)(t1)); \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_map_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(key_oplist, f, item->key); \ - ret |= f->m_interface->write_map_value(local, f); \ - ret |= M_CALL_OUT_SERIAL(value_oplist, f, item->value); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_map_end(local, f); \ - ) \ - return ret & M_SERIAL_FAIL; \ - } \ - , /* no OUT_SERIAL */ ) \ - \ - M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(dict_t t1, m_serial_read_t f) \ - { \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - size_t estimated_size = 0; \ - key_type key; \ - M_C(name,_clean)(t1); \ - M_IF(isSet)( \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_map_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(key_oplist, f, item->key); \ + ret |= f->m_interface->write_map_value(local, f); \ + ret |= M_CALL_OUT_SERIAL(value_oplist, f, item->value); \ + first_done = true; \ + } \ + ret |= f->m_interface->write_map_end(local, f); \ + ) \ + return ret & M_SERIAL_FAIL; \ + } \ + , /* no OUT_SERIAL */ ) \ + \ + M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(dict_t t1, m_serial_read_t f) \ + { \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + size_t estimated_size = 0; \ + key_type key; \ + M_C(name,_clean)(t1); \ + M_IF(isSet)( \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - M_CALL_INIT(key_oplist, key); \ - do { \ - ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ - if (ret != M_SERIAL_OK_DONE) { break; } \ - M_C(name, _push)(t1, key); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + M_CALL_INIT(key_oplist, key); \ + do { \ + ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ + if (ret != M_SERIAL_OK_DONE) { break; } \ + M_C(name, _push)(t1, key); \ } while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(key_oplist, key); \ - , \ - value_type value; \ + M_CALL_CLEAR(key_oplist, key); \ + , \ + value_type value; \ ret = f->m_interface->read_map_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - M_CALL_INIT(key_oplist, key); \ - M_CALL_INIT (value_oplist, value); \ - do { \ - ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ - if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ - ret = f->m_interface->read_map_value(local, f); \ - if (ret != M_SERIAL_OK_CONTINUE) return M_SERIAL_FAIL; \ - ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ - if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ - M_C(name, _set_at)(t1, key, value); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + M_CALL_INIT(key_oplist, key); \ + M_CALL_INIT (value_oplist, value); \ + do { \ + ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ + if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ + ret = f->m_interface->read_map_value(local, f); \ + if (ret != M_SERIAL_OK_CONTINUE) return M_SERIAL_FAIL; \ + ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ + if (ret != M_SERIAL_OK_DONE) return M_SERIAL_FAIL; \ + M_C(name, _set_at)(t1, key, value); \ } while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(key_oplist, key); \ - M_CALL_CLEAR(value_oplist, value); \ - ) /* End of IF isSet */ \ - return ret; \ - } \ - , /* no in_serial */ ) \ - \ - M_IF(isSet)( \ - static inline void \ - M_C(name, _splice)(dict_t d1, dict_t d2) \ - { \ - dict_it_t it; \ - /* NOTE: Despite using set_at, the accessing of the item in d1 \ - is not as random as other uses of the HASH table as d2 \ - uses the same order than d1 */ \ + M_CALL_CLEAR(key_oplist, key); \ + M_CALL_CLEAR(value_oplist, value); \ + ) /* End of IF isSet */ \ + return ret; \ + } \ + , /* no in_serial */ ) \ + \ + M_IF(isSet)( \ + static inline void \ + M_C(name, _splice)(dict_t d1, dict_t d2) \ + { \ + dict_it_t it; \ + /* NOTE: Despite using set_at, the accessing of the item in d1 \ + is not as random as other uses of the HASH table as d2 \ + uses the same order than d1 */ \ for (M_C(name, _it)(it, d2); !M_C(name, _end_p)(it); M_C(name, _next)(it)){ \ - const it_deref_t *item = M_C(name, _cref)(it); \ - M_C(name, _push)(d1, *item); \ - } \ - M_C(name, _clean)(d2); \ - } \ - , \ - M_IF_METHOD(UPDATE, value_oplist)( \ - static inline void \ - M_C(name, _splice)(dict_t d1, dict_t d2) \ - { \ - dict_it_t it; \ - /* NOTE: Despite using set_at, the accessing of the item in d1 \ - is not as random as other uses of the HASH table as d2 \ - uses the same order than d1 */ \ + const it_deref_t *item = M_C(name, _cref)(it); \ + M_C(name, _push)(d1, *item); \ + } \ + M_C(name, _clean)(d2); \ + } \ + , \ + M_IF_METHOD(UPDATE, value_oplist)( \ + static inline void \ + M_C(name, _splice)(dict_t d1, dict_t d2) \ + { \ + dict_it_t it; \ + /* NOTE: Despite using set_at, the accessing of the item in d1 \ + is not as random as other uses of the HASH table as d2 \ + uses the same order than d1 */ \ for (M_C(name, _it)(it, d2); !M_C(name, _end_p)(it); M_C(name, _next)(it)){ \ - const struct M_C(name, _pair_s) *item = M_C(name, _cref)(it); \ - value_type *ptr = M_C(name, _get)(d1, item->key); \ - if (ptr == NULL) { \ - M_C(name, _set_at)(d1, item->key, item->value); \ - } else { \ - M_CALL_UPDATE(value_oplist, *ptr, item->value); \ - } \ - } \ - M_C(name, _clean)(d2); \ - } \ - , /* NO UPDATE */) ) \ - \ - /* HASH method for dictionnary itself seems hard to implement: \ - we have to handle the case where two dictionnaries are structuraly \ - different, but functionnaly identical (seems they have the same \ - members, but put in a different order). \ - We cannot iterator over the dictionary to compute a hash, as the \ - order of the items in the dictionnary is not specified: they more \ - or less follow the hash of the keys, but if the low bits of the \ - hash of the key is equal, they order may be different. \ - Or if the table of the dictionnary has different values (this may \ + const struct M_C(name, _pair_s) *item = M_C(name, _cref)(it); \ + value_type *ptr = M_C(name, _get)(d1, item->key); \ + if (ptr == NULL) { \ + M_C(name, _set_at)(d1, item->key, item->value); \ + } else { \ + M_CALL_UPDATE(value_oplist, *ptr, item->value); \ + } \ + } \ + M_C(name, _clean)(d2); \ + } \ + , /* NO UPDATE */) ) \ + \ + /* HASH method for dictionnary itself seems hard to implement: \ + we have to handle the case where two dictionnaries are structuraly \ + different, but functionnaly identical (seems they have the same \ + members, but put in a different order). \ + We cannot iterator over the dictionary to compute a hash, as the \ + order of the items in the dictionnary is not specified: they more \ + or less follow the hash of the keys, but if the low bits of the \ + hash of the key is equal, they order may be different. \ + Or if the table of the dictionnary has different values (this may \ be avoided). */ @@ -1051,58 +1051,58 @@ #define DICTI_OPLIST_P1(arg) DICTI_OPLIST_P2 arg /* Validation of the given oplists */ -#define DICTI_OPLIST_P2(name, key_oplist, value_oplist) \ +#define DICTI_OPLIST_P2(name, key_oplist, value_oplist) \ M_IF_OPLIST(key_oplist)(DICTI_OPLIST_P3, DICTI_OPLIST_FAILURE)(name, key_oplist, value_oplist) -#define DICTI_OPLIST_P3(name, key_oplist, value_oplist) \ +#define DICTI_OPLIST_P3(name, key_oplist, value_oplist) \ M_IF_OPLIST(value_oplist)(DICTI_OPLIST_P4, DICTI_OPLIST_FAILURE)(name, key_oplist, value_oplist) /* Prepare a clean compilation failure */ -#define DICTI_OPLIST_FAILURE(name, key_oplist, value_oplist) \ +#define DICTI_OPLIST_FAILURE(name, key_oplist, value_oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_DICT_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist))) /* Define the oplist of a dictionnary NOTE: IT_REF is not exported so that the contained appears as not modifiable by algorithm.*/ -#define DICTI_OPLIST_P4(name, key_oplist, value_oplist) \ - (INIT(M_C(name, _init)), \ - INIT_SET(M_C(name, _init_set)), \ - INIT_WITH(API_1(M_INIT_KEY_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)), \ - CLEAN(M_C(name, _clean)), \ - TYPE(M_C(name, _ct)), \ - SUBTYPE(M_C(name, _subtype_ct)), \ - TEST_EMPTY(M_C(name,_empty_p)), \ - IT_TYPE(M_C(name, _it_ct)), \ - IT_FIRST(M_C(name,_it)), \ - IT_SET(M_C(name, _it_set)), \ - IT_END(M_C(name,_it_end)), \ - IT_END_P(M_C(name,_end_p)), \ - IT_LAST_P(M_C(name,_last_p)), \ - IT_NEXT(M_C(name,_next)), \ - IT_CREF(M_C(name,_cref)) \ - ,KEY_TYPE(M_C(name, _key_ct)) \ - ,VALUE_TYPE(M_C(name, _value_ct)) \ - ,SET_KEY(M_C(name, _set_at)) \ - ,GET_KEY(M_C(name, _get)) \ - ,GET_SET_KEY(M_C(name, _get_at)) \ - ,ERASE_KEY(M_C(name, _erase)) \ - ,KEY_OPLIST(key_oplist) \ - ,VALUE_OPLIST(value_oplist) \ - ,GET_SIZE(M_C(name, _size)) \ +#define DICTI_OPLIST_P4(name, key_oplist, value_oplist) \ + (INIT(M_C(name, _init)), \ + INIT_SET(M_C(name, _init_set)), \ + INIT_WITH(API_1(M_INIT_KEY_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)), \ + CLEAN(M_C(name, _clean)), \ + TYPE(M_C(name, _ct)), \ + SUBTYPE(M_C(name, _subtype_ct)), \ + TEST_EMPTY(M_C(name,_empty_p)), \ + IT_TYPE(M_C(name, _it_ct)), \ + IT_FIRST(M_C(name,_it)), \ + IT_SET(M_C(name, _it_set)), \ + IT_END(M_C(name,_it_end)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_LAST_P(M_C(name,_last_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_CREF(M_C(name,_cref)) \ + ,KEY_TYPE(M_C(name, _key_ct)) \ + ,VALUE_TYPE(M_C(name, _value_ct)) \ + ,SET_KEY(M_C(name, _set_at)) \ + ,GET_KEY(M_C(name, _get)) \ + ,GET_SET_KEY(M_C(name, _get_at)) \ + ,ERASE_KEY(M_C(name, _erase)) \ + ,KEY_OPLIST(key_oplist) \ + ,VALUE_OPLIST(value_oplist) \ + ,GET_SIZE(M_C(name, _size)) \ ,M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(GET_STR(M_C(name, _get_str)),) \ ,M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(M_C(name, _parse_str)),) \ ,M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_C(name, _out_str)),) \ ,M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(M_C(name, _in_str)),) \ ,M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ ,M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ - ,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_C(name, _equal_p)),) \ - ,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW key_oplist),) \ - ,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC key_oplist),) \ - ,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL key_oplist),) \ + ,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_C(name, _equal_p)),) \ + ,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW key_oplist),) \ + ,M_IF_METHOD(REALLOC, oplist)(REALLOC(M_GET_REALLOC key_oplist),) \ + ,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL key_oplist),) \ ) /* Deferred evaluation for the definition, @@ -1110,56 +1110,56 @@ #define DICTI_SET_OPLIST_P1(arg) DICTI_SET_OPLIST_P2 arg /* Validation of the given oplist */ -#define DICTI_SET_OPLIST_P2(name, oplist) \ +#define DICTI_SET_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(DICTI_SET_OPLIST_P3, DICTI_SET_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define DICTI_SET_OPLIST_FAILURE(name, oplist) \ +#define DICTI_SET_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_DICT_SET_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* Define the oplist of a set */ -#define DICTI_SET_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)), \ - CLEAN(M_C(name, _clean)), \ - TYPE(M_C(name, _ct)), \ - SUBTYPE(M_C(name, _subtype_ct)), \ - TEST_EMPTY(M_C(name,_empty_p)), \ - PUSH(M_C(name,_push)), \ - KEY_TYPE(M_C(name, _key_ct)), \ - VALUE_TYPE(M_C(name, _key_ct)), \ - GET_KEY(M_C(name, _get)), \ - GET_SET_KEY(M_C(name, _get_at)), \ - ERASE_KEY(M_C(name, _erase)), \ - KEY_OPLIST(oplist), \ - VALUE_OPLIST(oplist), \ - GET_SIZE(M_C(name, _size)), \ - IT_TYPE(M_C(name, _it_ct)), \ - IT_FIRST(M_C(name,_it)), \ - IT_SET(M_C(name, _it_set)), \ - IT_END(M_C(name,_it_end)), \ - IT_END_P(M_C(name,_end_p)), \ - IT_LAST_P(M_C(name,_last_p)), \ - IT_NEXT(M_C(name,_next)), \ - IT_REF(M_C(name,_ref)), \ - IT_CREF(M_C(name,_cref)) \ - ,OPLIST(oplist) \ - ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ - ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ - ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ - ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ - ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ - ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ - ,EQUAL(M_C(name, _equal_p)), \ - ,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 DICTI_SET_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)), \ + CLEAN(M_C(name, _clean)), \ + TYPE(M_C(name, _ct)), \ + SUBTYPE(M_C(name, _subtype_ct)), \ + TEST_EMPTY(M_C(name,_empty_p)), \ + PUSH(M_C(name,_push)), \ + KEY_TYPE(M_C(name, _key_ct)), \ + VALUE_TYPE(M_C(name, _key_ct)), \ + GET_KEY(M_C(name, _get)), \ + GET_SET_KEY(M_C(name, _get_at)), \ + ERASE_KEY(M_C(name, _erase)), \ + KEY_OPLIST(oplist), \ + VALUE_OPLIST(oplist), \ + GET_SIZE(M_C(name, _size)), \ + IT_TYPE(M_C(name, _it_ct)), \ + IT_FIRST(M_C(name,_it)), \ + IT_SET(M_C(name, _it_set)), \ + IT_END(M_C(name,_it_end)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_LAST_P(M_C(name,_last_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_REF(M_C(name,_ref)), \ + IT_CREF(M_C(name,_cref)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ + ,EQUAL(M_C(name, _equal_p)), \ + ,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 Lower Bound for hash table (TODO: Common macro for both implementation) */ @@ -1177,12 +1177,12 @@ #define DICTI_INITIAL_SIZE 16 #endif -#define DICTI_CONTRACT(name, map) do { \ - assert(map != NULL); \ - assert(map->used <= map->upper_limit); \ - assert(map->upper_limit >= DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE)); \ - assert(map->used >= map->lower_limit); \ - assert(M_POWEROF2_P(M_C(name, _array_list_pair_size)(map->table))); \ +#define DICTI_CONTRACT(name, map) do { \ + assert(map != NULL); \ + assert(map->used <= map->upper_limit); \ + assert(map->upper_limit >= DICTI_UPPER_BOUND(DICTI_INITIAL_SIZE)); \ + assert(map->used >= map->lower_limit); \ + assert(M_POWEROF2_P(M_C(name, _array_list_pair_size)(map->table))); \ } while (0) @@ -1209,14 +1209,14 @@ enum dicti_oa_element_e { #define DICTI_OA_UPPER_BOUND 0.7 #endif -#define DICTI_OA_CONTRACT(dict) do { \ - assert ( (dict) != NULL); \ - assert( (dict)->lower_limit <= (dict)->count); \ - assert( (dict)->count <= (dict)->upper_limit ); \ - assert( (dict)->data != NULL); \ - assert( M_POWEROF2_P((dict)->mask+1)); \ - assert( (dict)->mask+1 >= DICTI_INITIAL_SIZE); \ - assert( (dict)->count <= (dict)->mask+1); \ +#define DICTI_OA_CONTRACT(dict) do { \ + assert ( (dict) != NULL); \ + assert( (dict)->lower_limit <= (dict)->count); \ + assert( (dict)->count <= (dict)->upper_limit ); \ + assert( (dict)->data != NULL); \ + assert( M_POWEROF2_P((dict)->mask+1)); \ + assert( (dict)->mask+1 >= DICTI_INITIAL_SIZE); \ + assert( (dict)->count <= (dict)->mask+1); \ } while (0) #define DICTI_OA_DEF_P1(args) DICTI_OA_DEF_P2 args @@ -1234,8 +1234,8 @@ enum dicti_oa_element_e { M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_OA_DEF2): at least one of the given argument is not a valid oplist: " M_AS_STR(key_oplist) " / " M_AS_STR(value_oplist) ) #define DICTI_OA_DEF_P4(name, key_type, key_oplist, value_type, value_oplist, dict_t, dict_it_t, it_deref_t) \ - DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, 0, \ - DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, \ + DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, 0, \ + DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, \ dict_t, dict_it_t, it_deref_t) #define DICTI_OASET_DEF_P1(args) DICTI_OASET_DEF_P2 args @@ -1249,745 +1249,745 @@ enum dicti_oa_element_e { M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(DICT_OASET_DEF): the given argument is not a valid oplist: " M_AS_STR(key_oplist) ) #define DICTI_OASET_DEF_P4(name, key_type, key_oplist, dict_t, dict_it_t, it_deref_t) \ - DICTI_OA_DEF_P5(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, 1, \ + DICTI_OA_DEF_P5(name, key_type, key_oplist, key_type, M_EMPTY_OPLIST, 1, \ DICTI_OA_LOWER_BOUND, DICTI_OA_UPPER_BOUND, dict_t, dict_it_t, it_deref_t ) #define DICTI_OA_DEF_P5(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t, it_deref_t) \ - \ - /* NOTE: \ - if isSet is true, all methods of value_oplist are NOP methods */ \ - \ - typedef struct M_C(name, _pair_s) { \ - key_type key; \ - M_IF(isSet)( , value_type value;) \ - } M_C(name, _pair_ct); \ - \ - /* Define type returned by the _ref method of an iterator */ \ - M_IF(isSet)( \ - typedef key_type it_deref_t; \ - , \ - typedef struct M_C(name, _pair_s) it_deref_t; \ - ) \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ - M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \ - \ - /* NOTE: We don't want a real oplist for this sub type */ \ - ARRAY_DEF(M_C(name, _array_pair), M_C(name, _pair_ct), \ - (INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \ - INIT_SET(M_MEMCPY_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \ - \ - typedef struct M_C(name,_s) { \ - size_t mask, count, count_delete; \ - size_t upper_limit, lower_limit; \ - struct M_C(name, _pair_s) *data; \ - } dict_t[1]; \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - typedef struct M_C(name, _it_s) { \ - const struct M_C(name,_s) *dict; \ - size_t index; \ - } dict_it_t[1]; \ - \ - /* Define internal types for oplist */ \ - typedef dict_t M_C(name, _ct); \ - typedef it_deref_t M_C(name, _subtype_ct); \ - typedef key_type M_C(name, _key_ct); \ - typedef value_type M_C(name, _value_ct); \ - typedef dict_it_t M_C(name, _it_ct); \ - \ - static inline void \ - M_C(name,_int_limit)(dict_t dict, size_t size) \ - { \ - dict->upper_limit = (size_t) ((double) size * coeff_up) - 1; \ + \ + /* NOTE: \ + if isSet is true, all methods of value_oplist are NOP methods */ \ + \ + typedef struct M_C(name, _pair_s) { \ + key_type key; \ + M_IF(isSet)( , value_type value;) \ + } M_C(name, _pair_ct); \ + \ + /* Define type returned by the _ref method of an iterator */ \ + M_IF(isSet)( \ + typedef key_type it_deref_t; \ + , \ + typedef struct M_C(name, _pair_s) it_deref_t; \ + ) \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, key_type, key_oplist) \ + M_CHECK_COMPATIBLE_OPLIST(name, 2, value_type, value_oplist) \ + \ + /* NOTE: We don't want a real oplist for this sub type */ \ + ARRAY_DEF(M_C(name, _array_pair), M_C(name, _pair_ct), \ + (INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \ + INIT_SET(M_MEMCPY_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \ + \ + typedef struct M_C(name,_s) { \ + size_t mask, count, count_delete; \ + size_t upper_limit, lower_limit; \ + struct M_C(name, _pair_s) *data; \ + } dict_t[1]; \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + typedef struct M_C(name, _it_s) { \ + const struct M_C(name,_s) *dict; \ + size_t index; \ + } dict_it_t[1]; \ + \ + /* Define internal types for oplist */ \ + typedef dict_t M_C(name, _ct); \ + typedef it_deref_t M_C(name, _subtype_ct); \ + typedef key_type M_C(name, _key_ct); \ + typedef value_type M_C(name, _value_ct); \ + typedef dict_it_t M_C(name, _it_ct); \ + \ + static inline void \ + M_C(name,_int_limit)(dict_t dict, size_t size) \ + { \ + dict->upper_limit = (size_t) ((double) size * coeff_up) - 1; \ dict->lower_limit = (size <= DICTI_INITIAL_SIZE) ? 0 : (size_t) ((double) size * coeff_down) ; \ - } \ - \ - static inline void \ - M_C(name, _init)(dict_t dict) \ - { \ + } \ + \ + static inline void \ + M_C(name, _init)(dict_t dict) \ + { \ assert(0 <= (coeff_down) && (coeff_down)*2 < (coeff_up) && (coeff_up) < 1); \ - dict->mask = DICTI_INITIAL_SIZE-1; \ - dict->count = 0; \ - dict->count_delete = 0; \ - M_C(name,_int_limit)(dict, DICTI_INITIAL_SIZE); \ + dict->mask = DICTI_INITIAL_SIZE-1; \ + dict->count = 0; \ + dict->count_delete = 0; \ + M_C(name,_int_limit)(dict, DICTI_INITIAL_SIZE); \ dict->data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), NULL, DICTI_INITIAL_SIZE); \ - if (dict->data == NULL) { \ - M_MEMORY_FULL(sizeof (M_C(name, _pair_ct)) * DICTI_INITIAL_SIZE); \ - return ; \ - } \ - for(size_t i = 0; i < DICTI_INITIAL_SIZE; i++) { \ - M_CALL_OOR_SET(key_oplist, dict->data[i].key, DICTI_OA_EMPTY); \ - } \ - DICTI_OA_CONTRACT(dict); \ - } \ - \ - static inline void \ - M_C(name, _clear)(dict_t dict) \ - { \ - DICTI_OA_CONTRACT(dict); \ - for(size_t i = 0; i <= dict->mask; i++) { \ - if (!M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, DICTI_OA_EMPTY) \ + if (dict->data == NULL) { \ + M_MEMORY_FULL(sizeof (M_C(name, _pair_ct)) * DICTI_INITIAL_SIZE); \ + return ; \ + } \ + for(size_t i = 0; i < DICTI_INITIAL_SIZE; i++) { \ + M_CALL_OOR_SET(key_oplist, dict->data[i].key, DICTI_OA_EMPTY); \ + } \ + DICTI_OA_CONTRACT(dict); \ + } \ + \ + static inline void \ + M_C(name, _clear)(dict_t dict) \ + { \ + DICTI_OA_CONTRACT(dict); \ + for(size_t i = 0; i <= dict->mask; i++) { \ + if (!M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, DICTI_OA_EMPTY) \ && !M_CALL_OOR_EQUAL(key_oplist, dict->data[i].key, DICTI_OA_DELETED)) { \ - M_CALL_CLEAR(key_oplist, dict->data[i].key); \ - M_CALL_CLEAR(value_oplist, dict->data[i].value); \ - } \ - } \ - M_CALL_FREE(key_oplist, dict->data); \ - /* Not really needed, but safer */ \ - dict->mask = 0; \ - dict->data = NULL; \ - } \ - \ - static inline value_type * \ - M_C(name, _get)(const dict_t dict, key_type const key) \ - { \ - DICTI_OA_CONTRACT(dict); \ - /* NOTE: Key can not be the representation of empty or deleted */ \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ - \ - M_C(name, _pair_ct) *const data = dict->data; \ - const size_t mask = dict->mask; \ - size_t p = M_CALL_HASH(key_oplist, key) & mask; \ - \ - /* Random access, and probably cache miss */ \ - if (M_LIKELY (M_CALL_EQUAL(key_oplist, data[p].key, key)) ) \ - return &data[p].M_IF(isSet)(key, value); \ + M_CALL_CLEAR(key_oplist, dict->data[i].key); \ + M_CALL_CLEAR(value_oplist, dict->data[i].value); \ + } \ + } \ + M_CALL_FREE(key_oplist, dict->data); \ + /* Not really needed, but safer */ \ + dict->mask = 0; \ + dict->data = NULL; \ + } \ + \ + static inline value_type * \ + M_C(name, _get)(const dict_t dict, key_type const key) \ + { \ + DICTI_OA_CONTRACT(dict); \ + /* NOTE: Key can not be the representation of empty or deleted */ \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ + \ + M_C(name, _pair_ct) *const data = dict->data; \ + const size_t mask = dict->mask; \ + size_t p = M_CALL_HASH(key_oplist, key) & mask; \ + \ + /* Random access, and probably cache miss */ \ + if (M_LIKELY (M_CALL_EQUAL(key_oplist, data[p].key, key)) ) \ + return &data[p].M_IF(isSet)(key, value); \ else if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) ) \ - return NULL; \ - \ - /* Unlikely case */ \ - size_t s = 1; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - if (M_CALL_EQUAL(key_oplist, data[p].key, key)) \ - return &data[p].M_IF(isSet)(key, value); \ - assert (s <= dict->mask); \ - } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ - \ - return NULL; \ - } \ - \ - static inline value_type const * \ - M_C(name, _cget)(const dict_t map, key_type const key) \ - { \ - return M_CONST_CAST(value_type, M_C(name,_get)(map,key)); \ - } \ - \ - M_IF_DEBUG( \ - static inline bool \ - M_C(name,_int_control_after_resize)(const dict_t h) \ - { \ - /* This function checks if the reshashing of the dict is ok */ \ - M_C(name, _pair_ct) *data = h->data; \ - size_t empty = 0; \ - size_t del = 0; \ - /* Count the number of empty elements and the number of deleted */ \ - for(size_t i = 0 ; i <= h->mask ; i++) { \ - empty += M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY); \ - del += M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED); \ - } \ - assert(del == 0); \ - assert(empty + h->count == h->mask + 1); \ - return true; \ - } \ - ) \ - \ - static inline void \ - M_C(name,_int_resize_up)(dict_t h, size_t newSize, bool updateLimit) \ - { \ - size_t oldSize = h->mask+1; \ - assert (newSize >= oldSize); \ - assert (M_POWEROF2_P(newSize)); \ - M_C(name, _pair_ct) *data = h->data; \ - /* resize can be called just to delete the items */ \ - if (newSize > oldSize) { \ - data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), data, newSize); \ - if (M_UNLIKELY (data == NULL) ) { \ - M_MEMORY_FULL(sizeof (M_C(name, _pair_ct)) * newSize); \ - return ; \ - } \ - \ - /* First mark the extended space as empty */ \ - for(size_t i = oldSize ; i < newSize; i++) \ - M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ - } \ - \ - /* Then let's rehash all the entries in their **exact** position. \ - If we can't, let's put them in the 'tmp' array. \ - It has been measured that the size of this 'tmp' array is \ - around 6% of the size of updated dictionnary. \ - NOTE: This should be much cache friendly than typical hash code */ \ - M_C(name, _array_pair_ct) tmp; \ - M_C(name, _array_pair_init)(tmp); \ - const size_t mask = (newSize -1); \ - \ - for(size_t i = 0 ; i < oldSize; i++) { \ + return NULL; \ + \ + /* Unlikely case */ \ + size_t s = 1; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + if (M_CALL_EQUAL(key_oplist, data[p].key, key)) \ + return &data[p].M_IF(isSet)(key, value); \ + assert (s <= dict->mask); \ + } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ + \ + return NULL; \ + } \ + \ + static inline value_type const * \ + M_C(name, _cget)(const dict_t map, key_type const key) \ + { \ + return M_CONST_CAST(value_type, M_C(name,_get)(map,key)); \ + } \ + \ + M_IF_DEBUG( \ + static inline bool \ + M_C(name,_int_control_after_resize)(const dict_t h) \ + { \ + /* This function checks if the reshashing of the dict is ok */ \ + M_C(name, _pair_ct) *data = h->data; \ + size_t empty = 0; \ + size_t del = 0; \ + /* Count the number of empty elements and the number of deleted */ \ + for(size_t i = 0 ; i <= h->mask ; i++) { \ + empty += M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY); \ + del += M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED); \ + } \ + assert(del == 0); \ + assert(empty + h->count == h->mask + 1); \ + return true; \ + } \ + ) \ + \ + static inline void \ + M_C(name,_int_resize_up)(dict_t h, size_t newSize, bool updateLimit) \ + { \ + size_t oldSize = h->mask+1; \ + assert (newSize >= oldSize); \ + assert (M_POWEROF2_P(newSize)); \ + M_C(name, _pair_ct) *data = h->data; \ + /* resize can be called just to delete the items */ \ + if (newSize > oldSize) { \ + data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), data, newSize); \ + if (M_UNLIKELY (data == NULL) ) { \ + M_MEMORY_FULL(sizeof (M_C(name, _pair_ct)) * newSize); \ + return ; \ + } \ + \ + /* First mark the extended space as empty */ \ + for(size_t i = oldSize ; i < newSize; i++) \ + M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ + } \ + \ + /* Then let's rehash all the entries in their **exact** position. \ + If we can't, let's put them in the 'tmp' array. \ + It has been measured that the size of this 'tmp' array is \ + around 6% of the size of updated dictionnary. \ + NOTE: This should be much cache friendly than typical hash code */ \ + M_C(name, _array_pair_ct) tmp; \ + M_C(name, _array_pair_init)(tmp); \ + const size_t mask = (newSize -1); \ + \ + for(size_t i = 0 ; i < oldSize; i++) { \ if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED) && !M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY)) { \ - size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \ - if (p != i) { \ + size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \ + if (p != i) { \ if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) || M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_DELETED))) { \ - M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ - } else { \ + M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ + M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ + } else { \ M_C(name, _pair_ct) *ptr = M_C(name, _array_pair_push_raw) (tmp); \ - M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ - } \ - M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ - } \ - } else { \ - M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ - } \ - } \ - \ - /* Let's put back the entries in the tmp array in their right place */ \ - /* NOTE: There should be very few entries in this array \ - which contains what we weren't be able to fit in the first pass */ \ - while (M_C(name, _array_pair_size)(tmp) > 0) { \ - M_C(name, _pair_ct) const *item = M_C(name, _array_pair_back)(tmp); \ - size_t p = M_CALL_HASH(key_oplist, item->key) & mask; \ - /* NOTE: since the first pass, the bucket might be free now */ \ - if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) { \ - size_t s = 1; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - assert (s <= h->mask); \ + M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ + M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ + } \ + M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ + } \ + } else { \ + M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ + } \ + } \ + \ + /* Let's put back the entries in the tmp array in their right place */ \ + /* NOTE: There should be very few entries in this array \ + which contains what we weren't be able to fit in the first pass */ \ + while (M_C(name, _array_pair_size)(tmp) > 0) { \ + M_C(name, _pair_ct) const *item = M_C(name, _array_pair_back)(tmp); \ + size_t p = M_CALL_HASH(key_oplist, item->key) & mask; \ + /* NOTE: since the first pass, the bucket might be free now */ \ + if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) { \ + size_t s = 1; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + assert (s <= h->mask); \ } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ - } \ - M_C(name, _array_pair_pop_move)(&data[p], tmp); \ - } \ - \ - M_C(name, _array_pair_clear) (tmp); \ - h->mask = newSize-1; \ - h->count_delete = h->count; \ - if (updateLimit == true) { \ - M_C(name,_int_limit)(h, newSize); \ - } \ - h->data = data; \ - M_IF_DEBUG (assert (M_C(name,_int_control_after_resize)(h));) \ - DICTI_OA_CONTRACT(h); \ - } \ - \ - static inline void \ - M_IF(isSet)(M_C(name, _push), M_C(name,_set_at)) \ - (dict_t dict, key_type const key \ - M_IF(isSet)(, M_DEFERRED_COMMA value_type const value) ) \ - { \ - DICTI_OA_CONTRACT(dict); \ - /* NOTE: key can not be the representation of empty or deleted */ \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ - \ - M_C(name, _pair_ct) *const data = dict->data; \ - const size_t mask = dict->mask; \ - size_t p = M_CALL_HASH(key_oplist, key) & mask; \ - \ - /* NOTE: Likely cache miss */ \ - if (M_UNLIKELY (M_CALL_EQUAL(key_oplist, data[p].key, key)) ) { \ - M_CALL_SET(value_oplist, data[p].value, value); \ - return; \ - } \ + } \ + M_C(name, _array_pair_pop_move)(&data[p], tmp); \ + } \ + \ + M_C(name, _array_pair_clear) (tmp); \ + h->mask = newSize-1; \ + h->count_delete = h->count; \ + if (updateLimit == true) { \ + M_C(name,_int_limit)(h, newSize); \ + } \ + h->data = data; \ + M_IF_DEBUG (assert (M_C(name,_int_control_after_resize)(h));) \ + DICTI_OA_CONTRACT(h); \ + } \ + \ + static inline void \ + M_IF(isSet)(M_C(name, _push), M_C(name,_set_at)) \ + (dict_t dict, key_type const key \ + M_IF(isSet)(, M_DEFERRED_COMMA value_type const value) ) \ + { \ + DICTI_OA_CONTRACT(dict); \ + /* NOTE: key can not be the representation of empty or deleted */ \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ + \ + M_C(name, _pair_ct) *const data = dict->data; \ + const size_t mask = dict->mask; \ + size_t p = M_CALL_HASH(key_oplist, key) & mask; \ + \ + /* NOTE: Likely cache miss */ \ + if (M_UNLIKELY (M_CALL_EQUAL(key_oplist, data[p].key, key)) ) { \ + M_CALL_SET(value_oplist, data[p].value, value); \ + return; \ + } \ if (M_UNLIKELY (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ) ) { \ - size_t delPos = SIZE_MAX; \ + size_t delPos = SIZE_MAX; \ if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_DELETED)) delPos = p; \ - size_t s = 1U; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \ - M_CALL_SET(value_oplist, data[p].value, value); \ - return; \ - } \ - assert (s <= dict->mask); \ + size_t s = 1U; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \ + M_CALL_SET(value_oplist, data[p].value, value); \ + return; \ + } \ + assert (s <= dict->mask); \ if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_DELETED) && delPos == (size_t)-1) delPos = p; \ - } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ - if (delPos != SIZE_MAX) { \ - p = delPos; \ - dict->count_delete --; \ - } \ - } \ - \ - M_CALL_INIT_SET(key_oplist, data[p].key, key); \ - M_CALL_INIT_SET(value_oplist, data[p].value, value); \ - dict->count++; \ - dict->count_delete ++; \ - \ - if (M_UNLIKELY (dict->count_delete >= dict->upper_limit)) { \ - size_t newSize = dict->mask+1; \ - if (dict->count > (dict->mask / 2)) { \ - newSize += newSize; \ - if (M_UNLIKELY (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ - } \ - } \ - M_C(name,_int_resize_up)(dict, newSize, true); \ - } \ - DICTI_OA_CONTRACT(dict); \ - } \ - \ - static inline value_type * \ - M_C(name,_get_at)(dict_t dict, key_type const key) \ - { \ - DICTI_OA_CONTRACT(dict); \ - /* NOTE: key can not be the representation of empty or deleted */ \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ - \ - M_C(name, _pair_ct) *const data = dict->data; \ - const size_t mask = dict->mask; \ - size_t p = M_CALL_HASH(key_oplist, key) & mask; \ - \ - if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \ - return &data[p].M_IF(isSet)(key, value); \ - } \ + } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ + if (delPos != SIZE_MAX) { \ + p = delPos; \ + dict->count_delete --; \ + } \ + } \ + \ + M_CALL_INIT_SET(key_oplist, data[p].key, key); \ + M_CALL_INIT_SET(value_oplist, data[p].value, value); \ + dict->count++; \ + dict->count_delete ++; \ + \ + if (M_UNLIKELY (dict->count_delete >= dict->upper_limit)) { \ + size_t newSize = dict->mask+1; \ + if (dict->count > (dict->mask / 2)) { \ + newSize += newSize; \ + if (M_UNLIKELY (newSize <= dict->mask+1)) { \ + M_MEMORY_FULL((size_t)-1); \ + } \ + } \ + M_C(name,_int_resize_up)(dict, newSize, true); \ + } \ + DICTI_OA_CONTRACT(dict); \ + } \ + \ + static inline value_type * \ + M_C(name,_get_at)(dict_t dict, key_type const key) \ + { \ + DICTI_OA_CONTRACT(dict); \ + /* NOTE: key can not be the representation of empty or deleted */ \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ + \ + M_C(name, _pair_ct) *const data = dict->data; \ + const size_t mask = dict->mask; \ + size_t p = M_CALL_HASH(key_oplist, key) & mask; \ + \ + if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \ + return &data[p].M_IF(isSet)(key, value); \ + } \ if (M_UNLIKELY (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ) ) { \ - size_t delPos = SIZE_MAX; \ + size_t delPos = SIZE_MAX; \ if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_DELETED)) delPos = p; \ - size_t s = 1U; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \ - return &data[p].M_IF(isSet)(key, value); \ - } \ - assert (s <= dict->mask); \ + size_t s = 1U; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + if (M_CALL_EQUAL(key_oplist, data[p].key, key)) { \ + return &data[p].M_IF(isSet)(key, value); \ + } \ + assert (s <= dict->mask); \ if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_DELETED) && delPos == (size_t)-1) delPos = p; \ - } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ - if (delPos != SIZE_MAX) { \ - p = delPos; \ - dict->count_delete --; \ - } \ - } \ - \ - M_CALL_INIT_SET(key_oplist, data[p].key, key); \ - M_CALL_INIT(value_oplist, data[p].value); \ - dict->count++; \ - dict->count_delete ++; \ - \ - if (M_UNLIKELY (dict->count_delete >= dict->upper_limit)) { \ - size_t newSize = dict->mask+1; \ - if (dict->count > (dict->mask / 2)) { \ - newSize += newSize; \ - if (M_UNLIKELY (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ - } \ - } \ - M_C(name,_int_resize_up)(dict, newSize, true); \ - /* data is now invalid */ \ - return M_C(name, _get)(dict, key); \ - } \ - DICTI_OA_CONTRACT(dict); \ - return &data[p].M_IF(isSet)(key, value); \ - } \ - \ - static inline void \ - M_C(name,_int_resize_down)(dict_t h, size_t newSize) \ - { \ - size_t oldSize = h->mask+1; \ - assert (newSize <= oldSize && M_POWEROF2_P(newSize)); \ - if (M_UNLIKELY (newSize < DICTI_INITIAL_SIZE)) \ - newSize = DICTI_INITIAL_SIZE; \ - const size_t mask = newSize -1; \ - M_C(name, _pair_ct) *data = h->data; \ - M_C(name, _array_pair_ct) tmp; \ - M_C(name, _array_pair_init)(tmp); \ - \ - /* Pass 1: scan lower entries, and move them if needed */ \ - for(size_t i = 0; i < newSize; i++) { \ - if (M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY)) \ - continue; \ - if (M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED)) { \ - M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ - continue; \ - } \ - size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \ - if (p != i) { \ + } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ + if (delPos != SIZE_MAX) { \ + p = delPos; \ + dict->count_delete --; \ + } \ + } \ + \ + M_CALL_INIT_SET(key_oplist, data[p].key, key); \ + M_CALL_INIT(value_oplist, data[p].value); \ + dict->count++; \ + dict->count_delete ++; \ + \ + if (M_UNLIKELY (dict->count_delete >= dict->upper_limit)) { \ + size_t newSize = dict->mask+1; \ + if (dict->count > (dict->mask / 2)) { \ + newSize += newSize; \ + if (M_UNLIKELY (newSize <= dict->mask+1)) { \ + M_MEMORY_FULL((size_t)-1); \ + } \ + } \ + M_C(name,_int_resize_up)(dict, newSize, true); \ + /* data is now invalid */ \ + return M_C(name, _get)(dict, key); \ + } \ + DICTI_OA_CONTRACT(dict); \ + return &data[p].M_IF(isSet)(key, value); \ + } \ + \ + static inline void \ + M_C(name,_int_resize_down)(dict_t h, size_t newSize) \ + { \ + size_t oldSize = h->mask+1; \ + assert (newSize <= oldSize && M_POWEROF2_P(newSize)); \ + if (M_UNLIKELY (newSize < DICTI_INITIAL_SIZE)) \ + newSize = DICTI_INITIAL_SIZE; \ + const size_t mask = newSize -1; \ + M_C(name, _pair_ct) *data = h->data; \ + M_C(name, _array_pair_ct) tmp; \ + M_C(name, _array_pair_init)(tmp); \ + \ + /* Pass 1: scan lower entries, and move them if needed */ \ + for(size_t i = 0; i < newSize; i++) { \ + if (M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY)) \ + continue; \ + if (M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED)) { \ + M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ + continue; \ + } \ + size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \ + if (p != i) { \ if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) || M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_DELETED)) { \ - M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ - } else { \ - M_C(name, _pair_ct) *ptr = M_C(name, _array_pair_push_raw) (tmp); \ - M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ - } \ - M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ - } \ - } \ - /* Pass 2: scan upper entries and move them back */ \ - for(size_t i = newSize; i < oldSize; i++) { \ - if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED) \ - && !M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY)) { \ - size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \ - assert (p < i); \ - if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) { \ - size_t s = 1; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - assert (s <= h->mask); \ + M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ + M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ + } else { \ + M_C(name, _pair_ct) *ptr = M_C(name, _array_pair_push_raw) (tmp); \ + M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ + M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ + } \ + M_CALL_OOR_SET(key_oplist, data[i].key, DICTI_OA_EMPTY); \ + } \ + } \ + /* Pass 2: scan upper entries and move them back */ \ + for(size_t i = newSize; i < oldSize; i++) { \ + if (!M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_DELETED) \ + && !M_CALL_OOR_EQUAL(key_oplist, data[i].key, DICTI_OA_EMPTY)) { \ + size_t p = M_CALL_HASH(key_oplist, data[i].key) & mask; \ + assert (p < i); \ + if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) { \ + size_t s = 1; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + assert (s <= h->mask); \ } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ - } \ - M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ - } \ - } \ - /* Pass 3: scan moved entries and move them back */ \ - while (M_C(name, _array_pair_size)(tmp) > 0) { \ - M_C(name, _pair_ct) const *item = M_C(name, _array_pair_back)(tmp); \ - size_t p = M_CALL_HASH(key_oplist, item->key) & mask; \ - if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) { \ - size_t s = 1; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - assert (s <= h->mask); \ + } \ + M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ + M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ + } \ + } \ + /* Pass 3: scan moved entries and move them back */ \ + while (M_C(name, _array_pair_size)(tmp) > 0) { \ + M_C(name, _pair_ct) const *item = M_C(name, _array_pair_back)(tmp); \ + size_t p = M_CALL_HASH(key_oplist, item->key) & mask; \ + if (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) { \ + size_t s = 1; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + assert (s <= h->mask); \ } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ); \ - } \ - M_C(name, _array_pair_pop_move)(&data[p], tmp); \ - } \ - \ - M_C(name, _array_pair_clear) (tmp); \ - h->count_delete = h->count; \ - if (newSize != oldSize) { \ - h->mask = newSize-1; \ - M_C(name,_int_limit)(h, newSize); \ + } \ + M_C(name, _array_pair_pop_move)(&data[p], tmp); \ + } \ + \ + M_C(name, _array_pair_clear) (tmp); \ + h->count_delete = h->count; \ + if (newSize != oldSize) { \ + h->mask = newSize-1; \ + M_C(name,_int_limit)(h, newSize); \ h->data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), data, newSize); \ - assert (h->data != NULL); \ - } \ - M_IF_DEBUG (assert (M_C(name,_int_control_after_resize)(h));) \ - assert (h->lower_limit < h->count && h->count < h->upper_limit); \ - DICTI_OA_CONTRACT(h); \ - } \ - \ - static inline bool \ - M_C(name,_erase)(dict_t dict, const key_type key) \ - { \ - DICTI_OA_CONTRACT(dict); \ - /* NOTE: key can't be the representation of empty or deleted */ \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ - assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ - \ - M_C(name, _pair_ct) *const data = dict->data; \ - const size_t mask = dict->mask; \ - size_t p = M_CALL_HASH(key_oplist, key) & mask; \ - \ - /* Random access, and probably cache miss */ \ - if (M_UNLIKELY (!M_CALL_EQUAL(key_oplist, data[p].key, key)) ) { \ - if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) \ - return false; \ - size_t s = 1; \ - do { \ - p = (p + DICTI_OA_PROBING(s)) & mask; \ - if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ) \ - return false; \ - assert (s <= dict->mask); \ - } while (!M_CALL_EQUAL(key_oplist, data[p].key, key)); \ - } \ - M_CALL_CLEAR(key_oplist, data[p].key); \ - M_CALL_CLEAR(value_oplist, data[p].value); \ - M_CALL_OOR_SET(key_oplist, data[p].key, DICTI_OA_DELETED); \ - assert (dict->count >= 1); \ - dict->count--; \ - if (M_UNLIKELY (dict->count < dict->lower_limit)) { \ - M_C(name,_int_resize_down)(dict, (dict->mask+1) >> 1); \ - } \ - DICTI_OA_CONTRACT(dict); \ - return true; \ - } \ - \ - static inline bool \ - M_C(name,_empty_p)(const dict_t dict) \ - { \ - DICTI_OA_CONTRACT(dict); \ - return dict->count == 0; \ - } \ - \ - static inline size_t \ - M_C(name,_size)(const dict_t dict) \ - { \ - DICTI_OA_CONTRACT(dict); \ - return dict->count; \ - } \ - \ - static inline void \ - M_C(name, _init_set)(dict_t map, const dict_t org) \ - { \ - DICTI_OA_CONTRACT(org); \ - assert (map != org); \ - map->mask = org->mask; \ - map->count = org->count; \ - map->count_delete = org->count_delete; \ - map->upper_limit = org->upper_limit; \ - map->lower_limit = org->lower_limit; \ + assert (h->data != NULL); \ + } \ + M_IF_DEBUG (assert (M_C(name,_int_control_after_resize)(h));) \ + assert (h->lower_limit < h->count && h->count < h->upper_limit); \ + DICTI_OA_CONTRACT(h); \ + } \ + \ + static inline bool \ + M_C(name,_erase)(dict_t dict, const key_type key) \ + { \ + DICTI_OA_CONTRACT(dict); \ + /* NOTE: key can't be the representation of empty or deleted */ \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_EMPTY)); \ + assert (!M_CALL_OOR_EQUAL(key_oplist, key, DICTI_OA_DELETED)); \ + \ + M_C(name, _pair_ct) *const data = dict->data; \ + const size_t mask = dict->mask; \ + size_t p = M_CALL_HASH(key_oplist, key) & mask; \ + \ + /* Random access, and probably cache miss */ \ + if (M_UNLIKELY (!M_CALL_EQUAL(key_oplist, data[p].key, key)) ) { \ + if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY)) \ + return false; \ + size_t s = 1; \ + do { \ + p = (p + DICTI_OA_PROBING(s)) & mask; \ + if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, DICTI_OA_EMPTY) ) \ + return false; \ + assert (s <= dict->mask); \ + } while (!M_CALL_EQUAL(key_oplist, data[p].key, key)); \ + } \ + M_CALL_CLEAR(key_oplist, data[p].key); \ + M_CALL_CLEAR(value_oplist, data[p].value); \ + M_CALL_OOR_SET(key_oplist, data[p].key, DICTI_OA_DELETED); \ + assert (dict->count >= 1); \ + dict->count--; \ + if (M_UNLIKELY (dict->count < dict->lower_limit)) { \ + M_C(name,_int_resize_down)(dict, (dict->mask+1) >> 1); \ + } \ + DICTI_OA_CONTRACT(dict); \ + return true; \ + } \ + \ + static inline bool \ + M_C(name,_empty_p)(const dict_t dict) \ + { \ + DICTI_OA_CONTRACT(dict); \ + return dict->count == 0; \ + } \ + \ + static inline size_t \ + M_C(name,_size)(const dict_t dict) \ + { \ + DICTI_OA_CONTRACT(dict); \ + return dict->count; \ + } \ + \ + static inline void \ + M_C(name, _init_set)(dict_t map, const dict_t org) \ + { \ + DICTI_OA_CONTRACT(org); \ + assert (map != org); \ + map->mask = org->mask; \ + map->count = org->count; \ + map->count_delete = org->count_delete; \ + map->upper_limit = org->upper_limit; \ + map->lower_limit = org->lower_limit; \ map->data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), NULL, map->mask+1); \ - if (map->data == NULL) { \ - M_MEMORY_FULL(sizeof (M_C(name, _pair_ct)) * (map->mask+1)); \ - return ; \ - } \ - for(size_t i = 0; i <= org->mask; i++) { \ - if (M_CALL_OOR_EQUAL(key_oplist, org->data[i].key, DICTI_OA_EMPTY)) { \ - M_CALL_OOR_SET(key_oplist, map->data[i].key, DICTI_OA_EMPTY); \ + if (map->data == NULL) { \ + M_MEMORY_FULL(sizeof (M_C(name, _pair_ct)) * (map->mask+1)); \ + return ; \ + } \ + for(size_t i = 0; i <= org->mask; i++) { \ + if (M_CALL_OOR_EQUAL(key_oplist, org->data[i].key, DICTI_OA_EMPTY)) { \ + M_CALL_OOR_SET(key_oplist, map->data[i].key, DICTI_OA_EMPTY); \ } else if (M_CALL_OOR_EQUAL(key_oplist, org->data[i].key, DICTI_OA_DELETED)) { \ - M_CALL_OOR_SET(key_oplist, map->data[i].key, DICTI_OA_DELETED); \ - } else { \ - M_CALL_INIT_SET(key_oplist, map->data[i].key, org->data[i].key); \ + M_CALL_OOR_SET(key_oplist, map->data[i].key, DICTI_OA_DELETED); \ + } else { \ + M_CALL_INIT_SET(key_oplist, map->data[i].key, org->data[i].key); \ M_CALL_INIT_SET(value_oplist, map->data[i].value, org->data[i].value); \ - } \ - } \ - DICTI_OA_CONTRACT(map); \ - } \ - \ - static inline void \ - M_C(name, _set)(dict_t map, const dict_t org) \ - { \ - DICTI_OA_CONTRACT(map); \ - DICTI_OA_CONTRACT(org); \ - if (M_LIKELY (map != org)) { \ - M_C(name, _clear)(map); \ - M_C(name, _init_set)(map, org); \ - } \ - DICTI_OA_CONTRACT(map); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(dict_t map, dict_t org) \ - { \ - DICTI_OA_CONTRACT(org); \ - assert (map != org); \ - map->mask = org->mask; \ - map->count = org->count; \ - map->count_delete = org->count_delete; \ - map->upper_limit = org->upper_limit; \ - map->lower_limit = org->lower_limit; \ - map->data = org->data; \ - /* Mark org as cleared (safety) */ \ - org->mask = 0; \ - org->data = NULL; \ - DICTI_OA_CONTRACT(map); \ - } \ - \ - static inline void \ - M_C(name, _move)(dict_t map, dict_t org) \ - { \ - DICTI_OA_CONTRACT(map); \ - DICTI_OA_CONTRACT(org); \ - if (M_LIKELY (map != org)) { \ - M_C(name, _clear)(map); \ - M_C(name, _init_move)(map, org); \ - } \ - DICTI_OA_CONTRACT(map); \ - } \ - \ - static inline void \ - M_C(name, _swap)(dict_t d1, dict_t d2) \ - { \ - DICTI_OA_CONTRACT(d1); \ - DICTI_OA_CONTRACT(d2); \ - M_SWAP (size_t, d1->mask, d2->mask); \ - M_SWAP (size_t, d1->count, d2->count); \ - M_SWAP (size_t, d1->count_delete, d2->count_delete); \ - M_SWAP (size_t, d1->upper_limit, d2->upper_limit); \ - M_SWAP (size_t, d1->lower_limit, d2->lower_limit); \ - M_SWAP (M_C(name, _pair_ct) *, d1->data, d2->data); \ - DICTI_OA_CONTRACT(d1); \ - DICTI_OA_CONTRACT(d2); \ - } \ - \ - static inline void \ - M_C(name, _clean)(dict_t d) \ - { \ - DICTI_OA_CONTRACT(d); \ - for(size_t i = 0; i <= d->mask; i++) { \ - if (!M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_EMPTY) \ + } \ + } \ + DICTI_OA_CONTRACT(map); \ + } \ + \ + static inline void \ + M_C(name, _set)(dict_t map, const dict_t org) \ + { \ + DICTI_OA_CONTRACT(map); \ + DICTI_OA_CONTRACT(org); \ + if (M_LIKELY (map != org)) { \ + M_C(name, _clear)(map); \ + M_C(name, _init_set)(map, org); \ + } \ + DICTI_OA_CONTRACT(map); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(dict_t map, dict_t org) \ + { \ + DICTI_OA_CONTRACT(org); \ + assert (map != org); \ + map->mask = org->mask; \ + map->count = org->count; \ + map->count_delete = org->count_delete; \ + map->upper_limit = org->upper_limit; \ + map->lower_limit = org->lower_limit; \ + map->data = org->data; \ + /* Mark org as cleared (safety) */ \ + org->mask = 0; \ + org->data = NULL; \ + DICTI_OA_CONTRACT(map); \ + } \ + \ + static inline void \ + M_C(name, _move)(dict_t map, dict_t org) \ + { \ + DICTI_OA_CONTRACT(map); \ + DICTI_OA_CONTRACT(org); \ + if (M_LIKELY (map != org)) { \ + M_C(name, _clear)(map); \ + M_C(name, _init_move)(map, org); \ + } \ + DICTI_OA_CONTRACT(map); \ + } \ + \ + static inline void \ + M_C(name, _swap)(dict_t d1, dict_t d2) \ + { \ + DICTI_OA_CONTRACT(d1); \ + DICTI_OA_CONTRACT(d2); \ + M_SWAP (size_t, d1->mask, d2->mask); \ + M_SWAP (size_t, d1->count, d2->count); \ + M_SWAP (size_t, d1->count_delete, d2->count_delete); \ + M_SWAP (size_t, d1->upper_limit, d2->upper_limit); \ + M_SWAP (size_t, d1->lower_limit, d2->lower_limit); \ + M_SWAP (M_C(name, _pair_ct) *, d1->data, d2->data); \ + DICTI_OA_CONTRACT(d1); \ + DICTI_OA_CONTRACT(d2); \ + } \ + \ + static inline void \ + M_C(name, _clean)(dict_t d) \ + { \ + DICTI_OA_CONTRACT(d); \ + for(size_t i = 0; i <= d->mask; i++) { \ + if (!M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_EMPTY) \ && !M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_DELETED)) { \ - M_CALL_CLEAR(key_oplist, d->data[i].key); \ - M_CALL_CLEAR(value_oplist, d->data[i].value); \ - } \ - } \ - d->count = 0; \ - d->count_delete = 0; \ - d->mask = DICTI_INITIAL_SIZE-1; \ - M_C(name,_int_limit)(d, DICTI_INITIAL_SIZE); \ - d->data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), \ - d->data, DICTI_INITIAL_SIZE); \ - assert(d->data != NULL); \ - for(size_t i = 0; i <= d->mask; i++) { \ - M_CALL_OOR_SET(key_oplist, d->data[i].key, DICTI_OA_EMPTY); \ - } \ - DICTI_OA_CONTRACT(d); \ - } \ - \ - static inline void \ - M_C(name, _it)(dict_it_t it, const dict_t d) \ - { \ - DICTI_OA_CONTRACT(d); \ - assert (it != NULL); \ - it->dict = d; \ - size_t i = 0; \ - while ((M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_EMPTY) \ + M_CALL_CLEAR(key_oplist, d->data[i].key); \ + M_CALL_CLEAR(value_oplist, d->data[i].value); \ + } \ + } \ + d->count = 0; \ + d->count_delete = 0; \ + d->mask = DICTI_INITIAL_SIZE-1; \ + M_C(name,_int_limit)(d, DICTI_INITIAL_SIZE); \ + d->data = M_CALL_REALLOC(key_oplist, M_C(name, _pair_ct), \ + d->data, DICTI_INITIAL_SIZE); \ + assert(d->data != NULL); \ + for(size_t i = 0; i <= d->mask; i++) { \ + M_CALL_OOR_SET(key_oplist, d->data[i].key, DICTI_OA_EMPTY); \ + } \ + DICTI_OA_CONTRACT(d); \ + } \ + \ + static inline void \ + M_C(name, _it)(dict_it_t it, const dict_t d) \ + { \ + DICTI_OA_CONTRACT(d); \ + assert (it != NULL); \ + it->dict = d; \ + size_t i = 0; \ + while ((M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_EMPTY) \ || M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_DELETED)) \ - && i <= d->mask) { \ - i++; \ - } \ - it->index = i; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(dict_it_t it, const dict_it_t ref) \ - { \ - assert (it != NULL); \ - assert (ref != NULL); \ - it->dict = ref->dict; \ - it->index = ref->index; \ - DICTI_OA_CONTRACT (it->dict); \ - } \ - \ - static inline void \ - M_C(name, _it_last)(dict_it_t it, const dict_t d) \ - { \ - DICTI_OA_CONTRACT(d); \ - assert (it != NULL); \ - it->dict = d; \ - size_t i = d->mask; \ - while ((M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_EMPTY) \ + && i <= d->mask) { \ + i++; \ + } \ + it->index = i; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(dict_it_t it, const dict_it_t ref) \ + { \ + assert (it != NULL); \ + assert (ref != NULL); \ + it->dict = ref->dict; \ + it->index = ref->index; \ + DICTI_OA_CONTRACT (it->dict); \ + } \ + \ + static inline void \ + M_C(name, _it_last)(dict_it_t it, const dict_t d) \ + { \ + DICTI_OA_CONTRACT(d); \ + assert (it != NULL); \ + it->dict = d; \ + size_t i = d->mask; \ + while ((M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_EMPTY) \ || M_CALL_OOR_EQUAL(key_oplist, d->data[i].key, DICTI_OA_DELETED)) \ - && i <= d->mask) { \ - i--; \ - } \ - it->index = i; \ - } \ - \ - static inline void \ - M_C(name, _it_end)(dict_it_t it, const dict_t d) \ - { \ - DICTI_OA_CONTRACT(d); \ - assert (it != NULL); \ - it->dict = d; \ - it->index = d->mask+1; \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const dict_it_t it) \ - { \ - assert (it != NULL); \ - DICTI_OA_CONTRACT (it->dict); \ - return it->index > it->dict->mask; \ - } \ - \ - static inline void \ - M_C(name, _next)(dict_it_t it) \ - { \ - assert (it != NULL); \ - DICTI_OA_CONTRACT (it->dict); \ - size_t i = it->index + 1; \ - while (i <= it->dict->mask && \ + && i <= d->mask) { \ + i--; \ + } \ + it->index = i; \ + } \ + \ + static inline void \ + M_C(name, _it_end)(dict_it_t it, const dict_t d) \ + { \ + DICTI_OA_CONTRACT(d); \ + assert (it != NULL); \ + it->dict = d; \ + it->index = d->mask+1; \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const dict_it_t it) \ + { \ + assert (it != NULL); \ + DICTI_OA_CONTRACT (it->dict); \ + return it->index > it->dict->mask; \ + } \ + \ + static inline void \ + M_C(name, _next)(dict_it_t it) \ + { \ + assert (it != NULL); \ + DICTI_OA_CONTRACT (it->dict); \ + size_t i = it->index + 1; \ + while (i <= it->dict->mask && \ (M_CALL_OOR_EQUAL(key_oplist, it->dict->data[i].key, DICTI_OA_EMPTY) \ || M_CALL_OOR_EQUAL(key_oplist, it->dict->data[i].key, DICTI_OA_DELETED))) { \ - i++; \ - } \ - it->index = i; \ - } \ - \ - static inline void \ - M_C(name, _previous)(dict_it_t it) \ - { \ - assert (it != NULL); \ - DICTI_OA_CONTRACT (it->dict); \ - /* if index was 0, the operation will overflow, and stops the loop */ \ - size_t i = it->index - 1; \ - while (i <= it->dict->mask && \ + i++; \ + } \ + it->index = i; \ + } \ + \ + static inline void \ + M_C(name, _previous)(dict_it_t it) \ + { \ + assert (it != NULL); \ + DICTI_OA_CONTRACT (it->dict); \ + /* if index was 0, the operation will overflow, and stops the loop */ \ + size_t i = it->index - 1; \ + while (i <= it->dict->mask && \ (M_CALL_OOR_EQUAL(key_oplist, it->dict->data[i].key, DICTI_OA_EMPTY) \ || M_CALL_OOR_EQUAL(key_oplist, it->dict->data[i].key, DICTI_OA_DELETED))) { \ - i--; \ - } \ - it->index = i; \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(const dict_it_t it) \ - { \ - assert (it != NULL); \ - dict_it_t it2; \ - M_C(name,_it_set)(it2, it); \ - M_C(name, _next)(it2); \ - return M_C(name, _end_p)(it2); \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const dict_it_t it1,const dict_it_t it2) \ - { \ - assert (it1 != NULL && it2 != NULL); \ - DICTI_OA_CONTRACT (it1->dict); \ - DICTI_OA_CONTRACT (it2->dict); \ - return it1->dict == it2->dict && it1->index == it2->index; \ - } \ - \ - static inline it_deref_t * \ - M_C(name, _ref)(const dict_it_t it) \ - { \ - assert (it != NULL); \ - DICTI_OA_CONTRACT (it -> dict); \ - const size_t i = it->index; \ - assert (i <= it->dict->mask); \ + i--; \ + } \ + it->index = i; \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(const dict_it_t it) \ + { \ + assert (it != NULL); \ + dict_it_t it2; \ + M_C(name,_it_set)(it2, it); \ + M_C(name, _next)(it2); \ + return M_C(name, _end_p)(it2); \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const dict_it_t it1,const dict_it_t it2) \ + { \ + assert (it1 != NULL && it2 != NULL); \ + DICTI_OA_CONTRACT (it1->dict); \ + DICTI_OA_CONTRACT (it2->dict); \ + return it1->dict == it2->dict && it1->index == it2->index; \ + } \ + \ + static inline it_deref_t * \ + M_C(name, _ref)(const dict_it_t it) \ + { \ + assert (it != NULL); \ + DICTI_OA_CONTRACT (it -> dict); \ + const size_t i = it->index; \ + assert (i <= it->dict->mask); \ assert (!M_CALL_OOR_EQUAL(key_oplist, it->dict->data[i].key, DICTI_OA_EMPTY)); \ assert (!M_CALL_OOR_EQUAL(key_oplist, it->dict->data[i].key, DICTI_OA_DELETED)); \ - return &it->dict->data[i] M_IF(isSet)(.key, ); \ - } \ - \ - static inline const it_deref_t * \ - M_C(name, _cref)(const dict_it_t it) \ - { \ - return M_CONST_CAST(it_deref_t, M_C(name, _ref)(it)); \ - } \ - \ - static inline void \ - M_C(name,_reserve)(dict_t dict, size_t capacity) \ - { \ - DICTI_OA_CONTRACT(dict); \ - size_t size; \ - /* Get the size which will allow to fit this capacity \ - NOTE: Stricly speaking we need to perform a round up to ensure \ - that no reallocation of the hash map occurs up to capacity */ \ + return &it->dict->data[i] M_IF(isSet)(.key, ); \ + } \ + \ + static inline const it_deref_t * \ + M_C(name, _cref)(const dict_it_t it) \ + { \ + return M_CONST_CAST(it_deref_t, M_C(name, _ref)(it)); \ + } \ + \ + static inline void \ + M_C(name,_reserve)(dict_t dict, size_t capacity) \ + { \ + DICTI_OA_CONTRACT(dict); \ + size_t size; \ + /* Get the size which will allow to fit this capacity \ + NOTE: Stricly speaking we need to perform a round up to ensure \ + that no reallocation of the hash map occurs up to capacity */ \ size = (size_t) m_core_roundpow2 ((uint64_t) ((double) capacity * (1.0 / coeff_up))); \ - /* Test for overflow of the computation */ \ - if (M_UNLIKELY (size < capacity)) { \ - M_MEMORY_FULL((size_t)-1); \ - } \ - assert (M_POWEROF2_P(size)); \ - if (size > dict->mask+1) { \ - dict->upper_limit = (size_t) ((double) size * coeff_up) - 1; \ - M_C(name,_int_resize_up)(dict, size, false); \ - } \ - DICTI_OA_CONTRACT(dict); \ - } \ - \ - M_IF_METHOD(EQUAL, value_oplist)( \ - static inline bool \ - M_C(name, _equal_p)(const dict_t dict1, const dict_t dict2) \ - { \ - DICTI_OA_CONTRACT(dict1); \ - DICTI_OA_CONTRACT(dict2); \ - /* NOTE: Key type has mandatory equal operator */ \ - /* Easy case */ \ - if (M_LIKELY (dict1->count != dict2->count)) \ - return false; \ - if (M_UNLIKELY (dict1->count == 0)) \ - return true; \ - /* Otherwise this is the slow path */ \ - dict_it_t it; \ - for(M_C(name, _it)(it, dict1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)) { \ - const it_deref_t *item = M_C(name, _cref)(it); \ + /* Test for overflow of the computation */ \ + if (M_UNLIKELY (size < capacity)) { \ + M_MEMORY_FULL((size_t)-1); \ + } \ + assert (M_POWEROF2_P(size)); \ + if (size > dict->mask+1) { \ + dict->upper_limit = (size_t) ((double) size * coeff_up) - 1; \ + M_C(name,_int_resize_up)(dict, size, false); \ + } \ + DICTI_OA_CONTRACT(dict); \ + } \ + \ + M_IF_METHOD(EQUAL, value_oplist)( \ + static inline bool \ + M_C(name, _equal_p)(const dict_t dict1, const dict_t dict2) \ + { \ + DICTI_OA_CONTRACT(dict1); \ + DICTI_OA_CONTRACT(dict2); \ + /* NOTE: Key type has mandatory equal operator */ \ + /* Easy case */ \ + if (M_LIKELY (dict1->count != dict2->count)) \ + return false; \ + if (M_UNLIKELY (dict1->count == 0)) \ + return true; \ + /* Otherwise this is the slow path */ \ + dict_it_t it; \ + for(M_C(name, _it)(it, dict1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)) { \ + const it_deref_t *item = M_C(name, _cref)(it); \ value_type *ptr = M_C(name, _get)(dict2, M_IF(isSet)(*item, item->key)); \ - if (ptr == NULL) \ - return false; \ - if (M_CALL_EQUAL(value_oplist, item->value, *ptr) == false) \ - return false; \ - } \ - return true; \ - } \ - , /* no value equal */ ) \ - \ + if (ptr == NULL) \ + return false; \ + if (M_CALL_EQUAL(value_oplist, item->value, *ptr) == false) \ + return false; \ + } \ + return true; \ + } \ + , /* no value equal */ ) \ + \ DICTI_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) diff --git a/m-funcobj.h b/m-funcobj.h index f3712c50..a9ff6f23 100644 --- a/m-funcobj.h +++ b/m-funcobj.h @@ -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) diff --git a/m-genint.h b/m-genint.h index 2376730d..e02fe747 100644 --- a/m-genint.h +++ b/m-genint.h @@ -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))) diff --git a/m-i-list.h b/m-i-list.h index 83ee6683..e16e1a3d 100644 --- a/m-i-list.h +++ b/m-i-list.h @@ -38,7 +38,7 @@ ... } tmp_str_t; */ -#define ILIST_INTERFACE(name, type) \ +#define ILIST_INTERFACE(name, type) \ struct ilist_head_s name @@ -46,9 +46,9 @@ The type needs to have ILIST_INTERFACE(). USAGE: ILIST_DEF(name, type [, oplist_of_the_type]) */ -#define ILIST_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - ILISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define ILIST_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + ILISTI_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 @@ -59,9 +59,9 @@ The type needs to have ILIST_INTERFACE(). USAGE: ILIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */ -#define ILIST_DEF_AS(name, name_t, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - ILISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define ILIST_DEF_AS(name, name_t, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + ILISTI_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 @@ -70,9 +70,9 @@ /* Define the oplist of a doubly-linked instrusive list of type. USAGE: ILIST_OPLIST(name [, oplist_of_the_type]) */ -#define ILIST_OPLIST(...) \ - ILISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST), \ +#define ILIST_OPLIST(...) \ + ILISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST), \ (__VA_ARGS__ ))) @@ -88,70 +88,70 @@ typedef struct ilist_head_s { #define ILISTI_OPLIST_P1(arg) ILISTI_OPLIST_P2 arg /* Validation of the given oplist */ -#define ILISTI_OPLIST_P2(name, oplist) \ +#define ILISTI_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(ILISTI_OPLIST_P3, ILISTI_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define ILISTI_OPLIST_FAILURE(name, oplist) \ +#define ILISTI_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_ILIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* Define the oplist of an ilist of type */ -#define ILISTI_OPLIST_P3(name, oplist) \ - (INIT(M_C(name, _init)), \ - CLEAR(M_C(name, _clear)), \ - INIT_MOVE(M_C(name, _init_move)), \ - MOVE(M_C(name, _move)), \ - TYPE(M_C(name,_ct)), \ - CLEAN(M_C(name,_clean)), \ - SUBTYPE(M_C(name,_subtype_ct)), \ - TEST_EMPTY(M_C(name,_empty_p)), \ - IT_TYPE(M_C(name,_it_ct)), \ - IT_FIRST(M_C(name,_it)), \ - IT_SET(M_C(name,_it_set)), \ - IT_LAST(M_C(name,_it_last)), \ - IT_END(M_C(name,_it_end)), \ - IT_END_P(M_C(name,_end_p)), \ - IT_LAST_P(M_C(name,_last_p)), \ - IT_EQUAL_P(M_C(name,_it_equal_p)), \ - IT_NEXT(M_C(name,_next)), \ - IT_PREVIOUS(M_C(name,_previous)), \ - IT_REF(M_C(name,_ref)), \ - IT_CREF(M_C(name,_cref)), \ - IT_REMOVE(M_C(name,_remove)), \ - M_IF_METHOD(NEW, oplist)(IT_INSERT(M_C(name,_insert)),), \ - OPLIST(oplist), \ - SPLICE_BACK(M_C(name,_splice_back)) \ - ,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \ - ,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \ +#define ILISTI_OPLIST_P3(name, oplist) \ + (INIT(M_C(name, _init)), \ + CLEAR(M_C(name, _clear)), \ + INIT_MOVE(M_C(name, _init_move)), \ + MOVE(M_C(name, _move)), \ + TYPE(M_C(name,_ct)), \ + CLEAN(M_C(name,_clean)), \ + SUBTYPE(M_C(name,_subtype_ct)), \ + TEST_EMPTY(M_C(name,_empty_p)), \ + IT_TYPE(M_C(name,_it_ct)), \ + IT_FIRST(M_C(name,_it)), \ + IT_SET(M_C(name,_it_set)), \ + IT_LAST(M_C(name,_it_last)), \ + IT_END(M_C(name,_it_end)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_LAST_P(M_C(name,_last_p)), \ + IT_EQUAL_P(M_C(name,_it_equal_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_PREVIOUS(M_C(name,_previous)), \ + IT_REF(M_C(name,_ref)), \ + IT_CREF(M_C(name,_cref)), \ + IT_REMOVE(M_C(name,_remove)), \ + M_IF_METHOD(NEW, oplist)(IT_INSERT(M_C(name,_insert)),), \ + OPLIST(oplist), \ + SPLICE_BACK(M_C(name,_splice_back)) \ + ,M_IF_METHOD(NEW, oplist)(NEW(M_GET_NEW oplist),) \ + ,M_IF_METHOD(DEL, oplist)(DEL(M_GET_DEL oplist),) \ ) /* Contract respected by all intrusive lists */ -#define ILISTI_CONTRACT(name, list) do { \ - assert(list != NULL); \ - assert(list->name.prev != NULL); \ - assert(list->name.next != NULL); \ - assert(list->name.next->prev == &list->name); \ - assert(list->name.prev->next == &list->name); \ +#define ILISTI_CONTRACT(name, list) do { \ + assert(list != NULL); \ + assert(list->name.prev != NULL); \ + assert(list->name.next != NULL); \ + assert(list->name.next->prev == &list->name); \ + assert(list->name.prev->next == &list->name); \ assert(!(list->name.prev == &list->name) || list->name.prev == list->name.next); \ } while (0) -#define ILISTI_NODE_CONTRACT(node) do { \ - assert((node) != NULL); \ - assert((node)->prev != NULL); \ - assert((node)->next != NULL); \ - assert((node)->next->prev == node); \ - assert((node)->prev->next == node); \ +#define ILISTI_NODE_CONTRACT(node) do { \ + assert((node) != NULL); \ + assert((node)->prev != NULL); \ + assert((node)->next != NULL); \ + assert((node)->next->prev == node); \ + assert((node)->prev->next == node); \ } while (0) /* Indirection call to allow expanding all arguments (TBC) */ #define ILISTI_DEF_P1(arg) ILISTI_DEF_P2 arg /* Validate the oplist before going further */ -#define ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \ +#define ILISTI_DEF_P2(name, type, oplist, list_t, it_t) \ M_IF_OPLIST(oplist)(ILISTI_DEF_P3, ILISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t) /* Stop processing with a compilation failure */ -#define ILISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \ +#define ILISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ILIST_DEF): the given argument is not a valid oplist: " #oplist) /* Definition of the type and function for an intrusive doubly-linked list. @@ -162,500 +162,500 @@ typedef struct ilist_head_s { list_t: type of the intrusive list (name##_t) it_t: iterator of the intrusive list (name##_it_t) */ -#define ILISTI_DEF_P3(name, type, oplist, list_t, it_t) \ - \ - /* Define the list as a structure containing pointers \ - * to the front & back nodes */ \ - typedef struct M_C(name, _s) { \ - struct ilist_head_s name; \ - } list_t[1]; \ - \ - /* Define internal types pointers to such a list */ \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - /* Define iterator of such a list */ \ - typedef struct M_C(name, _it_s) { \ - struct ilist_head_s *head; \ - struct ilist_head_s *previous; \ - struct ilist_head_s *current; \ - struct ilist_head_s *next; \ - } it_t[1]; \ - \ - /* Define types used by oplist */ \ - typedef type M_C(name, _subtype_ct); \ - typedef list_t M_C(name, _ct); \ - typedef it_t M_C(name, _it_ct); \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ - static inline void \ - M_C(name, _init)(list_t list) \ - { \ - assert (list != NULL); \ - list->name.next = &list->name; \ - list->name.prev = &list->name; \ - ILISTI_CONTRACT(name, list); \ - } \ - \ - static inline void \ - M_C(name, _clean)(list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - for(struct ilist_head_s *it = list->name.next, *next ; \ - it != &list->name; it = next) { \ - /* Cannot check node contract as previous node may be deleted */ \ - type *obj = M_TYPE_FROM_FIELD(type, it, \ - struct ilist_head_s, name); \ - /* Read next now before the object is destroyed */ \ - next = it->next; \ - assert (next != NULL); \ - M_CALL_CLEAR(oplist, *obj); \ - /* Delete also the object if a DELETE operand is registered */ \ - M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \ - } \ - /* Nothing remains in the list anymore */ \ - list->name.next = &list->name; \ - list->name.prev = &list->name; \ - ILISTI_CONTRACT(name, list); \ - } \ - \ - static inline void \ - M_C(name, _clear)(list_t list) \ - { \ - /* Nothing to do more than clean the list itself */ \ - M_C(name, _clean)(list); \ - /* For safety purpose (create invalid represenation of object) */ \ - list->name.next = NULL; \ - list->name.prev = NULL; \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(const list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - return list->name.next == &list->name; \ - } \ - \ - \ - static inline void \ - M_C(name, _init_move)(list_t list, list_t ref) \ - { \ - ILISTI_CONTRACT(name, ref); \ - assert (list != ref); \ - M_C(name,_init)(list); \ - if (!M_C(name,_empty_p)(ref)) { \ - list->name.next = ref->name.next; \ - list->name.prev = ref->name.prev; \ - list->name.next->prev = &list->name; \ - list->name.prev->next = &list->name; \ - } \ - ref->name.next = NULL; \ - ref->name.prev = NULL; \ - ILISTI_CONTRACT(name, list); \ - } \ - \ - static inline void \ - M_C(name, _move)(list_t list, list_t ref) \ - { \ - M_C(name, _clear)(list); \ - M_C(name, _init_move)(list, ref); \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - size_t s = 0; \ - /* Scan the full list to count the number of elements */ \ - for(const struct ilist_head_s *it = list->name.next ; \ - it != &list->name; it = it->next) { \ - ILISTI_NODE_CONTRACT(it); \ - s++; \ - } \ - return s; \ - } \ - \ - static inline void \ - M_C(name, _push_back)(list_t list, type *obj) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (obj != NULL); \ - struct ilist_head_s *prev = list->name.prev; \ - list->name.prev = &obj->name; \ - obj->name.prev = prev; \ - obj->name.next = &list->name; \ - prev->next = &obj->name; \ - ILISTI_CONTRACT(name, list); \ - } \ - \ - static inline void \ - M_C(name, _push_front)(list_t list, type *obj) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (obj != NULL); \ - struct ilist_head_s *next = list->name.next; \ - list->name.next = &obj->name; \ - obj->name.next = next; \ - obj->name.prev = &list->name; \ - next->prev = &obj->name; \ - ILISTI_CONTRACT(name, list); \ - } \ - \ - static inline void \ - M_C(name, _push_after)(type *obj_pos, type *obj) \ - { \ - assert (obj_pos != NULL && obj != NULL); \ - /* We don't have the list, so we have no contract at list level */ \ - ILISTI_NODE_CONTRACT(&obj_pos->name); \ - struct ilist_head_s *next = obj_pos->name.next; \ - obj_pos->name.next = &obj->name; \ - obj->name.next = next; \ - obj->name.prev = &obj_pos->name; \ - next->prev = &obj->name; \ - } \ - \ - static inline void \ - M_C(name, _init_field)(type *obj) \ - { \ - assert (obj != NULL); \ - /* Init the fields of the node. To be used in object constructor */ \ - obj->name.next = NULL; \ - obj->name.prev = NULL; \ - } \ - \ - static inline void \ - M_C(name, _unlink)(type *obj) \ - { \ - assert (obj != NULL); \ - /* We don't have the list, so we have no contract at list level */ \ - ILISTI_NODE_CONTRACT(&obj->name); \ - struct ilist_head_s *next = obj->name.next; \ - struct ilist_head_s *prev = obj->name.prev; \ - next->prev = prev; \ - prev->next = next; \ - /* Note: not really needed, but safer */ \ - obj->name.next = NULL; \ - obj->name.prev = NULL; \ - } \ - \ - static inline type * \ - M_C(name, _back)(const list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert(!M_C(name, _empty_p)(list)); \ - return M_TYPE_FROM_FIELD(type, list->name.prev, \ - struct ilist_head_s, name); \ - } \ - \ - static inline type * \ - M_C(name, _front)(const list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert(!M_C(name, _empty_p)(list)); \ - return M_TYPE_FROM_FIELD(type, list->name.next, \ - struct ilist_head_s, name); \ - } \ - \ - static inline type * \ - M_C(name, _next_obj)(const list_t list, type const *obj) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (obj != NULL); \ - ILISTI_NODE_CONTRACT(&obj->name); \ - return obj->name.next == &list->name ? NULL : \ - M_TYPE_FROM_FIELD(type, obj->name.next, \ - struct ilist_head_s, name); \ - } \ - \ - static inline type * \ - M_C(name, _previous_obj)(const list_t list, type const *obj) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (obj != NULL); \ - ILISTI_NODE_CONTRACT(&obj->name); \ - return obj->name.prev == &list->name ? NULL : \ - M_TYPE_FROM_FIELD(type, obj->name.prev, \ - struct ilist_head_s, name); \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (it != NULL); \ - it->head = list->name.next->prev; \ - it->current = list->name.next; \ - it->next = list->name.next->next; \ - it->previous = it->head; \ - ILISTI_NODE_CONTRACT(it->current); \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t it, const it_t cit) \ - { \ - assert (it != NULL && cit != NULL); \ - it->head = cit->head; \ - it->current = cit->current; \ - it->next = cit->next; \ - it->previous = cit->previous; \ - ILISTI_NODE_CONTRACT(it->current); \ - } \ - \ - static inline void \ - M_C(name, _it_last)(it_t it, list_t const list) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (it != NULL); \ - it->head = list->name.next->prev; \ - it->current = list->name.prev; \ - it->next = it->head; \ - it->previous = list->name.prev->prev; \ - ILISTI_NODE_CONTRACT(it->current); \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it, list_t const list) \ - { \ - assert (it != NULL && list != NULL); \ - it->head = list->name.next->prev; \ - it->current = it->head; \ - it->next = list->name.next; \ - it->previous = list->name.prev; \ - ILISTI_NODE_CONTRACT(it->current); \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const it_t it) \ - { \ - assert (it != NULL); \ - ILISTI_NODE_CONTRACT(it->current); \ - return it->current == it->head; \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(const it_t it) \ - { \ - assert (it != NULL); \ - ILISTI_NODE_CONTRACT(it->current); \ - return it->next == it->head || it->current == it->head; \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - assert (it != NULL); \ - /* Cannot check node for it->current: it may have been deleted! */ \ - /* Note: Can't set it->previous to it->current. \ - it->current may have been unlinked from the list */ \ - it->current = it->next; \ - assert (it->current != NULL); \ - it->next = it->current->next; \ - it->previous = it->current->prev; \ - assert (it->next != NULL && it->previous != NULL); \ - ILISTI_NODE_CONTRACT(it->current); \ - } \ - \ - static inline void \ - M_C(name, _previous)(it_t it) \ - { \ - assert (it != NULL); \ - /* Cannot check node for it->current: it may have been deleted! */ \ - /* Note: Can't set it->next to it->current. \ - it->current may have been unlinked from the list */ \ - it->current = it->previous; \ - assert (it->current != NULL); \ - it->next = it->current->next; \ - it->previous = it->current->prev; \ - assert (it->next != NULL && it->previous != NULL); \ - ILISTI_NODE_CONTRACT(it->current); \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const it_t it1, const it_t it2 ) \ - { \ - assert (it1 != NULL && it2 != NULL); \ - /* No need to check for next & previous */ \ - return it1->head == it2->head && it1->current == it2->current; \ - } \ - \ - static inline type * \ - M_C(name, _ref)(const it_t it) \ - { \ - assert (it != NULL && it->current != NULL); \ - ILISTI_NODE_CONTRACT(it->current); \ - /* check if 'it' was not deleted */ \ - assert (it->current->next == it->next); \ - assert (it->current->prev == it->previous); \ - assert (!M_C(name, _end_p)(it)); \ - return M_TYPE_FROM_FIELD(type, it->current, \ - struct ilist_head_s, name); \ - } \ - \ - static inline type const * \ - M_C(name, _cref)(const it_t it) \ - { \ - type *ptr = M_C(name, _ref)(it); \ - return M_CONST_CAST(type, ptr); \ - } \ - \ - static inline void \ - M_C(name, _remove)(list_t list, it_t it) \ - { \ - ILISTI_CONTRACT(name, list); \ - ILISTI_NODE_CONTRACT(it->current); \ - (void)list; /* list param is not used */ \ - type *obj = M_TYPE_FROM_FIELD(type, it->current, \ - struct ilist_head_s, name); \ - M_C(name, _unlink)(obj); \ - M_CALL_CLEAR(oplist, obj); \ - M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \ - M_C(name, _next)(it); \ - } \ - \ - M_IF_METHOD(NEW, oplist)( \ - static inline void \ - M_C(name, _insert)(list_t list, it_t it, type x) \ - { \ - ILISTI_CONTRACT(name, list); \ - ILISTI_NODE_CONTRACT(it->current); \ - type *p = M_CALL_NEW(oplist, type); \ - if (M_UNLIKELY (p == NULL)) { \ - M_MEMORY_FULL (sizeof (type)); \ - return ; \ - } \ - M_CALL_INIT_SET(oplist, *p, x); \ - type *obj = M_C(name, _ref)(it); \ - M_C(name, _push_after)(obj, p); \ - it->current = p; \ - (void) list; \ - ILISTI_CONTRACT(name, list); \ - } \ - , /* NEW not defined */) \ - \ - static inline type * \ - M_C(name, _pop_back)(list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (!M_C(name, _empty_p)(list)); \ - type *obj = M_C(name, _back)(list); \ - list->name.prev = list->name.prev->prev; \ - list->name.prev->next = &list->name; \ - return obj; \ - } \ - \ - static inline type * \ - M_C(name, _pop_front)(list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - assert (!M_C(name, _empty_p)(list)); \ - type *obj = M_C(name, _front)(list); \ - list->name.next = list->name.next->next; \ - list->name.next->prev = &list->name; \ - return obj; \ - } \ - \ - static inline void \ - M_C(name, _splice)(list_t list1, list_t list2) \ - { \ - ILISTI_CONTRACT(name, list1); \ - ILISTI_CONTRACT(name, list2); \ - struct ilist_head_s *midle1 = list1->name.prev; \ - struct ilist_head_s *midle2 = list2->name.next; \ - midle1->next = midle2; \ - midle2->prev = midle1; \ - list1->name.prev = list2->name.prev; \ - list2->name.prev->next = &list1->name; \ - list2->name.next = &list2->name; \ - list2->name.prev = &list2->name; \ - ILISTI_CONTRACT(name, list1); \ - ILISTI_CONTRACT(name, list2); \ - } \ - \ - static inline void \ - M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \ - { \ - ILISTI_CONTRACT(name, nv); \ - ILISTI_CONTRACT(name, ov); \ - ILISTI_NODE_CONTRACT(it->current); \ - assert (it != NULL); \ - (void) ov; \ - type *obj = M_C(name, _ref)(it); \ - M_C(name, _unlink)(obj); \ - M_C(name, _push_back)(nv, obj); \ - M_C(name, _next)(it); \ - ILISTI_CONTRACT(name, nv); \ - ILISTI_CONTRACT(name, ov); \ - } \ - \ - static inline void \ - M_C(name, _splice_at)(list_t nlist, it_t npos, \ - list_t olist, it_t opos) \ - { \ - ILISTI_CONTRACT(name, nlist); \ - ILISTI_CONTRACT(name, olist); \ - assert (npos != NULL && opos != NULL); \ - assert (!M_C(name, _end_p)(opos)); \ - /* npos may be end */ \ - (void) olist, (void) nlist; \ - type *obj = M_C(name, _ref)(opos); \ - struct ilist_head_s *ref = npos->current; \ - /* Remove object */ \ - M_C(name, _unlink)(obj); \ - /* Push 'obj' after 'ref' */ \ - struct ilist_head_s *next = ref->next; \ - ref->next = &obj->name; \ - obj->name.next = next; \ - obj->name.prev = ref; \ - next->prev = &obj->name; \ - /* Move iterator in old list */ \ - M_C(name, _next)(opos); \ - /* Set npos iterator to new position of object */ \ - npos->previous = ref; \ - npos->current = &obj->name; \ - npos->next = next; \ - ILISTI_CONTRACT(name, nlist); \ - ILISTI_CONTRACT(name, olist); \ - } \ - \ - static inline void \ - M_C(name, _swap)(list_t d, list_t e) \ - { \ - ILISTI_CONTRACT(name, d); \ - ILISTI_CONTRACT(name, e); \ - struct ilist_head_s *d_item = d->name.next; \ - struct ilist_head_s *e_item = e->name.next; \ - d->name.next = e_item == &e->name ? &d->name : e_item; \ - e->name.next = d_item == &d->name ? &e->name : d_item; \ - d_item = d->name.prev; \ - e_item = e->name.prev; \ - d->name.prev = e_item == &e->name ? &d->name : e_item; \ - e->name.prev = d_item == &d->name ? &e->name : d_item; \ - d->name.next->prev = &d->name; \ - d->name.prev->next = &d->name; \ - e->name.next->prev = &e->name; \ - e->name.prev->next = &e->name; \ - ILISTI_CONTRACT(name, d); \ - ILISTI_CONTRACT(name, e); \ - } \ - \ - static inline void \ - M_C(name, _reverse)(list_t list) \ - { \ - ILISTI_CONTRACT(name, list); \ - struct ilist_head_s *next, *it; \ - for(it = list->name.next ; it != &list->name; it = next) { \ - next = it->next; \ - it->next = it->prev; \ - it->prev = next; \ - } \ - next = it->next; \ - it->next = it->prev; \ - it->prev = next; \ - ILISTI_CONTRACT(name, list); \ - } \ - \ - /* Used of macro from m-list */ \ +#define ILISTI_DEF_P3(name, type, oplist, list_t, it_t) \ + \ + /* Define the list as a structure containing pointers \ + * to the front & back nodes */ \ + typedef struct M_C(name, _s) { \ + struct ilist_head_s name; \ + } list_t[1]; \ + \ + /* Define internal types pointers to such a list */ \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + /* Define iterator of such a list */ \ + typedef struct M_C(name, _it_s) { \ + struct ilist_head_s *head; \ + struct ilist_head_s *previous; \ + struct ilist_head_s *current; \ + struct ilist_head_s *next; \ + } it_t[1]; \ + \ + /* Define types used by oplist */ \ + typedef type M_C(name, _subtype_ct); \ + typedef list_t M_C(name, _ct); \ + typedef it_t M_C(name, _it_ct); \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ + static inline void \ + M_C(name, _init)(list_t list) \ + { \ + assert (list != NULL); \ + list->name.next = &list->name; \ + list->name.prev = &list->name; \ + ILISTI_CONTRACT(name, list); \ + } \ + \ + static inline void \ + M_C(name, _clean)(list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + for(struct ilist_head_s *it = list->name.next, *next ; \ + it != &list->name; it = next) { \ + /* Cannot check node contract as previous node may be deleted */ \ + type *obj = M_TYPE_FROM_FIELD(type, it, \ + struct ilist_head_s, name); \ + /* Read next now before the object is destroyed */ \ + next = it->next; \ + assert (next != NULL); \ + M_CALL_CLEAR(oplist, *obj); \ + /* Delete also the object if a DELETE operand is registered */ \ + M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \ + } \ + /* Nothing remains in the list anymore */ \ + list->name.next = &list->name; \ + list->name.prev = &list->name; \ + ILISTI_CONTRACT(name, list); \ + } \ + \ + static inline void \ + M_C(name, _clear)(list_t list) \ + { \ + /* Nothing to do more than clean the list itself */ \ + M_C(name, _clean)(list); \ + /* For safety purpose (create invalid represenation of object) */ \ + list->name.next = NULL; \ + list->name.prev = NULL; \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(const list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + return list->name.next == &list->name; \ + } \ + \ + \ + static inline void \ + M_C(name, _init_move)(list_t list, list_t ref) \ + { \ + ILISTI_CONTRACT(name, ref); \ + assert (list != ref); \ + M_C(name,_init)(list); \ + if (!M_C(name,_empty_p)(ref)) { \ + list->name.next = ref->name.next; \ + list->name.prev = ref->name.prev; \ + list->name.next->prev = &list->name; \ + list->name.prev->next = &list->name; \ + } \ + ref->name.next = NULL; \ + ref->name.prev = NULL; \ + ILISTI_CONTRACT(name, list); \ + } \ + \ + static inline void \ + M_C(name, _move)(list_t list, list_t ref) \ + { \ + M_C(name, _clear)(list); \ + M_C(name, _init_move)(list, ref); \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + size_t s = 0; \ + /* Scan the full list to count the number of elements */ \ + for(const struct ilist_head_s *it = list->name.next ; \ + it != &list->name; it = it->next) { \ + ILISTI_NODE_CONTRACT(it); \ + s++; \ + } \ + return s; \ + } \ + \ + static inline void \ + M_C(name, _push_back)(list_t list, type *obj) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (obj != NULL); \ + struct ilist_head_s *prev = list->name.prev; \ + list->name.prev = &obj->name; \ + obj->name.prev = prev; \ + obj->name.next = &list->name; \ + prev->next = &obj->name; \ + ILISTI_CONTRACT(name, list); \ + } \ + \ + static inline void \ + M_C(name, _push_front)(list_t list, type *obj) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (obj != NULL); \ + struct ilist_head_s *next = list->name.next; \ + list->name.next = &obj->name; \ + obj->name.next = next; \ + obj->name.prev = &list->name; \ + next->prev = &obj->name; \ + ILISTI_CONTRACT(name, list); \ + } \ + \ + static inline void \ + M_C(name, _push_after)(type *obj_pos, type *obj) \ + { \ + assert (obj_pos != NULL && obj != NULL); \ + /* We don't have the list, so we have no contract at list level */ \ + ILISTI_NODE_CONTRACT(&obj_pos->name); \ + struct ilist_head_s *next = obj_pos->name.next; \ + obj_pos->name.next = &obj->name; \ + obj->name.next = next; \ + obj->name.prev = &obj_pos->name; \ + next->prev = &obj->name; \ + } \ + \ + static inline void \ + M_C(name, _init_field)(type *obj) \ + { \ + assert (obj != NULL); \ + /* Init the fields of the node. To be used in object constructor */ \ + obj->name.next = NULL; \ + obj->name.prev = NULL; \ + } \ + \ + static inline void \ + M_C(name, _unlink)(type *obj) \ + { \ + assert (obj != NULL); \ + /* We don't have the list, so we have no contract at list level */ \ + ILISTI_NODE_CONTRACT(&obj->name); \ + struct ilist_head_s *next = obj->name.next; \ + struct ilist_head_s *prev = obj->name.prev; \ + next->prev = prev; \ + prev->next = next; \ + /* Note: not really needed, but safer */ \ + obj->name.next = NULL; \ + obj->name.prev = NULL; \ + } \ + \ + static inline type * \ + M_C(name, _back)(const list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert(!M_C(name, _empty_p)(list)); \ + return M_TYPE_FROM_FIELD(type, list->name.prev, \ + struct ilist_head_s, name); \ + } \ + \ + static inline type * \ + M_C(name, _front)(const list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert(!M_C(name, _empty_p)(list)); \ + return M_TYPE_FROM_FIELD(type, list->name.next, \ + struct ilist_head_s, name); \ + } \ + \ + static inline type * \ + M_C(name, _next_obj)(const list_t list, type const *obj) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (obj != NULL); \ + ILISTI_NODE_CONTRACT(&obj->name); \ + return obj->name.next == &list->name ? NULL : \ + M_TYPE_FROM_FIELD(type, obj->name.next, \ + struct ilist_head_s, name); \ + } \ + \ + static inline type * \ + M_C(name, _previous_obj)(const list_t list, type const *obj) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (obj != NULL); \ + ILISTI_NODE_CONTRACT(&obj->name); \ + return obj->name.prev == &list->name ? NULL : \ + M_TYPE_FROM_FIELD(type, obj->name.prev, \ + struct ilist_head_s, name); \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (it != NULL); \ + it->head = list->name.next->prev; \ + it->current = list->name.next; \ + it->next = list->name.next->next; \ + it->previous = it->head; \ + ILISTI_NODE_CONTRACT(it->current); \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t it, const it_t cit) \ + { \ + assert (it != NULL && cit != NULL); \ + it->head = cit->head; \ + it->current = cit->current; \ + it->next = cit->next; \ + it->previous = cit->previous; \ + ILISTI_NODE_CONTRACT(it->current); \ + } \ + \ + static inline void \ + M_C(name, _it_last)(it_t it, list_t const list) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (it != NULL); \ + it->head = list->name.next->prev; \ + it->current = list->name.prev; \ + it->next = it->head; \ + it->previous = list->name.prev->prev; \ + ILISTI_NODE_CONTRACT(it->current); \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it, list_t const list) \ + { \ + assert (it != NULL && list != NULL); \ + it->head = list->name.next->prev; \ + it->current = it->head; \ + it->next = list->name.next; \ + it->previous = list->name.prev; \ + ILISTI_NODE_CONTRACT(it->current); \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const it_t it) \ + { \ + assert (it != NULL); \ + ILISTI_NODE_CONTRACT(it->current); \ + return it->current == it->head; \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(const it_t it) \ + { \ + assert (it != NULL); \ + ILISTI_NODE_CONTRACT(it->current); \ + return it->next == it->head || it->current == it->head; \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + assert (it != NULL); \ + /* Cannot check node for it->current: it may have been deleted! */ \ + /* Note: Can't set it->previous to it->current. \ + it->current may have been unlinked from the list */ \ + it->current = it->next; \ + assert (it->current != NULL); \ + it->next = it->current->next; \ + it->previous = it->current->prev; \ + assert (it->next != NULL && it->previous != NULL); \ + ILISTI_NODE_CONTRACT(it->current); \ + } \ + \ + static inline void \ + M_C(name, _previous)(it_t it) \ + { \ + assert (it != NULL); \ + /* Cannot check node for it->current: it may have been deleted! */ \ + /* Note: Can't set it->next to it->current. \ + it->current may have been unlinked from the list */ \ + it->current = it->previous; \ + assert (it->current != NULL); \ + it->next = it->current->next; \ + it->previous = it->current->prev; \ + assert (it->next != NULL && it->previous != NULL); \ + ILISTI_NODE_CONTRACT(it->current); \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const it_t it1, const it_t it2 ) \ + { \ + assert (it1 != NULL && it2 != NULL); \ + /* No need to check for next & previous */ \ + return it1->head == it2->head && it1->current == it2->current; \ + } \ + \ + static inline type * \ + M_C(name, _ref)(const it_t it) \ + { \ + assert (it != NULL && it->current != NULL); \ + ILISTI_NODE_CONTRACT(it->current); \ + /* check if 'it' was not deleted */ \ + assert (it->current->next == it->next); \ + assert (it->current->prev == it->previous); \ + assert (!M_C(name, _end_p)(it)); \ + return M_TYPE_FROM_FIELD(type, it->current, \ + struct ilist_head_s, name); \ + } \ + \ + static inline type const * \ + M_C(name, _cref)(const it_t it) \ + { \ + type *ptr = M_C(name, _ref)(it); \ + return M_CONST_CAST(type, ptr); \ + } \ + \ + static inline void \ + M_C(name, _remove)(list_t list, it_t it) \ + { \ + ILISTI_CONTRACT(name, list); \ + ILISTI_NODE_CONTRACT(it->current); \ + (void)list; /* list param is not used */ \ + type *obj = M_TYPE_FROM_FIELD(type, it->current, \ + struct ilist_head_s, name); \ + M_C(name, _unlink)(obj); \ + M_CALL_CLEAR(oplist, obj); \ + M_IF_METHOD(DEL, oplist)(M_CALL_DEL(oplist, obj), (void) 0); \ + M_C(name, _next)(it); \ + } \ + \ + M_IF_METHOD(NEW, oplist)( \ + static inline void \ + M_C(name, _insert)(list_t list, it_t it, type x) \ + { \ + ILISTI_CONTRACT(name, list); \ + ILISTI_NODE_CONTRACT(it->current); \ + type *p = M_CALL_NEW(oplist, type); \ + if (M_UNLIKELY (p == NULL)) { \ + M_MEMORY_FULL (sizeof (type)); \ + return ; \ + } \ + M_CALL_INIT_SET(oplist, *p, x); \ + type *obj = M_C(name, _ref)(it); \ + M_C(name, _push_after)(obj, p); \ + it->current = p; \ + (void) list; \ + ILISTI_CONTRACT(name, list); \ + } \ + , /* NEW not defined */) \ + \ + static inline type * \ + M_C(name, _pop_back)(list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (!M_C(name, _empty_p)(list)); \ + type *obj = M_C(name, _back)(list); \ + list->name.prev = list->name.prev->prev; \ + list->name.prev->next = &list->name; \ + return obj; \ + } \ + \ + static inline type * \ + M_C(name, _pop_front)(list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + assert (!M_C(name, _empty_p)(list)); \ + type *obj = M_C(name, _front)(list); \ + list->name.next = list->name.next->next; \ + list->name.next->prev = &list->name; \ + return obj; \ + } \ + \ + static inline void \ + M_C(name, _splice)(list_t list1, list_t list2) \ + { \ + ILISTI_CONTRACT(name, list1); \ + ILISTI_CONTRACT(name, list2); \ + struct ilist_head_s *midle1 = list1->name.prev; \ + struct ilist_head_s *midle2 = list2->name.next; \ + midle1->next = midle2; \ + midle2->prev = midle1; \ + list1->name.prev = list2->name.prev; \ + list2->name.prev->next = &list1->name; \ + list2->name.next = &list2->name; \ + list2->name.prev = &list2->name; \ + ILISTI_CONTRACT(name, list1); \ + ILISTI_CONTRACT(name, list2); \ + } \ + \ + static inline void \ + M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \ + { \ + ILISTI_CONTRACT(name, nv); \ + ILISTI_CONTRACT(name, ov); \ + ILISTI_NODE_CONTRACT(it->current); \ + assert (it != NULL); \ + (void) ov; \ + type *obj = M_C(name, _ref)(it); \ + M_C(name, _unlink)(obj); \ + M_C(name, _push_back)(nv, obj); \ + M_C(name, _next)(it); \ + ILISTI_CONTRACT(name, nv); \ + ILISTI_CONTRACT(name, ov); \ + } \ + \ + static inline void \ + M_C(name, _splice_at)(list_t nlist, it_t npos, \ + list_t olist, it_t opos) \ + { \ + ILISTI_CONTRACT(name, nlist); \ + ILISTI_CONTRACT(name, olist); \ + assert (npos != NULL && opos != NULL); \ + assert (!M_C(name, _end_p)(opos)); \ + /* npos may be end */ \ + (void) olist, (void) nlist; \ + type *obj = M_C(name, _ref)(opos); \ + struct ilist_head_s *ref = npos->current; \ + /* Remove object */ \ + M_C(name, _unlink)(obj); \ + /* Push 'obj' after 'ref' */ \ + struct ilist_head_s *next = ref->next; \ + ref->next = &obj->name; \ + obj->name.next = next; \ + obj->name.prev = ref; \ + next->prev = &obj->name; \ + /* Move iterator in old list */ \ + M_C(name, _next)(opos); \ + /* Set npos iterator to new position of object */ \ + npos->previous = ref; \ + npos->current = &obj->name; \ + npos->next = next; \ + ILISTI_CONTRACT(name, nlist); \ + ILISTI_CONTRACT(name, olist); \ + } \ + \ + static inline void \ + M_C(name, _swap)(list_t d, list_t e) \ + { \ + ILISTI_CONTRACT(name, d); \ + ILISTI_CONTRACT(name, e); \ + struct ilist_head_s *d_item = d->name.next; \ + struct ilist_head_s *e_item = e->name.next; \ + d->name.next = e_item == &e->name ? &d->name : e_item; \ + e->name.next = d_item == &d->name ? &e->name : d_item; \ + d_item = d->name.prev; \ + e_item = e->name.prev; \ + d->name.prev = e_item == &e->name ? &d->name : e_item; \ + e->name.prev = d_item == &d->name ? &e->name : d_item; \ + d->name.next->prev = &d->name; \ + d->name.prev->next = &d->name; \ + e->name.next->prev = &e->name; \ + e->name.prev->next = &e->name; \ + ILISTI_CONTRACT(name, d); \ + ILISTI_CONTRACT(name, e); \ + } \ + \ + static inline void \ + M_C(name, _reverse)(list_t list) \ + { \ + ILISTI_CONTRACT(name, list); \ + struct ilist_head_s *next, *it; \ + for(it = list->name.next ; it != &list->name; it = next) { \ + next = it->next; \ + it->next = it->prev; \ + it->prev = next; \ + } \ + next = it->next; \ + it->next = it->prev; \ + it->prev = next; \ + ILISTI_CONTRACT(name, list); \ + } \ + \ + /* Used of macro from m-list */ \ LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) diff --git a/m-i-shared.h b/m-i-shared.h index 74612cc2..e9ad71ae 100644 --- a/m-i-shared.h +++ b/m-i-shared.h @@ -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 diff --git a/m-list.h b/m-list.h index 0a4f82fe..73f6c884 100644 --- a/m-list.h +++ b/m-list.h @@ -29,9 +29,9 @@ /* Define a singly linked list of a given type. USAGE: LIST_DEF(name, type [, oplist_of_the_type]) */ -#define LIST_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - LISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define LIST_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + LISTI_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 @@ -40,9 +40,9 @@ /* Define a singly linked list of a given type as the provided type name_t with the iterator named it_t USAGE: LIST_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */ -#define LIST_DEF_AS(name, name_t, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - LISTI_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define LIST_DEF_AS(name, name_t, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + LISTI_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 @@ -50,9 +50,9 @@ /* Define a singly linked list of a given type allowing both push. USAGE: LIST_DUAL_PUSH_DEF_AS(name, name_t, type [, oplist_of_the_type]) */ -#define LIST_DUAL_PUSH_DEF(name, ...) \ - M_BEGIN_PROTECTED_CODE \ - LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define LIST_DUAL_PUSH_DEF(name, ...) \ + M_BEGIN_PROTECTED_CODE \ + LISTI_DUAL_PUSH_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 @@ -61,9 +61,9 @@ /* Define a singly linked list of a given type allowing both push. as the provided type name_t with the iterator named it_t USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */ -#define LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - LISTI_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ +#define LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + LISTI_DUAL_PUSH_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 @@ -71,9 +71,9 @@ /* Define the oplist of a list of the given type. USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */ -#define LIST_OPLIST(...) \ - LISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_DEFAULT_OPLIST ), \ +#define LIST_OPLIST(...) \ + LISTI_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST ), \ (__VA_ARGS__ ))) @@ -84,58 +84,58 @@ #define LISTI_OPLIST_P1(arg) LISTI_OPLIST_P2 arg /* Validation of the given oplist */ -#define LISTI_OPLIST_P2(name, oplist) \ +#define LISTI_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(LISTI_OPLIST_P3, LISTI_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define LISTI_OPLIST_FAILURE(name, oplist) \ +#define LISTI_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a list and list_dual_push */ -#define LISTI_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)), \ - MOVE(M_C(name, _move)), \ - INIT_MOVE(M_C(name, _init_move)), \ - SWAP(M_C(name, _swap)), \ - TYPE(M_C(name,_ct)), \ - SUBTYPE(M_C(name,_subtype_ct)), \ - TEST_EMPTY(M_C(name,_empty_p)), \ - 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_REF(M_C(name,_ref)), \ - IT_CREF(M_C(name,_cref)), \ - IT_INSERT(M_C(name, _insert)), \ - IT_REMOVE(M_C(name,_remove)), \ - CLEAN(M_C(name,_clean)), \ - PUSH(M_C(name,_push_back)), \ - POP(M_C(name,_pop_back)), \ - PUSH_MOVE(M_C(name,_push_move)), \ - POP_MOVE(M_C(name,_pop_move)) \ - ,SPLICE_BACK(M_C(name,_splice_back)) \ - ,SPLICE_AT(M_C(name,_splice_at)) \ - ,REVERSE(M_C(name,_reverse)) \ - ,OPLIST(oplist) \ - ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ - ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ - ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ - ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ - ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ - ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ - ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \ - ,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ - ,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 LISTI_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)), \ + MOVE(M_C(name, _move)), \ + INIT_MOVE(M_C(name, _init_move)), \ + SWAP(M_C(name, _swap)), \ + TYPE(M_C(name,_ct)), \ + SUBTYPE(M_C(name,_subtype_ct)), \ + TEST_EMPTY(M_C(name,_empty_p)), \ + 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_REF(M_C(name,_ref)), \ + IT_CREF(M_C(name,_cref)), \ + IT_INSERT(M_C(name, _insert)), \ + IT_REMOVE(M_C(name,_remove)), \ + CLEAN(M_C(name,_clean)), \ + PUSH(M_C(name,_push_back)), \ + POP(M_C(name,_pop_back)), \ + PUSH_MOVE(M_C(name,_push_move)), \ + POP_MOVE(M_C(name,_pop_move)) \ + ,SPLICE_BACK(M_C(name,_splice_back)) \ + ,SPLICE_AT(M_C(name,_splice_at)) \ + ,REVERSE(M_C(name,_reverse)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),) \ + ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),) \ + ,M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ + ,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 evaluation for the list definition, @@ -143,17 +143,17 @@ #define LISTI_DEF_P1(arg) LISTI_DEF_P2 arg /* Validate the oplist before going further */ -#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \ +#define LISTI_DEF_P2(name, type, oplist, list_t, it_t) \ M_IF_OPLIST(oplist)(LISTI_DEF_P3, LISTI_DEF_FAILURE)(name, type, oplist, list_t, it_t) /* Stop processing with a compilation failure */ -#define LISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \ +#define LISTI_DEF_FAILURE(name, type, oplist, list_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DEF): the given argument is not a valid oplist: " #oplist) /* Define allocation functions. If MEMPOOL, we need to define it */ #define LISTI_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \ M_IF_METHOD(MEMPOOL, oplist)( \ - \ + \ MEMPOOL_DEF(M_C(name, _mempool), struct M_C(name, _s)) \ M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \ static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \ @@ -162,9 +162,9 @@ static inline void M_C(name,_int_del)(struct M_C(name, _s) *ptr) { \ M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \ } \ - \ + \ , /* No mempool allocation */ \ - \ + \ static inline struct M_C(name, _s) *M_C(name, _int_new)(void) { \ return M_CALL_NEW(oplist, struct M_C(name, _s)); \ } \ @@ -182,38 +182,38 @@ - it_t: alias for M_C(name, _it_t) [ iterator of the container ] - node_t: alias for M_C(name, _node_t) [ node ] */ -#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \ - \ - /* Define the node of a list, and the list as a pointer to a node */ \ - typedef struct M_C(name, _s) { \ - struct M_C(name, _s) *next; /* Next node or NULL if final node */ \ - type data; /* The data itself */ \ - } *list_t[1]; \ - \ - /* Define an iterator of a list */ \ - typedef struct M_C(name, _it_s) { \ - struct M_C(name, _s) *previous; /* Previous node or NULL */ \ - struct M_C(name, _s) *current; /* Current node or NULL */ \ - } it_t[1]; \ - \ - /* Definition of the synonyms of the type */ \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - typedef list_t M_C(name, _ct); \ - typedef it_t M_C(name, _it_ct); \ - typedef type M_C(name, _subtype_ct); \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ - LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \ - LISTI_DEF_P4(name, type, oplist, list_t, it_t) \ +#define LISTI_DEF_P3(name, type, oplist, list_t, it_t) \ + \ + /* Define the node of a list, and the list as a pointer to a node */ \ + typedef struct M_C(name, _s) { \ + struct M_C(name, _s) *next; /* Next node or NULL if final node */ \ + type data; /* The data itself */ \ + } *list_t[1]; \ + \ + /* Define an iterator of a list */ \ + typedef struct M_C(name, _it_s) { \ + struct M_C(name, _s) *previous; /* Previous node or NULL */ \ + struct M_C(name, _s) *current; /* Current node or NULL */ \ + } it_t[1]; \ + \ + /* Definition of the synonyms of the type */ \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + typedef list_t M_C(name, _ct); \ + typedef it_t M_C(name, _it_ct); \ + typedef type M_C(name, _subtype_ct); \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ + LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \ + LISTI_DEF_P4(name, type, oplist, list_t, it_t) \ LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) /* Define the internal contract of a list (there is nothing worthy to be checked) */ -#define LISTI_CONTRACT(v) do { \ - assert (v != NULL); \ +#define LISTI_CONTRACT(v) do { \ + assert (v != NULL); \ } while (0) @@ -224,442 +224,442 @@ - list_t: alias for type of the container - it_t: alias for iterator of the container */ -#define LISTI_DEF_P4(name, type, oplist, list_t, it_t) \ - \ - static inline void \ - M_C(name, _init)(list_t v) \ - { \ - assert (v != NULL); \ - *v = NULL; \ - } \ - \ - static inline void \ - M_C(name, _clean)(list_t v) \ - { \ - LISTI_CONTRACT(v); \ - struct M_C(name, _s) *it = *v; \ - *v = NULL; \ - while (it != NULL) { \ - struct M_C(name, _s) *next = it->next; \ - M_CALL_CLEAR(oplist, it->data); \ - M_C(name,_int_del)(it); \ - it = next; \ - } \ - LISTI_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _clear)(list_t v) \ - { \ - M_C(name, _clean)(v); \ - } \ - \ - static inline type const * \ - M_C(name, _back)(const list_t v) \ - { \ - LISTI_CONTRACT(v); \ - assert(*v != NULL); \ - return M_CONST_CAST(type, &((*v)->data)); \ - } \ - \ - static inline type * \ - M_C(name, _push_raw)(list_t v) \ - { \ - LISTI_CONTRACT(v); \ - struct M_C(name, _s) *next; \ - next = M_C(name, _int_new)(); \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - return NULL; \ - } \ - type *ret = &next->data; \ - next->next = *v; \ - *v = next; \ - LISTI_CONTRACT(v); \ - return ret; \ - } \ - \ - static inline void \ - M_C(name, _push_back)(list_t v, type const x) \ - { \ - type *data = M_C(name, _push_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return; \ - M_CALL_INIT_SET(oplist, *data, x); \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _push_new)(list_t v) \ - { \ - type *data = M_C(name, _push_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return NULL; \ - M_CALL_INIT(oplist, *data); \ - return data; \ - } \ - , /* No INIT */) \ - \ - static inline void \ - M_C(name, _pop_back)(type *data, list_t v) \ - { \ - LISTI_CONTRACT(v); \ - assert(*v != NULL); \ - if (data != NULL) { \ - M_DO_MOVE (oplist, *data, (*v)->data); \ - } else { \ - M_CALL_CLEAR(oplist, (*v)->data); \ - } \ - struct M_C(name, _s) *tofree = *v; \ - *v = (*v)->next; \ - M_C(name,_int_del)(tofree); \ - LISTI_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _push_move)(list_t v, type *x) \ - { \ - assert (x != NULL); \ - type *data = M_C(name, _push_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ - } \ - \ - static inline void \ - M_C(name, _pop_move)(type *data, list_t v) \ - { \ - LISTI_CONTRACT(v); \ - assert(*v != NULL && data != NULL); \ - M_DO_INIT_MOVE (oplist, *data, (*v)->data); \ - struct M_C(name, _s) *tofree = *v; \ - *v = (*v)->next; \ - M_C(name,_int_del)(tofree); \ - LISTI_CONTRACT(v); \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(const list_t v) \ - { \ - LISTI_CONTRACT(v); \ - return *v == NULL; \ - } \ - \ - static inline void \ - M_C(name, _swap)(list_t l, list_t v) \ - { \ - LISTI_CONTRACT(l); \ - LISTI_CONTRACT(v); \ - struct M_C(name, _s) *tmp = *l; \ - *l = *v; \ - *v = tmp; \ - LISTI_CONTRACT(l); \ - LISTI_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const list_t v) \ - { \ - LISTI_CONTRACT(v); \ - assert (it != NULL); \ - it->current = *v; \ - it->previous = NULL; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t it1, const it_t it2) \ - { \ - assert (it1 != NULL && it2 != NULL); \ - it1->current = it2->current; \ - it1->previous = it2->previous; \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it1, const list_t v) \ - { \ - LISTI_CONTRACT(v); \ - assert (it1 != NULL); \ - (void)v; /* unused */ \ - it1->current = NULL; \ - it1->previous = NULL; \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const it_t it) \ - { \ - assert (it != NULL); \ - return it->current == NULL; \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(const it_t it) \ - { \ - assert (it != NULL); \ - return it->current == NULL || it->current->next == NULL; \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - assert(it != NULL && it->current != NULL); \ - it->previous = it->current; \ - it->current = it->current->next; \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ - { \ - assert(it1 != NULL && it2 != NULL); \ - return it1->current == it2->current; \ - } \ - \ - static inline type * \ - M_C(name, _ref)(const it_t it) \ - { \ - assert(it != NULL && it->current != NULL); \ - return &(it->current->data); \ - } \ - \ - static inline type const * \ - M_C(name, _cref)(const it_t it) \ - { \ - assert(it != NULL && it->current != NULL); \ - return M_CONST_CAST(type, &(it->current->data)); \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const list_t list) \ - { \ - LISTI_CONTRACT(list); \ - size_t size = 0; \ - struct M_C(name, _s) *it = *list; \ - while (it != NULL) { \ - size ++; \ - it = it->next; \ - } \ - return size; \ - } \ - \ - static inline bool \ - M_C(name, _sublist_p)(const list_t list, const it_t itsub) \ - { \ - LISTI_CONTRACT(list); \ - assert (itsub != NULL); \ - struct M_C(name, _s) *it = *list; \ - while (it != NULL) { \ - if (it == itsub->current) return true; \ - it = it->next; \ - } \ - /* Not found. Check if search item is NULL */ \ - return (itsub->current == NULL); \ - } \ - \ - static inline type * \ - M_C(name, _get)(const list_t list, size_t i) \ - { \ - LISTI_CONTRACT(list); \ - struct M_C(name, _s) *it = *list; \ - /* FIXME: How to avoid the double iteration over the list? */ \ - size_t len = M_C(name,_size)(list); \ - assert (i < len); \ - size_t j = len-1; \ - while (true) { \ - assert (it != NULL); \ - if (i == j) return &it->data; \ - it = it->next; \ - j--; \ - } \ - } \ - \ - static inline type const * \ - M_C(name, _cget)(const list_t l, size_t i) \ - { \ - return M_CONST_CAST(type, M_C(name, _get)(l,i)); \ - } \ - \ - static inline void \ - M_C(name, _insert)(list_t list, it_t insertion_point, \ - type const x) \ - { \ - LISTI_CONTRACT(list); \ - assert (insertion_point != NULL); \ - assert(M_C(name, _sublist_p)(list, insertion_point)); \ - struct M_C(name, _s) *next = M_C(name, _int_new)(); \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - return; \ - } \ - M_CALL_INIT_SET(oplist, next->data, x); \ - struct M_C(name, _s) *current = insertion_point->current; \ - if (M_UNLIKELY (current == NULL)) { \ - next->next = *list; \ - *list = next; \ - } else { \ - next->next = current->next; \ - current->next = next; \ - } \ - /* Update insertion_point to this element */ \ - insertion_point->current = next; \ - LISTI_CONTRACT(list); \ - } \ - \ - static inline void \ - M_C(name, _remove)(list_t list, it_t removing_point) \ - { \ - LISTI_CONTRACT(list); \ - assert (removing_point != NULL); \ - assert (removing_point->current != NULL); \ - assert(M_C(name, _sublist_p)(list, removing_point)); \ - struct M_C(name, _s) *next = removing_point->current->next; \ - if (M_UNLIKELY (removing_point->previous == NULL)) { \ - *list = next; \ - } else { \ - removing_point->previous->next = next; \ - } \ - M_CALL_CLEAR(oplist, removing_point->current->data); \ - M_C(name,_int_del) (removing_point->current); \ - removing_point->current = next; \ - LISTI_CONTRACT(list); \ - } \ - \ - static inline void \ - M_C(name, _init_set)(list_t list, const list_t org) \ - { \ - LISTI_CONTRACT(org); \ - struct M_C(name, _s) *next, *it_org; \ - struct M_C(name, _s) **update_list; \ - update_list = list; \ - it_org = *org; \ - while (it_org != NULL) { \ - next = M_C(name, _int_new)(); \ - *update_list = next; \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - /* FIXME: Partialy initialized list. What to do? */ \ - return; \ - } \ - update_list = &next->next; \ - M_CALL_INIT_SET(oplist, next->data, it_org->data); \ - it_org = it_org->next; \ - } \ - *update_list = NULL; \ - LISTI_CONTRACT(list); \ - } \ - \ - static inline void \ - M_C(name, _set)(list_t list, const list_t org) \ - { \ - if (M_UNLIKELY (list == org)) return; \ - M_C(name, _clear)(list); \ - M_C(name, _init_set)(list, org); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(list_t list, list_t org) \ - { \ - LISTI_CONTRACT(org); \ - assert (list != NULL && list != org); \ - *list = *org; \ - *org = NULL; /* safer */ \ - } \ - \ - static inline void \ - M_C(name, _move)(list_t list, list_t org) \ - { \ - assert (list != org); \ - M_C(name, _clear)(list); \ - M_C(name, _init_move)(list, org); \ - } \ - \ - static inline void \ - M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \ - { \ - LISTI_CONTRACT(nv); \ - LISTI_CONTRACT(ov); \ - assert (it != NULL); \ - assert (it->current != NULL); \ - assert (M_C(name, _sublist_p)(ov, it)); \ - /* Remove the item 'it' from the list 'ov' */ \ - struct M_C(name, _s) *current = it->current; \ - struct M_C(name, _s) *next = current->next; \ - if (it->previous == NULL) { \ - *ov = next; \ - } else { \ - it->previous->next = next; \ - } \ - /* Update the item 'it' to point to the next element */ \ - /* it->previous doesn't need to be updated */ \ - it->current = next; \ - /* Push back extracted 'current' in the list 'nv' */ \ - current->next = *nv; \ - *nv = current; \ - } \ - \ - static inline void \ - M_C(name, _splice_at)(list_t nlist, it_t npos, \ - list_t olist, it_t opos) \ - { \ - LISTI_CONTRACT(nlist); \ - LISTI_CONTRACT(olist); \ - assert (npos != NULL); \ - assert (opos != NULL); \ - assert (M_C(name, _sublist_p)(nlist, npos)); \ - assert (M_C(name, _sublist_p)(olist, opos)); \ - /* Remove the item 'opos' from the list 'olist' */ \ - struct M_C(name, _s) *current = opos->current; \ - struct M_C(name, _s) *next = current->next; \ - if (opos->previous == NULL) { \ - *olist = next; \ - } else { \ - opos->previous->next = next; \ - } \ - /* Update 'opos' to point to the next element */ \ - opos->current = next; \ - /* Insert 'current' into 'nlist' just after 'npos' */ \ - struct M_C(name, _s) *previous = npos->current; \ - if (M_UNLIKELY (previous == NULL)) { \ - current->next = *nlist; \ - *nlist = current; \ - } else { \ - current->next = previous->next; \ - previous->next = current; \ - } \ - /* Update 'npos' to point to the new current element */ \ - npos->previous = npos->current; \ - npos->current = current; \ - LISTI_CONTRACT(nlist); \ - LISTI_CONTRACT(olist); \ - } \ - \ - static inline void \ - M_C(name, _splice)(list_t list1, list_t list2) \ - { \ - LISTI_CONTRACT(list1); \ - LISTI_CONTRACT(list2); \ - assert (list1 != list2); \ - struct M_C(name, _s) **update_list = list1; \ - struct M_C(name, _s) *it = *list1; \ - while (it != NULL) { \ - update_list = &it->next; \ - it = it->next; \ - } \ - *update_list = *list2; \ - *list2 = NULL; \ - } \ - \ - static inline void \ - M_C(name, _reverse)(list_t list) \ - { \ - LISTI_CONTRACT(list); \ - struct M_C(name, _s) *previous = NULL, *it = *list, *next; \ - while (it != NULL) { \ - next = it->next; \ - it->next = previous; \ - previous = it; \ - it = next; \ - } \ - *list = previous; \ - } \ +#define LISTI_DEF_P4(name, type, oplist, list_t, it_t) \ + \ + static inline void \ + M_C(name, _init)(list_t v) \ + { \ + assert (v != NULL); \ + *v = NULL; \ + } \ + \ + static inline void \ + M_C(name, _clean)(list_t v) \ + { \ + LISTI_CONTRACT(v); \ + struct M_C(name, _s) *it = *v; \ + *v = NULL; \ + while (it != NULL) { \ + struct M_C(name, _s) *next = it->next; \ + M_CALL_CLEAR(oplist, it->data); \ + M_C(name,_int_del)(it); \ + it = next; \ + } \ + LISTI_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _clear)(list_t v) \ + { \ + M_C(name, _clean)(v); \ + } \ + \ + static inline type const * \ + M_C(name, _back)(const list_t v) \ + { \ + LISTI_CONTRACT(v); \ + assert(*v != NULL); \ + return M_CONST_CAST(type, &((*v)->data)); \ + } \ + \ + static inline type * \ + M_C(name, _push_raw)(list_t v) \ + { \ + LISTI_CONTRACT(v); \ + struct M_C(name, _s) *next; \ + next = M_C(name, _int_new)(); \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + return NULL; \ + } \ + type *ret = &next->data; \ + next->next = *v; \ + *v = next; \ + LISTI_CONTRACT(v); \ + return ret; \ + } \ + \ + static inline void \ + M_C(name, _push_back)(list_t v, type const x) \ + { \ + type *data = M_C(name, _push_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return; \ + M_CALL_INIT_SET(oplist, *data, x); \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _push_new)(list_t v) \ + { \ + type *data = M_C(name, _push_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return NULL; \ + M_CALL_INIT(oplist, *data); \ + return data; \ + } \ + , /* No INIT */) \ + \ + static inline void \ + M_C(name, _pop_back)(type *data, list_t v) \ + { \ + LISTI_CONTRACT(v); \ + assert(*v != NULL); \ + if (data != NULL) { \ + M_DO_MOVE (oplist, *data, (*v)->data); \ + } else { \ + M_CALL_CLEAR(oplist, (*v)->data); \ + } \ + struct M_C(name, _s) *tofree = *v; \ + *v = (*v)->next; \ + M_C(name,_int_del)(tofree); \ + LISTI_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _push_move)(list_t v, type *x) \ + { \ + assert (x != NULL); \ + type *data = M_C(name, _push_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return; \ + M_DO_INIT_MOVE (oplist, *data, *x); \ + } \ + \ + static inline void \ + M_C(name, _pop_move)(type *data, list_t v) \ + { \ + LISTI_CONTRACT(v); \ + assert(*v != NULL && data != NULL); \ + M_DO_INIT_MOVE (oplist, *data, (*v)->data); \ + struct M_C(name, _s) *tofree = *v; \ + *v = (*v)->next; \ + M_C(name,_int_del)(tofree); \ + LISTI_CONTRACT(v); \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(const list_t v) \ + { \ + LISTI_CONTRACT(v); \ + return *v == NULL; \ + } \ + \ + static inline void \ + M_C(name, _swap)(list_t l, list_t v) \ + { \ + LISTI_CONTRACT(l); \ + LISTI_CONTRACT(v); \ + struct M_C(name, _s) *tmp = *l; \ + *l = *v; \ + *v = tmp; \ + LISTI_CONTRACT(l); \ + LISTI_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const list_t v) \ + { \ + LISTI_CONTRACT(v); \ + assert (it != NULL); \ + it->current = *v; \ + it->previous = NULL; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t it1, const it_t it2) \ + { \ + assert (it1 != NULL && it2 != NULL); \ + it1->current = it2->current; \ + it1->previous = it2->previous; \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it1, const list_t v) \ + { \ + LISTI_CONTRACT(v); \ + assert (it1 != NULL); \ + (void)v; /* unused */ \ + it1->current = NULL; \ + it1->previous = NULL; \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const it_t it) \ + { \ + assert (it != NULL); \ + return it->current == NULL; \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(const it_t it) \ + { \ + assert (it != NULL); \ + return it->current == NULL || it->current->next == NULL; \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + assert(it != NULL && it->current != NULL); \ + it->previous = it->current; \ + it->current = it->current->next; \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ + { \ + assert(it1 != NULL && it2 != NULL); \ + return it1->current == it2->current; \ + } \ + \ + static inline type * \ + M_C(name, _ref)(const it_t it) \ + { \ + assert(it != NULL && it->current != NULL); \ + return &(it->current->data); \ + } \ + \ + static inline type const * \ + M_C(name, _cref)(const it_t it) \ + { \ + assert(it != NULL && it->current != NULL); \ + return M_CONST_CAST(type, &(it->current->data)); \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const list_t list) \ + { \ + LISTI_CONTRACT(list); \ + size_t size = 0; \ + struct M_C(name, _s) *it = *list; \ + while (it != NULL) { \ + size ++; \ + it = it->next; \ + } \ + return size; \ + } \ + \ + static inline bool \ + M_C(name, _sublist_p)(const list_t list, const it_t itsub) \ + { \ + LISTI_CONTRACT(list); \ + assert (itsub != NULL); \ + struct M_C(name, _s) *it = *list; \ + while (it != NULL) { \ + if (it == itsub->current) return true; \ + it = it->next; \ + } \ + /* Not found. Check if search item is NULL */ \ + return (itsub->current == NULL); \ + } \ + \ + static inline type * \ + M_C(name, _get)(const list_t list, size_t i) \ + { \ + LISTI_CONTRACT(list); \ + struct M_C(name, _s) *it = *list; \ + /* FIXME: How to avoid the double iteration over the list? */ \ + size_t len = M_C(name,_size)(list); \ + assert (i < len); \ + size_t j = len-1; \ + while (true) { \ + assert (it != NULL); \ + if (i == j) return &it->data; \ + it = it->next; \ + j--; \ + } \ + } \ + \ + static inline type const * \ + M_C(name, _cget)(const list_t l, size_t i) \ + { \ + return M_CONST_CAST(type, M_C(name, _get)(l,i)); \ + } \ + \ + static inline void \ + M_C(name, _insert)(list_t list, it_t insertion_point, \ + type const x) \ + { \ + LISTI_CONTRACT(list); \ + assert (insertion_point != NULL); \ + assert(M_C(name, _sublist_p)(list, insertion_point)); \ + struct M_C(name, _s) *next = M_C(name, _int_new)(); \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + return; \ + } \ + M_CALL_INIT_SET(oplist, next->data, x); \ + struct M_C(name, _s) *current = insertion_point->current; \ + if (M_UNLIKELY (current == NULL)) { \ + next->next = *list; \ + *list = next; \ + } else { \ + next->next = current->next; \ + current->next = next; \ + } \ + /* Update insertion_point to this element */ \ + insertion_point->current = next; \ + LISTI_CONTRACT(list); \ + } \ + \ + static inline void \ + M_C(name, _remove)(list_t list, it_t removing_point) \ + { \ + LISTI_CONTRACT(list); \ + assert (removing_point != NULL); \ + assert (removing_point->current != NULL); \ + assert(M_C(name, _sublist_p)(list, removing_point)); \ + struct M_C(name, _s) *next = removing_point->current->next; \ + if (M_UNLIKELY (removing_point->previous == NULL)) { \ + *list = next; \ + } else { \ + removing_point->previous->next = next; \ + } \ + M_CALL_CLEAR(oplist, removing_point->current->data); \ + M_C(name,_int_del) (removing_point->current); \ + removing_point->current = next; \ + LISTI_CONTRACT(list); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(list_t list, const list_t org) \ + { \ + LISTI_CONTRACT(org); \ + struct M_C(name, _s) *next, *it_org; \ + struct M_C(name, _s) **update_list; \ + update_list = list; \ + it_org = *org; \ + while (it_org != NULL) { \ + next = M_C(name, _int_new)(); \ + *update_list = next; \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + /* FIXME: Partialy initialized list. What to do? */ \ + return; \ + } \ + update_list = &next->next; \ + M_CALL_INIT_SET(oplist, next->data, it_org->data); \ + it_org = it_org->next; \ + } \ + *update_list = NULL; \ + LISTI_CONTRACT(list); \ + } \ + \ + static inline void \ + M_C(name, _set)(list_t list, const list_t org) \ + { \ + if (M_UNLIKELY (list == org)) return; \ + M_C(name, _clear)(list); \ + M_C(name, _init_set)(list, org); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(list_t list, list_t org) \ + { \ + LISTI_CONTRACT(org); \ + assert (list != NULL && list != org); \ + *list = *org; \ + *org = NULL; /* safer */ \ + } \ + \ + static inline void \ + M_C(name, _move)(list_t list, list_t org) \ + { \ + assert (list != org); \ + M_C(name, _clear)(list); \ + M_C(name, _init_move)(list, org); \ + } \ + \ + static inline void \ + M_C(name, _splice_back)(list_t nv, list_t ov, it_t it) \ + { \ + LISTI_CONTRACT(nv); \ + LISTI_CONTRACT(ov); \ + assert (it != NULL); \ + assert (it->current != NULL); \ + assert (M_C(name, _sublist_p)(ov, it)); \ + /* Remove the item 'it' from the list 'ov' */ \ + struct M_C(name, _s) *current = it->current; \ + struct M_C(name, _s) *next = current->next; \ + if (it->previous == NULL) { \ + *ov = next; \ + } else { \ + it->previous->next = next; \ + } \ + /* Update the item 'it' to point to the next element */ \ + /* it->previous doesn't need to be updated */ \ + it->current = next; \ + /* Push back extracted 'current' in the list 'nv' */ \ + current->next = *nv; \ + *nv = current; \ + } \ + \ + static inline void \ + M_C(name, _splice_at)(list_t nlist, it_t npos, \ + list_t olist, it_t opos) \ + { \ + LISTI_CONTRACT(nlist); \ + LISTI_CONTRACT(olist); \ + assert (npos != NULL); \ + assert (opos != NULL); \ + assert (M_C(name, _sublist_p)(nlist, npos)); \ + assert (M_C(name, _sublist_p)(olist, opos)); \ + /* Remove the item 'opos' from the list 'olist' */ \ + struct M_C(name, _s) *current = opos->current; \ + struct M_C(name, _s) *next = current->next; \ + if (opos->previous == NULL) { \ + *olist = next; \ + } else { \ + opos->previous->next = next; \ + } \ + /* Update 'opos' to point to the next element */ \ + opos->current = next; \ + /* Insert 'current' into 'nlist' just after 'npos' */ \ + struct M_C(name, _s) *previous = npos->current; \ + if (M_UNLIKELY (previous == NULL)) { \ + current->next = *nlist; \ + *nlist = current; \ + } else { \ + current->next = previous->next; \ + previous->next = current; \ + } \ + /* Update 'npos' to point to the new current element */ \ + npos->previous = npos->current; \ + npos->current = current; \ + LISTI_CONTRACT(nlist); \ + LISTI_CONTRACT(olist); \ + } \ + \ + static inline void \ + M_C(name, _splice)(list_t list1, list_t list2) \ + { \ + LISTI_CONTRACT(list1); \ + LISTI_CONTRACT(list2); \ + assert (list1 != list2); \ + struct M_C(name, _s) **update_list = list1; \ + struct M_C(name, _s) *it = *list1; \ + while (it != NULL) { \ + update_list = &it->next; \ + it = it->next; \ + } \ + *update_list = *list2; \ + *list2 = NULL; \ + } \ + \ + static inline void \ + M_C(name, _reverse)(list_t list) \ + { \ + LISTI_CONTRACT(list); \ + struct M_C(name, _s) *previous = NULL, *it = *list, *next; \ + while (it != NULL) { \ + next = it->next; \ + it->next = previous; \ + previous = it; \ + it = next; \ + } \ + *list = previous; \ + } \ /* Internal list function definition using only iterator functions @@ -672,196 +672,196 @@ - list_t: alias for M_C(name, _t) [ type of the container ] - it_t: alias for M_C(name, _it_t) [ iterator of the container ] */ -#define LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) \ - \ - M_IF_METHOD(GET_STR, oplist)( \ - static inline void \ - M_C(name, _get_str)(string_t str, const list_t list, \ - bool append) \ - { \ - assert (str != NULL && list != NULL); \ - (append ? string_cat_str : string_set_str) (str, "["); \ - it_t it; \ - for (M_C(name, _it)(it, list) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - type const *item = M_C(name, _cref)(it); \ - M_CALL_GET_STR(oplist, str, *item, true); \ - if (!M_C(name, _last_p)(it)) \ - string_push_back (str, M_GET_SEPARATOR oplist); \ - } \ - string_push_back (str, ']'); \ - } \ - , /* no str */ ) \ - \ - M_IF_METHOD(OUT_STR, oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *file, const list_t list) \ - { \ - assert (file != NULL && list != NULL); \ - fputc ('[', file); \ - it_t it; \ - for (M_C(name, _it)(it, list) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - type const *item = M_C(name, _cref)(it); \ - M_CALL_OUT_STR(oplist, file, *item); \ - if (!M_C(name, _last_p)(it)) \ - fputc (M_GET_SEPARATOR oplist, file); \ - } \ - fputc (']', file); \ - } \ - , /* no out_str */ ) \ - \ - M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ - static inline bool \ - M_C(name, _parse_str)(list_t list, const char str[], const char **endp) \ - { \ - assert (str != NULL && list != NULL); \ - M_C(name,_clean)(list); \ - bool success = false; \ - int c = *str++; \ - if (M_UNLIKELY (c != '[')) goto exit; \ - c = *str++; \ - if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \ - if (M_UNLIKELY (c == 0)) goto exit; \ - str--; \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ - do { c = *str++; } while (isspace(c)); \ - if (b == false || c == 0) { goto exit_clear; } \ - M_C(name, _push_back)(list, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - M_C(name, _reverse)(list); \ - success = (c == ']'); \ - exit_clear: \ - M_CALL_CLEAR(oplist, item); \ - exit: \ - if (endp) *endp = str; \ - return success; \ - } \ - , /* no PARSE_STR & INIT */ ) \ - \ - M_IF_METHOD2(IN_STR, INIT, oplist)( \ - static inline bool \ - M_C(name, _in_str)(list_t list, FILE *file) \ - { \ - assert (file != NULL && list != NULL); \ - M_C(name,_clean)(list); \ - int c = fgetc(file); \ - if (M_UNLIKELY (c != '[')) return false; \ - c = fgetc(file); \ - if (M_UNLIKELY (c == ']')) return true; \ - if (M_UNLIKELY (c == EOF)) return false; \ - ungetc(c, file); \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_IN_STR(oplist, item, file); \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false || c == EOF) { break; } \ - M_C(name, _push_back)(list, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - M_CALL_CLEAR(oplist, item); \ - M_C(name, _reverse)(list); \ - return c == ']'; \ - } \ - , /* no IN_STR & INIT */ ) \ - \ - M_IF_METHOD(OUT_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, const list_t list) \ - { \ - assert (list != NULL); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_return_code_t ret; \ - m_serial_local_t local; \ - bool first_done = false; \ - ret = f->m_interface->write_array_start(local, f, 0); \ - it_t it; \ - for (M_C(name, _it)(it, list) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - type const *item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_array_end(local, f); \ - return ret & M_SERIAL_FAIL; \ - } \ - , /* no OUT_SERIAL */ ) \ - \ - M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(list_t list, m_serial_read_t f) \ - { \ - assert (list != NULL); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_return_code_t ret; \ - m_serial_local_t local; \ - size_t estimated_size = 0; \ - M_C(name,_clean)(list); \ - ret = f->m_interface->read_array_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - ret = M_CALL_IN_SERIAL(oplist, item, f); \ - if (ret != M_SERIAL_OK_DONE) { break; } \ - M_C(name, _push_back)(list, item); \ - ret = f->m_interface->read_array_next(local, f); \ - } while (ret == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(oplist, item); \ - M_C(name, _reverse)(list); \ - return ret; \ - } \ - , /* no IN_SERIAL & INIT */ ) \ - \ - M_IF_METHOD(EQUAL, oplist)( \ - static inline bool \ - M_C(name, _equal_p)(const list_t list1, const list_t list2) \ - { \ - assert (list1 != NULL && list2 != NULL); \ - it_t it1; \ - it_t it2; \ - if (list1 == list2) return true; \ - M_C(name, _it)(it1, list1); \ - M_C(name, _it)(it2, list2); \ - while (!M_C(name, _end_p)(it1) \ - &&!M_C(name, _end_p)(it2)) { \ - type const *item1 = M_C(name, _cref)(it1); \ - type const *item2 = M_C(name, _cref)(it2); \ - bool b = M_CALL_EQUAL(oplist, *item1, *item2); \ - if (!b) return false; \ - M_C(name, _next)(it1); \ - M_C(name, _next)(it2); \ - } \ - return M_C(name, _end_p)(it1) \ - && M_C(name, _end_p)(it2); \ - } \ - , /* no equal */ ) \ - \ - M_IF_METHOD(HASH, oplist)( \ - static inline size_t \ - M_C(name, _hash)(const list_t list) \ - { \ - assert (list != NULL); \ - M_HASH_DECL(hash); \ - it_t it; \ - for(M_C(name, _it)(it, list) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)) { \ - type const *item = M_C(name, _cref)(it); \ - size_t hi = M_CALL_HASH(oplist, *item); \ - M_HASH_UP(hash, hi); \ - } \ - return M_HASH_FINAL (hash); \ - } \ - , /* no hash */ ) \ +#define LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) \ + \ + M_IF_METHOD(GET_STR, oplist)( \ + static inline void \ + M_C(name, _get_str)(string_t str, const list_t list, \ + bool append) \ + { \ + assert (str != NULL && list != NULL); \ + (append ? string_cat_str : string_set_str) (str, "["); \ + it_t it; \ + for (M_C(name, _it)(it, list) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + type const *item = M_C(name, _cref)(it); \ + M_CALL_GET_STR(oplist, str, *item, true); \ + if (!M_C(name, _last_p)(it)) \ + string_push_back (str, M_GET_SEPARATOR oplist); \ + } \ + string_push_back (str, ']'); \ + } \ + , /* no str */ ) \ + \ + M_IF_METHOD(OUT_STR, oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *file, const list_t list) \ + { \ + assert (file != NULL && list != NULL); \ + fputc ('[', file); \ + it_t it; \ + for (M_C(name, _it)(it, list) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + type const *item = M_C(name, _cref)(it); \ + M_CALL_OUT_STR(oplist, file, *item); \ + if (!M_C(name, _last_p)(it)) \ + fputc (M_GET_SEPARATOR oplist, file); \ + } \ + fputc (']', file); \ + } \ + , /* no out_str */ ) \ + \ + M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ + static inline bool \ + M_C(name, _parse_str)(list_t list, const char str[], const char **endp) \ + { \ + assert (str != NULL && list != NULL); \ + M_C(name,_clean)(list); \ + bool success = false; \ + int c = *str++; \ + if (M_UNLIKELY (c != '[')) goto exit; \ + c = *str++; \ + if (M_UNLIKELY (c == ']')) { success = true; goto exit;} \ + if (M_UNLIKELY (c == 0)) goto exit; \ + str--; \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ + do { c = *str++; } while (isspace(c)); \ + if (b == false || c == 0) { goto exit_clear; } \ + M_C(name, _push_back)(list, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + M_C(name, _reverse)(list); \ + success = (c == ']'); \ + exit_clear: \ + M_CALL_CLEAR(oplist, item); \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } \ + , /* no PARSE_STR & INIT */ ) \ + \ + M_IF_METHOD2(IN_STR, INIT, oplist)( \ + static inline bool \ + M_C(name, _in_str)(list_t list, FILE *file) \ + { \ + assert (file != NULL && list != NULL); \ + M_C(name,_clean)(list); \ + int c = fgetc(file); \ + if (M_UNLIKELY (c != '[')) return false; \ + c = fgetc(file); \ + if (M_UNLIKELY (c == ']')) return true; \ + if (M_UNLIKELY (c == EOF)) return false; \ + ungetc(c, file); \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_IN_STR(oplist, item, file); \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false || c == EOF) { break; } \ + M_C(name, _push_back)(list, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + M_CALL_CLEAR(oplist, item); \ + M_C(name, _reverse)(list); \ + return c == ']'; \ + } \ + , /* no IN_STR & INIT */ ) \ + \ + M_IF_METHOD(OUT_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, const list_t list) \ + { \ + assert (list != NULL); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_return_code_t ret; \ + m_serial_local_t local; \ + bool first_done = false; \ + ret = f->m_interface->write_array_start(local, f, 0); \ + it_t it; \ + for (M_C(name, _it)(it, list) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + type const *item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_array_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ + first_done = true; \ + } \ + ret |= f->m_interface->write_array_end(local, f); \ + return ret & M_SERIAL_FAIL; \ + } \ + , /* no OUT_SERIAL */ ) \ + \ + M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(list_t list, m_serial_read_t f) \ + { \ + assert (list != NULL); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_return_code_t ret; \ + m_serial_local_t local; \ + size_t estimated_size = 0; \ + M_C(name,_clean)(list); \ + ret = f->m_interface->read_array_start(local, f, &estimated_size); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + ret = M_CALL_IN_SERIAL(oplist, item, f); \ + if (ret != M_SERIAL_OK_DONE) { break; } \ + M_C(name, _push_back)(list, item); \ + ret = f->m_interface->read_array_next(local, f); \ + } while (ret == M_SERIAL_OK_CONTINUE); \ + M_CALL_CLEAR(oplist, item); \ + M_C(name, _reverse)(list); \ + return ret; \ + } \ + , /* no IN_SERIAL & INIT */ ) \ + \ + M_IF_METHOD(EQUAL, oplist)( \ + static inline bool \ + M_C(name, _equal_p)(const list_t list1, const list_t list2) \ + { \ + assert (list1 != NULL && list2 != NULL); \ + it_t it1; \ + it_t it2; \ + if (list1 == list2) return true; \ + M_C(name, _it)(it1, list1); \ + M_C(name, _it)(it2, list2); \ + while (!M_C(name, _end_p)(it1) \ + &&!M_C(name, _end_p)(it2)) { \ + type const *item1 = M_C(name, _cref)(it1); \ + type const *item2 = M_C(name, _cref)(it2); \ + bool b = M_CALL_EQUAL(oplist, *item1, *item2); \ + if (!b) return false; \ + M_C(name, _next)(it1); \ + M_C(name, _next)(it2); \ + } \ + return M_C(name, _end_p)(it1) \ + && M_C(name, _end_p)(it2); \ + } \ + , /* no equal */ ) \ + \ + M_IF_METHOD(HASH, oplist)( \ + static inline size_t \ + M_C(name, _hash)(const list_t list) \ + { \ + assert (list != NULL); \ + M_HASH_DECL(hash); \ + it_t it; \ + for(M_C(name, _it)(it, list) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)) { \ + type const *item = M_C(name, _cref)(it); \ + size_t hi = M_CALL_HASH(oplist, *item); \ + M_HASH_UP(hash, hi); \ + } \ + return M_HASH_FINAL (hash); \ + } \ + , /* no hash */ ) \ /* Deferred evaluation for the dual-push list definition, @@ -869,11 +869,11 @@ #define LISTI_DUAL_PUSH_DEF_P1(arg) LISTI_DUAL_PUSH_DEF_P2 arg /* Validate the oplist before going further */ -#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \ +#define LISTI_DUAL_PUSH_DEF_P2(name, type, oplist, list_t, it_t) \ M_IF_OPLIST(oplist)(LISTI_DUAL_PUSH_DEF_P3, LISTI_DUAL_PUSH_DEF_FAILURE)(name, type, oplist, list_t, it_t) /* Stop processing with a compilation failure */ -#define LISTI_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \ +#define LISTI_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DUAL_PUSH_DEF): the given argument is not a valid oplist: " #oplist) /* Internal dual-push list definition @@ -883,49 +883,49 @@ - list_t: alias for M_C(name, _t) [ type of the container ] - it_t: alias for M_C(name, _it_t) [ iterator of the container ] */ -#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \ - \ - /* Node of a list (it is liked the singly linked list) */ \ - struct M_C(name, _s) { \ - struct M_C(name, _s) *next; \ - type data; \ - }; \ - \ - /* Dual Push singly linked list. \ - Support Push Back / Push Front / Pop back in O(1). \ - Doesn't support Pop front. \ - This is done by keeping a pointer to both back & front \ - */ \ - typedef struct M_C(name, _head_s) { \ - struct M_C(name,_s) *front; /* Pointer to the front node or NULL */ \ - struct M_C(name,_s) *back; /* Pointer to the back node or NULL */ \ - } list_t[1]; \ - \ - /* Define the iterator over a dual push singly linked list */ \ - typedef struct M_C(name, _it_s) { \ - struct M_C(name, _s) *previous; \ - struct M_C(name, _s) *current; \ - } it_t[1]; \ - \ - /* Definition of the synonyms of the type */ \ - typedef struct M_C(name, _head_s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _head_s) *M_C(name, _srcptr); \ - typedef list_t M_C(name, _ct); \ - typedef it_t M_C(name, _it_ct); \ - typedef type M_C(name, _subtype_ct); \ - \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ - LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \ - LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ +#define LISTI_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \ + \ + /* Node of a list (it is liked the singly linked list) */ \ + struct M_C(name, _s) { \ + struct M_C(name, _s) *next; \ + type data; \ + }; \ + \ + /* Dual Push singly linked list. \ + Support Push Back / Push Front / Pop back in O(1). \ + Doesn't support Pop front. \ + This is done by keeping a pointer to both back & front \ + */ \ + typedef struct M_C(name, _head_s) { \ + struct M_C(name,_s) *front; /* Pointer to the front node or NULL */ \ + struct M_C(name,_s) *back; /* Pointer to the back node or NULL */ \ + } list_t[1]; \ + \ + /* Define the iterator over a dual push singly linked list */ \ + typedef struct M_C(name, _it_s) { \ + struct M_C(name, _s) *previous; \ + struct M_C(name, _s) *current; \ + } it_t[1]; \ + \ + /* Definition of the synonyms of the type */ \ + typedef struct M_C(name, _head_s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _head_s) *M_C(name, _srcptr); \ + typedef list_t M_C(name, _ct); \ + typedef it_t M_C(name, _it_ct); \ + typedef type M_C(name, _subtype_ct); \ + \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ + LISTI_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \ + LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ LISTI_ITBASE_DEF(name, type, oplist, list_t, it_t) /* Define the internal contract of an dual-push list */ -#define LISTI_DUAL_PUSH_CONTRACT(l) do { \ - assert (l != NULL); \ - assert ( (l->back == NULL && l->front == NULL) \ - || (l->back != NULL && l->front != NULL)); \ +#define LISTI_DUAL_PUSH_CONTRACT(l) do { \ + assert (l != NULL); \ + assert ( (l->back == NULL && l->front == NULL) \ + || (l->back != NULL && l->front != NULL)); \ } while (0) /* Internal dual-push list definition @@ -935,520 +935,520 @@ - list_t: alias for type of the container - it_t: alias for iterator of the container */ -#define LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ - \ - static inline void \ - M_C(name, _init)(list_t v) \ - { \ - assert( v != NULL); \ - v->front = NULL; \ - v->back = NULL; \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _clean)(list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - struct M_C(name, _s) *it = v->back; \ - while (it != NULL) { \ - struct M_C(name, _s) *next = it->next; \ - M_CALL_CLEAR(oplist, it->data); \ - M_C(name,_int_del)(it); \ - it = next; \ - } \ - v->front = NULL; \ - v->back = NULL; \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _clear)(list_t v) \ - { \ - M_C(name, _clean)(v); \ - } \ - \ - static inline type const * \ - M_C(name, _back)(const list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - assert (v->back != NULL); \ - return M_CONST_CAST(type, &(v->back->data)); \ - } \ - \ - static inline type * \ - M_C(name, _push_back_raw)(list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - struct M_C(name, _s) *next = M_C(name, _int_new)(); \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - return NULL; \ - } \ - type *ret = &next->data; \ - next->next = v->back; \ - v->back = next; \ - /* Update front too if the list was empty */ \ - /* This C code shall generate branchless code */ \ - struct M_C(name, _s) *front = v->front; \ - front = (front == NULL) ? next : front; \ - v->front = front; \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - return ret; \ - } \ - \ - static inline void \ - M_C(name, _push_back)(list_t v, type const x) \ - { \ - type *data = M_C(name, _push_back_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return; \ - M_CALL_INIT_SET(oplist, *data, x); \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _push_back_new)(list_t v) \ - { \ - type *data = M_C(name, _push_back_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return NULL; \ - M_CALL_INIT(oplist, *data); \ - return data; \ - } \ - , /* No INIT */ ) \ - \ - static inline void \ - M_C(name, _push_back_move)(list_t v, type *x) \ - { \ - assert (x != NULL); \ - type *data = M_C(name, _push_back_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ - } \ - \ - static inline void \ - M_C(name, _push_move)(list_t v, type *x) \ - { \ - M_C(name, _push_back_move)(v, x); \ - } \ - \ - static inline void \ - M_C(name, _pop_back)(type *data, list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - assert (v->back != NULL); \ - struct M_C(name, _s) *tofree = v->back; \ - if (data != NULL) { \ - M_DO_MOVE(oplist, *data, tofree->data); \ - } else { \ - M_CALL_CLEAR(oplist, tofree->data); \ - } \ - v->back = tofree->next; \ - M_C(name,_int_del)(tofree); \ - /* Update front too if the list became empty */ \ - /* This C code shall generate branchless code */ \ - struct M_C(name, _s) *front = v->front; \ - front = (front == tofree) ? NULL : front; \ - v->front = front; \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - } \ - \ - static inline void \ - M_C(name, _pop_move)(type *data, list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - assert (v->back != NULL); \ - assert (data != NULL); \ - struct M_C(name, _s) *tofree = v->back; \ - M_DO_INIT_MOVE (oplist, *data, tofree->data); \ - v->back = tofree->next; \ - M_C(name,_int_del)(tofree); \ - /* Update front too if the list became empty */ \ - /* This C code shall generate branchless code */ \ - struct M_C(name, _s) *front = v->front; \ - front = (front == tofree) ? NULL : front; \ - v->front = front; \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - } \ - \ - static inline type const * \ - M_C(name, _front)(list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - assert (v->front != NULL); \ - return M_CONST_CAST(type, &(v->front->data)); \ - } \ - \ - static inline type * \ - M_C(name, _push_front_raw)(list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - struct M_C(name, _s) *next = M_C(name, _int_new)(); \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - return NULL; \ - } \ - type *ret = &next->data; \ - next->next = NULL; \ - if (M_LIKELY(v->front != NULL)) { \ - v->front->next = next; \ - } else { \ - /* Update back too as the list was empty */ \ - v->back = next; \ - } \ - v->front = next; \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - return ret; \ - } \ - \ - static inline void \ - M_C(name, _push_front)(list_t v, type const x) \ - { \ - type *data = M_C(name, _push_front_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return; \ - M_CALL_INIT_SET(oplist, *data, x); \ - } \ - \ - static inline void \ - M_C(name, _push_front_move)(list_t v, type *x) \ - { \ - assert (x != NULL); \ - type *data = M_C(name, _push_front_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - static inline type * \ - M_C(name, _push_front_new)(list_t v) \ - { \ - type *data = M_C(name, _push_back_raw)(v); \ - if (M_UNLIKELY (data == NULL)) \ - return NULL; \ - M_CALL_INIT(oplist, *data); \ - return data; \ - } \ - , /* No INIT */) \ - \ - static inline bool \ - M_C(name, _empty_p)(const list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - return v->back == NULL; \ - } \ - \ - static inline void \ - M_C(name, _swap)(list_t l, list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(l); \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - M_SWAP(struct M_C(name, _s) *, l->front, v->front); \ - M_SWAP(struct M_C(name, _s) *, l->back, v->back); \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - assert (it != NULL); \ - it->current = v->back; \ - it->previous = NULL; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t it1, const it_t it2) \ - { \ - assert (it1 != NULL && it2 != NULL); \ - it1->current = it2->current; \ - it1->previous = it2->previous; \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it1, const list_t v) \ - { \ - assert (it1 != NULL); \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - (void)v; /* unused */ \ - it1->current = NULL; \ - it1->previous = NULL; \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const it_t it) \ - { \ - assert (it != NULL); \ - return it->current == NULL; \ - } \ - \ - static inline bool \ - M_C(name, _last_p)(const it_t it) \ - { \ - assert (it != NULL); \ - return it->current == NULL || it->current->next == NULL; \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - assert(it != NULL && it->current != NULL); \ - it->previous = it->current; \ - it->current = it->current->next; \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ - { \ - assert(it1 != NULL && it2 != NULL); \ - return it1->current == it2->current; \ - } \ - \ - static inline type * \ - M_C(name, _ref)(const it_t it) \ - { \ - assert(it != NULL && it->current != NULL); \ - return &(it->current->data); \ - } \ - \ - static inline type const * \ - M_C(name, _cref)(const it_t it) \ - { \ - assert(it != NULL && it->current != NULL); \ - return M_CONST_CAST(type, &(it->current->data)); \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const list_t v) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(v); \ - size_t size = 0; \ - struct M_C(name, _s) *it = v->back; \ - while (it != NULL) { \ - size ++; \ - it = it->next; \ - } \ - return size; \ - } \ - \ - static inline void \ - M_C(name, _insert)(list_t list, it_t insertion_point, \ - type const x) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(list); \ - assert (insertion_point != NULL); \ - struct M_C(name, _s) *next = M_C(name, _int_new)(); \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - return; \ - } \ - M_CALL_INIT_SET(oplist, next->data, x); \ - if (M_UNLIKELY (insertion_point->current == NULL)) { \ - next->next = list->back; \ - list->back = next; \ - /* update front if list is empty */ \ - struct M_C(name, _s) *front = list->front; \ - front = (front == NULL) ? next : front; \ - list->front = front; \ - } else { \ - next->next = insertion_point->current->next; \ - insertion_point->current->next = next; \ - /* update front if current == front */ \ - struct M_C(name, _s) *front = list->front; \ - front = (front == insertion_point->current) ? next : front; \ - list->front = front; \ - } \ - } \ - \ - static inline void \ - M_C(name, _remove)(list_t list, it_t removing_point) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(list); \ - assert (removing_point != NULL); \ - assert(removing_point->current != NULL); \ - struct M_C(name, _s) *next = removing_point->current->next; \ - struct M_C(name, _s) *previous = removing_point->previous; \ - if (M_UNLIKELY (previous == NULL)) { \ - list->back = next; \ - } else { \ - previous->next = next; \ - } \ - /* Update front */ \ - struct M_C(name, _s) *front = list->front; \ - front = (next == NULL) ? previous : front; \ - list->front = front; \ - /* Remove node */ \ - M_CALL_CLEAR(oplist, removing_point->current->data); \ - M_C(name,_int_del) (removing_point->current); \ - removing_point->current = next; \ - } \ - \ - static inline void \ - M_C(name, _set)(list_t list, const list_t org) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(list); \ - LISTI_DUAL_PUSH_CONTRACT(org); \ - struct M_C(name, _s) *next = NULL; \ - struct M_C(name, _s) *it_org; \ - struct M_C(name, _s) **update_list; \ - if (M_UNLIKELY (list == org)) return; \ - M_C(name, _clean)(list); \ - update_list = &list->back; \ - it_org = org->back; \ - while (it_org != NULL) { \ - next = M_C(name, _int_new)(); \ - *update_list = next; \ - if (M_UNLIKELY (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ - return; \ - } \ - update_list = &next->next; \ - M_CALL_INIT_SET(oplist, next->data, it_org->data); \ - it_org = it_org->next; \ - } \ - list->front = next; \ - *update_list = NULL; \ - } \ - \ - static inline void \ - M_C(name, _init_set)(list_t list, const list_t org) \ - { \ - assert (list != org); \ - M_C(name, _init)(list); \ - M_C(name, _set)(list, org); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(list_t list, list_t org) \ - { \ - assert (list != org); \ - list->back = org->back; \ - list->front = org->front; \ - org->back = NULL; \ - org->front = NULL; \ - } \ - \ - static inline void \ - M_C(name, _move)(list_t list, list_t org) \ - { \ - M_C(name, _clear)(list); \ - M_C(name, _init_move)(list, org); \ - } \ - \ - static inline void \ - M_C(name, _splice_back)(list_t list1, list_t list2, it_t it) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(list1); \ - LISTI_DUAL_PUSH_CONTRACT(list2); \ - assert (it->current != NULL); \ - /* First remove the item 'it' from the list 'list2' */ \ - struct M_C(name, _s) *current = it->current; \ - struct M_C(name, _s) *next = current->next; \ - if (it->previous == NULL) { \ - list2->back = next; \ - } else { \ - it->previous->next = next; \ - } \ - /* Update the front of 'list2' if it was the last element */ \ - struct M_C(name, _s) *front = list2->front; \ - front = (next == NULL) ? it->previous : front; \ - list2->front = front; \ - /* Update 'it' to point to the next element */ \ - it->current = next; \ - /* Move the extracted 'current' into the list 'nv' */ \ - current->next = list1->back; \ - list1->back = current; \ - /* Update the front field if the list 'nv' was empty */ \ - /* This C code shall generate branchless code */ \ - front = list1->front; \ - front = (front == NULL) ? current : front; \ - list1->front = front; \ - LISTI_DUAL_PUSH_CONTRACT(list1); \ - LISTI_DUAL_PUSH_CONTRACT(list2); \ - } \ - \ - static inline void \ - M_C(name, _splice_at)(list_t nlist, it_t npos, \ - list_t olist, it_t opos) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(nlist); \ - LISTI_DUAL_PUSH_CONTRACT(olist); \ - assert (npos != NULL && opos != NULL); \ - /* First remove the item 'opos' from the list 'olist' */ \ - struct M_C(name, _s) *current = opos->current; \ - struct M_C(name, _s) *next = current->next; \ - if (opos->previous == NULL) { \ - olist->back = next; \ - } else { \ - opos->previous->next = next; \ - } \ - /* Update the front of 'olist' if it was the last element */ \ - struct M_C(name, _s) *front = olist->front; \ - front = (next == NULL) ? opos->previous : front; \ - olist->front = front; \ - /* Update 'opos' to point to the next element */ \ - opos->current = next; \ - /* opos->previous is still valid & doesn't need to be updated */ \ - /* Insert into 'nlist' */ \ - struct M_C(name, _s) *npos_current = npos->current; \ - if (M_UNLIKELY (npos_current == NULL)) { \ - current->next = nlist->back; \ - nlist->back = current; \ - /* update 'front' if the list was empty (branchless) */ \ - front = nlist->front; \ - front = (front == NULL) ? current : front; \ - nlist->front = front; \ - } else { \ - current->next = npos_current->next; \ - npos_current->next = current; \ - /* update front if current == front (branchless) */ \ - front = nlist->front; \ - front = (front == npos_current) ? current : front; \ - nlist->front = front; \ - } \ - /* Update 'npos' to point to 'current'. */ \ - npos->previous = npos_current; \ - npos->current = current; \ - LISTI_DUAL_PUSH_CONTRACT(nlist); \ - LISTI_DUAL_PUSH_CONTRACT(olist); \ - } \ - \ - static inline void \ - M_C(name, _splice)(list_t list1, list_t list2) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(list1); \ - LISTI_DUAL_PUSH_CONTRACT(list2); \ - assert (list1 != list2); \ - if (M_LIKELY (list1->front != NULL)) { \ - list1->front->next = list2->back; \ - list1->front = list2->front; \ - } else { \ - /* list1 is empty */ \ - list1->back = list2->back; \ - list1->front = list2->front; \ - } \ - list2->back = NULL; \ - list2->front = NULL; \ - LISTI_DUAL_PUSH_CONTRACT(list1); \ - LISTI_DUAL_PUSH_CONTRACT(list2); \ - } \ - \ - static inline void \ - M_C(name, _reverse)(list_t list) \ - { \ - LISTI_DUAL_PUSH_CONTRACT(list); \ - list->front = list->back; \ - struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \ - while (it != NULL) { \ - next = it->next; \ - it->next = previous; \ - previous = it; \ - it = next; \ - } \ - list->back = previous; \ - LISTI_DUAL_PUSH_CONTRACT(list); \ - } \ +#define LISTI_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ + \ + static inline void \ + M_C(name, _init)(list_t v) \ + { \ + assert( v != NULL); \ + v->front = NULL; \ + v->back = NULL; \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _clean)(list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + struct M_C(name, _s) *it = v->back; \ + while (it != NULL) { \ + struct M_C(name, _s) *next = it->next; \ + M_CALL_CLEAR(oplist, it->data); \ + M_C(name,_int_del)(it); \ + it = next; \ + } \ + v->front = NULL; \ + v->back = NULL; \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _clear)(list_t v) \ + { \ + M_C(name, _clean)(v); \ + } \ + \ + static inline type const * \ + M_C(name, _back)(const list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + assert (v->back != NULL); \ + return M_CONST_CAST(type, &(v->back->data)); \ + } \ + \ + static inline type * \ + M_C(name, _push_back_raw)(list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + struct M_C(name, _s) *next = M_C(name, _int_new)(); \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + return NULL; \ + } \ + type *ret = &next->data; \ + next->next = v->back; \ + v->back = next; \ + /* Update front too if the list was empty */ \ + /* This C code shall generate branchless code */ \ + struct M_C(name, _s) *front = v->front; \ + front = (front == NULL) ? next : front; \ + v->front = front; \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + return ret; \ + } \ + \ + static inline void \ + M_C(name, _push_back)(list_t v, type const x) \ + { \ + type *data = M_C(name, _push_back_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return; \ + M_CALL_INIT_SET(oplist, *data, x); \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _push_back_new)(list_t v) \ + { \ + type *data = M_C(name, _push_back_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return NULL; \ + M_CALL_INIT(oplist, *data); \ + return data; \ + } \ + , /* No INIT */ ) \ + \ + static inline void \ + M_C(name, _push_back_move)(list_t v, type *x) \ + { \ + assert (x != NULL); \ + type *data = M_C(name, _push_back_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return; \ + M_DO_INIT_MOVE (oplist, *data, *x); \ + } \ + \ + static inline void \ + M_C(name, _push_move)(list_t v, type *x) \ + { \ + M_C(name, _push_back_move)(v, x); \ + } \ + \ + static inline void \ + M_C(name, _pop_back)(type *data, list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + assert (v->back != NULL); \ + struct M_C(name, _s) *tofree = v->back; \ + if (data != NULL) { \ + M_DO_MOVE(oplist, *data, tofree->data); \ + } else { \ + M_CALL_CLEAR(oplist, tofree->data); \ + } \ + v->back = tofree->next; \ + M_C(name,_int_del)(tofree); \ + /* Update front too if the list became empty */ \ + /* This C code shall generate branchless code */ \ + struct M_C(name, _s) *front = v->front; \ + front = (front == tofree) ? NULL : front; \ + v->front = front; \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + } \ + \ + static inline void \ + M_C(name, _pop_move)(type *data, list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + assert (v->back != NULL); \ + assert (data != NULL); \ + struct M_C(name, _s) *tofree = v->back; \ + M_DO_INIT_MOVE (oplist, *data, tofree->data); \ + v->back = tofree->next; \ + M_C(name,_int_del)(tofree); \ + /* Update front too if the list became empty */ \ + /* This C code shall generate branchless code */ \ + struct M_C(name, _s) *front = v->front; \ + front = (front == tofree) ? NULL : front; \ + v->front = front; \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + } \ + \ + static inline type const * \ + M_C(name, _front)(list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + assert (v->front != NULL); \ + return M_CONST_CAST(type, &(v->front->data)); \ + } \ + \ + static inline type * \ + M_C(name, _push_front_raw)(list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + struct M_C(name, _s) *next = M_C(name, _int_new)(); \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + return NULL; \ + } \ + type *ret = &next->data; \ + next->next = NULL; \ + if (M_LIKELY(v->front != NULL)) { \ + v->front->next = next; \ + } else { \ + /* Update back too as the list was empty */ \ + v->back = next; \ + } \ + v->front = next; \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + return ret; \ + } \ + \ + static inline void \ + M_C(name, _push_front)(list_t v, type const x) \ + { \ + type *data = M_C(name, _push_front_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return; \ + M_CALL_INIT_SET(oplist, *data, x); \ + } \ + \ + static inline void \ + M_C(name, _push_front_move)(list_t v, type *x) \ + { \ + assert (x != NULL); \ + type *data = M_C(name, _push_front_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return; \ + M_DO_INIT_MOVE (oplist, *data, *x); \ + } \ + \ + M_IF_METHOD(INIT, oplist)( \ + static inline type * \ + M_C(name, _push_front_new)(list_t v) \ + { \ + type *data = M_C(name, _push_back_raw)(v); \ + if (M_UNLIKELY (data == NULL)) \ + return NULL; \ + M_CALL_INIT(oplist, *data); \ + return data; \ + } \ + , /* No INIT */) \ + \ + static inline bool \ + M_C(name, _empty_p)(const list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + return v->back == NULL; \ + } \ + \ + static inline void \ + M_C(name, _swap)(list_t l, list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(l); \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + M_SWAP(struct M_C(name, _s) *, l->front, v->front); \ + M_SWAP(struct M_C(name, _s) *, l->back, v->back); \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + assert (it != NULL); \ + it->current = v->back; \ + it->previous = NULL; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t it1, const it_t it2) \ + { \ + assert (it1 != NULL && it2 != NULL); \ + it1->current = it2->current; \ + it1->previous = it2->previous; \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it1, const list_t v) \ + { \ + assert (it1 != NULL); \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + (void)v; /* unused */ \ + it1->current = NULL; \ + it1->previous = NULL; \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const it_t it) \ + { \ + assert (it != NULL); \ + return it->current == NULL; \ + } \ + \ + static inline bool \ + M_C(name, _last_p)(const it_t it) \ + { \ + assert (it != NULL); \ + return it->current == NULL || it->current->next == NULL; \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + assert(it != NULL && it->current != NULL); \ + it->previous = it->current; \ + it->current = it->current->next; \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ + { \ + assert(it1 != NULL && it2 != NULL); \ + return it1->current == it2->current; \ + } \ + \ + static inline type * \ + M_C(name, _ref)(const it_t it) \ + { \ + assert(it != NULL && it->current != NULL); \ + return &(it->current->data); \ + } \ + \ + static inline type const * \ + M_C(name, _cref)(const it_t it) \ + { \ + assert(it != NULL && it->current != NULL); \ + return M_CONST_CAST(type, &(it->current->data)); \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const list_t v) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(v); \ + size_t size = 0; \ + struct M_C(name, _s) *it = v->back; \ + while (it != NULL) { \ + size ++; \ + it = it->next; \ + } \ + return size; \ + } \ + \ + static inline void \ + M_C(name, _insert)(list_t list, it_t insertion_point, \ + type const x) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(list); \ + assert (insertion_point != NULL); \ + struct M_C(name, _s) *next = M_C(name, _int_new)(); \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + return; \ + } \ + M_CALL_INIT_SET(oplist, next->data, x); \ + if (M_UNLIKELY (insertion_point->current == NULL)) { \ + next->next = list->back; \ + list->back = next; \ + /* update front if list is empty */ \ + struct M_C(name, _s) *front = list->front; \ + front = (front == NULL) ? next : front; \ + list->front = front; \ + } else { \ + next->next = insertion_point->current->next; \ + insertion_point->current->next = next; \ + /* update front if current == front */ \ + struct M_C(name, _s) *front = list->front; \ + front = (front == insertion_point->current) ? next : front; \ + list->front = front; \ + } \ + } \ + \ + static inline void \ + M_C(name, _remove)(list_t list, it_t removing_point) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(list); \ + assert (removing_point != NULL); \ + assert(removing_point->current != NULL); \ + struct M_C(name, _s) *next = removing_point->current->next; \ + struct M_C(name, _s) *previous = removing_point->previous; \ + if (M_UNLIKELY (previous == NULL)) { \ + list->back = next; \ + } else { \ + previous->next = next; \ + } \ + /* Update front */ \ + struct M_C(name, _s) *front = list->front; \ + front = (next == NULL) ? previous : front; \ + list->front = front; \ + /* Remove node */ \ + M_CALL_CLEAR(oplist, removing_point->current->data); \ + M_C(name,_int_del) (removing_point->current); \ + removing_point->current = next; \ + } \ + \ + static inline void \ + M_C(name, _set)(list_t list, const list_t org) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(list); \ + LISTI_DUAL_PUSH_CONTRACT(org); \ + struct M_C(name, _s) *next = NULL; \ + struct M_C(name, _s) *it_org; \ + struct M_C(name, _s) **update_list; \ + if (M_UNLIKELY (list == org)) return; \ + M_C(name, _clean)(list); \ + update_list = &list->back; \ + it_org = org->back; \ + while (it_org != NULL) { \ + next = M_C(name, _int_new)(); \ + *update_list = next; \ + if (M_UNLIKELY (next == NULL)) { \ + M_MEMORY_FULL(sizeof (struct M_C(name, _s))); \ + return; \ + } \ + update_list = &next->next; \ + M_CALL_INIT_SET(oplist, next->data, it_org->data); \ + it_org = it_org->next; \ + } \ + list->front = next; \ + *update_list = NULL; \ + } \ + \ + static inline void \ + M_C(name, _init_set)(list_t list, const list_t org) \ + { \ + assert (list != org); \ + M_C(name, _init)(list); \ + M_C(name, _set)(list, org); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(list_t list, list_t org) \ + { \ + assert (list != org); \ + list->back = org->back; \ + list->front = org->front; \ + org->back = NULL; \ + org->front = NULL; \ + } \ + \ + static inline void \ + M_C(name, _move)(list_t list, list_t org) \ + { \ + M_C(name, _clear)(list); \ + M_C(name, _init_move)(list, org); \ + } \ + \ + static inline void \ + M_C(name, _splice_back)(list_t list1, list_t list2, it_t it) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(list1); \ + LISTI_DUAL_PUSH_CONTRACT(list2); \ + assert (it->current != NULL); \ + /* First remove the item 'it' from the list 'list2' */ \ + struct M_C(name, _s) *current = it->current; \ + struct M_C(name, _s) *next = current->next; \ + if (it->previous == NULL) { \ + list2->back = next; \ + } else { \ + it->previous->next = next; \ + } \ + /* Update the front of 'list2' if it was the last element */ \ + struct M_C(name, _s) *front = list2->front; \ + front = (next == NULL) ? it->previous : front; \ + list2->front = front; \ + /* Update 'it' to point to the next element */ \ + it->current = next; \ + /* Move the extracted 'current' into the list 'nv' */ \ + current->next = list1->back; \ + list1->back = current; \ + /* Update the front field if the list 'nv' was empty */ \ + /* This C code shall generate branchless code */ \ + front = list1->front; \ + front = (front == NULL) ? current : front; \ + list1->front = front; \ + LISTI_DUAL_PUSH_CONTRACT(list1); \ + LISTI_DUAL_PUSH_CONTRACT(list2); \ + } \ + \ + static inline void \ + M_C(name, _splice_at)(list_t nlist, it_t npos, \ + list_t olist, it_t opos) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(nlist); \ + LISTI_DUAL_PUSH_CONTRACT(olist); \ + assert (npos != NULL && opos != NULL); \ + /* First remove the item 'opos' from the list 'olist' */ \ + struct M_C(name, _s) *current = opos->current; \ + struct M_C(name, _s) *next = current->next; \ + if (opos->previous == NULL) { \ + olist->back = next; \ + } else { \ + opos->previous->next = next; \ + } \ + /* Update the front of 'olist' if it was the last element */ \ + struct M_C(name, _s) *front = olist->front; \ + front = (next == NULL) ? opos->previous : front; \ + olist->front = front; \ + /* Update 'opos' to point to the next element */ \ + opos->current = next; \ + /* opos->previous is still valid & doesn't need to be updated */ \ + /* Insert into 'nlist' */ \ + struct M_C(name, _s) *npos_current = npos->current; \ + if (M_UNLIKELY (npos_current == NULL)) { \ + current->next = nlist->back; \ + nlist->back = current; \ + /* update 'front' if the list was empty (branchless) */ \ + front = nlist->front; \ + front = (front == NULL) ? current : front; \ + nlist->front = front; \ + } else { \ + current->next = npos_current->next; \ + npos_current->next = current; \ + /* update front if current == front (branchless) */ \ + front = nlist->front; \ + front = (front == npos_current) ? current : front; \ + nlist->front = front; \ + } \ + /* Update 'npos' to point to 'current'. */ \ + npos->previous = npos_current; \ + npos->current = current; \ + LISTI_DUAL_PUSH_CONTRACT(nlist); \ + LISTI_DUAL_PUSH_CONTRACT(olist); \ + } \ + \ + static inline void \ + M_C(name, _splice)(list_t list1, list_t list2) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(list1); \ + LISTI_DUAL_PUSH_CONTRACT(list2); \ + assert (list1 != list2); \ + if (M_LIKELY (list1->front != NULL)) { \ + list1->front->next = list2->back; \ + list1->front = list2->front; \ + } else { \ + /* list1 is empty */ \ + list1->back = list2->back; \ + list1->front = list2->front; \ + } \ + list2->back = NULL; \ + list2->front = NULL; \ + LISTI_DUAL_PUSH_CONTRACT(list1); \ + LISTI_DUAL_PUSH_CONTRACT(list2); \ + } \ + \ + static inline void \ + M_C(name, _reverse)(list_t list) \ + { \ + LISTI_DUAL_PUSH_CONTRACT(list); \ + list->front = list->back; \ + struct M_C(name, _s) *previous = NULL, *it = list->back, *next; \ + while (it != NULL) { \ + next = it->next; \ + it->next = previous; \ + previous = it; \ + it = next; \ + } \ + list->back = previous; \ + LISTI_DUAL_PUSH_CONTRACT(list); \ + } \ #endif diff --git a/m-mempool.h b/m-mempool.h index 00c85fbe..206575ac 100644 --- a/m-mempool.h +++ b/m-mempool.h @@ -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) diff --git a/m-mutex.h b/m-mutex.h index d4f59056..b70864ee 100644 --- a/m-mutex.h +++ b/m-mutex.h @@ -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 diff --git a/m-prioqueue.h b/m-prioqueue.h index 00d3d6a4..c6b6d82d 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -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 diff --git a/m-rbtree.h b/m-rbtree.h index 8b33162a..effe54e3 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -65,54 +65,54 @@ #define RBTREEI_OPLIST_P1(arg) RBTREEI_OPLIST_P2 arg /* Validation of the given oplist */ -#define RBTREEI_OPLIST_P2(name, oplist) \ +#define RBTREEI_OPLIST_P2(name, oplist) \ M_IF_OPLIST(oplist)(RBTREEI_OPLIST_P3, RBTREEI_OPLIST_FAILURE)(name, oplist) /* Prepare a clean compilation failure */ -#define RBTREEI_OPLIST_FAILURE(name, oplist) \ +#define RBTREEI_OPLIST_FAILURE(name, oplist) \ ((M_LIB_ERROR(ARGUMENT_OF_RBTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a rbtree NOTE: IT_REF is not exported so that the contained appears as not modifiable by algorithm.*/ -#define RBTREEI_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)), \ - 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_SET(M_C(name,_it_set)), \ - IT_LAST(M_C(name,_it_last)), \ - IT_END(M_C(name,_it_end)), \ - IT_END_P(M_C(name,_end_p)), \ - IT_LAST_P(M_C(name,_last_p)), \ - IT_EQUAL_P(M_C(name,_it_equal_p)), \ - IT_NEXT(M_C(name,_next)), \ - IT_CREF(M_C(name,_cref)), \ - CLEAN(M_C(name,_clean)), \ - PUSH(M_C(name,_push)), \ - GET_MIN(M_C(name,_min)), \ - GET_MAX(M_C(name,_max)), \ - M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),), \ - M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),), \ - M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),), \ - M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),), \ - M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \ - M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),), \ - M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \ - M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ - ,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 RBTREEI_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)), \ + 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_SET(M_C(name,_it_set)), \ + IT_LAST(M_C(name,_it_last)), \ + IT_END(M_C(name,_it_end)), \ + IT_END_P(M_C(name,_end_p)), \ + IT_LAST_P(M_C(name,_last_p)), \ + IT_EQUAL_P(M_C(name,_it_equal_p)), \ + IT_NEXT(M_C(name,_next)), \ + IT_CREF(M_C(name,_cref)), \ + CLEAN(M_C(name,_clean)), \ + PUSH(M_C(name,_push)), \ + GET_MIN(M_C(name,_min)), \ + GET_MAX(M_C(name,_max)), \ + M_IF_METHOD(GET_STR, oplist)(GET_STR(M_C(name, _get_str)),), \ + M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_C(name, _parse_str)),), \ + M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_C(name, _out_str)),), \ + M_IF_METHOD(IN_STR, oplist)(IN_STR(M_C(name, _in_str)),), \ + M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_C(name, _out_serial)),), \ + M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_C(name, _in_serial)),), \ + M_IF_METHOD(EQUAL, oplist)(EQUAL(M_C(name, _equal_p)),), \ + M_IF_METHOD(HASH, oplist)(HASH(M_C(name, _hash)),) \ + ,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),) \ ) /* Max depth of the binary tree @@ -161,11 +161,11 @@ typedef enum { #define RBTREEI_DEF_P1(arg) RBTREEI_DEF_P2 arg /* Validate the oplist before going further */ -#define RBTREEI_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \ +#define RBTREEI_DEF_P2(name, type, oplist, tree_t, node_t, it_t) \ M_IF_OPLIST(oplist)(RBTREEI_DEF_P3, RBTREEI_DEF_FAILURE)(name, type, oplist, tree_t, node_t, it_t) /* Stop processing with a compilation failure */ -#define RBTREEI_DEF_FAILURE(name, type, oplist, tree_t, note_t, it_t) \ +#define RBTREEI_DEF_FAILURE(name, type, oplist, tree_t, note_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(RBTREE_DEF): the given argument is not a valid oplist: " #oplist) /* Internal rbtree definition @@ -176,976 +176,976 @@ typedef enum { - it_t: alias for the iterator of the container - node_t: alias for the node of an element of the container */ -#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \ - \ - /* Node of Red/Black tree. \ - Each node has up to two child, a color (Red or black) \ - and the data stored in it */ \ - typedef struct M_C(name, _node_s) { \ - struct M_C(name, _node_s) *child[2]; \ - type data; \ - rbtreei_color_e color; \ - } node_t; \ - \ - /* Define the Red/Black tree */ \ - typedef struct M_C(name, _s) { \ - size_t size; /* Number of elements in the tree */ \ - node_t *node; /* Root node of the tree */ \ - } tree_t[1]; \ - typedef struct M_C(name, _s) *M_C(name, _ptr); \ - typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - \ - /* Iterator on a tree. The iterator stores the full path to the \ - current node through all its parents and its depth */ \ - typedef struct M_C(name, _it_s) { \ - node_t *stack[RBTREEI_MAX_STACK]; \ - int8_t which[RBTREEI_MAX_STACK]; \ - unsigned int cpt; \ - } it_t[1]; \ - \ - /* Definition of the alias used by the oplists */ \ - typedef type M_C(name, _subtype_ct); \ - typedef tree_t M_C(name, _ct); \ - typedef it_t M_C(name, _it_ct); \ - \ - /* Link with fast memory allocator if requested */ \ - M_IF_METHOD(MEMPOOL, oplist)( \ - /* Definition of the memory pool of this kind of node */ \ - MEMPOOL_DEF(M_C(name, _mempool), node_t) \ - /* Definition of the global variable used to reference this pool */ \ - M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \ - /* Allocator function */ \ - static inline node_t *M_C(name,_int_new)(void) { \ - return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \ - } \ - /* Deallocator function */ \ - static inline void M_C(name,_int_del)(node_t *ptr) { \ - M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \ - } \ - \ - , /* No mempool allocation */ \ - /* Callic allocator function (common case) */ \ - static inline node_t *M_C(name,_int_new)(void) { \ - return M_CALL_NEW(oplist, node_t); \ - } \ - /* Callic deallocator function (common case) */ \ - static inline void M_C(name,_int_del)(node_t *ptr) { \ - M_CALL_DEL(oplist, ptr); \ - } ) \ - \ - /* Check if the given oplist is compatible with the given type */ \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - \ - /* Generate all functions */ \ +#define RBTREEI_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \ + \ + /* Node of Red/Black tree. \ + Each node has up to two child, a color (Red or black) \ + and the data stored in it */ \ + typedef struct M_C(name, _node_s) { \ + struct M_C(name, _node_s) *child[2]; \ + type data; \ + rbtreei_color_e color; \ + } node_t; \ + \ + /* Define the Red/Black tree */ \ + typedef struct M_C(name, _s) { \ + size_t size; /* Number of elements in the tree */ \ + node_t *node; /* Root node of the tree */ \ + } tree_t[1]; \ + typedef struct M_C(name, _s) *M_C(name, _ptr); \ + typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ + \ + /* Iterator on a tree. The iterator stores the full path to the \ + current node through all its parents and its depth */ \ + typedef struct M_C(name, _it_s) { \ + node_t *stack[RBTREEI_MAX_STACK]; \ + int8_t which[RBTREEI_MAX_STACK]; \ + unsigned int cpt; \ + } it_t[1]; \ + \ + /* Definition of the alias used by the oplists */ \ + typedef type M_C(name, _subtype_ct); \ + typedef tree_t M_C(name, _ct); \ + typedef it_t M_C(name, _it_ct); \ + \ + /* Link with fast memory allocator if requested */ \ + M_IF_METHOD(MEMPOOL, oplist)( \ + /* Definition of the memory pool of this kind of node */ \ + MEMPOOL_DEF(M_C(name, _mempool), node_t) \ + /* Definition of the global variable used to reference this pool */ \ + M_GET_MEMPOOL_LINKAGE oplist M_C(name, _mempool_t) M_GET_MEMPOOL oplist; \ + /* Allocator function */ \ + static inline node_t *M_C(name,_int_new)(void) { \ + return M_C(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \ + } \ + /* Deallocator function */ \ + static inline void M_C(name,_int_del)(node_t *ptr) { \ + M_C(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \ + } \ + \ + , /* No mempool allocation */ \ + /* Callic allocator function (common case) */ \ + static inline node_t *M_C(name,_int_new)(void) { \ + return M_CALL_NEW(oplist, node_t); \ + } \ + /* Callic deallocator function (common case) */ \ + static inline void M_C(name,_int_del)(node_t *ptr) { \ + M_CALL_DEL(oplist, ptr); \ + } ) \ + \ + /* Check if the given oplist is compatible with the given type */ \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + \ + /* Generate all functions */ \ RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t) -#define RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \ - \ - static inline void \ - M_C(name, _init)(tree_t tree) \ - { \ - assert (tree != NULL); \ - tree->size = 0; \ - tree->node = NULL; \ - RBTREEI_CONTRACT(tree); \ - } \ - \ - static inline void \ - M_C(name, _clean)(tree_t tree) \ - { \ - RBTREEI_CONTRACT(tree); \ - node_t *stack[RBTREEI_MAX_STACK]; \ - unsigned int cpt = 0; \ - /* If nothing (no node) nothing to clean: return */ \ - if (tree->node == NULL) return; \ - /* Parse all the tree */ \ - stack[cpt++] = tree->node; \ - while (cpt > 0) { \ - node_t *n = stack[cpt-1]; \ - /* Go down to the bottom left node that exists */ \ - while (true) { \ - RBTREEI_CONTRACT_NODE(n); \ - /* If there is a left child, get it */ \ - if (n->child[0] != NULL) { \ - assert (cpt < RBTREEI_MAX_STACK); \ - stack[cpt++] = n->child[0]; \ - n = n->child[0]; \ - stack[cpt-2]->child[0] = NULL; \ - /* If there is a right child, get it */ \ - } else if (n->child[1] != NULL) { \ - assert (cpt < RBTREEI_MAX_STACK); \ - stack[cpt++] = n->child[1]; \ - n = n->child[1]; \ - stack[cpt-2]->child[1] = NULL; \ - /* No left nor right child, node can be deleted */ \ - } else { \ - break; \ - } \ - } \ - assert (n == stack[cpt - 1]); \ - /* Clear the bottom left node */ \ - M_CALL_CLEAR(oplist, n->data); \ - M_C(name,_int_del) (n); \ - assert((stack[cpt-1] = NULL) == NULL); \ - /* Go up to the parent */ \ - cpt--; \ - } \ - /* Mark the root node as empty */ \ - tree->node = NULL; \ - tree->size = 0; \ - } \ - \ - static inline void \ - M_C(name, _clear)(tree_t tree) \ - { \ - /* Nothing more than clean the tree as everything is cleared */ \ - M_C(name, _clean)(tree); \ - } \ - \ - static inline void \ - M_C(name, _push)(tree_t tree, type const data) \ - { \ - RBTREEI_CONTRACT(tree); \ - node_t *tab[RBTREEI_MAX_STACK]; \ - int8_t which[RBTREEI_MAX_STACK]; \ - unsigned int cpt = 0; \ - node_t *n = tree->node; \ - /* If there is no root node, create a new node */ \ - if (n == NULL) { \ - n = M_C(name,_int_new)(); \ - if (M_UNLIKELY (n == NULL)) { \ - M_MEMORY_FULL(sizeof (node_t)); \ - return; \ - } \ - /* Copy the data in the root node */ \ - M_CALL_INIT_SET(oplist, n->data, data); \ - /* Mark the root node as black */ \ - n->child[0] = n->child[1] = NULL; \ - RBTREEI_SET_BLACK (n); \ - tree->node = n; \ - assert(tree->size == 0); \ - tree->size = 1; \ - RBTREEI_CONTRACT(tree); \ - return; \ - } \ - /* Search for insertion point in the tree */ \ - tab[cpt] = n; \ - while (n != NULL) { \ - RBTREEI_CONTRACT_NODE(n); \ - int cmp = M_CALL_CMP(oplist, n->data, data); \ - if (cmp == 0) { \ - /* key found ==> stop analysis */ \ - break; \ - } else { \ - /* go left (if cmp > 0) or right (if cmp < 0) */ \ - int s = (cmp < 0); \ - which[cpt++] = (int8_t) s; \ - n = n->child[s]; \ - } \ - /* We cannot overflow the max depth of a tree */ \ - assert (cpt < RBTREEI_MAX_STACK); \ - tab[cpt] = n; \ - } \ - /* If found, update the data (default is set) */ \ - if (n != NULL) { \ - /* FIXME: Use of SET method instead of UPDATE ? */ \ - M_IF_METHOD (UPDATE, oplist)(M_CALL_UPDATE(oplist, n->data, data) \ - , M_CALL_SET(oplist, n->data, data)); \ - RBTREEI_CONTRACT (tree); \ - return; \ - } \ - /* Create new node to store the data */ \ - n = M_C(name,_int_new)(); \ - if (M_UNLIKELY (n == NULL) ) { \ - M_MEMORY_FULL (sizeof (node_t)); \ - return; \ - } \ - /* Copy the data and mark the node as red */ \ - M_CALL_INIT_SET(oplist, n->data, data); \ - n->child[0] = n->child[1] = NULL; \ - RBTREEI_SET_RED (n); \ - /* Add it in the iterator */ \ - assert (tab[cpt] == NULL); \ - tab[cpt] = n; \ - /* Add it in the tree */ \ - tree->size ++; \ - assert(tab[cpt-1]->child[0+which[cpt-1]] == NULL); \ - tab[cpt-1]->child[0+which[cpt-1]] = n; \ - /* Fix the tree to still respect the red/back properties */ \ - while (cpt >= 2 \ - && RBTREEI_IS_RED(tab[cpt-1]) \ - && tab[cpt-2]->child[1-which[cpt-2]] != NULL \ - && RBTREEI_IS_RED(tab[cpt-2]->child[1-which[cpt-2]])) { \ - RBTREEI_SET_BLACK(tab[cpt-1]); \ - RBTREEI_SET_BLACK(tab[cpt-2]->child[1-which[cpt-2]]); \ - RBTREEI_SET_RED(tab[cpt-2]); \ - cpt-=2; \ - } \ - /* root is always black */ \ - RBTREEI_SET_BLACK(tab[0]); \ - if (cpt <= 1 || RBTREEI_IS_BLACK(tab[cpt-1])) { \ - RBTREEI_CONTRACT (tree); \ - return; \ - } \ - /* Read the grand-parent, the parent and the element */ \ - node_t *pp = tab[cpt-2]; \ - node_t *p = tab[cpt-1]; \ - node_t *x = tab[cpt]; \ - int i = which[cpt-2]; \ - int j = 1 - i; \ - assert (i == 0 || i == 1); \ - /* We need to do some rotations */ \ - if (i == which[cpt-1]) { \ - /* The child is the left child of its parent */ \ - /* OR The child is the right child of its parent */ \ - /* Right rotation: cpt is the new grand-parent. \ - x is its left child, the grand-parent is the right one */ \ - pp->child[i] = p->child[j]; \ - p->child[i] = x; \ - p->child[j] = pp; \ - RBTREEI_SET_BLACK(p); \ - RBTREEI_SET_RED(pp); \ - } else { \ - assert (j == which[cpt-1]); \ - /* The child is the right child of its parent */ \ - /* OR The child is the left child of its parent */ \ - /* Left rotation */ \ - pp->child[i] = x->child[j]; \ - p->child[j] = x->child[i]; \ - x->child[i] = p; \ - x->child[j] = pp; \ - RBTREEI_SET_BLACK(x); \ - RBTREEI_SET_RED(p); \ - RBTREEI_SET_RED(pp); \ - p = x; \ - } \ - /* Insert the new grand parent */ \ - if (cpt == 2) { \ - tree->node = p; \ - } else { \ - assert (cpt >= 3); \ - tab[cpt-3]->child[which[cpt-3]] = p; \ - } \ - /* Done */ \ - RBTREEI_CONTRACT (tree); \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const tree_t tree) \ - { \ - RBTREEI_CONTRACT (tree); \ - return tree->size; \ - } \ - \ - /* Set the iterator to the first (child=0) or last (child=1) element */ \ - static inline void \ - M_C(name, _int_it)(it_t it, const tree_t tree, int child) \ - { \ - RBTREEI_CONTRACT (tree); \ - assert (it != NULL); \ - assert (child == 0 || child == 1); \ - unsigned int cpt = 0; \ - if (tree->node != NULL) { \ - it->which[cpt] = (int8_t) child; \ - node_t *n = it->stack[cpt++] = tree->node; \ - /* Go down the tree and fill in the iterator */ \ - while (n->child[child] != NULL) { \ - assert (cpt < RBTREEI_MAX_STACK); \ - n = n->child[child]; \ - it->which[cpt] = (int8_t) child; \ - it->stack[cpt++] = n; \ - } \ - assert (n == it->stack[cpt - 1]); \ - } \ - it->cpt = cpt; \ - } \ - \ - static inline void \ - M_C(name, _it)(it_t it, const tree_t tree) \ - { \ - M_C(name, _int_it)(it, tree, 0); \ - } \ - \ - static inline void \ - M_C(name, _it_last)(it_t it, const tree_t tree) \ - { \ - M_C(name,_int_it)(it, tree, 1); \ - } \ - \ - static inline void \ - M_C(name, _it_end)(it_t it, const tree_t tree) \ - { \ - RBTREEI_CONTRACT (tree); \ - assert (it != NULL); \ - it->cpt = 0; \ - } \ - \ - static inline void \ - M_C(name, _it_set)(it_t it, const it_t ref) \ - { \ - assert (it != NULL && ref != NULL); \ - *it = *ref; \ - } \ - \ - static inline bool \ - M_C(name, _end_p)(const it_t it) \ - { \ - assert (it != NULL); \ - return it->cpt == 0; \ - } \ - \ - /* Go to the next (child = 0)or previous element (child = 1) */ \ - static inline void \ - M_C(name, _int_next)(it_t it, int child) \ - { \ - assert (it != NULL); \ - assert (child == 0 || child == 1); \ - if (it->cpt == 0) return; \ - unsigned int cpt = it->cpt - 1; \ - node_t *n = it->stack[cpt]; \ - /* Get the other child */ \ - const int right = 1 ^ child; \ - if (n->child[right] != NULL && it->which[cpt] == child) { \ - /* Going right */ \ - assert (cpt < RBTREEI_MAX_STACK); \ - n = n->child[right]; \ - it->which[cpt++] = (int8_t) right; \ - it->stack[cpt] = n; \ - it->which[cpt++] = (int8_t) child; \ - /* Going left */ \ - while (n->child[child] != NULL) { \ - assert (cpt < RBTREEI_MAX_STACK); \ - n = n->child[child]; \ - it->which[cpt] = (int8_t) child; \ - it->stack[cpt++] = n; \ - } \ - assert (n == it->stack[cpt - 1]); \ - } else { \ - /* Going up */ \ - while (cpt > 0 && it->which[cpt-1] == right) cpt--; \ - } \ - it->cpt = cpt; \ - } \ - \ - static inline void \ - M_C(name, _next)(it_t it) \ - { \ - M_C(name, _int_next)(it, 0); \ - } \ - \ - static inline void \ - M_C(name, _previous)(it_t it) \ - { \ - M_C(name, _int_next)(it, 1); \ - } \ - \ - static inline type * \ - M_C(name, _ref)(const it_t it) \ - { \ - assert(it != NULL && it->cpt > 0); \ - /* NOTE: partially unsafe if the user modify the order of the el */ \ - return &(it->stack[it->cpt-1]->data); \ - } \ - \ - static inline type const * \ - M_C(name, _cref)(const it_t it) \ - { \ - return M_CONST_CAST(type, M_C(name, _ref)(it)); \ - } \ - \ - static inline bool \ - M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ - { \ - assert(it1 != NULL && it2 != NULL); \ - return it1->cpt == it2->cpt \ - && it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]; \ - } \ - \ - \ - static inline void \ - M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \ - { \ - RBTREEI_CONTRACT (tree); \ - assert (it != NULL); \ - unsigned int cpt = 0; \ - node_t *n = tree->node; \ - it->stack[cpt] = n; \ - while (n != NULL) { \ - int cmp = M_CALL_CMP(oplist, n->data, data); \ - if (cmp == 0) \ - break; \ - int child = (cmp < 0); \ - it->which[cpt++] = (int8_t) child; \ - n = n->child[child]; \ - assert (cpt < RBTREEI_MAX_STACK); \ - it->stack[cpt] = n; \ - } \ - it->cpt = cpt; \ - } \ - \ - static inline bool \ - M_C(name, _it_until_p)(it_t it, type const data) \ - { \ - assert (it != NULL); \ - if (it->cpt == 0) return true; \ - assert (it->cpt > 0 && it->cpt < RBTREEI_MAX_STACK); \ - node_t *n = it->stack[it->cpt-1]; \ - int cmp = M_CALL_CMP(oplist, n->data, data); \ - return (cmp >= 0); \ - } \ - \ - static inline bool \ - M_C(name, _it_while_p)(it_t it, type const data) \ - { \ - assert (it != NULL); \ - if (it->cpt == 0) return true; \ - assert (it->cpt > 0 && it->cpt < RBTREEI_MAX_STACK); \ - node_t *n = it->stack[it->cpt-1]; \ - int cmp = M_CALL_CMP(oplist, n->data, data); \ - return (cmp <= 0); \ - } \ - \ - static inline bool M_ATTR_DEPRECATED \ - M_C(name, _it_to_p)(it_t it, type const data) \ - { \ - return M_C(name, _it_until_p)(it, data); \ - } \ - \ - static inline type * \ - M_C(name, _min)(const tree_t tree) \ - { \ - RBTREEI_CONTRACT (tree); \ - node_t *n = tree->node; \ - if (M_UNLIKELY (n == NULL) ) return NULL; \ - while (n->child[0] != NULL) { \ - RBTREEI_CONTRACT_NODE (n); \ - n = n->child[0]; \ - } \ - return &n->data; \ - } \ - \ - static inline type * \ - M_C(name, _max)(const tree_t tree) \ - { \ - RBTREEI_CONTRACT (tree); \ - node_t *n = tree->node; \ - if (M_UNLIKELY (n == NULL) ) return NULL; \ - while (n->child[1] != NULL) { \ - RBTREEI_CONTRACT_NODE (n); \ - n = n->child[1]; \ - } \ - return &n->data; \ - } \ - \ - static inline type const * \ - M_C(name, _cmin)(const tree_t tree) \ - { \ - return M_CONST_CAST(type, M_C(name, _min)(tree)); \ - } \ - \ - static inline type const * \ - M_C(name, _cmax)(const tree_t tree) \ - { \ - return M_CONST_CAST(type, M_C(name, _max)(tree)); \ - } \ - \ - static inline type * \ - M_C(name, _get)(const tree_t tree, type const data) \ - { \ - RBTREEI_CONTRACT (tree); \ - node_t *n = tree->node; \ - /* Go down the tree */ \ - while (n != NULL) { \ - RBTREEI_CONTRACT_NODE (n); \ - int cmp = M_CALL_CMP(oplist, n->data, data); \ - if (cmp == 0) { \ - return &n->data; \ - } else { \ - /* Go left (if cmp > 0) or right (if cmp < 0) */ \ - n = n->child[cmp < 0]; \ - } \ - } \ - return NULL; \ - } \ - \ - static inline type const * \ - M_C(name, _cget)(const tree_t tree, type const data) \ - { \ - return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \ - } \ - \ - /* Create a copy of the given node (recursively) */ \ - static inline node_t * \ - M_C(name, _int_copyn)(const node_t *o) \ - { \ - if (o == NULL) return NULL; \ - node_t *n = M_C(name,_int_new)(); \ - if (M_UNLIKELY (n == NULL) ) { \ - M_MEMORY_FULL (sizeof (node_t)); \ - return NULL; \ - } \ - M_CALL_INIT_SET(oplist, n->data, o->data); \ - n->child[0] = M_C(name, _int_copyn)(o->child[0]); \ - n->child[1] = M_C(name, _int_copyn)(o->child[1]); \ - RBTREEI_COPY_COLOR (n, o); \ - return n; \ - } \ - \ - static inline void \ - M_C(name, _init_set)(tree_t tree, const tree_t ref) \ - { \ - RBTREEI_CONTRACT (ref); \ - assert (tree != NULL && tree != ref); \ - tree->size = ref->size; \ - /* Copy the root node recursively */ \ - tree->node = M_C(name, _int_copyn)(ref->node); \ - RBTREEI_CONTRACT (tree); \ - } \ - \ - static inline void \ - M_C(name, _set)(tree_t tree, const tree_t ref) \ - { \ - RBTREEI_CONTRACT (tree); \ - RBTREEI_CONTRACT (ref); \ - if (tree == ref) return; \ - M_C(name,_clear)(tree); \ - M_C(name,_init_set)(tree, ref); \ - } \ - \ - static inline void \ - M_C(name, _init_move)(tree_t tree, tree_t ref) \ - { \ - RBTREEI_CONTRACT (ref); \ - assert (tree != NULL && tree != ref); \ - tree->size = ref->size; \ - tree->node = ref->node; \ - ref->node = NULL; \ - ref->size = 0; \ - RBTREEI_CONTRACT (tree); \ - } \ - \ - static inline void \ - M_C(name, _move)(tree_t tree, tree_t ref) \ - { \ - RBTREEI_CONTRACT (tree); \ - RBTREEI_CONTRACT (ref); \ - assert (tree != ref); \ - M_C(name,_clear)(tree); \ - M_C(name,_init_move)(tree, ref); \ - RBTREEI_CONTRACT (tree); \ - } \ - \ - static inline void \ - M_C(name, _swap)(tree_t tree1, tree_t tree2) \ - { \ - RBTREEI_CONTRACT (tree1); \ - RBTREEI_CONTRACT (tree2); \ - M_SWAP(size_t, tree1->size, tree2->size); \ - M_SWAP(node_t *, tree1->node, tree2->node); \ - RBTREEI_CONTRACT (tree1); \ - RBTREEI_CONTRACT (tree2); \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(const tree_t tree) \ - { \ - RBTREEI_CONTRACT (tree); \ - return tree->size == 0; \ - } \ - \ - /* Take care of the case n == NULL too */ \ - static inline bool \ - M_C(name, _int_is_black)(const node_t *n) \ - { \ - return (n == NULL) ? true : RBTREEI_IS_BLACK(n); \ - } \ - \ - static inline void \ - M_C(name, _int_set_black)(node_t *n) \ - { \ - if (n != NULL) RBTREEI_SET_BLACK(n); \ - } \ - \ - static inline node_t * \ - M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \ - { \ - assert (pp != NULL && ppp != NULL); \ - bool left = !right; \ - node_t *p = pp->child[right]; \ - assert (p != NULL); \ - pp->child[right] = p->child[left]; \ - p->child[left] = pp; \ - /* Fix grandparent with new parent */ \ - assert(ppp->child[0] == pp || ppp->child[1] == pp); \ - ppp->child[(ppp->child[0] != pp)] = p; \ - return p; \ - } \ - \ - M_IF_DEBUG( \ - /* Compute the depth of a node */ \ - static size_t \ - M_C(name, _int_depth)(const node_t *n) \ - { \ - if (n == NULL) return 1; \ - return RBTREEI_IS_BLACK (n) \ - + M_C(name, _int_depth)(n->child[0]); \ - } \ - ) \ - \ - static inline bool \ - M_C(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \ - { \ - RBTREEI_CONTRACT (tree); \ - node_t *tab[RBTREEI_MAX_STACK]; \ - int8_t which[RBTREEI_MAX_STACK]; \ - unsigned int cpt = 0; \ - node_t *n = tree->node; \ - which[0] = 0; \ - tab[cpt++] = (node_t*) &tree->node; /* FIXME: To clean! */ \ - /* Search for the deletion point */ \ - tab[cpt] = n; \ - while (n != NULL) { \ - RBTREEI_CONTRACT_NODE (n); \ - assert(M_C(name, _int_depth)(n->child[0]) \ - == M_C(name, _int_depth)(n->child[1])); \ - int cmp = M_CALL_CMP(oplist, n->data, key); \ - if (cmp == 0) { \ - break; \ - } \ - int i = (cmp < 0); \ - which[cpt++] = (int8_t) i; \ - n = n->child[i]; \ - assert (cpt < RBTREEI_MAX_STACK); \ - tab[cpt] = n; \ - } \ - assert (tab[cpt] == n); \ - /* If not found, fail */ \ - if (n == NULL) { \ - return false; \ - } \ - unsigned int cpt_n = cpt; \ - node_t *v = n; /* the replacement node */ \ - node_t *u; /* the deleted node */ \ - rbtreei_color_e v_color = RBTREEI_GET_COLOR(v); \ - /* Classical removal of a node from a binary tree */ \ - if (v->child[0] != NULL && v->child[1] != NULL) { \ - /* node has 2 child. */ \ - /* Get the element right next to the deleted one */ \ - v = v->child[1]; \ - which[cpt++] = 1; \ - tab[cpt] = v; \ - while (v != NULL) { \ - /* Always left node */ \ - RBTREEI_CONTRACT_NODE (v); \ - assert(M_C(name, _int_depth)(v->child[0]) \ - == M_C(name, _int_depth)(v->child[1])); \ - which[cpt++] = 0; \ - v = v->child[0]; \ - assert (cpt < RBTREEI_MAX_STACK); \ - tab[cpt] = v; \ - } \ - /* Pop the last element to get the last non-null element */ \ - v = tab[--cpt]; \ - assert (v != NULL); \ - u = v->child[1]; \ - /* Replace 'v' by 'u' in the tree */ \ - assert(tab[cpt-1]->child[which[cpt-1]] == v); \ - tab[cpt-1]->child[which[cpt-1]] = u; \ - /* Replace 'n' by 'v' in the tree */ \ - assert(tab[cpt_n-1] != NULL); \ - assert(tab[cpt_n-1]->child[which[cpt_n-1]] == n); \ - tab[cpt_n-1]->child[which[cpt_n-1]] = v; \ - v->child[0] = n->child[0]; \ - v->child[1] = n->child[1]; \ - v_color = RBTREEI_GET_COLOR(v); \ - RBTREEI_COPY_COLOR(v, n); \ - tab[cpt_n] = v; \ - /* For the algorithm, 'u' is now the deleted node */ \ - } else { \ - /* 1 or no child to the node. Replace the element */ \ - v = n; \ - u = v->child[(n->child[0] == NULL)]; \ - assert (cpt_n >= 1 && tab[cpt_n-1]->child[which[cpt_n-1]] == n); \ - assert (n->child[(n->child[0] != NULL)] == NULL); \ - tab[cpt_n-1]->child[which[cpt_n-1]] = u; \ - /* in all cases, this node shall be set to black */ \ - } \ - \ - /* Rebalance from child to root */ \ - if (v_color == RBTREE_BLACK \ - && M_C(name, _int_is_black)(u)) { \ - /* tab[0] is NULL, tab[1] is root, u is double black */ \ - node_t *p = u, *s; \ - while (cpt >= 2) { \ - p = tab[--cpt]; \ - bool nbChild = which[cpt]; \ - assert (p != NULL && u == p->child[nbChild]); \ - s = p->child[!nbChild]; \ - /* if sibling is red, perform a rotation to move sibling up */ \ - if (!M_C(name, _int_is_black)(s)) { \ - p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \ - RBTREEI_SET_BLACK(p); /* was sibling */ \ - tab[cpt] = p; \ - which[cpt++] = nbChild; \ - p = p->child[nbChild]; /* was parent */ \ - assert (p != NULL); \ - RBTREEI_SET_RED(p); \ - s = p->child[!nbChild]; \ - assert (M_C(name, _int_is_black)(s)); \ - } \ - assert (p != NULL && u == p->child[nbChild]); \ - /* if both childreen of s are black */ \ - /* perform recoloring and recur on parent if black */ \ - if (s != NULL \ - && M_C(name, _int_is_black)(s->child[0]) \ - && M_C(name, _int_is_black)(s->child[1])) { \ +#define RBTREEI_DEF_P4(name, type, oplist, tree_t, node_t, it_t) \ + \ + static inline void \ + M_C(name, _init)(tree_t tree) \ + { \ + assert (tree != NULL); \ + tree->size = 0; \ + tree->node = NULL; \ + RBTREEI_CONTRACT(tree); \ + } \ + \ + static inline void \ + M_C(name, _clean)(tree_t tree) \ + { \ + RBTREEI_CONTRACT(tree); \ + node_t *stack[RBTREEI_MAX_STACK]; \ + unsigned int cpt = 0; \ + /* If nothing (no node) nothing to clean: return */ \ + if (tree->node == NULL) return; \ + /* Parse all the tree */ \ + stack[cpt++] = tree->node; \ + while (cpt > 0) { \ + node_t *n = stack[cpt-1]; \ + /* Go down to the bottom left node that exists */ \ + while (true) { \ + RBTREEI_CONTRACT_NODE(n); \ + /* If there is a left child, get it */ \ + if (n->child[0] != NULL) { \ + assert (cpt < RBTREEI_MAX_STACK); \ + stack[cpt++] = n->child[0]; \ + n = n->child[0]; \ + stack[cpt-2]->child[0] = NULL; \ + /* If there is a right child, get it */ \ + } else if (n->child[1] != NULL) { \ + assert (cpt < RBTREEI_MAX_STACK); \ + stack[cpt++] = n->child[1]; \ + n = n->child[1]; \ + stack[cpt-2]->child[1] = NULL; \ + /* No left nor right child, node can be deleted */ \ + } else { \ + break; \ + } \ + } \ + assert (n == stack[cpt - 1]); \ + /* Clear the bottom left node */ \ + M_CALL_CLEAR(oplist, n->data); \ + M_C(name,_int_del) (n); \ + assert((stack[cpt-1] = NULL) == NULL); \ + /* Go up to the parent */ \ + cpt--; \ + } \ + /* Mark the root node as empty */ \ + tree->node = NULL; \ + tree->size = 0; \ + } \ + \ + static inline void \ + M_C(name, _clear)(tree_t tree) \ + { \ + /* Nothing more than clean the tree as everything is cleared */ \ + M_C(name, _clean)(tree); \ + } \ + \ + static inline void \ + M_C(name, _push)(tree_t tree, type const data) \ + { \ + RBTREEI_CONTRACT(tree); \ + node_t *tab[RBTREEI_MAX_STACK]; \ + int8_t which[RBTREEI_MAX_STACK]; \ + unsigned int cpt = 0; \ + node_t *n = tree->node; \ + /* If there is no root node, create a new node */ \ + if (n == NULL) { \ + n = M_C(name,_int_new)(); \ + if (M_UNLIKELY (n == NULL)) { \ + M_MEMORY_FULL(sizeof (node_t)); \ + return; \ + } \ + /* Copy the data in the root node */ \ + M_CALL_INIT_SET(oplist, n->data, data); \ + /* Mark the root node as black */ \ + n->child[0] = n->child[1] = NULL; \ + RBTREEI_SET_BLACK (n); \ + tree->node = n; \ + assert(tree->size == 0); \ + tree->size = 1; \ + RBTREEI_CONTRACT(tree); \ + return; \ + } \ + /* Search for insertion point in the tree */ \ + tab[cpt] = n; \ + while (n != NULL) { \ + RBTREEI_CONTRACT_NODE(n); \ + int cmp = M_CALL_CMP(oplist, n->data, data); \ + if (cmp == 0) { \ + /* key found ==> stop analysis */ \ + break; \ + } else { \ + /* go left (if cmp > 0) or right (if cmp < 0) */ \ + int s = (cmp < 0); \ + which[cpt++] = (int8_t) s; \ + n = n->child[s]; \ + } \ + /* We cannot overflow the max depth of a tree */ \ + assert (cpt < RBTREEI_MAX_STACK); \ + tab[cpt] = n; \ + } \ + /* If found, update the data (default is set) */ \ + if (n != NULL) { \ + /* FIXME: Use of SET method instead of UPDATE ? */ \ + M_IF_METHOD (UPDATE, oplist)(M_CALL_UPDATE(oplist, n->data, data) \ + , M_CALL_SET(oplist, n->data, data)); \ + RBTREEI_CONTRACT (tree); \ + return; \ + } \ + /* Create new node to store the data */ \ + n = M_C(name,_int_new)(); \ + if (M_UNLIKELY (n == NULL) ) { \ + M_MEMORY_FULL (sizeof (node_t)); \ + return; \ + } \ + /* Copy the data and mark the node as red */ \ + M_CALL_INIT_SET(oplist, n->data, data); \ + n->child[0] = n->child[1] = NULL; \ + RBTREEI_SET_RED (n); \ + /* Add it in the iterator */ \ + assert (tab[cpt] == NULL); \ + tab[cpt] = n; \ + /* Add it in the tree */ \ + tree->size ++; \ + assert(tab[cpt-1]->child[0+which[cpt-1]] == NULL); \ + tab[cpt-1]->child[0+which[cpt-1]] = n; \ + /* Fix the tree to still respect the red/back properties */ \ + while (cpt >= 2 \ + && RBTREEI_IS_RED(tab[cpt-1]) \ + && tab[cpt-2]->child[1-which[cpt-2]] != NULL \ + && RBTREEI_IS_RED(tab[cpt-2]->child[1-which[cpt-2]])) { \ + RBTREEI_SET_BLACK(tab[cpt-1]); \ + RBTREEI_SET_BLACK(tab[cpt-2]->child[1-which[cpt-2]]); \ + RBTREEI_SET_RED(tab[cpt-2]); \ + cpt-=2; \ + } \ + /* root is always black */ \ + RBTREEI_SET_BLACK(tab[0]); \ + if (cpt <= 1 || RBTREEI_IS_BLACK(tab[cpt-1])) { \ + RBTREEI_CONTRACT (tree); \ + return; \ + } \ + /* Read the grand-parent, the parent and the element */ \ + node_t *pp = tab[cpt-2]; \ + node_t *p = tab[cpt-1]; \ + node_t *x = tab[cpt]; \ + int i = which[cpt-2]; \ + int j = 1 - i; \ + assert (i == 0 || i == 1); \ + /* We need to do some rotations */ \ + if (i == which[cpt-1]) { \ + /* The child is the left child of its parent */ \ + /* OR The child is the right child of its parent */ \ + /* Right rotation: cpt is the new grand-parent. \ + x is its left child, the grand-parent is the right one */ \ + pp->child[i] = p->child[j]; \ + p->child[i] = x; \ + p->child[j] = pp; \ + RBTREEI_SET_BLACK(p); \ + RBTREEI_SET_RED(pp); \ + } else { \ + assert (j == which[cpt-1]); \ + /* The child is the right child of its parent */ \ + /* OR The child is the left child of its parent */ \ + /* Left rotation */ \ + pp->child[i] = x->child[j]; \ + p->child[j] = x->child[i]; \ + x->child[i] = p; \ + x->child[j] = pp; \ + RBTREEI_SET_BLACK(x); \ + RBTREEI_SET_RED(p); \ + RBTREEI_SET_RED(pp); \ + p = x; \ + } \ + /* Insert the new grand parent */ \ + if (cpt == 2) { \ + tree->node = p; \ + } else { \ + assert (cpt >= 3); \ + tab[cpt-3]->child[which[cpt-3]] = p; \ + } \ + /* Done */ \ + RBTREEI_CONTRACT (tree); \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const tree_t tree) \ + { \ + RBTREEI_CONTRACT (tree); \ + return tree->size; \ + } \ + \ + /* Set the iterator to the first (child=0) or last (child=1) element */ \ + static inline void \ + M_C(name, _int_it)(it_t it, const tree_t tree, int child) \ + { \ + RBTREEI_CONTRACT (tree); \ + assert (it != NULL); \ + assert (child == 0 || child == 1); \ + unsigned int cpt = 0; \ + if (tree->node != NULL) { \ + it->which[cpt] = (int8_t) child; \ + node_t *n = it->stack[cpt++] = tree->node; \ + /* Go down the tree and fill in the iterator */ \ + while (n->child[child] != NULL) { \ + assert (cpt < RBTREEI_MAX_STACK); \ + n = n->child[child]; \ + it->which[cpt] = (int8_t) child; \ + it->stack[cpt++] = n; \ + } \ + assert (n == it->stack[cpt - 1]); \ + } \ + it->cpt = cpt; \ + } \ + \ + static inline void \ + M_C(name, _it)(it_t it, const tree_t tree) \ + { \ + M_C(name, _int_it)(it, tree, 0); \ + } \ + \ + static inline void \ + M_C(name, _it_last)(it_t it, const tree_t tree) \ + { \ + M_C(name,_int_it)(it, tree, 1); \ + } \ + \ + static inline void \ + M_C(name, _it_end)(it_t it, const tree_t tree) \ + { \ + RBTREEI_CONTRACT (tree); \ + assert (it != NULL); \ + it->cpt = 0; \ + } \ + \ + static inline void \ + M_C(name, _it_set)(it_t it, const it_t ref) \ + { \ + assert (it != NULL && ref != NULL); \ + *it = *ref; \ + } \ + \ + static inline bool \ + M_C(name, _end_p)(const it_t it) \ + { \ + assert (it != NULL); \ + return it->cpt == 0; \ + } \ + \ + /* Go to the next (child = 0)or previous element (child = 1) */ \ + static inline void \ + M_C(name, _int_next)(it_t it, int child) \ + { \ + assert (it != NULL); \ + assert (child == 0 || child == 1); \ + if (it->cpt == 0) return; \ + unsigned int cpt = it->cpt - 1; \ + node_t *n = it->stack[cpt]; \ + /* Get the other child */ \ + const int right = 1 ^ child; \ + if (n->child[right] != NULL && it->which[cpt] == child) { \ + /* Going right */ \ + assert (cpt < RBTREEI_MAX_STACK); \ + n = n->child[right]; \ + it->which[cpt++] = (int8_t) right; \ + it->stack[cpt] = n; \ + it->which[cpt++] = (int8_t) child; \ + /* Going left */ \ + while (n->child[child] != NULL) { \ + assert (cpt < RBTREEI_MAX_STACK); \ + n = n->child[child]; \ + it->which[cpt] = (int8_t) child; \ + it->stack[cpt++] = n; \ + } \ + assert (n == it->stack[cpt - 1]); \ + } else { \ + /* Going up */ \ + while (cpt > 0 && it->which[cpt-1] == right) cpt--; \ + } \ + it->cpt = cpt; \ + } \ + \ + static inline void \ + M_C(name, _next)(it_t it) \ + { \ + M_C(name, _int_next)(it, 0); \ + } \ + \ + static inline void \ + M_C(name, _previous)(it_t it) \ + { \ + M_C(name, _int_next)(it, 1); \ + } \ + \ + static inline type * \ + M_C(name, _ref)(const it_t it) \ + { \ + assert(it != NULL && it->cpt > 0); \ + /* NOTE: partially unsafe if the user modify the order of the el */ \ + return &(it->stack[it->cpt-1]->data); \ + } \ + \ + static inline type const * \ + M_C(name, _cref)(const it_t it) \ + { \ + return M_CONST_CAST(type, M_C(name, _ref)(it)); \ + } \ + \ + static inline bool \ + M_C(name, _it_equal_p)(const it_t it1, const it_t it2) \ + { \ + assert(it1 != NULL && it2 != NULL); \ + return it1->cpt == it2->cpt \ + && it1->stack[it1->cpt-1] == it2->stack[it2->cpt-1]; \ + } \ + \ + \ + static inline void \ + M_C(name, _it_from)(it_t it, const tree_t tree, type const data) \ + { \ + RBTREEI_CONTRACT (tree); \ + assert (it != NULL); \ + unsigned int cpt = 0; \ + node_t *n = tree->node; \ + it->stack[cpt] = n; \ + while (n != NULL) { \ + int cmp = M_CALL_CMP(oplist, n->data, data); \ + if (cmp == 0) \ + break; \ + int child = (cmp < 0); \ + it->which[cpt++] = (int8_t) child; \ + n = n->child[child]; \ + assert (cpt < RBTREEI_MAX_STACK); \ + it->stack[cpt] = n; \ + } \ + it->cpt = cpt; \ + } \ + \ + static inline bool \ + M_C(name, _it_until_p)(it_t it, type const data) \ + { \ + assert (it != NULL); \ + if (it->cpt == 0) return true; \ + assert (it->cpt > 0 && it->cpt < RBTREEI_MAX_STACK); \ + node_t *n = it->stack[it->cpt-1]; \ + int cmp = M_CALL_CMP(oplist, n->data, data); \ + return (cmp >= 0); \ + } \ + \ + static inline bool \ + M_C(name, _it_while_p)(it_t it, type const data) \ + { \ + assert (it != NULL); \ + if (it->cpt == 0) return true; \ + assert (it->cpt > 0 && it->cpt < RBTREEI_MAX_STACK); \ + node_t *n = it->stack[it->cpt-1]; \ + int cmp = M_CALL_CMP(oplist, n->data, data); \ + return (cmp <= 0); \ + } \ + \ + static inline bool M_ATTR_DEPRECATED \ + M_C(name, _it_to_p)(it_t it, type const data) \ + { \ + return M_C(name, _it_until_p)(it, data); \ + } \ + \ + static inline type * \ + M_C(name, _min)(const tree_t tree) \ + { \ + RBTREEI_CONTRACT (tree); \ + node_t *n = tree->node; \ + if (M_UNLIKELY (n == NULL) ) return NULL; \ + while (n->child[0] != NULL) { \ + RBTREEI_CONTRACT_NODE (n); \ + n = n->child[0]; \ + } \ + return &n->data; \ + } \ + \ + static inline type * \ + M_C(name, _max)(const tree_t tree) \ + { \ + RBTREEI_CONTRACT (tree); \ + node_t *n = tree->node; \ + if (M_UNLIKELY (n == NULL) ) return NULL; \ + while (n->child[1] != NULL) { \ + RBTREEI_CONTRACT_NODE (n); \ + n = n->child[1]; \ + } \ + return &n->data; \ + } \ + \ + static inline type const * \ + M_C(name, _cmin)(const tree_t tree) \ + { \ + return M_CONST_CAST(type, M_C(name, _min)(tree)); \ + } \ + \ + static inline type const * \ + M_C(name, _cmax)(const tree_t tree) \ + { \ + return M_CONST_CAST(type, M_C(name, _max)(tree)); \ + } \ + \ + static inline type * \ + M_C(name, _get)(const tree_t tree, type const data) \ + { \ + RBTREEI_CONTRACT (tree); \ + node_t *n = tree->node; \ + /* Go down the tree */ \ + while (n != NULL) { \ + RBTREEI_CONTRACT_NODE (n); \ + int cmp = M_CALL_CMP(oplist, n->data, data); \ + if (cmp == 0) { \ + return &n->data; \ + } else { \ + /* Go left (if cmp > 0) or right (if cmp < 0) */ \ + n = n->child[cmp < 0]; \ + } \ + } \ + return NULL; \ + } \ + \ + static inline type const * \ + M_C(name, _cget)(const tree_t tree, type const data) \ + { \ + return M_CONST_CAST(type, M_C(name, _get)(tree, data)); \ + } \ + \ + /* Create a copy of the given node (recursively) */ \ + static inline node_t * \ + M_C(name, _int_copyn)(const node_t *o) \ + { \ + if (o == NULL) return NULL; \ + node_t *n = M_C(name,_int_new)(); \ + if (M_UNLIKELY (n == NULL) ) { \ + M_MEMORY_FULL (sizeof (node_t)); \ + return NULL; \ + } \ + M_CALL_INIT_SET(oplist, n->data, o->data); \ + n->child[0] = M_C(name, _int_copyn)(o->child[0]); \ + n->child[1] = M_C(name, _int_copyn)(o->child[1]); \ + RBTREEI_COPY_COLOR (n, o); \ + return n; \ + } \ + \ + static inline void \ + M_C(name, _init_set)(tree_t tree, const tree_t ref) \ + { \ + RBTREEI_CONTRACT (ref); \ + assert (tree != NULL && tree != ref); \ + tree->size = ref->size; \ + /* Copy the root node recursively */ \ + tree->node = M_C(name, _int_copyn)(ref->node); \ + RBTREEI_CONTRACT (tree); \ + } \ + \ + static inline void \ + M_C(name, _set)(tree_t tree, const tree_t ref) \ + { \ + RBTREEI_CONTRACT (tree); \ + RBTREEI_CONTRACT (ref); \ + if (tree == ref) return; \ + M_C(name,_clear)(tree); \ + M_C(name,_init_set)(tree, ref); \ + } \ + \ + static inline void \ + M_C(name, _init_move)(tree_t tree, tree_t ref) \ + { \ + RBTREEI_CONTRACT (ref); \ + assert (tree != NULL && tree != ref); \ + tree->size = ref->size; \ + tree->node = ref->node; \ + ref->node = NULL; \ + ref->size = 0; \ + RBTREEI_CONTRACT (tree); \ + } \ + \ + static inline void \ + M_C(name, _move)(tree_t tree, tree_t ref) \ + { \ + RBTREEI_CONTRACT (tree); \ + RBTREEI_CONTRACT (ref); \ + assert (tree != ref); \ + M_C(name,_clear)(tree); \ + M_C(name,_init_move)(tree, ref); \ + RBTREEI_CONTRACT (tree); \ + } \ + \ + static inline void \ + M_C(name, _swap)(tree_t tree1, tree_t tree2) \ + { \ + RBTREEI_CONTRACT (tree1); \ + RBTREEI_CONTRACT (tree2); \ + M_SWAP(size_t, tree1->size, tree2->size); \ + M_SWAP(node_t *, tree1->node, tree2->node); \ + RBTREEI_CONTRACT (tree1); \ + RBTREEI_CONTRACT (tree2); \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(const tree_t tree) \ + { \ + RBTREEI_CONTRACT (tree); \ + return tree->size == 0; \ + } \ + \ + /* Take care of the case n == NULL too */ \ + static inline bool \ + M_C(name, _int_is_black)(const node_t *n) \ + { \ + return (n == NULL) ? true : RBTREEI_IS_BLACK(n); \ + } \ + \ + static inline void \ + M_C(name, _int_set_black)(node_t *n) \ + { \ + if (n != NULL) RBTREEI_SET_BLACK(n); \ + } \ + \ + static inline node_t * \ + M_C(name, _int_rotate)(node_t *pp, node_t *ppp, const bool right) \ + { \ + assert (pp != NULL && ppp != NULL); \ + bool left = !right; \ + node_t *p = pp->child[right]; \ + assert (p != NULL); \ + pp->child[right] = p->child[left]; \ + p->child[left] = pp; \ + /* Fix grandparent with new parent */ \ + assert(ppp->child[0] == pp || ppp->child[1] == pp); \ + ppp->child[(ppp->child[0] != pp)] = p; \ + return p; \ + } \ + \ + M_IF_DEBUG( \ + /* Compute the depth of a node */ \ + static size_t \ + M_C(name, _int_depth)(const node_t *n) \ + { \ + if (n == NULL) return 1; \ + return RBTREEI_IS_BLACK (n) \ + + M_C(name, _int_depth)(n->child[0]); \ + } \ + ) \ + \ + static inline bool \ + M_C(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \ + { \ + RBTREEI_CONTRACT (tree); \ + node_t *tab[RBTREEI_MAX_STACK]; \ + int8_t which[RBTREEI_MAX_STACK]; \ + unsigned int cpt = 0; \ + node_t *n = tree->node; \ + which[0] = 0; \ + tab[cpt++] = (node_t*) &tree->node; /* FIXME: To clean! */ \ + /* Search for the deletion point */ \ + tab[cpt] = n; \ + while (n != NULL) { \ + RBTREEI_CONTRACT_NODE (n); \ + assert(M_C(name, _int_depth)(n->child[0]) \ + == M_C(name, _int_depth)(n->child[1])); \ + int cmp = M_CALL_CMP(oplist, n->data, key); \ + if (cmp == 0) { \ + break; \ + } \ + int i = (cmp < 0); \ + which[cpt++] = (int8_t) i; \ + n = n->child[i]; \ + assert (cpt < RBTREEI_MAX_STACK); \ + tab[cpt] = n; \ + } \ + assert (tab[cpt] == n); \ + /* If not found, fail */ \ + if (n == NULL) { \ + return false; \ + } \ + unsigned int cpt_n = cpt; \ + node_t *v = n; /* the replacement node */ \ + node_t *u; /* the deleted node */ \ + rbtreei_color_e v_color = RBTREEI_GET_COLOR(v); \ + /* Classical removal of a node from a binary tree */ \ + if (v->child[0] != NULL && v->child[1] != NULL) { \ + /* node has 2 child. */ \ + /* Get the element right next to the deleted one */ \ + v = v->child[1]; \ + which[cpt++] = 1; \ + tab[cpt] = v; \ + while (v != NULL) { \ + /* Always left node */ \ + RBTREEI_CONTRACT_NODE (v); \ + assert(M_C(name, _int_depth)(v->child[0]) \ + == M_C(name, _int_depth)(v->child[1])); \ + which[cpt++] = 0; \ + v = v->child[0]; \ + assert (cpt < RBTREEI_MAX_STACK); \ + tab[cpt] = v; \ + } \ + /* Pop the last element to get the last non-null element */ \ + v = tab[--cpt]; \ + assert (v != NULL); \ + u = v->child[1]; \ + /* Replace 'v' by 'u' in the tree */ \ + assert(tab[cpt-1]->child[which[cpt-1]] == v); \ + tab[cpt-1]->child[which[cpt-1]] = u; \ + /* Replace 'n' by 'v' in the tree */ \ + assert(tab[cpt_n-1] != NULL); \ + assert(tab[cpt_n-1]->child[which[cpt_n-1]] == n); \ + tab[cpt_n-1]->child[which[cpt_n-1]] = v; \ + v->child[0] = n->child[0]; \ + v->child[1] = n->child[1]; \ + v_color = RBTREEI_GET_COLOR(v); \ + RBTREEI_COPY_COLOR(v, n); \ + tab[cpt_n] = v; \ + /* For the algorithm, 'u' is now the deleted node */ \ + } else { \ + /* 1 or no child to the node. Replace the element */ \ + v = n; \ + u = v->child[(n->child[0] == NULL)]; \ + assert (cpt_n >= 1 && tab[cpt_n-1]->child[which[cpt_n-1]] == n); \ + assert (n->child[(n->child[0] != NULL)] == NULL); \ + tab[cpt_n-1]->child[which[cpt_n-1]] = u; \ + /* in all cases, this node shall be set to black */ \ + } \ + \ + /* Rebalance from child to root */ \ + if (v_color == RBTREE_BLACK \ + && M_C(name, _int_is_black)(u)) { \ + /* tab[0] is NULL, tab[1] is root, u is double black */ \ + node_t *p = u, *s; \ + while (cpt >= 2) { \ + p = tab[--cpt]; \ + bool nbChild = which[cpt]; \ + assert (p != NULL && u == p->child[nbChild]); \ + s = p->child[!nbChild]; \ + /* if sibling is red, perform a rotation to move sibling up */ \ + if (!M_C(name, _int_is_black)(s)) { \ + p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \ + RBTREEI_SET_BLACK(p); /* was sibling */ \ + tab[cpt] = p; \ + which[cpt++] = nbChild; \ + p = p->child[nbChild]; /* was parent */ \ + assert (p != NULL); \ + RBTREEI_SET_RED(p); \ + s = p->child[!nbChild]; \ + assert (M_C(name, _int_is_black)(s)); \ + } \ + assert (p != NULL && u == p->child[nbChild]); \ + /* if both childreen of s are black */ \ + /* perform recoloring and recur on parent if black */ \ + if (s != NULL \ + && M_C(name, _int_is_black)(s->child[0]) \ + && M_C(name, _int_is_black)(s->child[1])) { \ assert(M_C(name, _int_depth)(s->child[0]) == M_C(name, _int_depth)(s->child[1])); \ - RBTREEI_SET_RED(s); \ - if (RBTREEI_IS_RED(p)) { \ - RBTREEI_SET_BLACK(p); \ - RBTREEI_CONTRACT_NODE(p); \ + RBTREEI_SET_RED(s); \ + if (RBTREEI_IS_RED(p)) { \ + RBTREEI_SET_BLACK(p); \ + RBTREEI_CONTRACT_NODE(p); \ assert(M_C(name, _int_depth)(p->child[0]) == M_C(name, _int_depth)(p->child[1])); \ - break; \ - } \ - u = p; \ - } else { \ - assert (s != NULL); \ - /* at least one child of 's' is red */ \ - /* perform rotation(s) */ \ - bool childIsRight = !M_C(name, _int_is_black)(s->child[1]); \ - rbtreei_color_e p_color = RBTREEI_GET_COLOR (p); \ - if (childIsRight != nbChild) { \ - /* left-left or right-right case */ \ - p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \ - } else { \ - s = M_C(name, _int_rotate) (s, p, childIsRight); \ - p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \ - } \ - RBTREEI_SET_COLOR(p, p_color); \ - assert(p->child[0] != NULL && p->child[1] != NULL); \ - RBTREEI_SET_BLACK(p->child[0]); \ - RBTREEI_SET_BLACK(p->child[1]); \ - RBTREEI_CONTRACT_NODE(p); \ + break; \ + } \ + u = p; \ + } else { \ + assert (s != NULL); \ + /* at least one child of 's' is red */ \ + /* perform rotation(s) */ \ + bool childIsRight = !M_C(name, _int_is_black)(s->child[1]); \ + rbtreei_color_e p_color = RBTREEI_GET_COLOR (p); \ + if (childIsRight != nbChild) { \ + /* left-left or right-right case */ \ + p = M_C(name, _int_rotate) (p, tab[cpt-1], childIsRight); \ + } else { \ + s = M_C(name, _int_rotate) (s, p, childIsRight); \ + p = M_C(name, _int_rotate) (p, tab[cpt-1], !nbChild); \ + } \ + RBTREEI_SET_COLOR(p, p_color); \ + assert(p->child[0] != NULL && p->child[1] != NULL); \ + RBTREEI_SET_BLACK(p->child[0]); \ + RBTREEI_SET_BLACK(p->child[1]); \ + RBTREEI_CONTRACT_NODE(p); \ assert(M_C(name, _int_depth)(p->child[0]) == M_C(name, _int_depth)(p->child[1])); \ - break; \ - } \ - } /* while */ \ - if (cpt == 1 /* root has been reached? */ ) { \ - M_C(name, _int_set_black)(p); \ - assert (tree->node == p); \ - } \ - } else { \ - M_C(name, _int_set_black)(u); \ - } \ - assert (tree->node == NULL || RBTREEI_IS_BLACK(tree->node)); \ - /* delete it */ \ - if (data_ptr != NULL) \ - M_DO_MOVE(oplist, *data_ptr, n->data); \ - else \ - M_CALL_CLEAR(oplist, n->data); \ - M_C(name,_int_del) (n); \ - tree->size --; \ - RBTREEI_CONTRACT (tree); \ - return true; \ - } \ - \ - M_IF_METHOD(EQUAL, oplist)( \ - static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \ - RBTREEI_CONTRACT(t1); \ - RBTREEI_CONTRACT(t2); \ - if (t1->size != t2->size) return false; \ - it_t it1; \ - it_t it2; \ - /* NOTE: We can't compare two tree directly as they can be \ - structuraly different but functionnaly equal (you get this by \ - constructing the tree in a different way). We have to \ - compare the ordered value within the tree. */ \ - M_C(name, _it)(it1, t1); \ - M_C(name, _it)(it2, t2); \ - while (!M_C(name, _end_p)(it1) \ - && !M_C(name, _end_p)(it2)) { \ - type const *ref1 = M_C(name, _cref)(it1); \ - type const *ref2 = M_C(name, _cref)(it2); \ - if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \ - return false; \ - M_C(name, _next)(it1); \ - M_C(name, _next)(it2); \ - } \ - return M_C(name, _end_p)(it1) \ - && M_C(name, _end_p)(it2); \ - } \ - , /* NO EQUAL METHOD */ ) \ - \ - M_IF_METHOD(HASH, oplist)( \ - static inline size_t M_C(name,_hash)(const tree_t t1) { \ - RBTREEI_CONTRACT(t1); \ - M_HASH_DECL(hash); \ - /* NOTE: We can't compute the hash directly for the same reason \ - than for EQUAL operator. */ \ - it_t it1; \ - M_C(name, _it)(it1, t1); \ - while (!M_C(name, _end_p)(it1)) { \ - type const *ref1 = M_C(name, _cref)(it1); \ - M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \ - M_C(name, _next)(it1); \ - } \ - return M_HASH_FINAL (hash); \ - } \ - , /* NO HASH METHOD */ ) \ - \ - M_IF_METHOD(GET_STR, oplist)( \ - static inline void M_C(name, _get_str)(string_t str, \ + break; \ + } \ + } /* while */ \ + if (cpt == 1 /* root has been reached? */ ) { \ + M_C(name, _int_set_black)(p); \ + assert (tree->node == p); \ + } \ + } else { \ + M_C(name, _int_set_black)(u); \ + } \ + assert (tree->node == NULL || RBTREEI_IS_BLACK(tree->node)); \ + /* delete it */ \ + if (data_ptr != NULL) \ + M_DO_MOVE(oplist, *data_ptr, n->data); \ + else \ + M_CALL_CLEAR(oplist, n->data); \ + M_C(name,_int_del) (n); \ + tree->size --; \ + RBTREEI_CONTRACT (tree); \ + return true; \ + } \ + \ + M_IF_METHOD(EQUAL, oplist)( \ + static inline bool M_C(name,_equal_p)(const tree_t t1, const tree_t t2) { \ + RBTREEI_CONTRACT(t1); \ + RBTREEI_CONTRACT(t2); \ + if (t1->size != t2->size) return false; \ + it_t it1; \ + it_t it2; \ + /* NOTE: We can't compare two tree directly as they can be \ + structuraly different but functionnaly equal (you get this by \ + constructing the tree in a different way). We have to \ + compare the ordered value within the tree. */ \ + M_C(name, _it)(it1, t1); \ + M_C(name, _it)(it2, t2); \ + while (!M_C(name, _end_p)(it1) \ + && !M_C(name, _end_p)(it2)) { \ + type const *ref1 = M_C(name, _cref)(it1); \ + type const *ref2 = M_C(name, _cref)(it2); \ + if (M_CALL_EQUAL(oplist, *ref1, *ref2) == false) \ + return false; \ + M_C(name, _next)(it1); \ + M_C(name, _next)(it2); \ + } \ + return M_C(name, _end_p)(it1) \ + && M_C(name, _end_p)(it2); \ + } \ + , /* NO EQUAL METHOD */ ) \ + \ + M_IF_METHOD(HASH, oplist)( \ + static inline size_t M_C(name,_hash)(const tree_t t1) { \ + RBTREEI_CONTRACT(t1); \ + M_HASH_DECL(hash); \ + /* NOTE: We can't compute the hash directly for the same reason \ + than for EQUAL operator. */ \ + it_t it1; \ + M_C(name, _it)(it1, t1); \ + while (!M_C(name, _end_p)(it1)) { \ + type const *ref1 = M_C(name, _cref)(it1); \ + M_HASH_UP(hash, M_CALL_HASH(oplist, *ref1)); \ + M_C(name, _next)(it1); \ + } \ + return M_HASH_FINAL (hash); \ + } \ + , /* NO HASH METHOD */ ) \ + \ + M_IF_METHOD(GET_STR, oplist)( \ + static inline void M_C(name, _get_str)(string_t str, \ tree_t const t1, bool append) { \ - RBTREEI_CONTRACT(t1); \ - assert(str != NULL); \ - (append ? string_cat_str : string_set_str) (str, "["); \ - /* NOTE: The print is really naive, and not really efficient */ \ - bool commaToPrint = false; \ - it_t it1; \ - M_C(name, _it)(it1, t1); \ - while (!M_C(name, _end_p)(it1)) { \ - if (commaToPrint) \ - string_push_back (str, M_GET_SEPARATOR oplist); \ - commaToPrint = true; \ - type const *ref1 = M_C(name, _cref)(it1); \ - M_CALL_GET_STR(oplist, str, *ref1, true); \ - M_C(name, _next)(it1); \ - } \ - string_push_back (str, ']'); \ - } \ - , /* NO GET_STR */ ) \ - \ - M_IF_METHOD(OUT_STR, oplist)( \ - static inline void \ - M_C(name, _out_str)(FILE *file, tree_t const rbtree) \ - { \ - RBTREEI_CONTRACT(rbtree); \ - assert (file != NULL); \ - fputc ('[', file); \ - it_t it; \ - bool commaToPrint = false; \ - for (M_C(name, _it)(it, rbtree) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - if (commaToPrint) \ - fputc (M_GET_SEPARATOR oplist, file); \ - commaToPrint = true; \ - type const *item = M_C(name, _cref)(it); \ - M_CALL_OUT_STR(oplist, file, *item); \ - } \ - fputc (']', file); \ - } \ - , /* no out_str */ ) \ - \ - M_IF_METHOD(PARSE_STR, oplist)( \ - static inline bool \ - M_C(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \ - { \ - RBTREEI_CONTRACT(rbtree); \ - assert (str != NULL); \ - M_C(name,_clean)(rbtree); \ - bool success = false; \ - int c = *str++; \ - if (M_UNLIKELY (c != '[')) goto exit; \ - c = *str++; \ - if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \ - if (M_UNLIKELY (c == 0)) goto exit; \ - str--; \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ - do { c = *str++; } while (isspace(c)); \ - if (b == false || c == 0) goto exit_clear; \ - M_C(name, _push)(rbtree, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - success = (c == ']'); \ - exit_clear: \ - M_CALL_CLEAR(oplist, item); \ - exit: \ - if (endp) *endp = str; \ - return success; \ - } \ - , /* no parse_str */ ) \ - \ - M_IF_METHOD(IN_STR, oplist)( \ - static inline bool \ - M_C(name, _in_str)(tree_t rbtree, FILE *file) \ - { \ - RBTREEI_CONTRACT(rbtree); \ - assert (file != NULL); \ - M_C(name,_clean)(rbtree); \ - int c = fgetc(file); \ - if (M_UNLIKELY (c != '[')) return false; \ - c = fgetc(file); \ - if (M_UNLIKELY (c == ']')) return true; \ - if (M_UNLIKELY (c == EOF)) return false; \ - ungetc(c, file); \ - type item; \ - M_CALL_INIT(oplist, item); \ - do { \ - bool b = M_CALL_IN_STR(oplist, item, file); \ - do { c = fgetc(file); } while (isspace(c)); \ - if (b == false || c == EOF) break; \ - M_C(name, _push)(rbtree, item); \ - } while (c == M_GET_SEPARATOR oplist); \ - M_CALL_CLEAR(oplist, item); \ - return c == ']'; \ - } \ - , /* no in_str */ ) \ - \ - M_IF_METHOD(OUT_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ - { \ - RBTREEI_CONTRACT(t1); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - M_C(name, _subtype_ct) const *item; \ - bool first_done = false; \ - it_t it; \ - ret = f->m_interface->write_array_start(local, f, t1->size); \ - for (M_C(name, _it)(it, t1) ; \ - !M_C(name, _end_p)(it); \ - M_C(name, _next)(it)){ \ - item = M_C(name, _cref)(it); \ - if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ - ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ - first_done = true; \ - } \ - ret |= f->m_interface->write_array_end(local, f); \ - return ret & M_SERIAL_FAIL; \ - } \ - , /* no OUT_SERIAL */ ) \ - \ - M_IF_METHOD(IN_SERIAL, oplist)( \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \ - { \ - RBTREEI_CONTRACT(t1); \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - size_t estimated_size = 0; \ - type key; \ - M_C(name,_clean)(t1); \ - ret = f->m_interface->read_array_start(local, f, &estimated_size); \ - if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ - M_CALL_INIT(oplist, key); \ - do { \ - ret = M_CALL_IN_SERIAL(oplist, key, f); \ - if (ret != M_SERIAL_OK_DONE) { break; } \ - M_C(name, _push)(t1, key); \ + RBTREEI_CONTRACT(t1); \ + assert(str != NULL); \ + (append ? string_cat_str : string_set_str) (str, "["); \ + /* NOTE: The print is really naive, and not really efficient */ \ + bool commaToPrint = false; \ + it_t it1; \ + M_C(name, _it)(it1, t1); \ + while (!M_C(name, _end_p)(it1)) { \ + if (commaToPrint) \ + string_push_back (str, M_GET_SEPARATOR oplist); \ + commaToPrint = true; \ + type const *ref1 = M_C(name, _cref)(it1); \ + M_CALL_GET_STR(oplist, str, *ref1, true); \ + M_C(name, _next)(it1); \ + } \ + string_push_back (str, ']'); \ + } \ + , /* NO GET_STR */ ) \ + \ + M_IF_METHOD(OUT_STR, oplist)( \ + static inline void \ + M_C(name, _out_str)(FILE *file, tree_t const rbtree) \ + { \ + RBTREEI_CONTRACT(rbtree); \ + assert (file != NULL); \ + fputc ('[', file); \ + it_t it; \ + bool commaToPrint = false; \ + for (M_C(name, _it)(it, rbtree) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + if (commaToPrint) \ + fputc (M_GET_SEPARATOR oplist, file); \ + commaToPrint = true; \ + type const *item = M_C(name, _cref)(it); \ + M_CALL_OUT_STR(oplist, file, *item); \ + } \ + fputc (']', file); \ + } \ + , /* no out_str */ ) \ + \ + M_IF_METHOD(PARSE_STR, oplist)( \ + static inline bool \ + M_C(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \ + { \ + RBTREEI_CONTRACT(rbtree); \ + assert (str != NULL); \ + M_C(name,_clean)(rbtree); \ + bool success = false; \ + int c = *str++; \ + if (M_UNLIKELY (c != '[')) goto exit; \ + c = *str++; \ + if (M_UNLIKELY (c == ']')) { success = true; goto exit; } \ + if (M_UNLIKELY (c == 0)) goto exit; \ + str--; \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ + do { c = *str++; } while (isspace(c)); \ + if (b == false || c == 0) goto exit_clear; \ + M_C(name, _push)(rbtree, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + success = (c == ']'); \ + exit_clear: \ + M_CALL_CLEAR(oplist, item); \ + exit: \ + if (endp) *endp = str; \ + return success; \ + } \ + , /* no parse_str */ ) \ + \ + M_IF_METHOD(IN_STR, oplist)( \ + static inline bool \ + M_C(name, _in_str)(tree_t rbtree, FILE *file) \ + { \ + RBTREEI_CONTRACT(rbtree); \ + assert (file != NULL); \ + M_C(name,_clean)(rbtree); \ + int c = fgetc(file); \ + if (M_UNLIKELY (c != '[')) return false; \ + c = fgetc(file); \ + if (M_UNLIKELY (c == ']')) return true; \ + if (M_UNLIKELY (c == EOF)) return false; \ + ungetc(c, file); \ + type item; \ + M_CALL_INIT(oplist, item); \ + do { \ + bool b = M_CALL_IN_STR(oplist, item, file); \ + do { c = fgetc(file); } while (isspace(c)); \ + if (b == false || c == EOF) break; \ + M_C(name, _push)(rbtree, item); \ + } while (c == M_GET_SEPARATOR oplist); \ + M_CALL_CLEAR(oplist, item); \ + return c == ']'; \ + } \ + , /* no in_str */ ) \ + \ + M_IF_METHOD(OUT_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ + { \ + RBTREEI_CONTRACT(t1); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + M_C(name, _subtype_ct) const *item; \ + bool first_done = false; \ + it_t it; \ + ret = f->m_interface->write_array_start(local, f, t1->size); \ + for (M_C(name, _it)(it, t1) ; \ + !M_C(name, _end_p)(it); \ + M_C(name, _next)(it)){ \ + item = M_C(name, _cref)(it); \ + if (first_done) \ + ret |= f->m_interface->write_array_next(local, f); \ + ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ + first_done = true; \ + } \ + ret |= f->m_interface->write_array_end(local, f); \ + return ret & M_SERIAL_FAIL; \ + } \ + , /* no OUT_SERIAL */ ) \ + \ + M_IF_METHOD(IN_SERIAL, oplist)( \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \ + { \ + RBTREEI_CONTRACT(t1); \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + size_t estimated_size = 0; \ + type key; \ + M_C(name,_clean)(t1); \ + ret = f->m_interface->read_array_start(local, f, &estimated_size); \ + if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ + M_CALL_INIT(oplist, key); \ + do { \ + ret = M_CALL_IN_SERIAL(oplist, key, f); \ + if (ret != M_SERIAL_OK_DONE) { break; } \ + M_C(name, _push)(t1, key); \ } while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \ - M_CALL_CLEAR(oplist, key); \ - return ret; \ - } \ - , /* no in_serial */ ) \ - \ - \ + M_CALL_CLEAR(oplist, key); \ + return ret; \ + } \ + , /* no in_serial */ ) \ + \ + \ // TODO: specialized _sort shall do nothing, but shall check the requested order. How ? diff --git a/m-serial-json.h b/m-serial-json.h index 9410cc7d..a1968d07 100644 --- a/m-serial-json.h +++ b/m-serial-json.h @@ -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 diff --git a/m-shared.h b/m-shared.h index 21c36d62..4a9226a9 100644 --- a/m-shared.h +++ b/m-shared.h @@ -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 diff --git a/m-snapshot.h b/m-snapshot.h index 80f84603..287b0a4d 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -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 diff --git a/m-string.h b/m-string.h index 6c1d1e59..4b6bb969 100644 --- a/m-string.h +++ b/m-string.h @@ -47,11 +47,11 @@ M_BEGIN_PROTECTED_CODE // This macro defines the contract of a string. // Note: A ==> B is represented as not(A) or B // Note: use of strlen can slow down a lot the program in some cases. -#define STRINGI_CONTRACT(v) do { \ - M_ASSUME (v != NULL); \ - STRINGI_ASSUME (string_size(v) == strlen(string_get_cstr(v))); \ - M_ASSUME (string_get_cstr(v)[string_size(v)] == 0); \ - M_ASSUME (string_size(v) < string_capacity(v)); \ +#define STRINGI_CONTRACT(v) do { \ + M_ASSUME (v != NULL); \ + STRINGI_ASSUME (string_size(v) == strlen(string_get_cstr(v))); \ + M_ASSUME (string_get_cstr(v)[string_size(v)] == 0); \ + M_ASSUME (string_size(v) < string_capacity(v)); \ M_ASSUME (string_capacity(v) < sizeof (string_heap_ct) || !stringi_stack_p(v)); \ } while(0) @@ -1309,11 +1309,11 @@ typedef unsigned int string_unicode_t; */ /* The use of a string enables the compiler/linker to factorize it. */ -#define STRINGI_UTF8_STATE_TAB \ - "\000\040\010\020\030\040\040\040" \ - "\040\000\040\040\040\040\040\040" \ - "\040\010\040\040\040\040\040\040" \ - "\040\020\040\040\040\040\040\040" \ +#define STRINGI_UTF8_STATE_TAB \ + "\000\040\010\020\030\040\040\040" \ + "\040\000\040\040\040\040\040\040" \ + "\040\010\040\040\040\040\040\040" \ + "\040\020\040\040\040\040\040\040" \ "\040\040\040\040\040\040\040\040" /* Main generic UTF8 decoder @@ -1522,50 +1522,50 @@ string_utf8_p(string_t str) /* Define the split & the join functions in case of usage with the algorithm module */ -#define STRING_SPLIT(name, oplist, type_oplist) \ - static inline void M_C(name, _split)(M_GET_TYPE oplist cont, \ - const string_t str, const char sep) \ - { \ - size_t begin = 0; \ - string_t tmp; \ - size_t size = string_size(str); \ - string_init(tmp); \ - M_CALL_CLEAN(oplist, cont); \ - for(size_t i = 0 ; i < size; i++) { \ - char c = string_get_char(str, i); \ - if (c == sep) { \ - string_set_strn(tmp, &string_get_cstr(str)[begin], i - begin); \ - /* If push move method is available, use it */ \ - M_IF_METHOD(PUSH_MOVE,oplist)( \ - M_CALL_PUSH_MOVE(oplist, cont, &tmp); \ - string_init(tmp); \ - , \ - M_CALL_PUSH(oplist, cont, tmp); \ - ) \ - begin = i + 1; \ - } \ - } \ - string_set_strn(tmp, &string_get_cstr(str)[begin], size - begin); \ - M_CALL_PUSH(oplist, cont, tmp); \ - /* HACK: if method reverse is defined, it is likely that we have */ \ - /* inserted the items in the wrong order (aka for a list) */ \ - M_IF_METHOD(REVERSE, oplist) (M_CALL_REVERSE(oplist, cont);, ) \ - string_clear(tmp); \ - } \ - \ - static inline void M_C(name, _join)(string_t dst, M_GET_TYPE oplist cont, \ - const string_t str) \ - { \ - bool init_done = false; \ - string_clean (dst); \ - for M_EACH(item, cont, oplist) { \ - if (init_done) { \ - string_cat(dst, str); \ - } \ - string_cat (dst, *item); \ - init_done = true; \ - } \ - } \ +#define STRING_SPLIT(name, oplist, type_oplist) \ + static inline void M_C(name, _split)(M_GET_TYPE oplist cont, \ + const string_t str, const char sep) \ + { \ + size_t begin = 0; \ + string_t tmp; \ + size_t size = string_size(str); \ + string_init(tmp); \ + M_CALL_CLEAN(oplist, cont); \ + for(size_t i = 0 ; i < size; i++) { \ + char c = string_get_char(str, i); \ + if (c == sep) { \ + string_set_strn(tmp, &string_get_cstr(str)[begin], i - begin); \ + /* If push move method is available, use it */ \ + M_IF_METHOD(PUSH_MOVE,oplist)( \ + M_CALL_PUSH_MOVE(oplist, cont, &tmp); \ + string_init(tmp); \ + , \ + M_CALL_PUSH(oplist, cont, tmp); \ + ) \ + begin = i + 1; \ + } \ + } \ + string_set_strn(tmp, &string_get_cstr(str)[begin], size - begin); \ + M_CALL_PUSH(oplist, cont, tmp); \ + /* HACK: if method reverse is defined, it is likely that we have */ \ + /* inserted the items in the wrong order (aka for a list) */ \ + M_IF_METHOD(REVERSE, oplist) (M_CALL_REVERSE(oplist, cont);, ) \ + string_clear(tmp); \ + } \ + \ + static inline void M_C(name, _join)(string_t dst, M_GET_TYPE oplist cont, \ + const string_t str) \ + { \ + bool init_done = false; \ + string_clean (dst); \ + for M_EACH(item, cont, oplist) { \ + if (init_done) { \ + string_cat(dst, str); \ + } \ + string_cat (dst, *item); \ + init_done = true; \ + } \ + } \ /* Use of Compound Literals to init a constant string. @@ -1573,8 +1573,8 @@ string_utf8_p(string_t str) that the pointer to char is properly aligned to an int (this is a needed asumption by string_hash). Otherwise it could have been : - #define STRING_CTE(s) \ - ((const string_t){{.size = sizeof(s)-1, .alloc = sizeof(s), \ + #define STRING_CTE(s) \ + ((const string_t){{.size = sizeof(s)-1, .alloc = sizeof(s), \ .ptr = s}}) which produces faster code. Note: This code doesn't work with C++ (use of c99 feature @@ -1583,8 +1583,8 @@ string_utf8_p(string_t str) */ #ifndef __cplusplus /* Initialize a constant string with the given C string */ -# define STRING_CTE(s) \ - ((const string_t){{.u.heap = { .size = sizeof(s)-1, .alloc = sizeof(s) } , \ +# define STRING_CTE(s) \ + ((const string_t){{.u.heap = { .size = sizeof(s)-1, .alloc = sizeof(s) } , \ .ptr = ((struct { long long _n; char _d[sizeof (s)]; }){ 0, s })._d }}) #else namespace m_string { @@ -1605,12 +1605,12 @@ namespace m_string { }; } /* Initialize a constant string with the given C string (C++ mode) */ -#define STRING_CTE(s) \ +#define STRING_CTE(s) \ m_string::m_aligned_string(s).string #endif /* Initialize and set a string to the given formatted value. */ -#define STRINGI_INIT_PRINTF(v, ...) \ +#define STRINGI_INIT_PRINTF(v, ...) \ (string_init (v), string_printf (v, __VA_ARGS__) ) /* Initialize a string with the given list of arguments. @@ -1620,46 +1620,46 @@ namespace m_string { In C11 mode, it uses the fact that string_init_set is overloaded to handle both C string and string. */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) -#define STRINGI_INIT_WITH(v, ...) \ +#define STRINGI_INIT_WITH(v, ...) \ M_IF_NARGS_EQ1(__VA_ARGS__)(string_init_set, STRINGI_INIT_PRINTF)(v, __VA_ARGS__) #else -#define STRINGI_INIT_WITH(v, ...) \ +#define STRINGI_INIT_WITH(v, ...) \ M_IF_NARGS_EQ1(__VA_ARGS__)(string_init_set_str, STRINGI_INIT_PRINTF)(v, __VA_ARGS__) #endif /* NOTE: Use GCC extension (OBSOLETE) */ -#define STRING_DECL_INIT(v) \ +#define STRING_DECL_INIT(v) \ string_t v __attribute__((cleanup(stringi_clear2))) = {{ 0, 0, NULL}} /* NOTE: Use GCC extension (OBSOLETE) */ -#define STRING_DECL_INIT_PRINTF(v, format, ...) \ - STRING_DECL_INIT(v); \ +#define STRING_DECL_INIT_PRINTF(v, format, ...) \ + STRING_DECL_INIT(v); \ string_printf (v, format, __VA_ARGS__) /* Define the OPLIST of a STRING */ -#define STRING_OPLIST \ - (INIT(string_init),INIT_SET(string_init_set), SET(string_set), \ - INIT_WITH(STRINGI_INIT_WITH), \ - INIT_MOVE(string_init_move), MOVE(string_move), \ - SWAP(string_swap), CLEAN(string_clean), \ - TEST_EMPTY(string_empty_p), \ - CLEAR(string_clear), HASH(string_hash), EQUAL(string_equal_p), \ - CMP(string_cmp), TYPE(string_t), \ - PARSE_STR(string_parse_str), GET_STR(string_get_str), \ - OUT_STR(string_out_str), IN_STR(string_in_str), \ - OUT_SERIAL(string_out_serial), IN_SERIAL(string_in_serial), \ - EXT_ALGO(STRING_SPLIT), \ - OOR_EQUAL(string_oor_equal_p), OOR_SET(string_oor_set) \ - ,SUBTYPE(string_unicode_t) \ - ,IT_TYPE(string_it_t) \ - ,IT_FIRST(string_it) \ - ,IT_END(string_it_end) \ - ,IT_SET(string_it_set) \ - ,IT_END_P(string_end_p) \ - ,IT_EQUAL_P(string_it_equal_p) \ - ,IT_NEXT(string_next) \ - ,IT_CREF(string_cref) \ +#define STRING_OPLIST \ + (INIT(string_init),INIT_SET(string_init_set), SET(string_set), \ + INIT_WITH(STRINGI_INIT_WITH), \ + INIT_MOVE(string_init_move), MOVE(string_move), \ + SWAP(string_swap), CLEAN(string_clean), \ + TEST_EMPTY(string_empty_p), \ + CLEAR(string_clear), HASH(string_hash), EQUAL(string_equal_p), \ + CMP(string_cmp), TYPE(string_t), \ + PARSE_STR(string_parse_str), GET_STR(string_get_str), \ + OUT_STR(string_out_str), IN_STR(string_in_str), \ + OUT_SERIAL(string_out_serial), IN_SERIAL(string_in_serial), \ + EXT_ALGO(STRING_SPLIT), \ + OOR_EQUAL(string_oor_equal_p), OOR_SET(string_oor_set) \ + ,SUBTYPE(string_unicode_t) \ + ,IT_TYPE(string_it_t) \ + ,IT_FIRST(string_it) \ + ,IT_END(string_it_end) \ + ,IT_SET(string_it_set) \ + ,IT_END_P(string_end_p) \ + ,IT_EQUAL_P(string_it_equal_p) \ + ,IT_NEXT(string_next) \ + ,IT_CREF(string_cref) \ ) /* Register the OPLIST as a global one */ @@ -1669,35 +1669,35 @@ namespace m_string { /* Macro encapsulation to give a default value of 0 for start offset */ /* Search for a character in a string (string, character[, start=0]) */ -#define string_search_char(v, ...) \ +#define string_search_char(v, ...) \ M_APPLY(string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Reverse Search for a character in a string (string, character[, start=0]) */ -#define string_search_rchar(v, ...) \ +#define string_search_rchar(v, ...) \ M_APPLY(string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Search for a C string in a string (string, c_string[, start=0]) */ -#define string_search_str(v, ...) \ +#define string_search_str(v, ...) \ M_APPLY(string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Search for a string in a string (string, string[, start=0]) */ -#define string_search(v, ...) \ +#define string_search(v, ...) \ M_APPLY(string_search, v, M_IF_DEFAULT1(0, __VA_ARGS__)) /* PBRK for a string in a string (string, string[, start=0]) */ -#define string_search_pbrk(v, ...) \ +#define string_search_pbrk(v, ...) \ M_APPLY(string_search_pbrk, v, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Replace a C string to another C string in a string (string, c_src_string, c_dst_string, [, start=0]) */ -#define string_replace_str(v, s1, ...) \ +#define string_replace_str(v, s1, ...) \ M_APPLY(string_replace_str, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Replace a string to another string in a string (string, src_string, dst_string, [, start=0]) */ -#define string_replace(v, s1, ...) \ +#define string_replace(v, s1, ...) \ M_APPLY(string_replace, v, s1, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Strim a string from the given set of characters (default is " \n\r\t") */ -#define string_strim(...) \ +#define string_strim(...) \ M_APPLY(string_strim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__)) /* Macro encapsulation for C11 */ @@ -1706,17 +1706,17 @@ namespace m_string { /* Select either the string function or the str function depending on the b operade to the function. func1 is the string function / func2 is the str function. */ -# define STRINGI_SELECT2(func1,func2,a,b) \ - _Generic((b)+0, \ - char*: func2, \ - const char *: func2, \ - default : func1 \ +# define STRINGI_SELECT2(func1,func2,a,b) \ + _Generic((b)+0, \ + char*: func2, \ + const char *: func2, \ + default : func1 \ )(a,b) -# define STRINGI_SELECT3(func1,func2,a,b,c) \ - _Generic((b)+0, \ - char*: func2, \ - const char *: func2, \ - default : func1 \ +# define STRINGI_SELECT3(func1,func2,a,b,c) \ + _Generic((b)+0, \ + char*: func2, \ + const char *: func2, \ + default : func1 \ )(a,b,c) /* Init & Set the string a to the string (or C string) b (constructor) */ @@ -1739,8 +1739,8 @@ namespace m_string { #undef string_search /* Search for a string in a string (or C string) (string, string[, start=0]) */ -#define string_search(v, ...) \ - M_APPLY(STRINGI_SELECT3, string_search, string_search_str, \ +#define string_search(v, ...) \ + M_APPLY(STRINGI_SELECT3, string_search, string_search_str, \ v, M_IF_DEFAULT1(0, __VA_ARGS__)) /* Internal Macro: Provide GET_STR method to default type */ @@ -1764,372 +1764,372 @@ namespace m_string { /* Define a bounded (fixed) string of exactly 'max_size' characters * (excluding the final nul char). */ -#define BOUNDED_STRING_DEF(name, max_size) \ - M_BEGIN_PROTECTED_CODE \ - BOUNDED_STRING_DEF_P2(name, max_size, M_C(name, _t) ) \ +#define BOUNDED_STRING_DEF(name, max_size) \ + M_BEGIN_PROTECTED_CODE \ + BOUNDED_STRING_DEF_P2(name, max_size, M_C(name, _t) ) \ M_END_PROTECTED_CODE /* Define the OPLIST of a BOUNDED_STRING */ -#define BOUNDED_STRING_OPLIST(name) \ - (INIT(M_C(name,_init)), \ - INIT_SET(M_C(name,_init_set)), \ - SET(M_C(name,_set)), \ - CLEAR(M_C(name,_clear)), \ - HASH(M_C(name,_hash)), \ - EQUAL(M_C(name,_equal_p)), \ - CMP(M_C(name,_cmp)), \ - TYPE(M_C(name,_ct)), \ - OOR_EQUAL(M_C(name,_oor_equal_p)), \ - OOR_SET(M_C(name, _oor_set)), \ - PARSE_STR(M_C(name,_parse_str)), \ - GET_STR(M_C(name,_get_str)), \ - OUT_STR(M_C(name,_out_str)), \ - IN_STR(M_C(name,_in_str)), \ - OUT_SERIAL(M_C(name,_out_serial)), \ - IN_SERIAL(M_C(name,_in_serial)), \ +#define BOUNDED_STRING_OPLIST(name) \ + (INIT(M_C(name,_init)), \ + INIT_SET(M_C(name,_init_set)), \ + SET(M_C(name,_set)), \ + CLEAR(M_C(name,_clear)), \ + HASH(M_C(name,_hash)), \ + EQUAL(M_C(name,_equal_p)), \ + CMP(M_C(name,_cmp)), \ + TYPE(M_C(name,_ct)), \ + OOR_EQUAL(M_C(name,_oor_equal_p)), \ + OOR_SET(M_C(name, _oor_set)), \ + PARSE_STR(M_C(name,_parse_str)), \ + GET_STR(M_C(name,_get_str)), \ + OUT_STR(M_C(name,_out_str)), \ + IN_STR(M_C(name,_in_str)), \ + OUT_SERIAL(M_C(name,_out_serial)), \ + IN_SERIAL(M_C(name,_in_serial)), \ ) /************************** INTERNAL ***********************************/ /* Contract of a bounded string. * A bounded string last characters is always zero. */ -#define BOUNDED_STRINGI_CONTRACT(var, max_size) do { \ - assert(var != NULL); \ - assert(var->s[max_size] == 0); \ +#define BOUNDED_STRINGI_CONTRACT(var, max_size) do { \ + assert(var != NULL); \ + assert(var->s[max_size] == 0); \ } while (0) /* Expand the functions for a bounded string */ -#define BOUNDED_STRING_DEF_P2(name, max_size, bounded_t) \ - \ - /* Define of an array with one more to store the final nul char */ \ - typedef char M_C(name, _array_t)[max_size+1]; \ - \ - typedef struct M_C(name, _s) { \ - char s[max_size+1]; \ - } bounded_t[1]; \ - \ - /* Internal types for oplist */ \ - typedef bounded_t M_C(name, _ct); \ - \ - static inline void \ - M_C(name, _init)(bounded_t s) \ - { \ - assert(s != NULL); \ - assert(max_size >= 1); \ - s->s[0] = 0; \ - s->s[max_size] = 0; \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - } \ - \ - static inline void \ - M_C(name, _clear)(bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - /* nothing to do */ \ - (void) s; \ - } \ - \ - static inline void \ - M_C(name, _clean)(bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - s->s[0] = 0; \ - } \ - \ - static inline size_t \ - M_C(name, _size)(const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - return strlen(s->s); \ - } \ - \ - static inline size_t \ - M_C(name, _capacity)(const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - (void)s; /* unused */ \ - return max_size+1; \ - } \ - \ - static inline char \ - M_C(name, _get_char)(const bounded_t s, size_t index) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(index < max_size); \ - return s->s[index]; \ - } \ - \ - static inline bool \ - M_C(name, _empty_p)(const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - return s->s[0] == 0; \ - } \ - \ - static inline void \ - M_C(name, _set_str)(bounded_t s, const char str[]) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - m_core_strncpy(s->s, str, max_size); \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - } \ - \ - static inline void \ - M_C(name, _set_strn)(bounded_t s, const char str[], size_t n) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(str != NULL); \ - size_t len = M_MIN(max_size, n); \ - m_core_strncpy(s->s, str, len); \ - s->s[len] = 0; \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - } \ - \ - static inline const char * \ - M_C(name, _get_cstr)(const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - return s->s; \ - } \ - \ - static inline void \ - M_C(name, _set)(bounded_t s, const bounded_t str) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - BOUNDED_STRINGI_CONTRACT(str, max_size); \ - M_C(name, _set_str)(s, str->s); \ - } \ - \ - static inline void \ - M_C(name, _set_n)(bounded_t s, const bounded_t str, \ - size_t offset, size_t length) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - BOUNDED_STRINGI_CONTRACT(str, max_size); \ - assert (offset <= max_size); \ - M_C(name, _set_strn)(s, str->s+offset, length); \ - } \ - \ - static inline void \ - M_C(name, _init_set)(bounded_t s, const bounded_t str) \ - { \ - M_C(name,_init)(s); \ - M_C(name,_set)(s, str); \ - } \ - \ - static inline void \ - M_C(name, _init_set_str)(bounded_t s, const char str[]) \ - { \ - M_C(name,_init)(s); \ - M_C(name,_set_str)(s, str); \ - } \ - \ - static inline void \ - M_C(name, _cat_str)(bounded_t s, const char str[]) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert (str != NULL); \ - assert (strlen(s->s) <= max_size); \ - m_core_strncat(s->s, str, max_size-strlen(s->s)); \ - } \ - \ - static inline void \ - M_C(name, _cat)(bounded_t s, const bounded_t str) \ - { \ - BOUNDED_STRINGI_CONTRACT(str, max_size); \ - M_C(name, _cat_str)(s, str->s); \ - } \ - \ - static inline int \ - M_C(name, _cmp_str)(const bounded_t s, const char str[]) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(str != NULL); \ - return strcmp(s->s, str); \ - } \ - \ - static inline int \ - M_C(name, _cmp)(const bounded_t s, const bounded_t str) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - BOUNDED_STRINGI_CONTRACT(str, max_size); \ - return strcmp(s->s, str->s); \ - } \ - \ - static inline bool \ - M_C(name, _equal_str_p)(const bounded_t s, const char str[]) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(str != NULL); \ - return strcmp(s->s, str) == 0; \ - } \ - \ - static inline bool \ - M_C(name, _equal_p)(const bounded_t s, const bounded_t str) \ - { \ +#define BOUNDED_STRING_DEF_P2(name, max_size, bounded_t) \ + \ + /* Define of an array with one more to store the final nul char */ \ + typedef char M_C(name, _array_t)[max_size+1]; \ + \ + typedef struct M_C(name, _s) { \ + char s[max_size+1]; \ + } bounded_t[1]; \ + \ + /* Internal types for oplist */ \ + typedef bounded_t M_C(name, _ct); \ + \ + static inline void \ + M_C(name, _init)(bounded_t s) \ + { \ + assert(s != NULL); \ + assert(max_size >= 1); \ + s->s[0] = 0; \ + s->s[max_size] = 0; \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + } \ + \ + static inline void \ + M_C(name, _clear)(bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + /* nothing to do */ \ + (void) s; \ + } \ + \ + static inline void \ + M_C(name, _clean)(bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + s->s[0] = 0; \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + return strlen(s->s); \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + (void)s; /* unused */ \ + return max_size+1; \ + } \ + \ + static inline char \ + M_C(name, _get_char)(const bounded_t s, size_t index) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(index < max_size); \ + return s->s[index]; \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + return s->s[0] == 0; \ + } \ + \ + static inline void \ + M_C(name, _set_str)(bounded_t s, const char str[]) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + m_core_strncpy(s->s, str, max_size); \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + } \ + \ + static inline void \ + M_C(name, _set_strn)(bounded_t s, const char str[], size_t n) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(str != NULL); \ + size_t len = M_MIN(max_size, n); \ + m_core_strncpy(s->s, str, len); \ + s->s[len] = 0; \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + } \ + \ + static inline const char * \ + M_C(name, _get_cstr)(const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + return s->s; \ + } \ + \ + static inline void \ + M_C(name, _set)(bounded_t s, const bounded_t str) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + BOUNDED_STRINGI_CONTRACT(str, max_size); \ + M_C(name, _set_str)(s, str->s); \ + } \ + \ + static inline void \ + M_C(name, _set_n)(bounded_t s, const bounded_t str, \ + size_t offset, size_t length) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + BOUNDED_STRINGI_CONTRACT(str, max_size); \ + assert (offset <= max_size); \ + M_C(name, _set_strn)(s, str->s+offset, length); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(bounded_t s, const bounded_t str) \ + { \ + M_C(name,_init)(s); \ + M_C(name,_set)(s, str); \ + } \ + \ + static inline void \ + M_C(name, _init_set_str)(bounded_t s, const char str[]) \ + { \ + M_C(name,_init)(s); \ + M_C(name,_set_str)(s, str); \ + } \ + \ + static inline void \ + M_C(name, _cat_str)(bounded_t s, const char str[]) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert (str != NULL); \ + assert (strlen(s->s) <= max_size); \ + m_core_strncat(s->s, str, max_size-strlen(s->s)); \ + } \ + \ + static inline void \ + M_C(name, _cat)(bounded_t s, const bounded_t str) \ + { \ + BOUNDED_STRINGI_CONTRACT(str, max_size); \ + M_C(name, _cat_str)(s, str->s); \ + } \ + \ + static inline int \ + M_C(name, _cmp_str)(const bounded_t s, const char str[]) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(str != NULL); \ + return strcmp(s->s, str); \ + } \ + \ + static inline int \ + M_C(name, _cmp)(const bounded_t s, const bounded_t str) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + BOUNDED_STRINGI_CONTRACT(str, max_size); \ + return strcmp(s->s, str->s); \ + } \ + \ + static inline bool \ + M_C(name, _equal_str_p)(const bounded_t s, const char str[]) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(str != NULL); \ + return strcmp(s->s, str) == 0; \ + } \ + \ + static inline bool \ + M_C(name, _equal_p)(const bounded_t s, const bounded_t str) \ + { \ /* _equal_p may be called in context OOR. So contract cannot be verified */ \ return (s->s[max_size] == str->s[max_size]) & (strcmp(s->s, str->s) == 0); \ - } \ - \ - static inline int \ - M_C(name, _printf)(bounded_t s, const char format[], ...) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(format != NULL); \ - va_list args; \ - int ret; \ - va_start (args, format); \ - ret = vsnprintf (s->s, max_size+1, format, args); \ - va_end (args); \ - return ret; \ - } \ - \ - static inline int \ - M_C(name, _cat_printf)(bounded_t s, const char format[], ...) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(format != NULL); \ - va_list args; \ - int ret; \ - va_start (args, format); \ - size_t length = strlen(s->s); \ - assert(length <= max_size); \ - ret = vsnprintf (&s->s[length], max_size+1-length, format, args); \ - va_end (args); \ - return ret; \ - } \ - \ - static inline bool \ - M_C(name, _fgets)(bounded_t s, FILE *f, string_fgets_t arg) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(f != NULL); \ - assert(arg != STRING_READ_FILE); \ - char *ret = fgets(s->s, max_size+1, f); \ - s->s[max_size] = 0; \ - if (ret != NULL && arg == STRING_READ_PURE_LINE) { \ - size_t length = strlen(s->s); \ - if (length > 0 && s->s[length-1] == '\n') \ - s->s[length-1] = 0; \ - } \ - return ret != NULL; \ - } \ - \ - static inline bool \ - M_C(name, _fputs)(FILE *f, const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(f != NULL); \ - return fputs(s->s, f) >= 0; \ - } \ - \ - static inline size_t \ - M_C(name, _hash)(const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - /* Cannot use m_core_hash: alignment not sufficent */ \ - M_HASH_DECL(hash); \ - const char *str = s->s; \ - while (*str) { \ - size_t h = (size_t) *str++; \ - M_HASH_UP(hash, h); \ - } \ - return M_HASH_FINAL(hash); \ - } \ - \ - static inline bool \ - M_C(name, _oor_equal_p)(const bounded_t s, unsigned char n) \ - { \ - /* s may be invalid contract */ \ - assert (s != NULL); \ - assert ( (n == 0) || (n == 1)); \ - return s->s[max_size] == (char) (n+1); \ - } \ - \ - static inline void \ - M_C(name, _oor_set)(bounded_t s, unsigned char n) \ - { \ - /* s may be invalid contract */ \ - assert (s != NULL); \ - assert ( (n == 0) || (n == 1)); \ - s->s[max_size] = (char) (n+1); \ - } \ - \ - static inline void \ - M_C(name, _get_str)(string_t v, const bounded_t s, bool append) \ - { \ - STRINGI_CONTRACT(v); \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - /* Build dummy string to reuse string_get_str */ \ - uintptr_t ptr = (uintptr_t) &s->s[0]; \ - string_t v2; \ - v2->u.heap.size = strlen(s->s); \ - v2->u.heap.alloc = v2->u.heap.size + 1; \ - v2->ptr = (char*)ptr; \ - string_get_str(v, v2, append); \ - } \ - \ - static inline void \ - M_C(name, _out_str)(FILE *f, const bounded_t s) \ - { \ - BOUNDED_STRINGI_CONTRACT(s, max_size); \ - assert(f != NULL); \ - /* Build dummy string to reuse string_get_str */ \ - uintptr_t ptr = (uintptr_t) &s->s[0]; \ - string_t v2; \ - v2->u.heap.size = strlen(s->s); \ - v2->u.heap.alloc = v2->u.heap.size + 1; \ - v2->ptr = (char*)ptr; \ - string_out_str(f, v2); \ - } \ - \ - static inline bool \ - M_C(name, _in_str)(bounded_t v, FILE *f) \ - { \ - BOUNDED_STRINGI_CONTRACT(v, max_size); \ - assert(f != NULL); \ - string_t v2; \ - string_init(v2); \ - bool ret = string_in_str(v2, f); \ - m_core_strncpy(v->s, string_get_cstr(v2), max_size); \ - string_clear(v2); \ - return ret; \ - } \ - \ - static inline bool \ - M_C(name, _parse_str)(bounded_t v, const char str[], const char **endptr) \ - { \ - BOUNDED_STRINGI_CONTRACT(v, max_size); \ - assert(str != NULL); \ - string_t v2; \ - string_init(v2); \ - bool ret = string_parse_str(v2, str, endptr); \ - m_core_strncpy(v->s, string_get_cstr(v2), max_size); \ - string_clear(v2); \ - return ret; \ - } \ - \ - static inline m_serial_return_code_t \ - M_C(name, _out_serial)(m_serial_write_t serial, const bounded_t v) \ - { \ - BOUNDED_STRINGI_CONTRACT(v, max_size); \ - assert (serial != NULL && serial->m_interface != NULL); \ - return serial->m_interface->write_string(serial, v->s, strlen(v->s) ); \ - } \ - \ - static inline m_serial_return_code_t \ - M_C(name, _in_serial)(bounded_t v, m_serial_read_t serial) \ - { \ - BOUNDED_STRINGI_CONTRACT(v, max_size); \ - assert (serial != NULL && serial->m_interface != NULL); \ - string_t tmp; \ - /* TODO: Not optimum */ \ - string_init(tmp); \ + } \ + \ + static inline int \ + M_C(name, _printf)(bounded_t s, const char format[], ...) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(format != NULL); \ + va_list args; \ + int ret; \ + va_start (args, format); \ + ret = vsnprintf (s->s, max_size+1, format, args); \ + va_end (args); \ + return ret; \ + } \ + \ + static inline int \ + M_C(name, _cat_printf)(bounded_t s, const char format[], ...) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(format != NULL); \ + va_list args; \ + int ret; \ + va_start (args, format); \ + size_t length = strlen(s->s); \ + assert(length <= max_size); \ + ret = vsnprintf (&s->s[length], max_size+1-length, format, args); \ + va_end (args); \ + return ret; \ + } \ + \ + static inline bool \ + M_C(name, _fgets)(bounded_t s, FILE *f, string_fgets_t arg) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(f != NULL); \ + assert(arg != STRING_READ_FILE); \ + char *ret = fgets(s->s, max_size+1, f); \ + s->s[max_size] = 0; \ + if (ret != NULL && arg == STRING_READ_PURE_LINE) { \ + size_t length = strlen(s->s); \ + if (length > 0 && s->s[length-1] == '\n') \ + s->s[length-1] = 0; \ + } \ + return ret != NULL; \ + } \ + \ + static inline bool \ + M_C(name, _fputs)(FILE *f, const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(f != NULL); \ + return fputs(s->s, f) >= 0; \ + } \ + \ + static inline size_t \ + M_C(name, _hash)(const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + /* Cannot use m_core_hash: alignment not sufficent */ \ + M_HASH_DECL(hash); \ + const char *str = s->s; \ + while (*str) { \ + size_t h = (size_t) *str++; \ + M_HASH_UP(hash, h); \ + } \ + return M_HASH_FINAL(hash); \ + } \ + \ + static inline bool \ + M_C(name, _oor_equal_p)(const bounded_t s, unsigned char n) \ + { \ + /* s may be invalid contract */ \ + assert (s != NULL); \ + assert ( (n == 0) || (n == 1)); \ + return s->s[max_size] == (char) (n+1); \ + } \ + \ + static inline void \ + M_C(name, _oor_set)(bounded_t s, unsigned char n) \ + { \ + /* s may be invalid contract */ \ + assert (s != NULL); \ + assert ( (n == 0) || (n == 1)); \ + s->s[max_size] = (char) (n+1); \ + } \ + \ + static inline void \ + M_C(name, _get_str)(string_t v, const bounded_t s, bool append) \ + { \ + STRINGI_CONTRACT(v); \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + /* Build dummy string to reuse string_get_str */ \ + uintptr_t ptr = (uintptr_t) &s->s[0]; \ + string_t v2; \ + v2->u.heap.size = strlen(s->s); \ + v2->u.heap.alloc = v2->u.heap.size + 1; \ + v2->ptr = (char*)ptr; \ + string_get_str(v, v2, append); \ + } \ + \ + static inline void \ + M_C(name, _out_str)(FILE *f, const bounded_t s) \ + { \ + BOUNDED_STRINGI_CONTRACT(s, max_size); \ + assert(f != NULL); \ + /* Build dummy string to reuse string_get_str */ \ + uintptr_t ptr = (uintptr_t) &s->s[0]; \ + string_t v2; \ + v2->u.heap.size = strlen(s->s); \ + v2->u.heap.alloc = v2->u.heap.size + 1; \ + v2->ptr = (char*)ptr; \ + string_out_str(f, v2); \ + } \ + \ + static inline bool \ + M_C(name, _in_str)(bounded_t v, FILE *f) \ + { \ + BOUNDED_STRINGI_CONTRACT(v, max_size); \ + assert(f != NULL); \ + string_t v2; \ + string_init(v2); \ + bool ret = string_in_str(v2, f); \ + m_core_strncpy(v->s, string_get_cstr(v2), max_size); \ + string_clear(v2); \ + return ret; \ + } \ + \ + static inline bool \ + M_C(name, _parse_str)(bounded_t v, const char str[], const char **endptr) \ + { \ + BOUNDED_STRINGI_CONTRACT(v, max_size); \ + assert(str != NULL); \ + string_t v2; \ + string_init(v2); \ + bool ret = string_parse_str(v2, str, endptr); \ + m_core_strncpy(v->s, string_get_cstr(v2), max_size); \ + string_clear(v2); \ + return ret; \ + } \ + \ + static inline m_serial_return_code_t \ + M_C(name, _out_serial)(m_serial_write_t serial, const bounded_t v) \ + { \ + BOUNDED_STRINGI_CONTRACT(v, max_size); \ + assert (serial != NULL && serial->m_interface != NULL); \ + return serial->m_interface->write_string(serial, v->s, strlen(v->s) ); \ + } \ + \ + static inline m_serial_return_code_t \ + M_C(name, _in_serial)(bounded_t v, m_serial_read_t serial) \ + { \ + BOUNDED_STRINGI_CONTRACT(v, max_size); \ + assert (serial != NULL && serial->m_interface != NULL); \ + string_t tmp; \ + /* TODO: Not optimum */ \ + string_init(tmp); \ m_serial_return_code_t r = serial->m_interface->read_string(serial, tmp); \ - m_core_strncpy(v->s, string_get_cstr(tmp), max_size); \ - string_clear(tmp); \ - BOUNDED_STRINGI_CONTRACT(v, max_size); \ - return r; \ + m_core_strncpy(v->s, string_get_cstr(tmp), max_size); \ + string_clear(tmp); \ + BOUNDED_STRINGI_CONTRACT(v, max_size); \ + return r; \ } @@ -2139,7 +2139,7 @@ namespace m_string { /* Use of Compound Literals to init a constant string. See above */ #ifndef __cplusplus -#define BOUNDED_STRING_CTE(name, string) \ +#define BOUNDED_STRING_CTE(name, string) \ ((const struct M_C(name, _s) *)((M_C(name, _array_t)){string})) #else namespace m_string { @@ -2153,7 +2153,7 @@ namespace m_string { } }; } -#define BOUNDED_STRING_CTE(name, string) \ +#define BOUNDED_STRING_CTE(name, string) \ ((const struct M_C(name, _s) *)(m_string::m_bounded_string(string).s)) #endif diff --git a/m-tuple.h b/m-tuple.h index 8ab743ed..4d12f4c9 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -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__,)),), \ diff --git a/m-variant.h b/m-variant.h index 78eecb5e..ec86dbca 100644 --- a/m-variant.h +++ b/m-variant.h @@ -33,8 +33,8 @@ /* Define the variant type and functions. USAGE: VARIANT_DEF2(name, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */ -#define VARIANT_DEF2(name, ...) \ - M_BEGIN_PROTECTED_CODE \ +#define VARIANT_DEF2(name, ...) \ + M_BEGIN_PROTECTED_CODE \ VARIANTI_DEF2_P1( (name, M_C(name, _t) VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) ) \ M_END_PROTECTED_CODE @@ -43,100 +43,100 @@ as the given name_t USAGE: VARIANT_DEF2_AS(name, name_t, [(field1, type1, oplist1), (field2, type2, oplist2), ...] ) */ -#define VARIANT_DEF2_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - VARIANTI_DEF2_P1( (name, name_t VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) ) \ +#define VARIANT_DEF2_AS(name, name_t, ...) \ + M_BEGIN_PROTECTED_CODE \ + VARIANTI_DEF2_P1( (name, name_t VARIANTI_INJECT_GLOBAL(__VA_ARGS__)) ) \ M_END_PROTECTED_CODE /* Define the oplist of a variant. USAGE: VARIANT_OPLIST(name[, oplist of the first type, ...]) */ -#define VARIANT_OPLIST(...) \ - M_IF_NARGS_EQ1(__VA_ARGS__) \ - (VARIANTI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \ +#define VARIANT_OPLIST(...) \ + M_IF_NARGS_EQ1(__VA_ARGS__) \ + (VARIANTI_OPLIST_P1((__VA_ARGS__, M_DEFAULT_OPLIST)), \ VARIANTI_OPLIST_P1((__VA_ARGS__ ))) /********************************** INTERNAL ************************************/ /* Contract of a variant. */ -#define VARIANTI_CONTRACT(name, my) do { \ - assert(my != NULL); \ - assert(my->type >= M_C(name, _EMPTY)); \ - assert(my->type <= (enum M_C(name, _enum)) M_C(name, _MAX_TYPE)); \ +#define VARIANTI_CONTRACT(name, my) do { \ + assert(my != NULL); \ + assert(my->type >= M_C(name, _EMPTY)); \ + assert(my->type <= (enum M_C(name, _enum)) M_C(name, _MAX_TYPE)); \ } while (0) /* Inject the oplist within the list of arguments */ -#define VARIANTI_INJECT_GLOBAL(...) \ +#define VARIANTI_INJECT_GLOBAL(...) \ M_MAP(VARIANTI_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 VARIANTI_INJECT_OPLIST_A( duo_or_trio ) \ +#define VARIANTI_INJECT_OPLIST_A( duo_or_trio ) \ VARIANTI_INJECT_OPLIST_B duo_or_trio -#define VARIANTI_INJECT_OPLIST_B( f, ... ) \ - M_DEFERRED_COMMA \ +#define VARIANTI_INJECT_OPLIST_B( f, ... ) \ + M_DEFERRED_COMMA \ M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)()), (f, __VA_ARGS__) ) // Deferred evaluation #define VARIANTI_DEF2_P1(...) VARIANTI_DEF2_P2 __VA_ARGS__ // Test if all third argument of all arguments is an oplist -#define VARIANTI_IF_ALL_OPLIST(...) \ +#define VARIANTI_IF_ALL_OPLIST(...) \ M_IF(M_REDUCE(VARIANTI_IS_OPLIST_P, M_AND, __VA_ARGS__)) // Test if the third argument is an oplist -#define VARIANTI_IS_OPLIST_P(a) \ +#define VARIANTI_IS_OPLIST_P(a) \ M_OPLIST_P(M_RET_ARG3 a) /* Validate the oplist before going further */ -#define VARIANTI_DEF2_P2(name, name_t, ...) \ +#define VARIANTI_DEF2_P2(name, name_t, ...) \ VARIANTI_IF_ALL_OPLIST(__VA_ARGS__)(VARIANTI_DEF2_P3, VARIANTI_DEF2_FAILURE)(name, name_t, __VA_ARGS__) /* Stop processing with a compilation failure */ -#define VARIANTI_DEF2_FAILURE(name, name_t, ...) \ +#define VARIANTI_DEF2_FAILURE(name, name_t, ...) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(VARIANT_DEF2): at least one of the given argument is not a valid oplist: " #__VA_ARGS__) /* Define the variant */ -#define VARIANTI_DEF2_P3(name, name_t, ...) \ - VARIANTI_DEFINE_TYPE(name, name_t, __VA_ARGS__) \ - VARIANTI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \ - VARIANTI_DEFINE_INIT(name, __VA_ARGS__) \ - VARIANTI_DEFINE_CLEAR(name, __VA_ARGS__) \ - VARIANTI_DEFINE_INIT_SET(name, __VA_ARGS__) \ - VARIANTI_DEFINE_SET(name, __VA_ARGS__) \ - VARIANTI_DEFINE_TEST_P(name, __VA_ARGS__) \ - VARIANTI_IF_ALL(INIT, __VA_ARGS__) \ - (VARIANTI_DEFINE_INIT_FIELD(name, __VA_ARGS__),) \ - VARIANTI_DEFINE_INIT_SETTER_FIELD(name, __VA_ARGS__) \ - VARIANTI_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \ - VARIANTI_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \ - VARIANTI_DEFINE_CLEAN_FUNC(name, __VA_ARGS__) \ - VARIANTI_IF_ALL(HASH, __VA_ARGS__) \ - (VARIANTI_DEFINE_HASH(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(EQUAL, __VA_ARGS__) \ - (VARIANTI_DEFINE_EQUAL(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(GET_STR, __VA_ARGS__) \ - (VARIANTI_DEFINE_GET_STR(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__) \ - (VARIANTI_DEFINE_PARSE_STR(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(OUT_STR, __VA_ARGS__) \ - (VARIANTI_DEFINE_OUT_STR(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \ - (VARIANTI_DEFINE_IN_STR(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(OUT_SERIAL, __VA_ARGS__) \ - (VARIANTI_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__) \ - (VARIANTI_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ - (VARIANTI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ - (VARIANTI_DEFINE_MOVE(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ - (VARIANTI_DEFINE_MOVER(name, __VA_ARGS__),) \ - VARIANTI_IF_ALL(SWAP, __VA_ARGS__) \ +#define VARIANTI_DEF2_P3(name, name_t, ...) \ + VARIANTI_DEFINE_TYPE(name, name_t, __VA_ARGS__) \ + VARIANTI_CONTROL_ALL_OPLIST(name, __VA_ARGS__) \ + VARIANTI_DEFINE_INIT(name, __VA_ARGS__) \ + VARIANTI_DEFINE_CLEAR(name, __VA_ARGS__) \ + VARIANTI_DEFINE_INIT_SET(name, __VA_ARGS__) \ + VARIANTI_DEFINE_SET(name, __VA_ARGS__) \ + VARIANTI_DEFINE_TEST_P(name, __VA_ARGS__) \ + VARIANTI_IF_ALL(INIT, __VA_ARGS__) \ + (VARIANTI_DEFINE_INIT_FIELD(name, __VA_ARGS__),) \ + VARIANTI_DEFINE_INIT_SETTER_FIELD(name, __VA_ARGS__) \ + VARIANTI_DEFINE_SETTER_FIELD(name, __VA_ARGS__) \ + VARIANTI_DEFINE_GETTER_FIELD(name, __VA_ARGS__) \ + VARIANTI_DEFINE_CLEAN_FUNC(name, __VA_ARGS__) \ + VARIANTI_IF_ALL(HASH, __VA_ARGS__) \ + (VARIANTI_DEFINE_HASH(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(EQUAL, __VA_ARGS__) \ + (VARIANTI_DEFINE_EQUAL(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(GET_STR, __VA_ARGS__) \ + (VARIANTI_DEFINE_GET_STR(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL2(PARSE_STR, INIT, __VA_ARGS__) \ + (VARIANTI_DEFINE_PARSE_STR(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(OUT_STR, __VA_ARGS__) \ + (VARIANTI_DEFINE_OUT_STR(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL2(IN_STR, INIT, __VA_ARGS__) \ + (VARIANTI_DEFINE_IN_STR(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(OUT_SERIAL, __VA_ARGS__) \ + (VARIANTI_DEFINE_OUT_SERIAL(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL2(IN_SERIAL, INIT, __VA_ARGS__) \ + (VARIANTI_DEFINE_IN_SERIAL(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ + (VARIANTI_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ + (VARIANTI_DEFINE_MOVE(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ + (VARIANTI_DEFINE_MOVER(name, __VA_ARGS__),) \ + VARIANTI_IF_ALL(SWAP, __VA_ARGS__) \ (VARIANTI_DEFINE_SWAP(name, __VA_ARGS__),) @@ -181,272 +181,272 @@ #define VARIANTI_CALL_SWAP(t, ...) M_APPLY_API(VARIANTI_GET_SWAP t, VARIANTI_GET_OPLIST t, __VA_ARGS__) /* Define the type */ -#define VARIANTI_DEFINE_TYPE(name, name_t, ...) \ - /* Define enum of all types of the variant */ \ - enum M_C(name, _enum) { M_C(name, _EMPTY) \ - M_MAP2(VARIANTI_DEFINE_UNION_ELE, name, __VA_ARGS__) \ - }; \ - /* Define enum equal to the number of types of the variant */ \ - enum M_C(name, _enum_max) { \ - M_C(name, _MAX_TYPE) = M_NARGS(__VA_ARGS__) \ - }; \ - /* Define the variant */ \ - typedef struct M_C(name, _s) { \ - enum M_C(name, _enum) type; \ - union { \ - M_MAP(VARIANTI_DEFINE_TYPE_ELE , __VA_ARGS__) \ - } value; \ - } 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 VARIANTI_DEFINE_TYPE(name, name_t, ...) \ + /* Define enum of all types of the variant */ \ + enum M_C(name, _enum) { M_C(name, _EMPTY) \ + M_MAP2(VARIANTI_DEFINE_UNION_ELE, name, __VA_ARGS__) \ + }; \ + /* Define enum equal to the number of types of the variant */ \ + enum M_C(name, _enum_max) { \ + M_C(name, _MAX_TYPE) = M_NARGS(__VA_ARGS__) \ + }; \ + /* Define the variant */ \ + typedef struct M_C(name, _s) { \ + enum M_C(name, _enum) type; \ + union { \ + M_MAP(VARIANTI_DEFINE_TYPE_ELE , __VA_ARGS__) \ + } value; \ + } 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 VARIANTI_DEFINE_UNION_ELE(name, a) \ +#define VARIANTI_DEFINE_UNION_ELE(name, a) \ , M_C4(name, _, VARIANTI_GET_FIELD a, _value) -#define VARIANTI_DEFINE_TYPE_ELE(a) \ +#define VARIANTI_DEFINE_TYPE_ELE(a) \ VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ; /* Control that all given oplists of all parameters are really oplists */ -#define VARIANTI_CONTROL_ALL_OPLIST(name, ...) \ +#define VARIANTI_CONTROL_ALL_OPLIST(name, ...) \ M_MAP2(VARIANTI_CONTROL_OPLIST, name, __VA_ARGS__) -#define VARIANTI_CONTROL_OPLIST(name, a) \ - M_CHECK_COMPATIBLE_OPLIST(name, VARIANTI_GET_FIELD a, \ +#define VARIANTI_CONTROL_OPLIST(name, a) \ + M_CHECK_COMPATIBLE_OPLIST(name, VARIANTI_GET_FIELD a, \ VARIANTI_GET_TYPE a, VARIANTI_GET_OPLIST a) /* Define the INIT function. Init the variant to empty */ -#define VARIANTI_DEFINE_INIT(name, ...) \ - static inline void M_C(name, _init)(M_C(name,_ct) my) { \ - my->type = M_C(name, _EMPTY); \ +#define VARIANTI_DEFINE_INIT(name, ...) \ + static inline void M_C(name, _init)(M_C(name,_ct) my) { \ + my->type = M_C(name, _EMPTY); \ } /* Define the INIT_SET function. */ -#define VARIANTI_DEFINE_INIT_SET(name, ...) \ - static inline void M_C(name, _init_set)(M_C(name,_ct) my , \ - M_C(name,_ct) const org) { \ - VARIANTI_CONTRACT(name, org); \ - my->type = org->type; \ - switch (org->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ +#define VARIANTI_DEFINE_INIT_SET(name, ...) \ + static inline void M_C(name, _init_set)(M_C(name,_ct) my , \ + M_C(name,_ct) const org) { \ + VARIANTI_CONTRACT(name, org); \ + my->type = org->type; \ + switch (org->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ } -#define VARIANTI_DEFINE_INIT_SET_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a , \ - org -> value.VARIANTI_GET_FIELD a ); \ +#define VARIANTI_DEFINE_INIT_SET_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a , \ + org -> value.VARIANTI_GET_FIELD a ); \ break; /* Define the SET function. */ -#define VARIANTI_DEFINE_SET(name, ...) \ - static inline void M_C(name, _set)(M_C(name,_ct) my , \ - M_C(name,_ct) const org) { \ - VARIANTI_CONTRACT(name, my); \ - VARIANTI_CONTRACT(name, org); \ - if (my->type != org->type) { \ - /* Different types: clear previous one and create new */ \ - M_C(name, _clear)(my); \ - M_C(name, _init_set)(my, org); \ - } else { \ - /* Same type: optimize the set */ \ - switch (org->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_SET_FUNC, name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - } \ +#define VARIANTI_DEFINE_SET(name, ...) \ + static inline void M_C(name, _set)(M_C(name,_ct) my , \ + M_C(name,_ct) const org) { \ + VARIANTI_CONTRACT(name, my); \ + VARIANTI_CONTRACT(name, org); \ + if (my->type != org->type) { \ + /* Different types: clear previous one and create new */ \ + M_C(name, _clear)(my); \ + M_C(name, _init_set)(my, org); \ + } else { \ + /* Same type: optimize the set */ \ + switch (org->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_SET_FUNC, name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + } \ } -#define VARIANTI_DEFINE_SET_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a , \ - org -> value.VARIANTI_GET_FIELD a ); \ +#define VARIANTI_DEFINE_SET_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a , \ + org -> value.VARIANTI_GET_FIELD a ); \ break; /* Define the CLEAR function. */ -#define VARIANTI_DEFINE_CLEAR(name, ...) \ - static inline void M_C(name, _clear)(M_C(name,_ct) my) { \ - VARIANTI_CONTRACT(name, my); \ - switch (my->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - my->type = M_C(name, _EMPTY); \ +#define VARIANTI_DEFINE_CLEAR(name, ...) \ + static inline void M_C(name, _clear)(M_C(name,_ct) my) { \ + VARIANTI_CONTRACT(name, my); \ + switch (my->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + my->type = M_C(name, _EMPTY); \ } -#define VARIANTI_DEFINE_CLEAR_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - VARIANTI_CALL_CLEAR(a, my -> value. VARIANTI_GET_FIELD a); \ +#define VARIANTI_DEFINE_CLEAR_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + VARIANTI_CALL_CLEAR(a, my -> value. VARIANTI_GET_FIELD a); \ break; /* Define the TEST_P function. */ -#define VARIANTI_DEFINE_TEST_P(name, ...) \ - static inline bool M_C(name, _empty_p)(M_C(name,_ct) const my) { \ - VARIANTI_CONTRACT(name, my); \ - return my->type == M_C(name, _EMPTY); \ - } \ - static inline enum M_C(name, _enum) \ - M_C(name, _type)(M_C(name,_ct) my) { \ - VARIANTI_CONTRACT(name, my); \ - return my->type; \ - } \ +#define VARIANTI_DEFINE_TEST_P(name, ...) \ + static inline bool M_C(name, _empty_p)(M_C(name,_ct) const my) { \ + VARIANTI_CONTRACT(name, my); \ + return my->type == M_C(name, _EMPTY); \ + } \ + static inline enum M_C(name, _enum) \ + M_C(name, _type)(M_C(name,_ct) my) { \ + VARIANTI_CONTRACT(name, my); \ + return my->type; \ + } \ M_MAP2(VARIANTI_DEFINE_TEST_FUNC, name, __VA_ARGS__) -#define VARIANTI_DEFINE_TEST_FUNC(name, a) \ - static inline bool \ - M_C4(name, _, VARIANTI_GET_FIELD a, _p)(M_C(name,_ct) const my) { \ - VARIANTI_CONTRACT(name, my); \ - return my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ +#define VARIANTI_DEFINE_TEST_FUNC(name, a) \ + static inline bool \ + M_C4(name, _, VARIANTI_GET_FIELD a, _p)(M_C(name,_ct) const my) { \ + VARIANTI_CONTRACT(name, my); \ + return my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ } /* Define the INIT function. */ -#define VARIANTI_DEFINE_INIT_FIELD(name, ...) \ +#define VARIANTI_DEFINE_INIT_FIELD(name, ...) \ M_MAP2(VARIANTI_DEFINE_INIT_FIELD_FUNC, name, __VA_ARGS__) -#define VARIANTI_DEFINE_INIT_FIELD_FUNC(name, a) \ - static inline void \ - M_C3(name, _init_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my) { \ - /* Reinit variable with the given value */ \ - my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ - VARIANTI_CALL_INIT(a, my -> value. VARIANTI_GET_FIELD a); \ +#define VARIANTI_DEFINE_INIT_FIELD_FUNC(name, a) \ + static inline void \ + M_C3(name, _init_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my) { \ + /* Reinit variable with the given value */ \ + my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT(a, my -> value. VARIANTI_GET_FIELD a); \ } /* Define the INIT_SET of a given type function. */ -#define VARIANTI_DEFINE_INIT_SETTER_FIELD(name, ...) \ +#define VARIANTI_DEFINE_INIT_SETTER_FIELD(name, ...) \ M_MAP2(VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC, name, __VA_ARGS__) -#define VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC(name, a) \ - static inline void \ - M_C3(name, _init_set_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \ +#define VARIANTI_DEFINE_INIT_SETTER_FIELD_FUNC(name, a) \ + static inline void \ + M_C3(name, _init_set_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \ VARIANTI_GET_TYPE a const VARIANTI_GET_FIELD a ) { \ - my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ - VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \ - VARIANTI_GET_FIELD a); \ + my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \ + VARIANTI_GET_FIELD a); \ } /* Define the SET of a given type function. */ -#define VARIANTI_DEFINE_SETTER_FIELD(name, ...) \ +#define VARIANTI_DEFINE_SETTER_FIELD(name, ...) \ M_MAP2(VARIANTI_DEFINE_SETTER_FIELD_FUNC, name, __VA_ARGS__) -#define VARIANTI_DEFINE_SETTER_FIELD_FUNC(name, a) \ - static inline void \ - M_C3(name, _set_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \ +#define VARIANTI_DEFINE_SETTER_FIELD_FUNC(name, a) \ + static inline void \ + M_C3(name, _set_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \ VARIANTI_GET_TYPE a const VARIANTI_GET_FIELD a ) { \ - VARIANTI_CONTRACT(name, my); \ - if (my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \ - VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a, \ - VARIANTI_GET_FIELD a); \ - } else { \ - M_C(name, _clear)(my); \ - /* Reinit variable with the given value */ \ - my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ - VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \ - VARIANTI_GET_FIELD a); \ - } \ + VARIANTI_CONTRACT(name, my); \ + if (my->type == M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \ + VARIANTI_CALL_SET(a, my -> value. VARIANTI_GET_FIELD a, \ + VARIANTI_GET_FIELD a); \ + } else { \ + M_C(name, _clear)(my); \ + /* Reinit variable with the given value */ \ + my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT_SET(a, my -> value. VARIANTI_GET_FIELD a, \ + VARIANTI_GET_FIELD a); \ + } \ } /* Define the GET_field of a given type function. */ -#define VARIANTI_DEFINE_GETTER_FIELD(name, ...) \ +#define VARIANTI_DEFINE_GETTER_FIELD(name, ...) \ M_MAP2(VARIANTI_DEFINE_GETTER_FIELD_FUNC, name, __VA_ARGS__) -#define VARIANTI_DEFINE_GETTER_FIELD_FUNC(name, a) \ - static inline VARIANTI_GET_TYPE a * \ - M_C3(name, _get_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my) { \ - VARIANTI_CONTRACT(name, my); \ - if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \ - return NULL; \ - } \ - return &my -> value . VARIANTI_GET_FIELD a; \ - } \ - \ - static inline VARIANTI_GET_TYPE a const * \ - M_C3(name, _cget_, VARIANTI_GET_FIELD a)(M_C(name,_ct) const my) { \ - VARIANTI_CONTRACT(name, my); \ - if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \ - return NULL; \ - } \ - return &my -> value . VARIANTI_GET_FIELD a; \ +#define VARIANTI_DEFINE_GETTER_FIELD_FUNC(name, a) \ + static inline VARIANTI_GET_TYPE a * \ + M_C3(name, _get_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my) { \ + VARIANTI_CONTRACT(name, my); \ + if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \ + return NULL; \ + } \ + return &my -> value . VARIANTI_GET_FIELD a; \ + } \ + \ + static inline VARIANTI_GET_TYPE a const * \ + M_C3(name, _cget_, VARIANTI_GET_FIELD a)(M_C(name,_ct) const my) { \ + VARIANTI_CONTRACT(name, my); \ + if (my->type != M_C4(name, _, VARIANTI_GET_FIELD a, _value) ) { \ + return NULL; \ + } \ + return &my -> value . VARIANTI_GET_FIELD a; \ } /* Define the EQUAL_P function. */ -#define VARIANTI_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; \ - VARIANTI_CONTRACT(name, e1); \ - VARIANTI_CONTRACT(name, e2); \ - if (e1->type != e2->type) return false; \ - switch (e1->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_EQUAL_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - return true; \ +#define VARIANTI_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; \ + VARIANTI_CONTRACT(name, e1); \ + VARIANTI_CONTRACT(name, e2); \ + if (e1->type != e2->type) return false; \ + switch (e1->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_EQUAL_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + return true; \ } -#define VARIANTI_DEFINE_EQUAL_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - b = VARIANTI_CALL_EQUAL(a, e1 -> value . VARIANTI_GET_FIELD a , \ - e2 -> value . VARIANTI_GET_FIELD a ); \ - return b; \ +#define VARIANTI_DEFINE_EQUAL_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + b = VARIANTI_CALL_EQUAL(a, e1 -> value . VARIANTI_GET_FIELD a , \ + e2 -> value . VARIANTI_GET_FIELD a ); \ + return b; \ break; /* Define the HASH function. */ -#define VARIANTI_DEFINE_HASH(name, ...) \ - static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \ - VARIANTI_CONTRACT(name, e1); \ - M_HASH_DECL(hash); \ - M_HASH_UP (hash, (unsigned int) (e1 -> type)); \ - switch (e1->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_HASH_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - return M_HASH_FINAL (hash); \ +#define VARIANTI_DEFINE_HASH(name, ...) \ + static inline size_t M_C(name, _hash)(M_C(name,_ct) const e1) { \ + VARIANTI_CONTRACT(name, e1); \ + M_HASH_DECL(hash); \ + M_HASH_UP (hash, (unsigned int) (e1 -> type)); \ + switch (e1->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_HASH_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + return M_HASH_FINAL (hash); \ } -#define VARIANTI_DEFINE_HASH_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ +#define VARIANTI_DEFINE_HASH_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ M_HASH_UP(hash, VARIANTI_CALL_HASH(a, e1 -> value . VARIANTI_GET_FIELD a) ); \ break; /* Define the INIT_MOVE function. */ -#define VARIANTI_DEFINE_INIT_MOVE(name, ...) \ - static inline void \ - M_C(name, _init_move)(M_C(name,_ct) el, M_C(name,_ct) org) { \ - VARIANTI_CONTRACT(name, org); \ - el -> type = org -> type; \ - switch (el->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_INIT_MOVE_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - org -> type = M_C(name, _EMPTY); \ +#define VARIANTI_DEFINE_INIT_MOVE(name, ...) \ + static inline void \ + M_C(name, _init_move)(M_C(name,_ct) el, M_C(name,_ct) org) { \ + VARIANTI_CONTRACT(name, org); \ + el -> type = org -> type; \ + switch (el->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_INIT_MOVE_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + org -> type = M_C(name, _EMPTY); \ } -#define VARIANTI_DEFINE_INIT_MOVE_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - VARIANTI_CALL_INIT_MOVE(a, el -> value . VARIANTI_GET_FIELD a, \ - org -> value . VARIANTI_GET_FIELD a); \ +#define VARIANTI_DEFINE_INIT_MOVE_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + VARIANTI_CALL_INIT_MOVE(a, el -> value . VARIANTI_GET_FIELD a, \ + org -> value . VARIANTI_GET_FIELD a); \ break; @@ -454,323 +454,323 @@ This is not optimized version. It can be optimized if both types are the same. */ -#define VARIANTI_DEFINE_MOVE(name, ...) \ - static inline void \ - M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \ - VARIANTI_CONTRACT(name, el); \ - VARIANTI_CONTRACT(name, org); \ - M_C(name, _clear)(el); \ - M_C(name, _init_move)(el , org); \ +#define VARIANTI_DEFINE_MOVE(name, ...) \ + static inline void \ + M_C(name, _move)(M_C(name,_ct) el, M_C(name,_ct) org) { \ + VARIANTI_CONTRACT(name, el); \ + VARIANTI_CONTRACT(name, org); \ + M_C(name, _clear)(el); \ + M_C(name, _init_move)(el , org); \ } /* Define the MOVE function of a given type */ -#define VARIANTI_DEFINE_MOVER(name, ...) \ +#define VARIANTI_DEFINE_MOVER(name, ...) \ M_MAP2(VARIANTI_DEFINE_MOVER_FUNC, name, __VA_ARGS__) -#define VARIANTI_DEFINE_MOVER_FUNC(name, a) \ - static inline void \ - M_C3(name, _move_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \ +#define VARIANTI_DEFINE_MOVER_FUNC(name, a) \ + static inline void \ + M_C3(name, _move_, VARIANTI_GET_FIELD a)(M_C(name,_ct) my, \ VARIANTI_GET_TYPE a VARIANTI_GET_FIELD a ) { \ - VARIANTI_CONTRACT(name, my); \ - M_C(name, _clear)(my); \ - /* Reinit variable with the given value */ \ - my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ - VARIANTI_CALL_INIT_MOVE(a, my -> value. VARIANTI_GET_FIELD a, \ - VARIANTI_GET_FIELD a); \ + VARIANTI_CONTRACT(name, my); \ + M_C(name, _clear)(my); \ + /* Reinit variable with the given value */ \ + my->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT_MOVE(a, my -> value. VARIANTI_GET_FIELD a, \ + VARIANTI_GET_FIELD a); \ } /* Define the SWAP function */ -#define VARIANTI_DEFINE_SWAP(name, ...) \ - static inline void \ - M_C(name, _swap)(M_C(name,_ct) el1, M_C(name,_ct) el2) { \ - VARIANTI_CONTRACT(name, el1); \ - VARIANTI_CONTRACT(name, el2); \ - if (el1->type == el2->type) { \ - switch (el1->type) { \ - case M_C(name, _EMPTY): break; \ - M_MAP2(VARIANTI_DEFINE_INIT_SWAP_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - } else { \ - M_C(name,_ct) tmp; \ - VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ - ( /* NOTE: Slow implementation */ \ - M_C(name, _init_move)(tmp, el1); \ - M_C(name, _init_move)(el1, el2); \ - M_C(name, _init_move)(el2, tmp); \ - , \ - /* NOTE: Very slow implementation */ \ - M_C(name, _init_set)(tmp, el1); \ - M_C(name, _set)(el1, el2); \ - M_C(name, _set)(el2, tmp); \ - M_C(name, _clear)(tmp); \ - ) \ - } \ +#define VARIANTI_DEFINE_SWAP(name, ...) \ + static inline void \ + M_C(name, _swap)(M_C(name,_ct) el1, M_C(name,_ct) el2) { \ + VARIANTI_CONTRACT(name, el1); \ + VARIANTI_CONTRACT(name, el2); \ + if (el1->type == el2->type) { \ + switch (el1->type) { \ + case M_C(name, _EMPTY): break; \ + M_MAP2(VARIANTI_DEFINE_INIT_SWAP_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + } else { \ + M_C(name,_ct) tmp; \ + VARIANTI_IF_ALL(INIT_MOVE, __VA_ARGS__) \ + ( /* NOTE: Slow implementation */ \ + M_C(name, _init_move)(tmp, el1); \ + M_C(name, _init_move)(el1, el2); \ + M_C(name, _init_move)(el2, tmp); \ + , \ + /* NOTE: Very slow implementation */ \ + M_C(name, _init_set)(tmp, el1); \ + M_C(name, _set)(el1, el2); \ + M_C(name, _set)(el2, tmp); \ + M_C(name, _clear)(tmp); \ + ) \ + } \ } -#define VARIANTI_DEFINE_INIT_SWAP_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - VARIANTI_CALL_SWAP(a, el1 -> value . VARIANTI_GET_FIELD a, \ - el2 -> value . VARIANTI_GET_FIELD a); \ +#define VARIANTI_DEFINE_INIT_SWAP_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + VARIANTI_CALL_SWAP(a, el1 -> value . VARIANTI_GET_FIELD a, \ + el2 -> value . VARIANTI_GET_FIELD a); \ break; /* Define the GET_STR function */ -#define VARIANTI_DEFINE_GET_STR(name, ...) \ - static inline void M_C(name, _get_str)(string_t str, \ - M_C(name,_ct) const el, \ - bool append) { \ - VARIANTI_CONTRACT(name, el); \ - assert (str != NULL); \ - void (*func)(string_t, const char *); \ - func = append ? string_cat_str : string_set_str; \ - switch (el->type) { \ - case M_C(name, _EMPTY): func(str, "@EMPTY@"); break; \ - M_MAP2(VARIANTI_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - string_push_back (str, '@'); \ +#define VARIANTI_DEFINE_GET_STR(name, ...) \ + static inline void M_C(name, _get_str)(string_t str, \ + M_C(name,_ct) const el, \ + bool append) { \ + VARIANTI_CONTRACT(name, el); \ + assert (str != NULL); \ + void (*func)(string_t, const char *); \ + func = append ? string_cat_str : string_set_str; \ + switch (el->type) { \ + case M_C(name, _EMPTY): func(str, "@EMPTY@"); break; \ + M_MAP2(VARIANTI_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + string_push_back (str, '@'); \ } -#define VARIANTI_DEFINE_GET_STR_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - func(str, "@" M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a) "@"); \ - VARIANTI_CALL_GET_STR(a, str, el -> value . VARIANTI_GET_FIELD a, true); \ +#define VARIANTI_DEFINE_GET_STR_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + func(str, "@" M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a) "@"); \ + VARIANTI_CALL_GET_STR(a, str, el -> value . VARIANTI_GET_FIELD a, true); \ break; /* Define the PARSE_STR function */ -#define VARIANTI_DEFINE_PARSE_STR(name, ...) \ - static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \ - const char str[], \ - const char **endp) { \ - VARIANTI_CONTRACT(name, el); \ - assert (str != NULL); \ - bool success = false; \ - char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \ - int c = *str++; \ - unsigned int i = 0; \ - M_C(name, _clean)(el); \ - if (c != '@') goto exit; \ - /* First read the name of the type */ \ - c = *str++; \ - while (c != '@' && c != 0 && i < sizeof(variantTypeBuf) - 1) { \ - variantTypeBuf[i++] = (char) c; \ - c = *str++; \ - } \ - if (c != '@') goto exit; \ - variantTypeBuf[i++] = 0; \ - assert(i < sizeof(variantTypeBuf)); \ - /* In function of the type */ \ - if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ - el->type = M_C(name, _EMPTY); \ - } \ - M_MAP2(VARIANTI_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \ - else goto exit; \ - success = (*str++ == '@'); \ - exit: \ - if (endp) *endp = str; \ - return success; \ +#define VARIANTI_DEFINE_PARSE_STR(name, ...) \ + static inline bool M_C(name, _parse_str)(M_C(name,_ct) el, \ + const char str[], \ + const char **endp) { \ + VARIANTI_CONTRACT(name, el); \ + assert (str != NULL); \ + bool success = false; \ + char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \ + int c = *str++; \ + unsigned int i = 0; \ + M_C(name, _clean)(el); \ + if (c != '@') goto exit; \ + /* First read the name of the type */ \ + c = *str++; \ + while (c != '@' && c != 0 && i < sizeof(variantTypeBuf) - 1) { \ + variantTypeBuf[i++] = (char) c; \ + c = *str++; \ + } \ + if (c != '@') goto exit; \ + variantTypeBuf[i++] = 0; \ + assert(i < sizeof(variantTypeBuf)); \ + /* In function of the type */ \ + if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ + el->type = M_C(name, _EMPTY); \ + } \ + M_MAP2(VARIANTI_DEFINE_PARSE_STR_FUNC , name, __VA_ARGS__) \ + else goto exit; \ + success = (*str++ == '@'); \ + exit: \ + if (endp) *endp = str; \ + return success; \ } -#define VARIANTI_DEFINE_PARSE_STR_FUNC(name, a) \ +#define VARIANTI_DEFINE_PARSE_STR_FUNC(name, a) \ else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \ - el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ - VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ + el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ bool b = VARIANTI_CALL_PARSE_STR(a, el -> value . VARIANTI_GET_FIELD a, str, &str); \ - if (!b) goto exit; \ + if (!b) goto exit; \ } /* Define the OUT_STR function */ -#define VARIANTI_DEFINE_OUT_STR(name, ...) \ - static inline void M_C(name, _out_str)(FILE *f, \ - M_C(name,_ct) const el) { \ - VARIANTI_CONTRACT(name, el); \ - assert (f != NULL); \ - switch (el->type) { \ - case M_C(name, _EMPTY): fprintf(f, "@EMPTY@"); break; \ - M_MAP2(VARIANTI_DEFINE_OUT_STR_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - fputc ('@', f); \ +#define VARIANTI_DEFINE_OUT_STR(name, ...) \ + static inline void M_C(name, _out_str)(FILE *f, \ + M_C(name,_ct) const el) { \ + VARIANTI_CONTRACT(name, el); \ + assert (f != NULL); \ + switch (el->type) { \ + case M_C(name, _EMPTY): fprintf(f, "@EMPTY@"); break; \ + M_MAP2(VARIANTI_DEFINE_OUT_STR_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + fputc ('@', f); \ } -#define VARIANTI_DEFINE_OUT_STR_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - fprintf(f, "@" M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) "@"); \ - VARIANTI_CALL_OUT_STR(a, f, el -> value . VARIANTI_GET_FIELD a); \ +#define VARIANTI_DEFINE_OUT_STR_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + fprintf(f, "@" M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) "@"); \ + VARIANTI_CALL_OUT_STR(a, f, el -> value . VARIANTI_GET_FIELD a); \ break; /* Define the IN_STR function */ -#define VARIANTI_DEFINE_IN_STR(name, ...) \ - static inline bool M_C(name, _in_str)(M_C(name,_ct) el, \ - FILE *f) { \ - VARIANTI_CONTRACT(name, el); \ - assert (f != NULL); \ - char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \ - M_C(name, _clean)(el); \ - if (fgetc(f) != '@') return false; \ - /* First read the name of the type */ \ - bool b = true; \ - int c = fgetc(f); \ - unsigned int i = 0; \ - while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \ - variantTypeBuf[i++] = (char) c; \ - c = fgetc(f); \ - } \ - if (c != '@') return false; \ - variantTypeBuf[i++] = 0; \ - assert(i < sizeof(variantTypeBuf)); \ - /* In function of the type */ \ - if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ - el->type = M_C(name, _EMPTY); \ - } \ - M_MAP2(VARIANTI_DEFINE_IN_STR_FUNC , name, __VA_ARGS__) \ - else { b = false; } \ - return b && (fgetc(f) == '@'); \ +#define VARIANTI_DEFINE_IN_STR(name, ...) \ + static inline bool M_C(name, _in_str)(M_C(name,_ct) el, \ + FILE *f) { \ + VARIANTI_CONTRACT(name, el); \ + assert (f != NULL); \ + char variantTypeBuf[M_MAX_IDENTIFIER_LENGTH+1]; \ + M_C(name, _clean)(el); \ + if (fgetc(f) != '@') return false; \ + /* First read the name of the type */ \ + bool b = true; \ + int c = fgetc(f); \ + unsigned int i = 0; \ + while (c != '@' && c != EOF && i < sizeof(variantTypeBuf) - 1) { \ + variantTypeBuf[i++] = (char) c; \ + c = fgetc(f); \ + } \ + if (c != '@') return false; \ + variantTypeBuf[i++] = 0; \ + assert(i < sizeof(variantTypeBuf)); \ + /* In function of the type */ \ + if (strcmp(variantTypeBuf, "EMPTY") == 0) { \ + el->type = M_C(name, _EMPTY); \ + } \ + M_MAP2(VARIANTI_DEFINE_IN_STR_FUNC , name, __VA_ARGS__) \ + else { b = false; } \ + return b && (fgetc(f) == '@'); \ } -#define VARIANTI_DEFINE_IN_STR_FUNC(name, a) \ +#define VARIANTI_DEFINE_IN_STR_FUNC(name, a) \ else if (strcmp (variantTypeBuf, M_APPLY (M_AS_STR, VARIANTI_GET_FIELD a)) == 0) { \ - el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ - VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ - b = VARIANTI_CALL_IN_STR(a, el -> value . VARIANTI_GET_FIELD a, f); \ + el->type = M_C4(name, _, VARIANTI_GET_FIELD a, _value); \ + VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ + b = VARIANTI_CALL_IN_STR(a, el -> value . VARIANTI_GET_FIELD a, f); \ } /* Return the STRING version of a parameter name */ -#define VARIANTI_STRINGIFY_NAME(a) \ +#define VARIANTI_STRINGIFY_NAME(a) \ M_APPLY(M_AS_STR, VARIANTI_GET_FIELD a) /* Define the OUT_SERIAL function */ -#define VARIANTI_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) { \ - VARIANTI_CONTRACT(name, el); \ - const int field_max = M_NARGS(__VA_ARGS__); \ - static const char *const field_name[] = \ - { M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - switch (el->type) { \ - case M_C(name, _EMPTY): \ +#define VARIANTI_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) { \ + VARIANTI_CONTRACT(name, el); \ + const int field_max = M_NARGS(__VA_ARGS__); \ + static const char *const field_name[] = \ + { M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + switch (el->type) { \ + case M_C(name, _EMPTY): \ return f->m_interface->write_variant_start(local, f, field_name, field_max, -1); \ - break; \ - M_MAP2(VARIANTI_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - ret |= f->m_interface->write_variant_end(local, f); \ - return ret & M_SERIAL_FAIL; \ + break; \ + M_MAP2(VARIANTI_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + ret |= f->m_interface->write_variant_end(local, f); \ + return ret & M_SERIAL_FAIL; \ } -#define VARIANTI_DEFINE_OUT_SERIAL_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - ret = f->m_interface->write_variant_start(local, f, field_name, field_max, \ - M_C4(name, _, VARIANTI_GET_FIELD a, _value) -1); \ - VARIANTI_CALL_OUT_SERIAL(a, f, el -> value . VARIANTI_GET_FIELD a); \ +#define VARIANTI_DEFINE_OUT_SERIAL_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + ret = f->m_interface->write_variant_start(local, f, field_name, field_max, \ + M_C4(name, _, VARIANTI_GET_FIELD a, _value) -1); \ + VARIANTI_CALL_OUT_SERIAL(a, f, el -> value . VARIANTI_GET_FIELD a); \ break; /* Define the IN_SERIAL function */ -#define VARIANTI_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) { \ - VARIANTI_CONTRACT(name, el); \ - const int field_max = M_NARGS(__VA_ARGS__); \ - static const char *const field_name[] = \ - { M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \ - assert (f != NULL && f->m_interface != NULL); \ - m_serial_local_t local; \ - m_serial_return_code_t ret; \ - int id = -1; \ - M_C(name, _clean)(el); \ +#define VARIANTI_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) { \ + VARIANTI_CONTRACT(name, el); \ + const int field_max = M_NARGS(__VA_ARGS__); \ + static const char *const field_name[] = \ + { M_REDUCE(VARIANTI_STRINGIFY_NAME, M_ID, __VA_ARGS__) }; \ + assert (f != NULL && f->m_interface != NULL); \ + m_serial_local_t local; \ + m_serial_return_code_t ret; \ + int id = -1; \ + M_C(name, _clean)(el); \ ret = f->m_interface->read_variant_start(local, f, field_name, field_max, &id); \ - if (ret != M_SERIAL_OK_CONTINUE) return ret; \ - assert (id >= 0 && id < field_max); \ - el->type = (enum M_C(name, _enum))(id+1); \ - switch (id+1) { \ - M_MAP2(VARIANTI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \ - default: assert(false); break; \ - } \ - if (ret == M_SERIAL_OK_DONE) \ - ret = f->m_interface->read_variant_end(local, f); \ - return ret; \ + if (ret != M_SERIAL_OK_CONTINUE) return ret; \ + assert (id >= 0 && id < field_max); \ + el->type = (enum M_C(name, _enum))(id+1); \ + switch (id+1) { \ + M_MAP2(VARIANTI_DEFINE_IN_SERIAL_FUNC , name, __VA_ARGS__) \ + default: assert(false); break; \ + } \ + if (ret == M_SERIAL_OK_DONE) \ + ret = f->m_interface->read_variant_end(local, f); \ + return ret; \ } -#define VARIANTI_DEFINE_IN_SERIAL_FUNC(name, a) \ - case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ - VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ - ret = VARIANTI_CALL_IN_SERIAL(a, el -> value . VARIANTI_GET_FIELD a, f); \ - break; \ +#define VARIANTI_DEFINE_IN_SERIAL_FUNC(name, a) \ + case M_C4(name, _, VARIANTI_GET_FIELD a, _value): \ + VARIANTI_CALL_INIT(a, el ->value . VARIANTI_GET_FIELD a ); \ + ret = VARIANTI_CALL_IN_SERIAL(a, el -> value . VARIANTI_GET_FIELD a, f); \ + break; \ /* Define the CLEAN function */ -#define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \ - static inline void M_C(name, _clean)(M_C(name,_ct) my) \ - { \ - VARIANTI_CONTRACT(name, my); \ - M_C(name, _clear)(my); \ - M_C(name, _init)(my); \ - } \ +#define VARIANTI_DEFINE_CLEAN_FUNC(name, ...) \ + static inline void M_C(name, _clean)(M_C(name,_ct) my) \ + { \ + VARIANTI_CONTRACT(name, my); \ + M_C(name, _clear)(my); \ + M_C(name, _init)(my); \ + } \ /* deferred evaluation of the oplist */ #define VARIANTI_OPLIST_P1(arg) VARIANTI_OPLIST_P2 arg /* Validate the oplist before going further */ -#define VARIANTI_OPLIST_P2(name, ...) \ +#define VARIANTI_OPLIST_P2(name, ...) \ M_IF(M_REDUCE(M_OPLIST_P, M_AND, __VA_ARGS__))(VARIANTI_OPLIST_P3, VARIANTI_OPLIST_FAILURE)(name, __VA_ARGS__) /* Prepare a clean compilation failure */ -#define VARIANTI_OPLIST_FAILURE(name, ...) \ +#define VARIANTI_OPLIST_FAILURE(name, ...) \ ((M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__))) /* Define the oplist */ -#define VARIANTI_OPLIST_P3(name, ...) \ - (INIT(M_C(name,_init)), \ - INIT_SET(M_C(name, _init_set)), \ - SET(M_C(name,_set)), \ - CLEAR(M_C(name, _clear)), \ - CLEAN(M_C(name, _clean)), \ - TYPE(M_C(name,_ct)), \ - TEST_EMPTY(M_C(name,_empty_p)), \ - 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 VARIANTI_OPLIST_P3(name, ...) \ + (INIT(M_C(name,_init)), \ + INIT_SET(M_C(name, _init_set)), \ + SET(M_C(name,_set)), \ + CLEAR(M_C(name, _clear)), \ + CLEAN(M_C(name, _clean)), \ + TYPE(M_C(name,_ct)), \ + TEST_EMPTY(M_C(name,_empty_p)), \ + 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_METHOD2_ALL(PARSE_STR, INIT, __VA_ARGS__)(PARSE_STR(M_C(name, _parse_str)),), \ - M_IF_METHOD2_ALL(IN_STR, INIT, __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_METHOD2_ALL(IN_STR, INIT, __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_METHOD2_ALL(IN_SERIAL, INIT, __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(INIT_MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \ - M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \ + M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(MOVE(M_C(name, _move)),), \ + M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_C(name, _swap)),), \ 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__,)),), \ ) /* Macros for testing for method presence */ -#define VARIANTI_TEST_METHOD_P2(method, f, t, op) \ +#define VARIANTI_TEST_METHOD_P2(method, f, t, op) \ M_TEST_METHOD_P(method, op) -#define VARIANTI_TEST_METHOD_P(method, trio) \ +#define VARIANTI_TEST_METHOD_P(method, trio) \ M_APPLY(VARIANTI_TEST_METHOD_P2, method, M_OPFLAT trio) -#define VARIANTI_IF_ALL(method, ...) \ +#define VARIANTI_IF_ALL(method, ...) \ M_IF(M_REDUCE2(VARIANTI_TEST_METHOD_P, M_AND, method, __VA_ARGS__)) -#define VARIANTI_TEST_METHOD2_P2(method1, method2, f, t, op) \ +#define VARIANTI_TEST_METHOD2_P2(method1, method2, f, t, op) \ M_AND(M_TEST_METHOD_P(method1, op), M_TEST_METHOD_P(method2, op)) -#define VARIANTI_TEST_METHOD2_P(method, trio) \ +#define VARIANTI_TEST_METHOD2_P(method, trio) \ M_APPLY(VARIANTI_TEST_METHOD2_P2, M_PAIR_1 method, M_PAIR_2 method, M_OPFLAT trio) -#define VARIANTI_IF_ALL2(method1, method2, ...) \ +#define VARIANTI_IF_ALL2(method1, method2, ...) \ M_IF(M_REDUCE2(VARIANTI_TEST_METHOD2_P, M_AND, (method1, method2), __VA_ARGS__)) #endif diff --git a/m-worker.h b/m-worker.h index d2cc94b4..1df8da95 100644 --- a/m-worker.h +++ b/m-worker.h @@ -43,8 +43,8 @@ /* Include needed system header for detection of how many core on the system */ #if defined(_WIN32) # include -#elif (defined(__APPLE__) && defined(__MACH__)) \ - || defined(__DragonFly__) || defined(__FreeBSD__) \ +#elif (defined(__APPLE__) && defined(__MACH__)) \ + || defined(__DragonFly__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) # include # include @@ -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