Ken Van Hoeylandt 5dc2599e55 implemented furi from flipper zero
added cmsis_core, furi, mlib and nanobake
implemented basic app structure from furi
implemented basic placeholder apps
2023-12-26 21:47:27 +01:00

1241 lines
88 KiB
C

/*
* M*LIB - ALGO module
*
* Copyright (c) 2017-2023, 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.
*/
#ifndef MSTARLIB_ALGO_H
#define MSTARLIB_ALGO_H
#include "m-core.h"
/* Define different kind of basic algorithms named 'name' over the container
which oplist is 'cont_oplist'.
USAGE:
ALGO_DEF(algogName, containerOplist|type if oplist has been registered) */
#define M_ALGO_DEF(name, cont_oplist) \
M_BEGIN_PROTECTED_CODE \
M_ALG0_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|type_if_registered_oplist, function[, extra arguments of function]) */
#define M_ALGO_FOR_EACH(container, cont_oplist, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_FOR_EACH, M_ALG0_FOR_EACH_ARG) \
(container, M_GLOBAL_OPLIST(cont_oplist), __VA_ARGS__)
/* Map a function (or a macro) to all elements of a container
and store it into another container.
USAGE:
ALGO_TRANSFORM(contDst, contDOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist,
function[, extra arguments of function]) */
#define M_ALGO_TRANSFORM(contD, contDop, contS, contSop, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_TRANSFORM, M_ALG0_TRANSFORM_ARG) \
(contD, M_GLOBAL_OPLIST(contDop), contS, M_GLOBAL_OPLIST(contSop), __VA_ARGS__)
/* Extract a subset of a container to copy into another container.
USAGE:
ALGO_EXTRACT(contDst, contDstOplist|type_if_registered_oplist, contSrc, contSrcOplist|type_if_registered_oplist
[, function [, extra arguments of function]]) */
#define M_ALGO_EXTRACT(contD, contDop, contS, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_EXTRACT, \
M_IF_NARGS_EQ2(__VA_ARGS__)(M_ALG0_EXTRACT_FUNC, M_ALG0_EXTRACT_ARG)) \
(contD, contDop, contS, __VA_ARGS__)
/* Perform a Reduce operation over a container.
USAGE:
ALGO_REDUCE(dstVar, container, contOplist|type_if_registered_oplist, reduceFunc
[, mapFunc[, extraParameters of map function]])
or
ALGO_REDUCE( (dstVar, dstOplist|type_if_registered_oplist), container, contOplist|type_if_registered_oplist, reduceFunc
[, mapFunc[, extraParameters of map function]])
if the destination variable is not of the same type than the elements of the containers.
*/
#define M_ALGO_REDUCE(dest, cont, contOp, ...) \
M_IF(M_PARENTHESIS_P(dest)) \
(M_ALG0_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__), \
M_ALG0_REDUCE_DISPATCH(dest, M_GET_OPLIST M_GLOBAL_OPLIST(contOp), M_GET_SUBTYPE M_GLOBAL_OPLIST(contOp), cont, contOp, __VA_ARGS__)) \
/* Insert into the container 'contDst' at position 'position' all the values
of container 'contSrc'.
USAGE:
ALGO_INSERT_AT(containerDst, containerDstOPLIST|type_if_registered_oplist, containerDstIterator, containerSrc, containerSrcOPLIST|type_if_registered_oplist)
*/
#define M_ALGO_INSERT_AT(contDst, contDstOp, position, contSrc, contSrcOp) \
M_ALG0_INSERT_AT(contDst, M_GLOBAL_OPLIST(contDstOp), position, contSrc, M_GLOBAL_OPLIST(contSrcOp) )
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
/* Try to expand the algorithms */
#define M_ALG0_DEF_P1(name, cont_oplist) \
M_ALG0_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 */
#define M_ALG0_DEF_P2(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_IF_OPLIST(cont_oplist)(M_ALG0_DEF_P3, M_ALG0_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
/* Then validate the second oplist */
#define M_ALG0_DEF_P3(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_IF_OPLIST(type_oplist)(M_ALG0_DEF_P4, M_ALG0_DEF_FAILURE)(name, container_t, cont_oplist, type_t, type_oplist, it_t)
/* Stop processing with a compilation failure if an oplist was invalid */
#define M_ALG0_DEF_FAILURE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ALGO_DEF): one of the given argument is not a valid oplist: " M_AS_STR(cont_oplist) " / " M_AS_STR(type_oplist) )
/* Expand all algorithms */
#define M_ALG0_DEF_P4(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_CHECK_COMPATIBLE_OPLIST(name, 10, container_t, cont_oplist) \
M_CHECK_COMPATIBLE_OPLIST(name, 11, type_t, type_oplist) \
\
M_ALG0_DEF_CALLBACK(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_IF_FUNCOBJ(M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t)) \
\
M_IF_METHOD(EQUAL, type_oplist)( \
M_ALG0_DEF_FIND(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
, /* NO EQUAL */) \
\
M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
if, M_F(name,_test_cb_ct), M_F(name,_eq_cb_ct), M_APPLY, M_APPLY) \
M_IF_FUNCOBJ(M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
fo, M_F(name,_test_obj_t), M_F(name,_eq_obj_t), M_F(name, _test_obj_call), M_F(name, _eq_obj_call))) \
\
M_ALG0_DEF_MAP(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
_, M_F(name,_test_cb_ct), M_APPLY) \
M_IF_FUNCOBJ(M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
_fo_, M_F(name,_test_obj_t), M_F(name,_test_obj_call)) ) \
\
/* If there is a IT_REF method, we consider the container as modifiable through iterator */ \
M_IF_METHOD(IT_REF, cont_oplist)( \
M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_VECTOR(name, container_t, cont_oplist, type_t, type_oplist, it_t)\
\
M_IF_METHOD(CMP, type_oplist)( \
M_ALG0_DEF_MINMAX(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, +, _sort) \
M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, -, _sort_dsc) \
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t)\
, /* No IT_REMOVE method */) \
, /* No CMP method */) \
\
M_IF_FUNCOBJ(M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, \
_sort_fo, M_ALG0_SORT_CALL_OBJ_P4, M_ALG0_SORT_PARAM_OBJ_P4, M_ALG0_SORT_ARG_OBJ_P4) ) \
, /* No IT_REF method */) \
\
M_IF_METHOD(EXT_ALGO, type_oplist)( \
M_GET_EXT_ALGO type_oplist (name, cont_oplist, type_oplist) \
, /* No EXT_ALGO method */ ) \
/* Define the types of the callbacks associated to the algorithms.
* Types remain internal */
#define M_ALG0_DEF_CALLBACK(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
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 void (*M_F(name, _apply_cb_ct))(type_t); \
/* Define the function objects associated to the algorithms.
* Created Function objects are part of the public interface */
#define M_ALG0_DEF_FUNCOBJ(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
FUNC_OBJ_ITF_DEF(M_F(name, _test_obj), bool, type_t const) \
FUNC_OBJ_ITF_DEF(M_F(name, _eq_obj), bool, type_t const, type_t const ) \
FUNC_OBJ_ITF_DEF(M_F(name, _cmp_obj), int, type_t const, type_t const ) \
FUNC_OBJ_ITF_DEF(M_F(name, _transform_obj), void, type_t *, type_t const ) \
FUNC_OBJ_ITF_DEF(M_F(name, _apply_obj), void, type_t * ) \
/* Define the sort functions with the CMP operator using the order selected */
#define M_ALG0_DEF_SORT(name, container_t, cont_oplist, type_t, type_oplist, it_t, order, sort_name) \
\
/* Define the encapsulation function that perform the selected order */ \
M_INLINE int M_C3(name,sort_name,_cmp)(type_t const*a,type_t const*b) \
{ \
return order M_CALL_CMP(type_oplist, *a, *b); \
} \
\
M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, M_ALG0_SORT_CALL_CMP_P4, M_EAT, /*empty*/ )
// Call the comparaison function of the type oplist (Using CMP operator)
#define M_ALG0_SORT_CALL_CMP_P4(name, sort_name, ref1, ref2) \
M_C3(name, sort_name,_cmp)(ref1, ref2)
// Call the created function object
#define M_ALG0_SORT_CALL_OBJ_P4(name, sort_name, ref1, ref2) \
M_F(name, _cmp_obj_call)(funcobj, *ref1, *ref2)
// Adding a parameter named 'funcobj' to the algorithm functions
#define M_ALG0_SORT_PARAM_OBJ_P4(name) M_DEFERRED_COMMA M_F(name, _cmp_obj_t) funcobj
#define M_ALG0_SORT_ARG_OBJ_P4 M_DEFERRED_COMMA funcobj
/* Define the sort funtions using either the CMP operator or a function object
- name: prefix of algorithms
- container_t: type of the container
- cont_oplist: oplist of the container
- type_t: type of the data within the container
- type_oplist: oplist of such type
- it_t: type of the iterator of the container
- sort_name: suffix used for creating the sort functions
- cmp_func: macro to call to get the CMP order
- cmp_param: macro to use to generate an extra argument for the function (needed for function object).
It is needed to add another argument to the function.
- cmp_arg: Name of such argument.
*/
#define M_ALG0_DEF_SORT_AUX(name, container_t, cont_oplist, type_t, type_oplist, it_t, sort_name, cmp_func, cmp_param, cmp_arg) \
\
/* Test if the container is sorted */ \
M_INLINE bool \
M_C3(name,sort_name,_p)(const container_t l cmp_param(name)) \
{ \
it_t it1; \
it_t it2; \
/* Linear comparaison of TAB[N] & TAB[N+1] to test if the order is correct */ \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
M_CALL_IT_SET(cont_oplist, it2, it1); \
M_CALL_IT_NEXT(cont_oplist, it2); \
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)) { \
return false; \
} \
M_CALL_IT_SET(cont_oplist, it1, it2); \
M_CALL_IT_NEXT(cont_oplist, it2); \
} \
return true; \
} \
\
/* Sort function. It can be generated from 3 algorithms: */ \
/* - a specialized version defined by the container */ \
/* - 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_INLINE void M_F(name,sort_name)(container_t l) \
{ \
M_CALL_SORT(cont_oplist, l, M_C3(name, sort_name,_cmp)); \
} \
, \
\
M_IF_METHOD2(SPLICE_BACK, SPLICE_AT, cont_oplist)( \
/******** MERGE SORT (unstable) ********/ \
/* NOTE: Only reasonable for lists (To move in m-list.h ?) */ \
\
/* Split the container 'l' into near even size l1 and l2 * \
using odd/even splitting */ \
M_INLINE void \
M_C3(name,sort_name,_split)(container_t l1, container_t l2, container_t l) \
{ \
it_t it; \
bool b = false; \
/* 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); \
b = !b; \
} \
/* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \
} \
\
/* Merge in empty 'l' the sorted container 'l1' and 'l2' */ \
M_INLINE void \
M_C3(name,sort_name,_merge)(container_t l, container_t l1, container_t l2 cmp_param(name)) \
{ \
/* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \
it_t it; \
it_t it1; \
it_t it2; \
M_CALL_IT_END(cont_oplist, it, l); \
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 */ \
int c = cmp_func(name, sort_name, M_CALL_IT_CREF(cont_oplist, it1), \
M_CALL_IT_CREF(cont_oplist, it2)); \
if (c <= 0) { \
/* 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' */ \
while (!M_CALL_IT_END_P(cont_oplist, it2)) { \
M_CALL_SPLICE_AT(cont_oplist, l, it, l2, it2); \
} \
return; \
} \
} else { \
/* Move the element of l2 in the new container */ \
M_CALL_SPLICE_AT(cont_oplist, l, it, l2, it2); \
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it2))) { \
/* Move all remaining elements of l1 in 'l' */ \
while (!M_CALL_IT_END_P(cont_oplist, it1)) { \
M_CALL_SPLICE_AT(cont_oplist, l, it, l1, it1); \
} \
return; \
} \
} \
} \
/* Cannot occur */ \
} \
\
/* Sort the container 'l' */ \
M_INLINE void \
M_F(name,sort_name)(container_t l cmp_param(name)) \
{ \
container_t l1; \
container_t l2; \
it_t it; \
it_t it1; \
it_t it2; \
/* First deal with 0, 1, or 2 size container */ \
M_CALL_IT_FIRST(cont_oplist, it, l); \
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it))) \
return; \
M_CALL_IT_SET(cont_oplist, it1, it); \
M_CALL_IT_NEXT(cont_oplist, it); \
if (M_UNLIKELY (M_CALL_IT_END_P(cont_oplist, it))) \
return; \
M_CALL_IT_SET(cont_oplist, it2, it); \
M_CALL_IT_NEXT(cont_oplist, it); \
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)); \
if (c > 0) { \
/* SWAP */ \
M_CALL_SPLICE_BACK(cont_oplist, l, l, it2); \
} \
return; \
} \
/* Container length is greater than 2: split, sort & merge */ \
M_CALL_INIT(cont_oplist, l1); \
M_CALL_INIT(cont_oplist, l2); \
M_C3(name,sort_name,_split)(l1, l2, l); \
M_F(name,sort_name)(l1 cmp_arg); \
M_F(name,sort_name)(l2 cmp_arg); \
M_C3(name,sort_name,_merge)(l, l1, l2 cmp_arg); \
/* l1 & l2 shall be empty now */ \
M_CALL_CLEAR(cont_oplist, l2); \
M_CALL_CLEAR(cont_oplist, l1); \
} \
, \
M_IF_METHOD(IT_PREVIOUS, cont_oplist)( \
/******** GENERIC INSERTION SORT *********/ \
M_INLINE void M_F(name,sort_name)(container_t l cmp_param(name)) \
{ \
it_t it1; \
it_t it2; \
it_t it2p1; \
/* NOTE: Do not use SET, this is a MOVE operation */ \
/* Start from i := 1 */ \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
M_CALL_IT_NEXT(cont_oplist, it1); \
while (!M_CALL_IT_END_P(cont_oplist, it1) ) { \
type_t x; \
/* x := TAB[i] */ \
memcpy (&x, M_CALL_IT_CREF(cont_oplist, it1), sizeof (type_t)); \
/* j := i -1 // jp1 := i (= j +1) */ \
M_CALL_IT_SET(cont_oplist, it2, it1); \
M_CALL_IT_PREVIOUS(cont_oplist, it2); \
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)) { \
/* TAB[jp1=j+1] := TAB[j] */ \
memcpy(M_CALL_IT_REF(cont_oplist, it2p1), \
M_CALL_IT_CREF(cont_oplist, it2), sizeof (type_t) ); \
/* jp1 := j (= jp1-1) */ \
M_CALL_IT_SET(cont_oplist, it2p1, it2); \
M_CALL_IT_PREVIOUS(cont_oplist, it2); \
} \
/* TAB[jp1] := x */ \
memcpy(M_CALL_IT_REF(cont_oplist, it2p1), &x, sizeof (type_t) ); \
/* i := i + 1 */ \
M_CALL_IT_NEXT(cont_oplist, it1); \
} \
} \
\
, \
/********** GENERIC SELECTION SORT ************/ \
M_INLINE void M_F(name,sort_name)(container_t l cmp_param(name)) \
{ \
it_t it1; \
it_t it2; \
for(M_CALL_IT_FIRST(cont_oplist, it1, l); \
!M_CALL_IT_LAST_P(cont_oplist, it1); \
M_CALL_IT_NEXT(cont_oplist, it1)) { \
it_t it_min; \
M_CALL_IT_SET(cont_oplist, it_min, it1); \
M_CALL_IT_SET(cont_oplist, it2, it1); \
for(M_CALL_IT_NEXT(cont_oplist, it2) ; \
!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_SET(cont_oplist, it_min, it2); \
} \
} \
if (M_CALL_IT_EQUAL_P(cont_oplist, it_min, it1) == false) { \
/* TODO: Use SWAP method of type_oplist if available */ \
type_t x; /* Do not use SET, as it is a MOVE operation */ \
memcpy (&x, M_CALL_IT_CREF(cont_oplist, it1), sizeof (type_t)); \
memcpy (M_CALL_IT_REF(cont_oplist, it1), \
M_CALL_IT_CREF(cont_oplist, it_min), sizeof (type_t)); \
memcpy (M_CALL_IT_REF(cont_oplist, it_min), &x, sizeof (type_t)); \
} \
} \
} \
) /* IF IT_PREVIOUS METHOD */ \
) /* SPLICE BACK METHOD */ \
) /* IF SORT METHOD */ \
/* Compute the union of two ***sorted*** containers */ \
M_IF_METHOD(IT_INSERT, cont_oplist)( \
M_INLINE void \
M_C3(name,sort_name,_union)(container_t dst, const container_t src cmp_param(name)) \
{ \
it_t itSrc; \
it_t itDst; \
it_t itIns; \
M_ASSERT(M_C3(name,sort_name,_p)(dst cmp_arg)); \
M_ASSERT(M_C3(name,sort_name,_p)(src cmp_arg)); \
/* Iterate over both dst & src containers */ \
M_CALL_IT_FIRST(cont_oplist, itSrc, src); \
M_CALL_IT_FIRST(cont_oplist, itDst, dst); \
M_CALL_IT_END(cont_oplist, itIns, dst); \
while (!M_CALL_IT_END_P(cont_oplist, itSrc) \
&& !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); \
/* Compare the current element of src and dst */ \
int cmp = cmp_func(name, sort_name, objDst, objSrc); \
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); \
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 */ \
/* 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); \
} \
} \
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_NEXT(cont_oplist, itSrc); \
} \
} \
, /* NO IT_INSERT */ ) \
\
/* Compute the intersection of two ***sorted*** containers */ \
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
M_INLINE void \
M_C3(name,sort_name,_intersect)(container_t dst, const container_t src cmp_param(name)) \
{ \
it_t itSrc; \
it_t itDst; \
M_ASSERT(M_C3(name,sort_name,_p)(dst cmp_arg)); \
M_ASSERT(M_C3(name,sort_name,_p)(src cmp_arg)); \
M_CALL_IT_FIRST(cont_oplist, itSrc, src); \
M_CALL_IT_FIRST(cont_oplist, itDst, dst); \
/* TODO: Not optimized at all for array ! O(n^2) */ \
while (!M_CALL_IT_END_P(cont_oplist, itSrc) \
&& !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); \
if (cmp == 0) { \
/* Keep it */ \
M_CALL_IT_NEXT(cont_oplist, itSrc); \
M_CALL_IT_NEXT(cont_oplist, itDst); \
} else if (cmp < 0) { \
M_CALL_IT_REMOVE(cont_oplist, dst, itDst); \
} else { \
M_CALL_IT_NEXT(cont_oplist, itSrc); \
} \
} \
while (!M_CALL_IT_END_P(cont_oplist, itDst)) { \
M_CALL_IT_REMOVE(cont_oplist, dst, itDst); \
} \
} \
, /* NO IT_REMOVE */ )
/* Define the find like algorithms of a given data
TODO: Define _find_sorted that find in a sorted random access container
(binary search)
*/
#define M_ALG0_DEF_FIND(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
/* It supposes that the container is not sorted */ \
/* Find the next occurrence from it (included) of data */ \
M_INLINE void \
M_F(name, _find_again) (it_t it, type_t const data) \
{ \
for ( /*nothing*/ ; !M_CALL_IT_END_P(cont_oplist, it) ; \
M_CALL_IT_NEXT(cont_oplist, it)) { \
if (M_CALL_EQUAL(type_oplist, *M_CALL_IT_CREF(cont_oplist, it), data)) \
return ; \
} \
} \
\
/* Find the first occurrence of data */ \
M_INLINE void \
M_F(name, _find) (it_t it, container_t const l, type_t const data) \
{ \
M_CALL_IT_FIRST(cont_oplist, it, l); \
M_F(name, _find_again)(it, data); \
} \
\
/* Test if data is within the container */ \
M_INLINE bool \
M_F(name, _contain_p) (container_t const l, type_t const data) \
{ \
it_t it; \
M_F(name,_find)(it, l, data); \
return !M_CALL_IT_END_P(cont_oplist, it); \
} \
\
/* Find the last occurrence of data in the container */ \
/* For the definition of _find_last, if the methods \
PREVIOUS & IT_LAST are defined, then search backwards */ \
M_IF_METHOD2(PREVIOUS, IT_LAST, cont_oplist) \
( \
M_INLINE void \
M_F(name, _find_last) (it_t it, container_t const l, type_t const data) \
{ \
for (M_CALL_IT_LAST(cont_oplist, it, l); \
!M_CALL_IT_END_P(cont_oplist, it) ; \
M_CALL_IT_PREVIOUS(cont_oplist, it)) { \
if (M_CALL_EQUAL(type_oplist, *M_CALL_IT_CREF(cont_oplist, it), data)) \
/* We can stop as soon as a match is found */ \
return; \
} \
} \
, \
/* Otherwise search forward, but don't stop on the first occurrence */ \
M_INLINE void \
M_F(name, _find_last) (it_t it, container_t const l, type_t const data) \
{ \
M_CALL_IT_END(cont_oplist, it, l); \
it_t it2; \
for (M_CALL_IT_FIRST(cont_oplist, it2, l); \
!M_CALL_IT_END_P(cont_oplist, it2) ; \
M_CALL_IT_NEXT(cont_oplist, it2)) { \
if (M_CALL_EQUAL(type_oplist, *M_CALL_IT_CREF(cont_oplist, it2), data)) \
/* We cannot stop as soon as a match is found */ \
M_CALL_IT_SET(cont_oplist, it, it2) ; \
} \
} \
) /* End of alternative of _find_last */ \
\
/* Count the number of occurrence of data in the container */ \
M_INLINE size_t \
M_F(name, _count) (container_t const l, type_t const data) \
{ \
it_t it; \
size_t count = 0; \
for (M_CALL_IT_FIRST(cont_oplist, it, l); \
!M_CALL_IT_END_P(cont_oplist, it) ; \
M_CALL_IT_NEXT(cont_oplist, it)) { \
if (M_CALL_EQUAL(type_oplist, *M_CALL_IT_CREF(cont_oplist, it), data)) \
count++ ; \
} \
return count; \
} \
\
\
/* Find the next mismatch between the containers */ \
M_INLINE void \
M_F(name, _mismatch_again) (it_t it1, it_t it2) \
{ \
for (/* nothing */ ; !M_CALL_IT_END_P(cont_oplist, it1) && \
!M_CALL_IT_END_P(cont_oplist, it2); \
M_CALL_IT_NEXT(cont_oplist, it1), \
M_CALL_IT_NEXT(cont_oplist, it2)) { \
if (!M_CALL_EQUAL(type_oplist, *M_CALL_IT_CREF(cont_oplist, it1), \
*M_CALL_IT_CREF(cont_oplist, it2))) \
break; \
} \
} \
\
/* Find the first mismatch between the containers */ \
M_INLINE void \
M_F(name, _mismatch) (it_t it1, it_t it2, container_t const l1, container_t const l2 ) \
{ \
M_CALL_IT_FIRST(cont_oplist, it1, l1); \
M_CALL_IT_FIRST(cont_oplist, it2, l2); \
M_F(name, _mismatch_again)(it1, it2); \
} \
/* Define the find like algorithms with a given callback of function object
TODO: Define _find_sorted that find in a sorted random access container
(binary search)
*/
#define M_ALG0_DEF_FIND_IF(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, test_t, eq_t, call_test, call_eq) \
\
/* Find the next occurrence that matches the condition */ \
M_INLINE void \
M_C3(name, _find_again_, suffix) (it_t it, test_t func) \
{ \
for (/*nothing */ ; !M_CALL_IT_END_P(cont_oplist, it) ; \
M_CALL_IT_NEXT(cont_oplist, it)) { \
if (call_test(func, *M_CALL_IT_CREF(cont_oplist, it))) \
return ; \
} \
} \
\
/* Find the first occurrence that matches the condition */ \
M_INLINE void \
M_C3(name, _find_, suffix) (it_t it, container_t l, test_t func) \
{ \
M_CALL_IT_FIRST(cont_oplist, it, l); \
M_C3(name, _find_again_, suffix)(it, func); \
} \
\
/* Count the number of occurrence that matches the condition */ \
M_INLINE size_t \
M_C3(name, _count_, suffix) (container_t const l, test_t func) \
{ \
it_t it; \
size_t count = 0; \
for (M_CALL_IT_FIRST(cont_oplist, it, l); \
!M_CALL_IT_END_P(cont_oplist, it) ; \
M_CALL_IT_NEXT(cont_oplist, it)) { \
if (call_test(func, *M_CALL_IT_CREF(cont_oplist, it))) { \
count++ ; \
} \
} \
return count; \
} \
\
/* Find the next mismatch between the containers according to the condition */ \
M_INLINE void \
M_C3(name, _mismatch_again_, suffix) (it_t it1, it_t it2, eq_t func) \
{ \
for (/*nothing */ ; !M_CALL_IT_END_P(cont_oplist, it1) && \
!M_CALL_IT_END_P(cont_oplist, it2); \
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))) \
break; \
} \
} \
\
/* Find the first mismatch between the containers according to the condition */ \
M_INLINE void \
M_C3(name, _mismatch_, suffix) (it_t it1, it_t it2, container_t const l1, \
container_t l2, eq_t func) \
{ \
M_CALL_IT_FIRST(cont_oplist, it1, l1); \
M_CALL_IT_FIRST(cont_oplist, it2, l2); \
M_C3(name, _mismatch_again_, suffix)(it1, it2, func); \
} \
/* Define the FILL algorithms */
#define M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
/* Fill all the container with value (overwritten) */ \
M_INLINE void \
M_F(name, _fill) (container_t l, type_t const value) \
{ \
for M_EACH(item, l, cont_oplist) { \
M_CALL_SET(type_oplist, *item, value); \
} \
} \
\
/* Fill the container with exactly 'n' occurrence of 'value' */ \
M_IF_METHOD(PUSH, cont_oplist)( \
M_INLINE void \
M_F(name, _fill_n) (container_t l, size_t n, type_t const value) \
{ \
M_CALL_RESET(cont_oplist, l); \
for(size_t i = 0; i < n; i++) { \
M_CALL_PUSH(cont_oplist, l, value); \
} \
} \
, /* PUSH method */ ) \
\
/* Fill the container with FOR('value'; 'value'+'inc') */ \
M_IF_METHOD(ADD, type_oplist)( \
M_INLINE void \
M_F(name, _fill_a) (container_t l, type_t const value, type_t const inc) \
{ \
type_t tmp; \
M_CALL_INIT_SET(type_oplist, tmp, value); \
for M_EACH(item, l, cont_oplist) { \
M_CALL_SET(type_oplist, *item, tmp); \
M_CALL_ADD(type_oplist, tmp, tmp, inc); \
} \
M_CALL_CLEAR(type_oplist, tmp); \
} \
\
/* Fill the container with n occurences of FOR('value'; 'value'+'inc') */ \
M_IF_METHOD(PUSH, cont_oplist)( \
M_INLINE void \
M_F(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \
{ \
type_t tmp; \
M_CALL_INIT_SET(type_oplist, tmp, value); \
M_CALL_RESET(cont_oplist, l); \
for(size_t i = 0; i < n; i++) { \
M_CALL_PUSH(cont_oplist, l, tmp); \
M_CALL_ADD(type_oplist, tmp, tmp, inc); \
} \
M_CALL_CLEAR(type_oplist, tmp); \
} \
, /* PUSH method */ ) \
, /* ADD method */ ) \
/* Define MAP algorithms */
#define M_ALG0_DEF_MAP(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
/* Apply func for all elements of the container */ \
M_INLINE void \
M_F(name, _for_each) (container_t l, M_F(name, _apply_cb_ct) func) \
{ \
for M_EACH(item, l, cont_oplist) { \
func(*item); \
} \
} \
\
M_IF_METHOD(INIT, type_oplist)( \
M_IF_METHOD(PUSH_MOVE, cont_oplist)( \
\
/* Apply func for all elements of the container src and push the result in dst */ \
M_INLINE void \
M_F(name, _transform) (container_t dst, \
container_t src, \
M_F(name, _transform_cb_ct) func) \
{ \
M_ASSERT(dst != src); \
M_CALL_RESET(cont_oplist, dst); \
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); \
} \
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_INLINE void \
M_F(name, _reduce) (type_t *dest, container_t const l, \
M_F(name, _transform_cb_ct) func) \
{ \
bool initDone = false; \
for M_EACH(item, l, cont_oplist) { \
if (initDone) { \
func(dest, *item); \
} else { \
M_CALL_SET(type_oplist, *dest, *item); \
initDone = true; \
} \
} \
} \
, /* END SET */) \
\
/* Reduce all transformed elements of the container in dst in function of func */ \
M_IF_METHOD(INIT, type_oplist)( \
M_INLINE \
void M_F(name, _map_reduce) (type_t *dest, \
const container_t l, \
M_F(name, _transform_cb_ct) redFunc, \
M_F(name, _transform_cb_ct) mapFunc) \
{ \
bool initDone = false; \
type_t tmp; \
M_CALL_INIT(type_oplist, tmp); \
for M_EACH(item, l, cont_oplist) { \
if (initDone) { \
mapFunc(&tmp, *item); \
redFunc(dest, tmp); \
} else { \
mapFunc(dest, *item); \
initDone = true; \
} \
} \
M_CALL_CLEAR(type_oplist, tmp); \
} \
, ) \
/* Define ALL_OF algorithms */
#define M_ALG0_DEF_ALL_OF(name, container_t, cont_oplist, type_t, type_oplist, it_t, suffix, func_t, call) \
\
M_INLINE bool \
M_C4(name, _any_of, suffix, p) (container_t const l, \
func_t func ) \
{ \
for M_EACH(item, l, cont_oplist) { \
if (call(func, *item)) \
return true; \
} \
return false; \
} \
\
M_INLINE bool \
M_C4(name, _all_of, suffix, p) (container_t const l, \
func_t func ) \
{ \
for M_EACH(item, l, cont_oplist) { \
if (!call(func, *item)) \
return false; \
} \
return true; \
} \
\
M_INLINE bool \
M_C4(name, _none_of, suffix, p) (container_t l, \
func_t func ) \
{ \
for M_EACH(item, l, cont_oplist) { \
if (call(func, *item)) \
return false; \
} \
return true; \
} \
/* Define MIN / MAX algorithms */
#define M_ALG0_DEF_MINMAX(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_INLINE type_t * \
M_F(name, _min) (const container_t l) \
{ \
type_t *min = NULL; \
for M_EACH(cref, l, cont_oplist) { \
if (min == NULL || \
M_CALL_CMP(type_oplist, *min, *cref) > 0) { \
min = cref; \
} \
} \
return min; \
} \
\
M_INLINE type_t * \
M_F(name, _max) (const container_t l) \
{ \
type_t *max = NULL; \
for M_EACH(cref, l, cont_oplist) { \
if (max == NULL || \
M_CALL_CMP(type_oplist, *max, *cref) < 0) { \
max = cref; \
} \
} \
return max; \
} \
\
M_INLINE void \
M_F(name, _minmax) (type_t **min_p, type_t **max_p, \
const container_t l) \
{ \
type_t *min = NULL; \
type_t *max = NULL; \
for M_EACH(cref, l, cont_oplist) { \
if (min == NULL || \
M_CALL_CMP(type_oplist, *min, *cref) > 0) { \
min = cref; \
} \
if (max == NULL || \
M_CALL_CMP(type_oplist, *max, *cref) < 0) { \
max = cref; \
} \
} \
*min_p = min; \
*max_p = max; \
} \
/* Define functions based on remove method */
#define M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_INLINE void \
M_F(name, _uniq)(container_t l) \
{ \
it_t it1; \
it_t it2; \
M_ASSERT(M_F(name, _sort_p)(l)); \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
M_CALL_IT_SET(cont_oplist, it2, it1); \
M_CALL_IT_NEXT(cont_oplist, it2); \
/* Not efficient for array! */ \
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 (M_CALL_CMP(type_oplist, *ref1, *ref2) == 0) { \
M_CALL_IT_REMOVE(cont_oplist, l, it2); \
} else { \
M_CALL_IT_SET(cont_oplist, it1, it2); \
M_CALL_IT_NEXT(cont_oplist, it2); \
} \
} \
} \
\
M_INLINE void \
M_F(name, _remove_val)(container_t l, type_t const val) \
{ \
it_t it1; \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
while (!M_CALL_IT_END_P(cont_oplist, it1)) { \
type_t const *ref1 = M_CALL_IT_CREF(cont_oplist, it1); \
if (M_CALL_EQUAL(type_oplist, *ref1, val)) { \
M_CALL_IT_REMOVE(cont_oplist, l, it1); \
} else { \
M_CALL_IT_NEXT(cont_oplist, it1); \
} \
} \
} \
\
M_INLINE void \
M_F(name, _remove_if)(container_t l, M_F(name, _test_cb_ct) func) \
{ \
it_t it1; \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
while (!M_CALL_IT_END_P(cont_oplist, it1)) { \
type_t const *ref1 = M_CALL_IT_CREF(cont_oplist, it1); \
if (func(*ref1)) { \
M_CALL_IT_REMOVE(cont_oplist, l, it1); \
} else { \
M_CALL_IT_NEXT(cont_oplist, it1); \
} \
} \
} \
/* Define vector algorithms */
#define M_ALG0_DEF_VECTOR(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_IF_METHOD(ADD, type_oplist)( \
M_INLINE void M_F(name, _add) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
for (M_CALL_IT_FIRST(cont_oplist, itSrc, src) , \
M_CALL_IT_FIRST(cont_oplist, itDst, dst) ; \
!M_CALL_IT_END_P(cont_oplist, itSrc) \
&& !M_CALL_IT_END_P(cont_oplist, itDst) ; \
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_ADD(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
, /* NO_ADD METHOD */ ) \
\
M_IF_METHOD(SUB, type_oplist)( \
M_INLINE void M_F(name, _sub) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
for (M_CALL_IT_FIRST(cont_oplist, itSrc, src) , \
M_CALL_IT_FIRST(cont_oplist, itDst, dst) ; \
!M_CALL_IT_END_P(cont_oplist, itSrc) \
&& !M_CALL_IT_END_P(cont_oplist, itDst) ; \
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_SUB(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
, /* NO_SUB METHOD */ ) \
\
M_IF_METHOD(MUL, type_oplist)( \
M_INLINE void M_F(name, _mul) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
for (M_CALL_IT_FIRST(cont_oplist, itSrc, src) , \
M_CALL_IT_FIRST(cont_oplist, itDst, dst) ; \
!M_CALL_IT_END_P(cont_oplist, itSrc) \
&& !M_CALL_IT_END_P(cont_oplist, itDst) ; \
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_MUL(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
, /* NO_MUL METHOD */ ) \
\
M_IF_METHOD(DIV, type_oplist)( \
M_INLINE void M_F(name, _div) (container_t dst, const container_t src) \
{ \
it_t itSrc; \
it_t itDst; \
for (M_CALL_IT_FIRST(cont_oplist, itSrc, src) , \
M_CALL_IT_FIRST(cont_oplist, itDst, dst) ; \
!M_CALL_IT_END_P(cont_oplist, itSrc) \
&& !M_CALL_IT_END_P(cont_oplist, itDst) ; \
M_CALL_IT_NEXT(cont_oplist, itSrc), \
M_CALL_IT_NEXT(cont_oplist, itDst) ) { \
type_t *dstItem = M_CALL_IT_REF(cont_oplist, itDst); \
type_t const *srcItem = M_CALL_IT_CREF(cont_oplist, itSrc); \
M_CALL_DIV(type_oplist, *dstItem, *dstItem, *srcItem); \
} \
} \
, /* NO_DIV METHOD */ ) \
\
//TODO: Algorithm missing
// _nth_element ( http://softwareengineering.stackexchange.com/questions/284767/kth-selection-routine-floyd-algorithm-489 )
// _average
// _sort_uniq (_sort + _uniq)
// fast _uniq for array
// _flatten (takes a set of containers and returns a new container containing all flatten objects)
/******************************** INTERNAL ***********************************/
#define M_ALG0_FOR_EACH(container, cont_oplist, func) do { \
for M_EACH(_item, container, cont_oplist) { \
func(*_item); \
} \
} while (0)
#define M_ALG0_FOR_EACH_ARG(container, cont_oplist, func, ...) do { \
for M_EACH(_item, container, cont_oplist) { \
func(__VA_ARGS__, *_item); \
} \
} while (0)
/******************************** INTERNAL ***********************************/
#define M_ALG0_TRANSFORM(contD, contDop, contS, contSop, func) do { \
M_CALL_RESET(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 M_ALG0_TRANSFORM_ARG(contD, contDop, contS, contSop, func, ...) do { \
M_CALL_RESET(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)
/******************************** INTERNAL ***********************************/
#define M_ALG0_EXTRACT(contDst, contDstOplist, contSrc, contSrcOplist) \
M_ALG0_EXTRACT_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist))
#define M_ALG0_EXTRACT_P1(contDst, contDstOplist, contSrc, contSrcOplist) do{ \
M_CALL_RESET(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 M_ALG0_EXTRACT_FUNC(contDst, contDstOplist, contSrc, contSrcOplist, condFunc) \
M_ALG0_EXTRACT_FUNC_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), condFunc)
#define M_ALG0_EXTRACT_FUNC_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
condFunc) do { \
M_CALL_RESET(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 M_ALG0_EXTRACT_ARG(contDst, contDstOplist, contSrc, contSrcOplist, \
condFunc, ...) \
M_ALG0_EXTRACT_ARG_P1(contDst, M_GLOBAL_OPLIST(contDstOplist), contSrc, M_GLOBAL_OPLIST(contSrcOplist), \
condFunc, __VA_ARGS__)
#define M_ALG0_EXTRACT_ARG_P1(contDst, contDstOplist, contSrc, contSrcOplist, \
condFunc, ...) do { \
M_CALL_RESET(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)
/******************************** INTERNAL ***********************************/
#define M_ALG0_REDUCE_DISPATCH(dest, destOp, dest_t, cont, contOp, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__) \
(M_ALG0_REDUCE_BASIC(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
M_IF_NARGS_EQ2(__VA_ARGS__) \
(M_ALG0_REDUCE_FOR_EACH(dest, dest_t, destOp, cont, contOp, __VA_ARGS__), \
M_ALG0_REDUCE_FOR_EACH_ARG(dest, dest_t, destOp, cont, contOp, __VA_ARGS__) ) )
/* The special functions handled by ALGO_REDUCE */
#define M_ALG0_REDUCE_AND(a,b) ((a) &= (b))
#define M_ALG0_REDUCE_OR(a,b) ((a) |= (b))
#define M_ALG0_REDUCE_SUM(a,b) ((a) += (b))
#define M_ALG0_REDUCE_PRODUCT(a,b) ((a) *= (b))
/* 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 M_ALG0_REDUCE_FUNC(reduceFunc) \
M_IF(M_KEYWORD_P(and, reduceFunc)) \
(M_ALG0_REDUCE_AND, \
M_IF(M_KEYWORD_P(or, reduceFunc)) \
(M_ALG0_REDUCE_OR, \
M_IF(M_KEYWORD_P(sum, reduceFunc)) \
(M_ALG0_REDUCE_SUM, \
M_IF(M_KEYWORD_P(product, reduceFunc)) \
(M_ALG0_REDUCE_PRODUCT, \
reduceFunc) \
) \
) \
)
#define M_ALG0_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) { \
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, *_item); \
} else { \
M_CALL_SET(destOp, dest, *_item); \
_init_done = true; \
} \
} \
} while (0)
#define M_ALG0_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) { \
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
} else { \
M_CALL_SET(destOp, dest, _tmp); \
_init_done = true; \
} \
} \
M_CALL_CLEAR(destOp, _tmp); \
} while (0)
#define M_ALG0_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) { \
M_ALG0_REDUCE_FUNC(reduceFunc) (dest, _tmp); \
} else { \
M_CALL_SET(destOp, dest, _tmp); \
_init_done = true; \
} \
} \
M_CALL_CLEAR(destOp, _tmp); \
} while (0)
/******************************** INTERNAL ***********************************/
#define M_ALG0_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)); \
} \
} while (0)
/******************************** INTERNAL ***********************************/
#if M_USE_SMALL_NAME
#define ALGO_DEF M_ALGO_DEF
#define ALGO_FOR_EACH M_ALGO_FOR_EACH
#define ALGO_TRANSFORM M_ALGO_TRANSFORM
#define ALGO_EXTRACT M_ALGO_EXTRACT
#define ALGO_REDUCE M_ALGO_REDUCE
#define ALGO_INSERT_AT M_ALGO_INSERT_AT
#endif
#endif