From 49a2e600c4a9470ffab8ce147305184b180713a0 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 15 May 2020 21:19:03 +0200 Subject: [PATCH] Add control of sub-oplist when creating a new oplist of a container Add test case of this new control Fix some corner bugs in some containers evolving their own oplists. --- m-array.h | 10 ++- m-bptree.h | 122 ++++++++++++++++----------- m-buffer.h | 10 ++- m-concurrent.h | 10 ++- m-deque.h | 10 ++- m-dict.h | 22 ++++- m-funcobj.h | 2 +- m-i-list.h | 10 ++- m-i-shared.h | 12 ++- m-list.h | 10 ++- m-prioqueue.h | 12 ++- m-rbtree.h | 24 ++++-- m-shared.h | 12 ++- m-snapshot.h | 10 ++- tests/Makefile | 19 +++-- tests/fail-chain-oplist.c | 169 ++++++++++++++++++++++++++++++++++++++ 16 files changed, 388 insertions(+), 76 deletions(-) create mode 100644 tests/fail-chain-oplist.c diff --git a/m-array.h b/m-array.h index 1a80a295..d7ffd601 100644 --- a/m-array.h +++ b/m-array.h @@ -53,10 +53,18 @@ so that all arguments are evaluated before further expansion */ #define ARRAYI_OPLIST_P1(arg) ARRAYI_OPLIST_P2 arg +/* Validation of the given oplist */ +#define ARRAYI_OPLIST_P2(name, oplist) \ + M_IF_OPLIST(oplist)(ARRAYI_OPLIST_P3, ARRAYI_OPLIST_FAILURE)(name, oplist) + +/* Prepare a clean compilation failure */ +#define ARRAYI_OPLIST_FAILURE(name, oplist) \ + M_LIB_ERROR(ARGUMENT_OF_ARRAY_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + /* OPLIST definition of a dynamic array */ /* FIXME: Do we want to export some methods as they are slow and are not fit to be used for building other methods (like _it_remove)? */ -#define ARRAYI_OPLIST_P2(name, oplist) \ +#define ARRAYI_OPLIST_P3(name, oplist) \ (INIT(M_C(name, _init)) \ ,INIT_SET(M_C(name, _init_set)) \ ,INIT_WITH(API_1(M_INIT_VAI)) \ diff --git a/m-bptree.h b/m-bptree.h index 5eae0350..24a19d22 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -78,16 +78,87 @@ 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_OPLISTR ), \ - (__VA_ARGS__ ))) + ((__VA_ARGS__, M_DEFAULT_OPLIST ), \ + (__VA_ARGS__ ))) /* Define the oplist of a rbtree of type (from BPTREE_DEF2). - USAGE: BPTREE_OPLIST2(name, key_oplist, value_oplist) + USAGE: BPTREE_OPLIST2(name[, key_oplist, value_oplist]) NOTE: IT_REF is not exported so that the contained appears as not modifiable by algorithm. */ -#define BPTREE_OPLIST2(name, key_oplist, value_oplist) \ +#define BPTREE_OPLIST2(...) \ + BPTREEI_OPLIST2_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST ), \ + (__VA_ARGS__ ))) + + + +/********************************** INTERNAL ************************************/ + +/* Deferred evaluation for the oplist definition, + so that all arguments are evaluated before further expansion */ +#define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg + +/* Validation of the given oplists */ +#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) \ + 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)), \ + 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,_t)), \ + SUBTYPE(M_C(name, _type_t)), \ + IT_TYPE(M_C(name, _it_t)), \ + 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 */ +#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) \ + 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) \ + M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist) + +#define BPTREEI_OPLIST2_P4(name, key_oplist, value_oplist) \ (INIT(M_C(name, _init)), \ INIT_SET(M_C(name, _init_set)), \ SET(M_C(name, _set)), \ @@ -128,51 +199,8 @@ ,M_IF_METHOD(REALLOC, key_oplist)(REALLOC(M_GET_REALLOC oplist),) \ ,M_IF_METHOD(DEL, key_oplist)(DEL(M_GET_DEL oplist),) \ ) - -/********************************** INTERNAL ************************************/ - -/* Deferred evaluation for the oplist definition, - so that all arguments are evaluated before further expansion */ -#define BPTREEI_KEY_OPLIST_P1(arg) BPTREEI_KEY_OPLIST_P2 arg - -/* OPLIST definition of a b+tree */ -#define BPTREEI_KEY_OPLIST_P2(name, oplist) \ - (INIT(M_C(name, _init)), \ - INIT_SET(M_C(name, _init_set)), \ - 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,_t)), \ - SUBTYPE(M_C(name, _type_t)), \ - IT_TYPE(M_C(name, _it_t)), \ - 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),) \ - ) /* Internal contract of a B+TREE node */ #ifdef NDEBUG diff --git a/m-buffer.h b/m-buffer.h index 1194c40f..1c6fe8e7 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -1066,8 +1066,16 @@ M_C(name, _init)(buffer_t v, size_t size) \ so that all arguments are evaluated before further expansion */ #define BUFFERI_OPLIST_P1(arg) BUFFERI_OPLIST_P2 arg -/* OPLIST defininition of a buffer */ +/* Validation of the given 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) \ + M_LIB_ERROR(ARGUMENT_OF_BUFFER_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + +/* OPLIST defininition 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)) \ diff --git a/m-concurrent.h b/m-concurrent.h index dc1b28d2..36bdafe8 100644 --- a/m-concurrent.h +++ b/m-concurrent.h @@ -62,12 +62,20 @@ so that all arguments are evaluated before further expansion */ #define CONCURRENTI_OPLIST_P1(arg) CONCURRENTI_OPLIST_P2 arg +/* Validation of the given oplist */ +#define CONCURRENTI_OPLIST_P2(name, oplist) \ + M_IF_OPLIST(oplist)(CONCURRENTI_OPLIST_P3, CONCURRENTI_OPLIST_FAILURE)(name, oplist) + +/* Prepare a clean compilation failure */ +#define CONCURRENTI_OPLIST_FAILURE(name, oplist) \ + M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + /* OPLIST definition GET_KEY is not present as its interface is not compatible with a concurrent container (_get returns a pointer to an internal data, data that may be destroyed by another thread). */ -#define CONCURRENTI_OPLIST_P2(name, 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)),) \ diff --git a/m-deque.h b/m-deque.h index 23bd1476..ad4f9e04 100644 --- a/m-deque.h +++ b/m-deque.h @@ -951,8 +951,16 @@ so that all arguments are evaluated before further expansion */ #define DEQUEI_OPLIST_P1(arg) DEQUEI_OPLIST_P2 arg -/* OPLIST definition of a deque */ +/* Validation of the given oplist */ #define DEQUEI_OPLIST_P2(name, oplist) \ + M_IF_OPLIST(oplist)(DEQUEI_OPLIST_P3, DEQUEI_OPLIST_FAILURE)(name, oplist) + +/* Prepare a clean compilation failure */ +#define DEQUEI_OPLIST_FAILURE(name, oplist) \ + 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)) \ diff --git a/m-dict.h b/m-dict.h index 64248cbf..c2bebaf4 100644 --- a/m-dict.h +++ b/m-dict.h @@ -952,10 +952,20 @@ so that all arguments are evaluated before further expansion */ #define DICTI_OPLIST_P1(arg) DICTI_OPLIST_P2 arg +/* Validation of the given oplists */ +#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) \ + 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) \ + 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_P2(name, key_oplist, value_oplist) \ +#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)), \ @@ -1001,8 +1011,16 @@ so that all arguments are evaluated before further expansion */ #define DICTI_SET_OPLIST_P1(arg) DICTI_SET_OPLIST_P2 arg +/* Validation of the given 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) \ + M_LIB_ERROR(ARGUMENT_OF_DICT_SET_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + /* Define the oplist of a set */ -#define DICTI_SET_OPLIST_P2(name, 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)), \ diff --git a/m-funcobj.h b/m-funcobj.h index f557c31c..5f4bc528 100644 --- a/m-funcobj.h +++ b/m-funcobj.h @@ -84,7 +84,7 @@ */ /* Specialization of the OPLIST in function if there is at least one member or not */ -#define FUNC_OBJ_INS_NO_ATTR_OPLIST(name, ...) \ +#define FUNC_OBJ_INS_NO_ATTR_OPLIST(name) \ (NAME(name), TYPE(M_C(name, _t)), \ CLEAR(M_C(name, _clear)), \ INIT(M_C(name,_init)) \ diff --git a/m-i-list.h b/m-i-list.h index 54ec41d7..a54c9e59 100644 --- a/m-i-list.h +++ b/m-i-list.h @@ -70,8 +70,16 @@ typedef struct ilist_head_s { /* Indirection call to allow expanding all arguments */ #define ILISTI_OPLIST_P1(arg) ILISTI_OPLIST_P2 arg +/* Validation of the given 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) \ + M_LIB_ERROR(ARGUMENT_OF_ILIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + /* Define the oplist of an ilist of type */ -#define ILISTI_OPLIST_P2(name,oplist) \ +#define ILISTI_OPLIST_P3(name, oplist) \ (INIT(M_C(name, _init)), \ CLEAR(M_C(name, _clear)), \ INIT_MOVE(M_C(name, _init_move)), \ diff --git a/m-i-shared.h b/m-i-shared.h index aaf98a1d..cca749b3 100644 --- a/m-i-shared.h +++ b/m-i-shared.h @@ -56,8 +56,16 @@ // Deferred evaluation #define ISHAREDI_PTR_OPLIST_P1(arg) ISHAREDI_PTR_OPLIST_P2 arg +/* Validation of the given 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) \ + M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + // Define the oplist -#define ISHAREDI_PTR_OPLIST_P2(name, oplist) ( \ +#define ISHAREDI_PTR_OPLIST_P3(name, oplist) ( \ INIT(M_INIT_DEFAULT), \ INIT_SET(M_C(name, _init_set2) M_IPTR), \ SET(M_C(name, _set) M_IPTR), \ @@ -112,6 +120,7 @@ *ptr = M_C(name, _init_set)(shared); \ } \ \ + M_IF_METHOD2(INIT, NEW, oplist)( \ static inline M_C(name,_t) \ M_C(name, _init_new)(void) \ { \ @@ -124,6 +133,7 @@ atomic_init (&ptr->M_C(name, _cpt), 1); \ return ptr; \ } \ + , /* End of INIT/NEW */) \ \ static inline void \ M_C(name, _clear)(M_C(name,_t) shared) \ diff --git a/m-list.h b/m-list.h index f03568fc..2420fec7 100644 --- a/m-list.h +++ b/m-list.h @@ -57,8 +57,16 @@ so that all arguments are evaluated before further expansion */ #define LISTI_OPLIST_P1(arg) LISTI_OPLIST_P2 arg +/* Validation of the given 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) \ + 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_P2(name, 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)), \ diff --git a/m-prioqueue.h b/m-prioqueue.h index 794bf7c9..8b2806ae 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -53,8 +53,16 @@ so that all arguments are evaluated before further expansion */ #define PRIOQUEUEI_OPLIST_P1(arg) PRIOQUEUEI_OPLIST_P2 arg +/* Validation of the given 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) \ + M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + /* Define oplist of a priority queue */ -#define PRIOQUEUEI_OPLIST_P2(name, oplist) \ +#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)) \ @@ -366,7 +374,7 @@ } \ } \ \ - , /* No EQUAL */ \) \ + , /* No EQUAL */ ) \ // TODO: set all & remove all function diff --git a/m-rbtree.h b/m-rbtree.h index ad51fedc..86c61466 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -51,10 +51,18 @@ so that all arguments are evaluated before further expansion */ #define RBTREEI_OPLIST_P1(arg) RBTREEI_OPLIST_P2 arg +/* Validation of the given 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) \ + 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_P2(name, 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)), \ @@ -148,7 +156,7 @@ typedef enum { /* Internal rbtree definition - name: prefix to be used - - type: type of the elements of the array + - type: type of the elements of the rbtree - oplist: oplist of the type of the elements of the container - tree_t: alias for M_C(name, _t) [ type of the container ] - it_t: alias for M_C(name, _it_t) [ iterator of the container ] @@ -1035,23 +1043,23 @@ typedef enum { M_C(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ { \ RBTREEI_CONTRACT(t1); \ - assert (f != NULL && f->m_interface != NULL); \ + assert (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ m_serial_return_code_t ret; \ const M_C(name, _type_t) *item; \ bool first_done = false; \ it_t it; \ - ret = f->m_interface->write_array_start(local, f, t1->size); \ + 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 |= 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); \ + ret |= f->m_interface->write_array_end(local, f); \ return ret & M_SERIAL_FAIL; \ } \ , /* no OUT_SERIAL */ ) \ @@ -1061,13 +1069,13 @@ typedef enum { M_C(name, _in_serial)(tree_t t1, m_serial_read_t f) \ { \ RBTREEI_CONTRACT(t1); \ - assert (f != NULL && f->m_interface != NULL); \ + 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); \ + 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 { \ diff --git a/m-shared.h b/m-shared.h index b068c2ed..27bde6a0 100644 --- a/m-shared.h +++ b/m-shared.h @@ -34,7 +34,7 @@ #define SHARED_PTR_OPLIST(...) \ SHAREDI_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ ((__VA_ARGS__, M_DEFAULT_OPLIST ), \ - _OPLIST(__VA_ARGS__ ))) + (__VA_ARGS__ ))) /* Define shared pointer and its function. @@ -68,7 +68,15 @@ // deferred evaluation #define SHAREDI_PTR_OPLIST_P1(arg) SHAREDI_PTR_OPLIST_P2 arg -#define SHAREDI_PTR_OPLIST_P2(name, oplist) ( \ +/* Validation of the given 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) \ + 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)), \ diff --git a/m-snapshot.h b/m-snapshot.h index 7110e0d1..3131948f 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -66,8 +66,16 @@ // deferred evaluation of the input #define SNAPSHOTI_OPLIST_P1(arg) SNAPSHOTI_OPLIST_P2 arg +/* Validation of the given 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) \ + M_LIB_ERROR(ARGUMENT_OF_SNAPSHOT_OPLIST_IS_NOT_AN_OPLIST, name, oplist) + /* Define the oplist of a snapshot */ -#define SNAPSHOTI_OPLIST_P2(name, oplist) \ +#define SNAPSHOTI_OPLIST_P3(name, oplist) \ (INIT(M_C(name, _init)) \ ,INIT_SET(M_C(name, _init_set)) \ ,SET(M_C(name, _set)) \ diff --git a/tests/Makefile b/tests/Makefile index c5a258e8..dd6a6518 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -64,7 +64,8 @@ depend: ##################################################################################################### check: depend - $(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` checkfail + $(MAKE) `ls test-*.c|$(SED) 's/\.c/\.log/g'` `ls fail-*.c|$(SED) 's/\.c/\.log/g'` + @echo All tests passed clean: $(RM) *.exe *.s *~ *.o *.log a*.dat @@ -74,19 +75,25 @@ clean: distclean: clean $(RM) *.depend depend -checkfail: fail-no-oplist - ##################################################################################################### # Proper failure generation (test if the code properly fails to compile) ##################################################################################################### # TODO: should grep failure message? -fail-no-oplist: - for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 ; do \ - if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c fail-no-oplist.c -o tmp.o -DTEST=$$i 2> fail-no-oplist-$$i.log ; then echo fail-no-oplist-$$i : ERROR; false; else echo fail-no-oplist-$$i : OK ; fi \ +FAIL_BASE= +FAIL_SEQ= +fail-generic.log: + for i in `seq 1 $(FAIL_SEQ)` ; do \ + if $(CC) $(CFLAGS) $(CPPFLAGS) -g -c $(FAIL_BASE).c -o tmp.o -DTEST=$$i 2> $(FAIL_BASE)-$$i.log ; then echo $(FAIL_BASE) -- TEST $$i : ERROR; false; else echo $(FAIL_BASE) -- TEST $$i : OK ; fi \ done +fail-no-oplist.log: + @$(MAKE) fail-generic.log FAIL_BASE=fail-no-oplist FAIL_SEQ=44 +fail-chain-oplist.log: + @$(MAKE) fail-generic.log FAIL_BASE=fail-chain-oplist FAIL_SEQ=17 + + ##################################################################################################### # Code generation analysis ##################################################################################################### diff --git a/tests/fail-chain-oplist.c b/tests/fail-chain-oplist.c new file mode 100644 index 00000000..06a61511 --- /dev/null +++ b/tests/fail-chain-oplist.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2017-2020, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* The goal of this test file is to check that invalid constructs + are properly rejected, and that it generates a helpfull error + message in this case. + It tests invalid oplist in an _OPLIST constructor of a container. +*/ +#include "m-core.h" + +#if !defined(TEST) +# warning Please define TEST variable to select the test to run + +#elif TEST == 1 + +#include "m-array.h" + +ARRAY_DEF(array, int) +ARRAY_DEF(array2, array_t, ARRAY_OPLIST(array, DEFAULT_OPLIST)) + +#elif TEST == 2 + +#include "m-list.h" + +LIST_DEF(list, int) +LIST_DEF(list2, list_t, LIST_OPLIST(list, DEFAULT_OPLIST)) + +#elif TEST == 3 + +#include "m-deque.h" + +DEQUE_DEF(deque, int) +DEQUE_DEF(deque2, deque_t, DEQUE_OPLIST(deque, DEFAULT_OPLIST)) + +#elif TEST == 4 + +#include "m-bptree.h" + +BPTREE_DEF(bptree, 4, int) +BPTREE_DEF(bptree2, 5, bptree_t, BPTREE_OPLIST(bptree, DEFAULT_OPLIST)) + +#elif TEST == 5 + +#include "m-bptree.h" + +BPTREE_DEF2(bptree, 4, int, int) +BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, DEFAULT_OPLIST, M_DEFAULT_OPLIST), int, M_DEFAULT_OPLIST) + +#elif TEST == 6 + +#include "m-bptree.h" + +BPTREE_DEF2(bptree, 4, int, int) +BPTREE_DEF2(bptree2, 5, bptree_t, BPTREE_OPLIST2(bptree, M_DEFAULT_OPLIST, DEFAULT_OPLIST), int, M_DEFAULT_OPLIST) + +#elif TEST == 7 + +#include "m-buffer.h" + +BUFFER_DEF(buffer, int, 4, BUFFER_THREAD_UNSAFE) +BUFFER_DEF(buffer2, buffer_t, 5, BUFFER_QUEUE, BUFFER_OPLIST(buffer, DEFAULT_OPLIST)) + +#elif TEST == 8 + +#include "m-array.h" +#include "m-concurrent.h" + +ARRAY_DEF(array, int) +CONCURRENT_DEF(array2, array_t, ARRAY_OPLIST(array, M_DEFAULT_OPLIST)) +ARRAY_DEF(array3, array2_t, CONCURRENT_OPLIST(array2, ARRAY_OPLIST(array, DEFAULT_OPLIST))) + +#elif TEST == 9 + +#include "m-dict.h" + +DICT_DEF2(dict, int, int) +DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, DEFAULT_OPLIST, M_DEFAULT_OPLIST) ) + +#elif TEST == 10 + +#include "m-dict.h" + +DICT_DEF2(dict, int, int) +DICT_DEF2(dict2, int, M_DEFAULT_OPLIST, dict_t, DICT_OPLIST(dict, M_DEFAULT_OPLIST, DEFAULT_OPLIST) ) + +#elif TEST == 11 + +#include "m-dict.h" +#include "m-array.h" + +DICT_SET_DEF(dict, int) +ARRAY_DEF(array, dict_t, DICT_SET_OPLIST(dict, DEFAULT_OPLIST) ) + +#elif TEST == 12 + +#include "m-i-list.h" +#include "m-concurrent.h" + +typedef struct tmp_str_s { + ILIST_INTERFACE(tmpstr, struct tmp_str_s); + int n; +} tmp_str_t; +ILIST_DEF(tmpstr, tmp_str_t, (CLEAR(M_NOTHING_DEFAULT))) +CONCURRENT_DEF(array, tmpstr_t, ILIST_OPLIST(tmpstr, X())) + +#elif TEST == 13 + +#include "m-i-shared.h" +#include "m-concurrent.h" + +typedef struct tmp_str_s { + ISHARED_PTR_INTERFACE(tmpstr, struct tmp_str_s); + int n; +} tmp_str_t; +ISHARED_PTR_DEF(tmpstr, tmp_str_t, (CLEAR(M_NOTHING_DEFAULT))) +CONCURRENT_DEF(array, tmpstr_t, ISHARED_PTR_OPLIST(tmpstr, X())) + +#elif TEST == 14 + +#include "m-prioqueue.h" + +PRIOQUEUE_DEF(prioqueue, int) +PRIOQUEUE_DEF(prioqueue2, prioqueue_t, PRIOQUEUE_OPLIST(prioqueue, M_DEFAULT_OPLIST())) + +#elif TEST == 15 + +#include "m-rbtree.h" + +RBTREE_DEF(rbtree, int) +RBTREE_DEF(rbtree2, rbtree_t, RBTREE_OPLIST(rbtree, M_DEFAULT_OPLIST2)) + +#elif TEST == 16 + +#include "m-shared.h" + +SHARED_PTR_DEF(shared, int) +SHARED_PTR_DEF(shared2, shared_t, SHARED_PTR_OPLIST(shared, M_DEFAULT_OPLISTop)) + +#elif TEST == 17 + +#include "m-snapshot.h" + +SNAPSHOT_SPSC_DEF(shared, int) +SNAPSHOT_SPSC_DEF(shared2, shared_t, SNAPSHOT_OPLIST(shared, M_DEFAULT_OPLIST x)) + +#else +# warning TEST variable is out of range. +#endif +