Adding macro M_CHAIN_OBJ
This commit is contained in:
1 parent
19e61467d5
commit
5f4303624f
3 files changed
+180
-6
No files matched your search
@@ -6843,7 +6843,7 @@ This is equivalent to C++ construct:
|
|||||||
|
|
||||||
void type() : field1(), field2() { rest of constructor }
|
void type() : field1(), field2() { rest of constructor }
|
||||||
|
|
||||||
M_CHAIN_INIT shall be the first instructions of the constructor function.
|
M_CHAIN_INIT / M_CHAIN_OBJ shall be the first instructions of the constructor function.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -6856,6 +6856,44 @@ Example:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##### M\_CHAIN\_OBJ(name, oplist, var [, value])
|
||||||
|
|
||||||
|
This macro executes the initialization method if 'var' to initialize it then
|
||||||
|
registers the execution of its CLEAR method if an exception is triggered
|
||||||
|
(and if the property NOCLEAR of the oplist is not defined)
|
||||||
|
until the further closing brace of the next block of instruction.
|
||||||
|
If exception are not enabled, it simply executes the initialization method.
|
||||||
|
|
||||||
|
The initialization method being used is :
|
||||||
|
|
||||||
|
* INIT method if there is no value
|
||||||
|
* INIT\_SET method if there is a value which is not between parenthesis
|
||||||
|
* INIT\_WITH method if there is a value which is between parenthesis.
|
||||||
|
|
||||||
|
name shall a unique identifier in the current block.
|
||||||
|
It can be chained multiple times to register multiple registrations.
|
||||||
|
|
||||||
|
Therefore it enables support for chaining
|
||||||
|
initialization at the begining of a constructor for the fields of the constructed
|
||||||
|
object so that even if the constructor failed and throw an exception,
|
||||||
|
the fields of the constructed object are properly cleared.
|
||||||
|
|
||||||
|
This is equivalent to C++ construct:
|
||||||
|
|
||||||
|
void type() : field1(), field2() { rest of constructor }
|
||||||
|
|
||||||
|
M_CHAIN_INIT / M_CHAIN_OBJ shall be the first instructions of the constructor function.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
void struct_init_set(struct_t d, struct_t s)
|
||||||
|
{
|
||||||
|
M_CHAIN_OBJ(s1, STRING_OPLIST, d->s1, s->s1)
|
||||||
|
M_CHAIN_OBJ(s2, STRING_OPLIST, d->s2, s->s2)
|
||||||
|
M_CHAIN_OBJ(nu, M_BASIC_OPLIST, d->num, s->num) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#### Memory / Error macros
|
#### Memory / Error macros
|
||||||
|
|
||||||
All these macro can be overridden before including the header m-core.h
|
All these macro can be overridden before including the header m-core.h
|
||||||
|
|||||||
@@ -4387,9 +4387,9 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
|||||||
the fields of the constructed object are properly cleared.
|
the fields of the constructed object are properly cleared.
|
||||||
This is equivalent to C++ construct: void type() : field1(), field2() { rest of constructor }
|
This is equivalent to C++ construct: void type() : field1(), field2() { rest of constructor }
|
||||||
M_CHAIN_INIT shall be the first instruction of the init function.
|
M_CHAIN_INIT shall be the first instruction of the init function.
|
||||||
First argument is the initialization code.
|
Second argument is the initialization code.
|
||||||
Second argument is the clear code.
|
Third argument is the clear code.
|
||||||
The clear code is only executed on exception.
|
The clear code is *only* executed on exception.
|
||||||
USAGE:
|
USAGE:
|
||||||
void init_function(struct_t s) {
|
void init_function(struct_t s) {
|
||||||
M_CHAIN_INIT(name, string_init(s->str), string_clear(s->str)) {
|
M_CHAIN_INIT(name, string_init(s->str), string_clear(s->str)) {
|
||||||
@@ -4408,6 +4408,61 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
|||||||
for( (void) 0; cont; cont = false)
|
for( (void) 0; cont; cont = false)
|
||||||
|
|
||||||
|
|
||||||
|
/* If exceptions are activated, M_CHAIN_OBJ enables support for chaining
|
||||||
|
initialization at the begining of a constructor for the fields of the constructed
|
||||||
|
object so that even if the constructor failed and throw an exception,
|
||||||
|
the fields of the constructed object are properly cleared.
|
||||||
|
This is equivalent to M_CHAIN_INIT except it takes an oplist.
|
||||||
|
This is equivalent to C++ construct: void type() : field1(), field2() { rest of constructor }
|
||||||
|
M_CHAIN_OBJ shall be the first instruction of the init function except
|
||||||
|
it can be freely mixed with M_CHAIN_INIT
|
||||||
|
First argument is a name identifier.
|
||||||
|
Second argument is the oplist of the variable to initialize.
|
||||||
|
Third argument is the variable to initialize.
|
||||||
|
Optional fourth argument is the value to use for initialization.
|
||||||
|
If there is no value, it will initialize using the INIT method.
|
||||||
|
Otherwise, if there is no parenthesis around the value, it will use the INIT_SET method.
|
||||||
|
Otherwise the INIT_WITH method.
|
||||||
|
The clear code is *only* executed on exception.
|
||||||
|
If the property NOCLEAR is defined for the object,
|
||||||
|
it won't generate an exception handler at all even if exceptions are activated,
|
||||||
|
and will only initialize the object.
|
||||||
|
USAGE:
|
||||||
|
void init_function(struct_t s) {
|
||||||
|
M_CHAIN_OBJ(name, STRING_OPLIST, s->str ) {
|
||||||
|
// Rest of initialization code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#define M_CHAIN_OBJ(name, oplist, ...) \
|
||||||
|
M_BY_NARGS( M_IF(M_GET_PROPERTY(oplist, NOCLEAR))(M_CHAIN_OBJ_A, M_CHAIN_OBJ_B), __VA_ARGS__) \
|
||||||
|
(name, oplist, __VA_ARGS__)
|
||||||
|
// Need to define an exception handler. Use of M_CHAIN_INIT
|
||||||
|
#define M_CHAIN_OBJ_B__NARGS_1(name, oplist, var) \
|
||||||
|
M_CHAIN_INIT( name, M_CALL_INIT(oplist, var), M_CALL_CLEAR(oplist, var) )
|
||||||
|
#define M_CHAIN_OBJ_B__NARGS_2(name, oplist, var, value) \
|
||||||
|
M_IF(M_PARENTHESIS_P(value))(M_CHAIN_OBJ_B__NARGS_2_WITH, M_CHAIN_OBJ_B__NARGS_2_SET) \
|
||||||
|
(name, oplist, var, value)
|
||||||
|
#define M_CHAIN_OBJ_B__NARGS_2_WITH(name, oplist, var, value) \
|
||||||
|
M_CHAIN_INIT( name, M_CALL_INIT_WITH(oplist, var, value), M_CALL_CLEAR(oplist, var) )
|
||||||
|
#define M_CHAIN_OBJ_B__NARGS_2_SET(name, oplist, var, value) \
|
||||||
|
M_CHAIN_INIT( name, M_CALL_INIT_SET(oplist, var, value), M_CALL_CLEAR(oplist, var) )
|
||||||
|
// No need to define an exception handler. Just call the INIT function.
|
||||||
|
#define M_CHAIN_OBJ_A__NARGS_1(name, oplist, var) \
|
||||||
|
M_CHAIN_FOR(name, M_CALL_INIT(oplist, var) )
|
||||||
|
#define M_CHAIN_OBJ_A__NARGS_2(name, oplist, var, value) \
|
||||||
|
M_CHAIN_FOR(name, \
|
||||||
|
M_IF(M_PARENTHESIS_P(value))(M_CALL_INIT_WITH, M_CALL_INIT_SET) \
|
||||||
|
(oplist, var, value) )
|
||||||
|
// Execute the 'init' function in a for loop construct
|
||||||
|
#define M_CHAIN_FOR(name, init ) \
|
||||||
|
M_CHAIN_FOR_B(M_C(m_var_, name), init)
|
||||||
|
#define M_CHAIN_FOR_B(cont, init) \
|
||||||
|
for(bool cont = true; cont; cont = false) \
|
||||||
|
for( init; cont ; cont = false) \
|
||||||
|
for( (void) 0; cont; cont = false)
|
||||||
|
|
||||||
|
|
||||||
/* Declare a variable, initialize it, continue if the initialization succeeds,
|
/* Declare a variable, initialize it, continue if the initialization succeeds,
|
||||||
and clears the variable afterwards.
|
and clears the variable afterwards.
|
||||||
Otherwise, stop the execution and execute else_code if defined.
|
Otherwise, stop the execution and execute else_code if defined.
|
||||||
|
|||||||
+83
-2
@@ -488,6 +488,27 @@ static void struct_init_set(struct_t x, const struct_t y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void struct_initb(struct_t x)
|
||||||
|
{
|
||||||
|
M_CHAIN_OBJ(o1, TESTOBJ_OPLIST, x->o1)
|
||||||
|
M_CHAIN_OBJ(o2, TESTOBJ_OPLIST, x->o2)
|
||||||
|
M_CHAIN_OBJ(o3, M_BASIC_OPLIST, x->num) {
|
||||||
|
if (++g_flow == g_throw) M_THROW(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void struct_init_setb(struct_t x, const struct_t y)
|
||||||
|
{
|
||||||
|
M_CHAIN_OBJ(o1, TESTOBJ_OPLIST, x->o1, y->o1) {
|
||||||
|
// Throw within the constructor (object partially constructed)
|
||||||
|
if (++g_flow == g_throw) M_THROW(1);
|
||||||
|
M_CHAIN_OBJ(o2, TESTOBJ_OPLIST, x->o2, y->o2)
|
||||||
|
M_CHAIN_OBJ(o3, M_BASIC_OPLIST, x->num, y->num) {
|
||||||
|
if (++g_flow == g_throw) M_THROW(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void struct_clear(struct_t x)
|
static void struct_clear(struct_t x)
|
||||||
{
|
{
|
||||||
testobj_clear(x->o1);
|
testobj_clear(x->o1);
|
||||||
@@ -496,7 +517,7 @@ static void struct_clear(struct_t x)
|
|||||||
|
|
||||||
#define M_OPL_struct_t() M_CLASSIC_OPLIST(struct)
|
#define M_OPL_struct_t() M_CLASSIC_OPLIST(struct)
|
||||||
|
|
||||||
static void test4(void)
|
static void test4a(void)
|
||||||
{
|
{
|
||||||
g_flow = 0;
|
g_flow = 0;
|
||||||
g_throw = 4;
|
g_throw = 4;
|
||||||
@@ -552,6 +573,65 @@ static void test4(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define STRUCTB_OPLIST \
|
||||||
|
(INIT(struct_initb), INIT_SET(struct_init_setb), CLEAR(struct_clear), TYPE(struct_t))
|
||||||
|
|
||||||
|
static void test4b(void)
|
||||||
|
{
|
||||||
|
g_flow = 0;
|
||||||
|
g_throw = 4;
|
||||||
|
M_TRY(main) {
|
||||||
|
assert(++g_flow == 1);
|
||||||
|
M_LET(a, STRUCTB_OPLIST) {
|
||||||
|
assert(++g_flow == 3);
|
||||||
|
M_LET( (b, a), STRUCTB_OPLIST) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} M_CATCH(main, 0) {
|
||||||
|
assert(++g_flow == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_flow = 0;
|
||||||
|
g_throw = 5;
|
||||||
|
M_TRY(main) {
|
||||||
|
assert(++g_flow == 1);
|
||||||
|
M_LET(a, STRUCTB_OPLIST) {
|
||||||
|
assert(++g_flow == 3);
|
||||||
|
M_LET( (b, a), STRUCTB_OPLIST) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} M_CATCH(main, 0) {
|
||||||
|
assert(++g_flow == 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_flow = 0;
|
||||||
|
g_throw = 2;
|
||||||
|
M_TRY(main) {
|
||||||
|
assert(++g_flow == 1);
|
||||||
|
M_LET(a, STRUCTB_OPLIST) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
} M_CATCH(main, 0) {
|
||||||
|
assert(++g_flow == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_flow = 0;
|
||||||
|
g_throw = 0;
|
||||||
|
M_TRY(main) {
|
||||||
|
assert(++g_flow == 1);
|
||||||
|
M_LET(a, STRUCTB_OPLIST) {
|
||||||
|
assert(++g_flow == 3);
|
||||||
|
M_LET( (b, a), STRUCTB_OPLIST) {
|
||||||
|
assert(++g_flow == 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} M_CATCH(main, 0) {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void test_final(void)
|
static void test_final(void)
|
||||||
{
|
{
|
||||||
// Throw without a try block shall raise the M_RAISE_FATAL macro
|
// Throw without a try block shall raise the M_RAISE_FATAL macro
|
||||||
@@ -568,7 +648,8 @@ int main(void)
|
|||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
||||||
test3();
|
test3();
|
||||||
test4();
|
test4a();
|
||||||
|
test4b();
|
||||||
testobj_final_check();
|
testobj_final_check();
|
||||||
test_final();
|
test_final();
|
||||||
exit(1); // Shall not be reached.
|
exit(1); // Shall not be reached.
|
||||||
|
|||||||
Reference in new issue
Block a user