Update _transform, _reduce and _map_reduce to be more flexible
Rename _map_reduce to _transform_reduce
This commit is contained in:
1 parent
34085aa637
commit
3fbe8ec0b6
4 files changed
+86
-37
No files matched your search
@@ -8200,31 +8200,40 @@ Apply the function `func` to each element of the container `c`.
|
||||
The function may transform the element provided it doesn't reallocate the
|
||||
object and if the container supports iterating over modifiable elements.
|
||||
|
||||
##### `void name_transform(container_t d, container_t c, void (*func)(type_t *out, const type_t in))`
|
||||
##### `void name_transform(container_t d, container_t c, bool (*func)(type_t *out, const type_t in, void *data), void *data)`
|
||||
|
||||
Apply the function `func` to each element of the container `c`
|
||||
and push the result into the container `d` so that `d = func(c)`
|
||||
Reset the container `d`, then
|
||||
apply the function `func` to each element of the container `c`
|
||||
and push its output `*out` into the container `d` if its return value is true.
|
||||
|
||||
`func` shall output in the initialized object `out`
|
||||
the transformed value of the constant object `in`.
|
||||
Afterwards `out` is pushed moved into `d`.
|
||||
`func` shall output in the initialized object `*out`
|
||||
the transformed value of the constant object `in` if it decides this value is kept (its return value is true in this case).
|
||||
Otherwise its return value is false.
|
||||
`data` is a user context data pointer free to be used and passed to `func`
|
||||
|
||||
This method is defined only if the base type exports an `INIT` method.
|
||||
This method is defined only if the container exports a `PUSH_MOVE` method.
|
||||
`c` and `d` cannot be the same containers.
|
||||
This method is defined only if the base type exports an `INIT` method and if the container exports a `PUSH` method.
|
||||
`c` and `d` shall not be the same containers.
|
||||
|
||||
##### `void name_reduce(type_t *dest, const container_t c, void (*func)(type_t *, type_t const))`
|
||||
##### `bool name_reduce(type_t *dest, const container_t c, void (*func)(type_t *, type_t const))`
|
||||
|
||||
Perform a reduction using the function `func` to the elements of the container `c`.
|
||||
The final result is stored in `*dest`.
|
||||
If there is no element, `*dest` is let unmodified.
|
||||
If there is no element, `*dest` is let unmodified and it returns `false`.
|
||||
Otherwise it returns `true` and `*dest` is modified.
|
||||
|
||||
##### `void name_map_reduce(type_t *dest, const container_t c, void (*redFunc)(type_t *, type_t const), void *(mapFunc)(type_t *, type_t const))`
|
||||
##### `bool name_transform_reduce(type_t *dest, const container_t c, void (*redFunc)(type_t *, type_t const), bool *(mapFunc)(type_t *, type_t const, void *data), void *data)`
|
||||
|
||||
Perform a reduction using the function `redFunc`
|
||||
to the transformed elements of the container `c` using `mapFunc`.
|
||||
to the transformed and kept elements of the container `c` using `mapFunc`.
|
||||
The final result is stored in `*dest`.
|
||||
If there is no element, `*dest` is let unmodified.
|
||||
|
||||
`func` shall output in the initialized object `*out`
|
||||
the transformed value of the constant object `in` if it decides this value is kept (its return value is true in this case).
|
||||
Otherwise its return value is false.
|
||||
`data` is a user context data pointer free to be used and passed to `func`
|
||||
|
||||
If there is no element, `*dest` is let unmodified and it returns `false`.
|
||||
Otherwise it returns `true` and `*dest` is modified.
|
||||
|
||||
##### `bool name_any_of_p(const container_t c, void *(func)(const type_t))`
|
||||
|
||||
|
||||
@@ -108,3 +108,6 @@ V0.8.0 : * Memory interface massive compatibility break to allow more efficient
|
||||
(It's because supporting emulation layer with new memory context parameter was complicated)
|
||||
* Remove obsole headers: m-c-mempool, m-mempool, m-shared, m-i-shared, -mconcurrent
|
||||
|
||||
V0.8.1 : * m-algo: Update interface of _transform to be more flexible: adding user context pointer, and filtering of the input elements.
|
||||
* m-algo: Update interface of _reduce to be more user friendly: return value indicates if the reduction is empty or not.
|
||||
* m-algo: Rename _map_reduce into _transform_reduce and update its interface to be more flexible: adding user context pointer, and filtering of the input elements and return value indicates if the reduction is empty or not.
|
||||
@@ -170,7 +170,8 @@
|
||||
typedef bool (*M_F(name, _test_cb_ct))(type_t const); \
|
||||
typedef bool (*M_F(name, _eq_cb_ct))(type_t const, type_t const); \
|
||||
typedef int (*M_F(name, _cmp_cb_ct))(type_t const, type_t const); \
|
||||
typedef void (*M_F(name, _transform_cb_ct))(type_t *, type_t const); \
|
||||
typedef bool (*M_F(name, _transform_cb_ct))(type_t *, type_t const, void*); \
|
||||
typedef void (*M_F(name, _reduce_cb_ct))(type_t *, type_t const); \
|
||||
typedef void (*M_F(name, _apply_cb_ct))(type_t M_IF_METHOD(IT_REF, cont_oplist)( , const) );
|
||||
|
||||
|
||||
@@ -181,7 +182,7 @@
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _test_obj), bool, type_t const) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _eq_obj), bool, type_t const, type_t const ) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _cmp_obj), int, type_t const, type_t const ) \
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), void, type_t *, type_t const )\
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), bool, type_t *, type_t const )\
|
||||
M_FUNC_OBJ_ITF_DEF(M_F(name, _apply_obj), void, type_t * ) \
|
||||
|
||||
|
||||
@@ -756,27 +757,28 @@
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, type_oplist)( \
|
||||
M_IF_METHOD(PUSH_MOVE, cont_oplist)( \
|
||||
M_IF_METHOD(PUSH, cont_oplist)( \
|
||||
\
|
||||
/* Apply func for all elements of the container src and push the result in dst */ \
|
||||
M_P(void, name, _transform, container_t dst, container_t src, M_F(name, _transform_cb_ct) func) \
|
||||
M_P(void, name, _transform, container_t dst, container_t src, M_F(name, _transform_cb_ct) func, void *data) \
|
||||
{ \
|
||||
M_ASSERT(dst != src); \
|
||||
M_CALL_RESET(cont_oplist, dst); \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT(type_oplist, tmp); \
|
||||
for M_EACH(item, src, cont_oplist) { \
|
||||
type_t tmp; \
|
||||
M_CALL_INIT(type_oplist, tmp); \
|
||||
func(&tmp, *item); \
|
||||
M_CALL_PUSH_MOVE(cont_oplist, dst, &tmp); \
|
||||
if (func(&tmp, *item, data)) { \
|
||||
M_CALL_PUSH(cont_oplist, dst, tmp); \
|
||||
} \
|
||||
} \
|
||||
M_CALL_CLEAR(type_oplist, tmp); \
|
||||
M_IF_METHOD(REVERSE, cont_oplist)(M_CALL_REVERSE(cont_oplist, dst),); \
|
||||
} \
|
||||
, /* END PUSH_MOVE */), /* END INIT */ ) \
|
||||
\
|
||||
/* Reduce all elements of the container in dst in function of func */ \
|
||||
M_IF_METHOD(SET, type_oplist)( \
|
||||
M_P(void, name, _reduce, type_t *dest, container_t const l, \
|
||||
M_F(name, _transform_cb_ct) func) \
|
||||
M_P(bool, name, _reduce, type_t *dest, container_t const l, M_F(name, _reduce_cb_ct) func) \
|
||||
{ \
|
||||
M_UNUSED_CONTEXT(); \
|
||||
bool initDone = false; \
|
||||
@@ -788,15 +790,15 @@
|
||||
initDone = true; \
|
||||
} \
|
||||
} \
|
||||
return initDone; \
|
||||
} \
|
||||
, /* END SET */) \
|
||||
\
|
||||
/* Reduce all transformed elements of the container in dst in function of func */ \
|
||||
M_IF_METHOD(INIT, type_oplist)( \
|
||||
M_P(void, name, _map_reduce, type_t *dest, \
|
||||
const container_t l, \
|
||||
M_F(name, _transform_cb_ct) redFunc, \
|
||||
M_F(name, _transform_cb_ct) mapFunc) \
|
||||
M_P(bool, name, _transform_reduce, type_t *dest, const container_t l, \
|
||||
M_F(name, _reduce_cb_ct) redFunc, \
|
||||
M_F(name, _transform_cb_ct) mapFunc, void *data) \
|
||||
{ \
|
||||
M_UNUSED_CONTEXT(); \
|
||||
bool initDone = false; \
|
||||
@@ -804,14 +806,15 @@
|
||||
M_CALL_INIT(type_oplist, tmp); \
|
||||
for M_EACH(item, l, cont_oplist) { \
|
||||
if (initDone) { \
|
||||
mapFunc(&tmp, *item); \
|
||||
redFunc(dest, tmp); \
|
||||
if (mapFunc(&tmp, *item, data) ) { \
|
||||
redFunc(dest, tmp); \
|
||||
} \
|
||||
} else { \
|
||||
mapFunc(dest, *item); \
|
||||
initDone = true; \
|
||||
initDone = mapFunc(dest, *item, data); \
|
||||
} \
|
||||
} \
|
||||
M_CALL_CLEAR(type_oplist, tmp); \
|
||||
return initDone; \
|
||||
} \
|
||||
, ) \
|
||||
|
||||
|
||||
+39
-5
@@ -82,11 +82,21 @@ static void g_f(int n)
|
||||
g_count++;
|
||||
}
|
||||
|
||||
static void func_map(int *d, int n)
|
||||
static bool func_map(int *d, int n, void *data)
|
||||
{
|
||||
assert (g_min <= n && n <= g_max);
|
||||
g_count++;
|
||||
*d = n * n;
|
||||
return (data == NULL) || (n != 0);
|
||||
}
|
||||
|
||||
static bool func_map_none(int *d, int n, void *data)
|
||||
{
|
||||
(void) d;
|
||||
(void) n;
|
||||
(void) data;
|
||||
g_count++;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void func_reduce(int *d, int n)
|
||||
@@ -156,13 +166,17 @@ static void test_list(void)
|
||||
g_min = 0;
|
||||
g_max = 99;
|
||||
g_count = 0;
|
||||
algo_list_transform(tmp, l, func_map);
|
||||
algo_list_transform(tmp, l, func_map, NULL);
|
||||
assert(g_count == 101);
|
||||
assert(list_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
assert(*list_int_get(tmp, (size_t) i) == i * i);
|
||||
}
|
||||
assert(*list_int_get(tmp, 100) == 17 * 17);
|
||||
g_count = 0;
|
||||
algo_list_transform(tmp, l, func_map, (void*)&g_count);
|
||||
assert(g_count == 101);
|
||||
assert(list_int_size(tmp) == 100);
|
||||
}
|
||||
|
||||
int *p = algo_list_min(l);
|
||||
@@ -305,19 +319,35 @@ static void test_array(void)
|
||||
assert(g_count == 101);
|
||||
|
||||
int n;
|
||||
algo_array_reduce(&n, l, func_reduce);
|
||||
bool b;
|
||||
b = algo_array_reduce(&n, l, func_reduce);
|
||||
assert(b);
|
||||
assert(n == 100*99/2+17);
|
||||
|
||||
g_min = 0;
|
||||
g_max = 99;
|
||||
g_count = 0;
|
||||
algo_array_map_reduce(&n, l, func_reduce, func_map);
|
||||
b = algo_array_transform_reduce(&n, l, func_reduce, func_map, NULL);
|
||||
assert(b);
|
||||
assert(g_count == 101);
|
||||
assert(n == (328350 + 17*17));
|
||||
|
||||
g_count = 0;
|
||||
b = algo_array_transform_reduce(&n, l, func_reduce, func_map, (void*) &g_count);
|
||||
assert(b);
|
||||
assert(g_count == 101);
|
||||
assert(n == (328350 + 17*17));
|
||||
|
||||
g_count = 0;
|
||||
n = -1;
|
||||
b = algo_array_transform_reduce(&n, l, func_reduce, func_map_none, NULL);
|
||||
assert(!b);
|
||||
assert(g_count == 101);
|
||||
assert(n == -1);
|
||||
|
||||
M_LET(tmp, array_int_t) {
|
||||
g_count = 0;
|
||||
algo_array_transform(tmp, l, func_map);
|
||||
algo_array_transform(tmp, l, func_map, NULL);
|
||||
assert(g_count == 101);
|
||||
assert(array_int_size(tmp) == 101);
|
||||
for(int i = 0; i < 100; i++) {
|
||||
@@ -326,6 +356,10 @@ static void test_array(void)
|
||||
}
|
||||
assert(*array_int_get(l, 100) == 17);
|
||||
assert(*array_int_get(tmp, 100) == 17 * 17);
|
||||
g_count = 0;
|
||||
algo_array_transform(tmp, l, func_map, (void*) &g_count);
|
||||
assert(g_count == 101);
|
||||
assert(array_int_size(tmp) == 100);
|
||||
|
||||
array_int_reset(tmp);
|
||||
#define FT(d,x) ((d) = (x) + 1)
|
||||
|
||||
Reference in new issue
Block a user