From f2d5de252b74f1d97365ea4312f4e049fbb1a549 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 6 Feb 2021 23:24:55 +0100 Subject: [PATCH] Add M_FILTER and M_FILTER_C macros (src, tests, doc) --- README.md | 17 +++++++++++++++++ m-core.h | 30 ++++++++++++++++++++++++++++++ tests/test-mcore.c | 11 +++++++++++ 3 files changed, 58 insertions(+) diff --git a/README.md b/README.md index adf82d19..b8d4a9e6 100644 --- a/README.md +++ b/README.md @@ -5710,6 +5710,23 @@ Replicate the value 'value' N times, separating then by commas. ==> D , D , D , D , D +##### M\_FILTER(func, data, ...) + +Filter the arglists by keeping only the element that match the function 'func(data, element)' + + M_FILTER(M_NOTEQUAL, 8, 1, 3, 4, 8, 9, 8, 10) + ==> + 1 3 4 9 10 + +##### M\_FILTER\_C(func, data, ...) + +Filter the arglists by keeping only the element that match the function 'func(data, element)' +separated by commas. + + M_FILTER(M_NOTEQUAL, 8, 1, 3, 4, 8, 9, 8, 10) + ==> + 1 , 3 , 4 , 9 , 10 + ##### M\_NARGS(args...) Return the number of argument of the given list. diff --git a/m-core.h b/m-core.h index 86ab5a7d..ecca701b 100644 --- a/m-core.h +++ b/m-core.h @@ -1575,6 +1575,36 @@ M_BEGIN_PROTECTED_CODE #define M_REPLICATE_C(N, value) \ M_MAP2_C(M_RET_ARG1, value, M_SEQ(1, N)) +/* Filter the elements of the list so that only the elements + that match the function f are returned. + f takes as argument (extra, item) and shall return 0 or 1. */ +#define M_FILTER(f, extra, ...) \ + M_MAP2( M_FILTER_00, (f, extra), __VA_ARGS__) + +/* Filter the elements of the list so that only the elements + that match the function f are returned. + f takes as argument (extra, item) and shall return 0 or 1. */ +#define M_FILTER_C(f, extra, ...) \ + M_REMOVE_PARENTHESIS (M_REDUCE2(M_FILTER_00, M_CAT_ARGLIST, (f, extra), __VA_ARGS__) ) + +/* d is (filter_function, extra_value) item is the element ot test */ +#define M_FILTER_00(d, item) \ + M_IF(M_PAIR_1 d(M_PAIR_2 d, item))(item, ) + +/* Concatene two arglists 'a' and 'b', + handling the case of empty arglist + handling the cases where the arglists are within parenthesis. + and returning an arglist within parenthesis if it concats. + (internal macro) +*/ +#define M_CAT_ARGLIST(a, b) \ + M_IF_EMPTY(a)(b, M_IF_EMPTY(b)(a,( M_REMOVE_PARENTHESIS (a) , M_REMOVE_PARENTHESIS (b)))) + +/* Remove the parenthesis if needed + (internal macro) */ +#define M_REMOVE_PARENTHESIS(list) \ + M_IF(M_PARENTHESIS_P(list))( M_OPFLAT list, list) + /* Return the input (delay evaluation) */ #define M_ID(...) __VA_ARGS__ diff --git a/tests/test-mcore.c b/tests/test-mcore.c index 31cd27f3..64385633 100644 --- a/tests/test-mcore.c +++ b/tests/test-mcore.c @@ -305,10 +305,21 @@ static void test_list(void) assert(M_KEEP_ARGS(1, 1, 0, 0, 0, 0)); assert(M_SKIP_ARGS(4, 0, 0, 0, 0, 1)); assert(M_MID_ARGS(2, 1, 0, 0, 1, 0)); + const int tab[] = { M_REPLICATE_C(5, 1) }; for(int i = 0; i < 5; i++) assert(tab[i] == 1); const char str[] = M_REPLICATE(10, "N"); assert(strcmp(str, "NNNNNNNNNN") == 0); + + assert(M_EQUAL(M_REMOVE_PARENTHESIS( 17 ), 17)); + assert(M_EQUAL(M_REMOVE_PARENTHESIS( (17) ), 17)); + + assert( M_FILTER(M_EQUAL, 17, 1, 42, 17, 89) ); + assert( M_FILTER_C(M_EQUAL, 17, 1, 42, 17, 89) ); + const int tab2[] = { M_FILTER_C(M_NOTEQUAL, 8, 1, 3, 4, 8, 9, 8, 10) }; + const int tabref[] = { 1, 3, 4, 9, 10 }; + assert (sizeof tab2 == sizeof tabref); + for(int i = 0; i < 5 ; i++) assert(tab2[i] == tabref[i]); } static void test_oplist(void)