Author SHA1 Message Date
Patrick Pelissier 2ef7f5b8f0 Fix issue of M_LET with LIST_BIF containers. 2025-07-26 10:44:21 +02:00
Patrick Pelissier 522f37f66d WIP on BI-F list. Still an issue to fix 2025-07-26 10:38:28 +02:00
Patrick Pelissier 089b8b3c61 Add BI_PUSH container (name TBC) 2025-07-26 10:38:27 +02:00
Patrick Pelissier 40c6a6c891 Add parametrisation of _push_front / _push_back for dual push list 2025-07-26 10:37:39 +02:00
Patrick Pelissier c095769f86 Prepare integration of new dual push lists 2025-07-26 10:36:47 +02:00
Patrick Pelissier 46759b5f2c Rename _push_raw method to _push_back_raw method (Cleaner semantic) 2025-07-26 10:35:48 +02:00
Patrick Pelissier 8c8a1e2822 Fix bug reported by florommel on dict's reserve 2025-07-18 20:11:13 +02:00
Patrick Pelissier ad646f5e04 Update links 2025-07-01 22:17:49 +02:00
Patrick Pelissier 9ecc031fd7 Fix doc 2025-06-10 22:18:24 +02:00
Patrick Pelissier ea3c2c5019 Update doc 2025-06-10 22:15:34 +02:00
Patrick Pelissier a9dc2eef12 Update doc 2025-05-31 00:11:49 +02:00
Patrick Pelissier 39a0a4f672 Fix format 2025-05-29 15:06:36 +02:00
Patrick Pelissier 4ffa4a15ac Rename example 2025-05-29 15:01:21 +02:00
Patrick Pelissier 2d5c9e71ae Add new example 2025-05-29 14:58:25 +02:00
Patrick Pelissier e802e22b7b Port to new API 2025-05-29 14:58:09 +02:00
Patrick Pelissier 3fbe8ec0b6 Update _transform, _reduce and _map_reduce to be more flexible
Rename _map_reduce to _transform_reduce
2025-05-29 10:41:20 +02:00
Patrick Pelissier 34085aa637 WIP to allow recursive variant 2025-05-29 10:40:19 +02:00
Patrick Pelissier 77033e2020 Move to V0.8.1 2025-05-29 10:39:42 +02:00
Patrick Pelissier 5c57ad1f51 Add example on tree 2025-05-24 17:40:29 +02:00
Patrick Pelissier 27621db95d Add method _left, right, _up and _down for tree to get directly an iterator to the requested element 2025-05-24 17:38:57 +02:00
Patrick Pelissier eab3f701a8 Fix displayed size in case of overflow computation 2025-05-24 10:18:15 +02:00
19 changed files with 589 additions and 222 deletions

No files matched your search

+1 -1
View File
@@ -34,7 +34,7 @@ DESTDIR=
# Package name & version. # Package name & version.
PACKAGE=m_lib-$(VERSION) PACKAGE=m_lib-$(VERSION)
VERSION=0.8.0 VERSION=0.8.1
# Define the contain of the distribution tarball # Define the contain of the distribution tarball
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-list.h m-thread.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h m-queue.h HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-list.h m-thread.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h m-queue.h
+72 -26
View File
@@ -119,7 +119,7 @@ there is no overhead in using this library rather than using
direct C low-level access as the compiler is able to **fully** optimize direct C low-level access as the compiler is able to **fully** optimize
the library usage the library usage
and the library is carefully designed. and the library is carefully designed.
In [fact](https://github.com/P-p-H-d/mlib/wiki/performance), M\*LIB In [fact](https://github.com/P-p-H-d/c-stl-comparison/wiki/Benchmark-result), M\*LIB
is one of the fastest generic C/C++ library you can find. is one of the fastest generic C/C++ library you can find.
M\*LIB uses internally the `malloc`, `realloc` and `free` functions to handle M\*LIB uses internally the `malloc`, `realloc` and `free` functions to handle
@@ -139,8 +139,8 @@ You can read or write your full and complex data structure into [JSON](https://e
M\*LIB is distributed under BSD-2 simplified license. M\*LIB is distributed under BSD-2 simplified license.
It is strongly advised not to read the source to know how to use the library It is strongly advised not to read the source to know how to use the library
as the code is quite complex and uses a lot of tricks as the code is quite complex and uses a lot of tricks.
but rather read the examples. You should rather read the examples.
In this documentation, In this documentation,
* _shall_ will be used to indicate a user constraint that is * _shall_ will be used to indicate a user constraint that is
@@ -149,6 +149,22 @@ mandatory to follow under penalty of undefined behavior.
All pointers expected by the functions of the library shall expect non-null argument except if indicated. All pointers expected by the functions of the library shall expect non-null argument except if indicated.
## Key points
* Genericity Mechanism through code generation by macro-base approaches while keeping code size reasonable,
* Minimum supported C Standard is C99,
* Header only library (easier to integrate),
* Performance: M\*LIB is highly optimized with Minimal Runtime Overhead in Release mode,
* Type Safety: Compiler catches type mismatches.
* Runtime errors: Assertion are enabled in Debug mode and check for contract violiation and runtime errors are enabled for robustness in debug mode,
* High focus on homogeneous API design and ease of use,
* Near 100% coverage in instruction and decision by the test suite,
* Actively maintained library,
* Can be used fully without any macro usage outside of its code generation section,
* Provide all the standard containers (vectors, lists, hash maps, sets, queues, etc.) and algorithms (sort, search) and even more,
* Fully customisable memory allocator,
* Can use _Generic keyword for uniform usage of the operators on any registered type.
## Components ## Components
The following headers define containers that don't require the user structure to be modified: The following headers define containers that don't require the user structure to be modified:
@@ -530,7 +546,7 @@ Each graph is presented first in linear scale and then in logarithmic scale to b
M\*LIB is on par with the STL or even faster. M\*LIB is on par with the STL or even faster.
All used bench codes are available in this [repository](https://github.com/P-p-H-d/c-stl-comparison) All used bench codes are available in this [repository](https://github.com/P-p-H-d/c-stl-comparison)
The results for several different libraries are also available [in a separate page](https://github.com/P-p-H-d/mlib/wiki/performance). The results for several different libraries are also available [in a separate page](https://github.com/P-p-H-d/c-stl-comparison/wiki/Benchmark-result).
#### Singly List #### Singly List
@@ -806,14 +822,15 @@ Example:
INIT_SET(mpz_init_set),CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT),TYPE(mpz_t)) INIT_SET(mpz_init_set),CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT),TYPE(mpz_t))
``` ```
This can simplify a lot `OPLIST` usage and it is recommended. > [!NOTE]
> Registering globaly the oplist when defining its type simplify a lot the `OPLIST` usage and it is **highly** recommended.
Then each times a macro expects an oplist, you can give instead its type. Then each times a macro expects an oplist, you can give instead its type.
This make the code much easier to read and understand. This make the code much easier to read and understand.
There is one exception however: the macros that are used to build oplist There is one exception however: the macros that are used to build oplist
(like `ARRAY_OPLIST`) don't perform this simplification and the oplist of (like `ARRAY_OPLIST`) don't perform this simplification and the oplist of
the basic type shall be given instead the type shall be explictely given instead
(This is due to limitation in the C preprocessing). (This is due to limitation in the C preprocessing).
### API Interface Adaptation ### API Interface Adaptation
@@ -1398,7 +1415,6 @@ This method is created only if the `INIT_SET` operator is provided.
The `_back` suffixed method will push it in the back of the container. The `_back` suffixed method will push it in the back of the container.
The `_front` suffixed method will push it in the front of the container. The `_front` suffixed method will push it in the front of the container.
##### `type_t *name_push_raw(name_t container)`
##### `type_t *name_push_back_raw(name_t container)` ##### `type_t *name_push_back_raw(name_t container)`
##### `type_t *name_push_front_raw(name_t container)` ##### `type_t *name_push_front_raw(name_t container)`
@@ -1868,7 +1884,7 @@ void name_clear(name_t list)
void name_reset(name_t list) void name_reset(name_t list)
type *name_back(const name_t list) type *name_back(const name_t list)
void name_push_back(name_t list, const type value) void name_push_back(name_t list, const type value)
type *name_push_raw(name_t list) type *name_push_back_raw(name_t list)
type *name_push_new(name_t list) type *name_push_new(name_t list)
void name_push_move(name_t list, type *value) void name_push_move(name_t list, type *value)
void name_emplace_back[suffix](name_t list, args...) void name_emplace_back[suffix](name_t list, args...)
@@ -2190,7 +2206,7 @@ void name_init_move(name_t array, name_t ref)
void name_move(name_t array, name_t ref) void name_move(name_t array, name_t ref)
void name_clear(name_t array) void name_clear(name_t array)
void name_reset(name_t array) void name_reset(name_t array)
type *name_push_raw(name_t array) type *name_push_back_raw(name_t array)
void name_push_back(name_t array, const type value) void name_push_back(name_t array, const type value)
type *name_push_new(name_t array) type *name_push_new(name_t array)
void name_push_move(name_t array, type *val) void name_push_move(name_t array, type *val)
@@ -2453,6 +2469,13 @@ Both oplist shall have at least the following operators (`INIT_SET`, `SET` and `
otherwise it won't generate compilable code. otherwise it won't generate compilable code.
The `key_oplist` shall also define the additional operators (`HASH` and `EQUAL`). The `key_oplist` shall also define the additional operators (`HASH` and `EQUAL`).
> [!NOTE]
> You can either call this macro with only `key_type` and `value_type`
> or with their type+oplists `key_type`, `key_oplist`, `value_type` and `value_oplist`.
> You cannot call it with an oplist for a type and not for the other
> (Otheriwse it won't be able to identify reliabely what is the third argument - a `value_type` or a `key_oplist` ?)
> Failure to respect this rule so will result in a too few argument error for `M_D1CT_DEF2_P2` internal macro.
Elements in the dictionary are **unordered**. Elements in the dictionary are **unordered**.
On insertion of a new element, contained objects may moved. On insertion of a new element, contained objects may moved.
Maximum number of elements of this dictionary is 3'006'477'107 elements. Maximum number of elements of this dictionary is 3'006'477'107 elements.
@@ -2520,6 +2543,13 @@ The elements may move when inserting / deleting other elements (and not just the
This implementation is in general faster for small types of keys This implementation is in general faster for small types of keys
(like integer or float) but are slower for larger types. (like integer or float) but are slower for larger types.
> [!NOTE]
> You can either call this macro with only `key_type` and `value_type`
> or with their type+oplists `key_type`, `key_oplist`, `value_type` and `value_oplist`.
> You cannot call it with an oplist for a type and not for the other
> (Otheriwse it won't be able to identify reliabely what is the third argument - a `value_type` or a `key_oplist` ?)
> Failure to respect this rule so will result in a too few argument error for `M_D1CT_DEF2_P2` internal macro.
`DICT_OA_DEF2_AS` is the same as `DICT_OA_DEF2` `DICT_OA_DEF2_AS` is the same as `DICT_OA_DEF2`
except the name of the types `name_t`, `name_it_t`, `name_itref_t` are provided. except the name of the types `name_t`, `name_it_t`, `name_itref_t` are provided.
@@ -3561,6 +3591,14 @@ Return a pointer to the type of the node which is
respectively. respectively.
It returns NULL if there is no such node. It returns NULL if there is no such node.
##### `it_t name_up(it_t it)`
##### `it_t name_down(it_t it)`
##### `it_t name_left(it_t it)`
##### `it_t name_right(it_t it)`
Return an iterator to point to the node which is up (resp. down, left and right) the given iterator.
Return a valid iterator in case of success, an invalid one otherwse (see `name_end_p`)
##### `bool name_it_up(it_t *it)` ##### `bool name_it_up(it_t *it)`
##### `bool name_it_down(it_t *it)` ##### `bool name_it_down(it_t *it)`
##### `bool name_it_left(it_t *it)` ##### `bool name_it_left(it_t *it)`
@@ -8192,31 +8230,40 @@ Apply the function `func` to each element of the container `c`.
The function may transform the element provided it doesn't reallocate the The function may transform the element provided it doesn't reallocate the
object and if the container supports iterating over modifiable elements. 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` Reset the container `d`, then
and push the result into the container `d` so that `d = func(c)` 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` `func` shall output in the initialized object `*out`
the transformed value of the constant object `in`. the transformed value of the constant object `in` if it decides this value is kept (its return value is true in this case).
Afterwards `out` is pushed moved into `d`. 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 base type exports an `INIT` method and if the container exports a `PUSH` method.
This method is defined only if the container exports a `PUSH_MOVE` method. `c` and `d` shall not be the same containers.
`c` and `d` cannot 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`. Perform a reduction using the function `func` to the elements of the container `c`.
The final result is stored in `*dest`. 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` 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`. 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))` ##### `bool name_any_of_p(const container_t c, void *(func)(const type_t))`
@@ -9189,7 +9236,7 @@ The following methods are modified to support the memory context parameter (the
* \<array\>_init_set * \<array\>_init_set
* \<array\>_move * \<array\>_move
* \<array\>_set_at * \<array\>_set_at
* \<array\>_push_raw * \<array\>_push_back_raw
* \<array\>_push_back * \<array\>_push_back
* \<array\>_push_new * \<array\>_push_new
* \<array\>_push_move * \<array\>_push_move
@@ -9288,7 +9335,7 @@ The following methods are modified to support the memory context parameter (the
* m-list * m-list
* \<list\>_reset * \<list\>_reset
* \<list\>_clear * \<list\>_clear
* \<list\>_push_raw * \<list\>_push_back_raw
* \<list\>_push_back * \<list\>_push_back
* \<list\>_push_new * \<list\>_push_new
* \<list\>_pop_back * \<list\>_pop_back
@@ -9308,7 +9355,6 @@ The following methods are modified to support the memory context parameter (the
* \<list\>_\<emplace_back\> * \<list\>_\<emplace_back\>
* \<list\>_\<emplace_front\> * \<list\>_\<emplace_front\>
* \<list\>_push_back_raw * \<list\>_push_back_raw
* \<list\>_push_raw
* \<list\>_push_back * \<list\>_push_back
* \<list\>_push_back_new * \<list\>_push_back_new
* \<list\>_push_back_move * \<list\>_push_back_move
+4
View File
@@ -108,3 +108,7 @@ 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) (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 * 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.
* Rename _push_raw method by _push_back_raw for all containers (clearer on the semantic)
+4 -2
View File
@@ -13,8 +13,10 @@ ALGO_DEF(array_mpz, ARRAY_OPLIST(array_mpz, M_CLASSIC_OPLIST(mpz)))
static inline void my_mpz_inc(mpz_t *d, const mpz_t a){ static inline void my_mpz_inc(mpz_t *d, const mpz_t a){
mpz_add(*d, *d, a); mpz_add(*d, *d, a);
} }
static inline void my_mpz_sqr(mpz_t *d, const mpz_t a){ static inline bool my_mpz_sqr(mpz_t *d, const mpz_t a, void *data){
(void) data;
mpz_mul(*d, a, a); mpz_mul(*d, a, a);
return true;
} }
int main(void) int main(void)
@@ -31,7 +33,7 @@ int main(void)
} }
/* Compute z = sum (a[i]^2) */ /* Compute z = sum (a[i]^2) */
array_mpz_map_reduce (&z, a, my_mpz_inc, my_mpz_sqr); array_mpz_transform_reduce (&z, a, my_mpz_inc, my_mpz_sqr, NULL);
gmp_printf ("Z=%Zd\n", z); gmp_printf ("Z=%Zd\n", z);
array_mpz_clear(a); array_mpz_clear(a);
+39
View File
@@ -0,0 +1,39 @@
#include <stdio.h>
#include "m-tree.h"
TREE_DEF(tree, int)
// Compute sum of the tree using iterator and a pre-order walk
static int tree_sum_iter(tree_t t)
{
int s = 0;
for(tree_it_t it = tree_it(t); !tree_end_p(it); tree_next(&it)) {
s += *tree_cref(it);
}
return s;
}
// Compute sum of the tree using recursive call
static int tree_sum_recur(tree_it_t it)
{
if (tree_end_p(it))
return 0;
if (tree_leaf_p(it))
return *tree_cref(it);
assert( tree_degree(it) == 2);
return *tree_cref(it) + tree_sum_recur(tree_down(it)) + tree_sum_recur(tree_right(tree_down(it)));
}
int main(void)
{
tree_t t;
tree_init(t);
tree_it_t r = tree_set_root(t, 1);
tree_it_t l = tree_insert_child(r, 2);
tree_insert_child(r, 5);
tree_insert_child(l, 3);
tree_insert_child(l, 4);
printf("sum = %d vs %d\n", tree_sum_iter(t), tree_sum_recur(tree_it(t)));
tree_clear(t);
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
#include <stdio.h>
#include "m-array.h"
#include "m-algo.h"
#include "m-string.h"
ARRAY_DEF(array_int, int)
#define M_OPL_array_int_t() ARRAY_OPLIST(array_int, M_BASIC_OPLIST)
ALGO_DEF(array_int, array_int_t)
static bool callback1(int *out, int in, void *data)
{
int *cpt = data;
bool ret = true;
if (*cpt == -1 && in == 11)
*cpt = 0; // Start when first reach 11
ret &= (*cpt >= 0); // Skip initial numbers unequal 11
ret &= (in % 2 != 0); // Collect odd numbers
(*cpt) += ret;
ret &= (*cpt <= 5); // Only take five numbers
*out = in * in; // Square each number
return ret;
}
static void callback_add_int(int *out, int in)
{
*out += in;
}
static void demo(void)
{
M_LET( (t, M_SEQ(0, 30)), vector, array_int_t) {
printf("t="); array_int_out_str(stdout, t);
int b = -1;
array_int_transform(vector, t, callback1, &b);
printf("\nvector="); array_int_out_str(stdout, vector); printf("\n");
array_int_reduce(&b, vector, callback_add_int);
printf("Sum=%d\n", b);
}
}
ARRAY_DEF(array_str, string_t)
#define M_OPL_array_str_t() ARRAY_OPLIST(array_str, M_STRING_OPLIST)
ALGO_DEF(array_str, array_str_t)
static bool callback2(string_t *out, const string_t in, void *data)
{
char *cp = data, c = *cp;
if (string_search_char(in, c) == M_STRING_FAILURE)
return false;
string_set(*out, in);
return true;
}
static void demo_split(void)
{
M_LET( (s, ("This is a sentence in C11.")), string_t)
M_LET(words, f_words, array_str_t) {
array_str_split(words, s, ' ');
array_str_transform(f_words, words, callback2, &(char){'i'});
printf("f_words="); array_str_out_str(stdout, f_words); printf("\n");
}
}
int main(void)
{
demo();
demo_split();
return 0;
}
+19 -16
View File
@@ -170,7 +170,8 @@
typedef bool (*M_F(name, _test_cb_ct))(type_t const); \ 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 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 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) ); 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, _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, _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, _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 * ) \ 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(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 */ \ /* 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_ASSERT(dst != src); \
M_CALL_RESET(cont_oplist, dst); \ M_CALL_RESET(cont_oplist, dst); \
for M_EACH(item, src, cont_oplist) { \
type_t tmp; \ type_t tmp; \
M_CALL_INIT(type_oplist, tmp); \ M_CALL_INIT(type_oplist, tmp); \
func(&tmp, *item); \ for M_EACH(item, src, cont_oplist) { \
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),); \ M_IF_METHOD(REVERSE, cont_oplist)(M_CALL_REVERSE(cont_oplist, dst),); \
} \ } \
, /* END PUSH_MOVE */), /* END INIT */ ) \ , /* END PUSH_MOVE */), /* END INIT */ ) \
\ \
/* Reduce all elements of the container in dst in function of func */ \ /* Reduce all elements of the container in dst in function of func */ \
M_IF_METHOD(SET, type_oplist)( \ M_IF_METHOD(SET, type_oplist)( \
M_P(void, name, _reduce, type_t *dest, container_t const l, \ M_P(bool, name, _reduce, type_t *dest, container_t const l, M_F(name, _reduce_cb_ct) func) \
M_F(name, _transform_cb_ct) func) \
{ \ { \
M_UNUSED_CONTEXT(); \ M_UNUSED_CONTEXT(); \
bool initDone = false; \ bool initDone = false; \
@@ -788,15 +790,15 @@
initDone = true; \ initDone = true; \
} \ } \
} \ } \
return initDone; \
} \ } \
, /* END SET */) \ , /* END SET */) \
\ \
/* Reduce all transformed elements of the container in dst in function of func */ \ /* Reduce all transformed elements of the container in dst in function of func */ \
M_IF_METHOD(INIT, type_oplist)( \ M_IF_METHOD(INIT, type_oplist)( \
M_P(void, name, _map_reduce, type_t *dest, \ M_P(bool, name, _transform_reduce, type_t *dest, const container_t l, \
const container_t l, \ M_F(name, _reduce_cb_ct) redFunc, \
M_F(name, _transform_cb_ct) redFunc, \ M_F(name, _transform_cb_ct) mapFunc, void *data) \
M_F(name, _transform_cb_ct) mapFunc) \
{ \ { \
M_UNUSED_CONTEXT(); \ M_UNUSED_CONTEXT(); \
bool initDone = false; \ bool initDone = false; \
@@ -804,14 +806,15 @@
M_CALL_INIT(type_oplist, tmp); \ M_CALL_INIT(type_oplist, tmp); \
for M_EACH(item, l, cont_oplist) { \ for M_EACH(item, l, cont_oplist) { \
if (initDone) { \ if (initDone) { \
mapFunc(&tmp, *item); \ if (mapFunc(&tmp, *item, data) ) { \
redFunc(dest, tmp); \ redFunc(dest, tmp); \
} \
} else { \ } else { \
mapFunc(dest, *item); \ initDone = mapFunc(dest, *item, data); \
initDone = true; \
} \ } \
} \ } \
M_CALL_CLEAR(type_oplist, tmp); \ M_CALL_CLEAR(type_oplist, tmp); \
return initDone; \
} \ } \
, ) \ , ) \
+5 -5
View File
@@ -367,7 +367,7 @@
return &v->ptr[v->size-1]; \ return &v->ptr[v->size-1]; \
} \ } \
\ \
M_P(type *, name, _push_raw, array_t v) \ M_P(type *, name, _push_back_raw, array_t v) \
{ \ { \
M_ARRA4_CONTRACT(v); \ M_ARRA4_CONTRACT(v); \
if (M_UNLIKELY (v->size >= v->alloc)) { \ if (M_UNLIKELY (v->size >= v->alloc)) { \
@@ -395,7 +395,7 @@
M_IF_METHOD(INIT_SET, oplist)( \ M_IF_METHOD(INIT_SET, oplist)( \
M_P(void, name, _push_back, array_t v, type const x) \ M_P(void, name, _push_back, array_t v, type const x) \
{ \ { \
type *data = M_F(name, _push_raw) M_R(v); \ type *data = M_F(name, _push_back_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return; \ return; \
M_IF_EXCEPTION( v->size --); \ M_IF_EXCEPTION( v->size --); \
@@ -407,7 +407,7 @@
M_IF_METHOD(INIT, oplist)( \ M_IF_METHOD(INIT, oplist)( \
M_P(type *, name, _push_new, array_t v) \ M_P(type *, name, _push_new, array_t v) \
{ \ { \
type *data = M_F(name, _push_raw) M_R(v); \ type *data = M_F(name, _push_back_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return NULL; \ return NULL; \
M_IF_EXCEPTION( v->size --); \ M_IF_EXCEPTION( v->size --); \
@@ -420,7 +420,7 @@
M_P(void, name, _push_move, array_t v, type *x) \ M_P(void, name, _push_move, array_t v, type *x) \
{ \ { \
M_ASSERT (x != NULL); \ M_ASSERT (x != NULL); \
type *data = M_F(name, _push_raw) M_R(v); \ type *data = M_F(name, _push_back_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return; \ return; \
M_CALL_INIT_MOVE (oplist, *data, *x); \ M_CALL_INIT_MOVE (oplist, *data, *x); \
@@ -1136,7 +1136,7 @@
#define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ #define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \ { \
M_F(name, _subtype_ct) *data = M_F(name, _push_raw) M_R(v); \ M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return; \ return; \
M_IF_EXCEPTION( v->size --); \ M_IF_EXCEPTION( v->size --); \
+4 -4
View File
@@ -71,7 +71,7 @@
/* Define M*LIB version */ /* Define M*LIB version */
#define M_CORE_VERSION_MAJOR 0 #define M_CORE_VERSION_MAJOR 0
#define M_CORE_VERSION_MINOR 8 #define M_CORE_VERSION_MINOR 8
#define M_CORE_VERSION_PATCHLEVEL 0 #define M_CORE_VERSION_PATCHLEVEL 1
/* M_ASSUME is equivalent to M_ASSERT, but gives hints to compiler /* M_ASSUME is equivalent to M_ASSERT, but gives hints to compiler
about how to optimize the code if NDEBUG is defined. about how to optimize the code if NDEBUG is defined.
@@ -4748,7 +4748,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
/* Initialize the container 'dest' as per 'oplist' INIT operator /* Initialize the container 'dest' as per 'oplist' INIT operator
and fill it with the given VA_ARGS arguments with the _push_raw method and fill it with the given VA_ARGS arguments with the _push_back_raw method
allowing INIT_WITH operator for the pushed argument if the given allowing INIT_WITH operator for the pushed argument if the given
argument is between parenthesis, otherwise an INIT_SET is performed. argument is between parenthesis, otherwise an INIT_SET is performed.
NOTE: Parenthesis detection is the best we can do to detect a special NOTE: Parenthesis detection is the best we can do to detect a special
@@ -4766,11 +4766,11 @@ m_core_parse2_enum (const char str[], const char **endptr)
M_INIT_WITH_VAI23_FUNC(M_PAIR_1 pair, M_PAIR_2 pair, a) M_INIT_WITH_VAI23_FUNC(M_PAIR_1 pair, M_PAIR_2 pair, a)
/* We first push a raw new item, and then we get back its pointer using _back. /* We first push a raw new item, and then we get back its pointer using _back.
_back (contrary to _push_raw) has no side effect, and so is safe to be used _back (contrary to _push_back_raw) has no side effect, and so is safe to be used
in a macro */ in a macro */
#define M_INIT_WITH_VAI23_FUNC(d, op, a) \ #define M_INIT_WITH_VAI23_FUNC(d, op, a) \
( \ ( \
(void) M_C(M_GET_NAME op, _push_raw)(d), \ (void) M_C(M_GET_NAME op, _push_back_raw)(d), \
M_IF(M_PARENTHESIS_P(a)) \ M_IF(M_PARENTHESIS_P(a)) \
(M_CALL_INIT_WITH, M_CALL_INIT_SET) \ (M_CALL_INIT_WITH, M_CALL_INIT_SET) \
(M_GET_OPLIST op, *M_C(M_GET_NAME op, _back)(d), M_REMOVE_PARENTHESIS(a)) \ (M_GET_OPLIST op, *M_C(M_GET_NAME op, _back)(d), M_REMOVE_PARENTHESIS(a)) \
-6
View File
@@ -280,12 +280,6 @@
return ret; \ return ret; \
} \ } \
\ \
/* Internal, for generic INIT_WITH */ \
M_P(type *, name, _push_raw, deque_t d) \
{ \
return M_F(name, _push_back_raw)M_R(d); \
} \
\
M_P(void, name, _push_back, deque_t d, type const x) \ M_P(void, name, _push_back, deque_t d, type const x) \
{ \ { \
type *p = M_F(name, _push_back_raw)M_R(d); \ type *p = M_F(name, _push_back_raw)M_R(d); \
+8 -2
View File
@@ -325,6 +325,9 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
{ \ { \
map->upper_limit = (m_index_t) ((double) size * M_D1CT_OA_UPPER_BOUND) - 1; \ map->upper_limit = (m_index_t) ((double) size * M_D1CT_OA_UPPER_BOUND) - 1; \
map->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (m_index_t) ((double) size * M_D1CT_OA_LOWER_BOUND) ; \ map->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (m_index_t) ((double) size * M_D1CT_OA_LOWER_BOUND) ; \
if (M_UNLIKELY(map->count <= map->lower_limit)) { \
map->lower_limit = 0; \
} \
} \ } \
\ \
M_P(void, name, _init, dict_t map) \ M_P(void, name, _init, dict_t map) \
@@ -1534,6 +1537,9 @@ enum m_d1ct_oa_element_e {
/* FIXME: Overflow not handled. What to do in case of it? */ \ /* FIXME: Overflow not handled. What to do in case of it? */ \
dict->upper_limit = (size_t) ((double) size * coeff_up) - 1; \ dict->upper_limit = (size_t) ((double) size * coeff_up) - 1; \
dict->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (size_t) ((double) size * coeff_down) ; \ dict->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (size_t) ((double) size * coeff_down) ; \
if (M_UNLIKELY(dict->count <= dict->lower_limit)) { \
dict->lower_limit = 0; \
} \
} \ } \
\ \
M_P(void, name, _init, dict_t dict) \ M_P(void, name, _init, dict_t dict) \
@@ -1662,7 +1668,7 @@ enum m_d1ct_oa_element_e {
M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} else { \ } else { \
M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \ M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_back_raw)M_R(tmp); \
M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \
} \ } \
@@ -1836,7 +1842,7 @@ enum m_d1ct_oa_element_e {
M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} else { \ } else { \
M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \ M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_back_raw)M_R(tmp); \
M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \
} \ } \
+218 -152
View File
@@ -44,15 +44,15 @@
M_END_PROTECTED_CODE M_END_PROTECTED_CODE
/* Define a singly linked list of a given type allowing both push. /* Define a singly linked list of a given type allowing both push and one pop (back)
USAGE: LIST_DUAL_PUSH_DEF_AS(name, name_t, type [, oplist_of_the_type]) */ USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */
#define M_LIST_DUAL_PUSH_DEF(name, ...) \ #define M_LIST_DUAL_PUSH_DEF(name, ...) \
M_LIST_DUAL_PUSH_DEF_AS(name, M_F(name,_t), M_F(name, _it_t), __VA_ARGS__) M_LIST_DUAL_PUSH_DEF_AS(name, M_F(name,_t), M_F(name, _it_t), __VA_ARGS__)
/* Define a singly linked list of a given type allowing both push. /* Define a singly linked list of a given type allowing both push and one pop (back)
as the provided type name_t with the iterator named it_t as the provided type name_t with the iterator named it_t
USAGE: LIST_DUAL_PUSH_DEF(name, type [, oplist_of_the_type]) */ USAGE: LIST_DUAL_PUSH_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define M_LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \ #define M_LIST_DUAL_PUSH_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \ M_BEGIN_PROTECTED_CODE \
M_L1ST_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ M_L1ST_DUAL_PUSH_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
@@ -61,6 +61,22 @@
M_END_PROTECTED_CODE M_END_PROTECTED_CODE
/* Define a singly linked list of a given type allowing both push and one pop (front)
USAGE: LIST_BIF_DEF(name, type [, oplist_of_the_type]) */
#define M_LIST_BIF_DEF(name, ...) \
M_LIST_BIF_DEF_AS(name, M_F(name,_t), M_F(name, _it_t), __VA_ARGS__)
/* Define a singly linked list of a given type allowing both push and one pop (front)
as the provided type name_t with the iterator named it_t
USAGE: LIST_BIF_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define M_LIST_BIF_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_L1ST_BIF_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \
(name, __VA_ARGS__, name_t, it_t ))) \
M_END_PROTECTED_CODE
/* Define the oplist of a list of the given type. /* Define the oplist of a list of the given type.
USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */ USAGE: LIST_OPLIST(name [, oplist_of_the_type]) */
#define M_LIST_OPLIST(...) \ #define M_LIST_OPLIST(...) \
@@ -68,6 +84,10 @@
((__VA_ARGS__, M_BASIC_OPLIST ), \ ((__VA_ARGS__, M_BASIC_OPLIST ), \
(__VA_ARGS__ ))) (__VA_ARGS__ )))
/* Define the oplist of a list of the given type.
USAGE: LIST_BIF_OPLIST(name [, oplist_of_the_type]) */
#define M_LIST_BIF_OPLIST(...) M_OPEXTEND(M_LIST_OPLIST(__VA_ARGS__), REVERSE(0))
/* Define an init value to init global variables of type list. /* Define an init value to init global variables of type list.
USAGE: USAGE:
list_t global_variable = LIST_INIT_VALUE(); list_t global_variable = LIST_INIT_VALUE();
@@ -128,8 +148,8 @@
IT_INSERT(M_F(name, _insert)), \ IT_INSERT(M_F(name, _insert)), \
IT_REMOVE(M_F(name,_remove)), \ IT_REMOVE(M_F(name,_remove)), \
RESET(M_F(name,_reset)), \ RESET(M_F(name,_reset)), \
PUSH(M_F(name,_push_back)), \ PUSH(M_F(name,_push)), \
POP(M_F(name,_pop_back)), \ POP(M_F(name,_pop)), \
PUSH_MOVE(M_F(name,_push_move)), \ PUSH_MOVE(M_F(name,_push_move)), \
POP_MOVE(M_F(name,_pop_move)) \ POP_MOVE(M_F(name,_pop_move)) \
,SPLICE_BACK(M_F(name,_splice_back)) \ ,SPLICE_BACK(M_F(name,_splice_back)) \
@@ -172,8 +192,8 @@
IT_INSERT(API_0P(M_F(name, _insert))), \ IT_INSERT(API_0P(M_F(name, _insert))), \
IT_REMOVE(API_0P(M_F(name,_remove))), \ IT_REMOVE(API_0P(M_F(name,_remove))), \
RESET(API_0P(M_F(name,_reset))), \ RESET(API_0P(M_F(name,_reset))), \
PUSH(API_0P(M_F(name,_push_back))), \ PUSH(API_0P(M_F(name,_push))), \
POP(API_0P(M_F(name,_pop_back))), \ POP(API_0P(M_F(name,_pop))), \
PUSH_MOVE(API_0P(M_F(name,_push_move))), \ PUSH_MOVE(API_0P(M_F(name,_push_move))), \
POP_MOVE(API_0P(M_F(name,_pop_move))) \ POP_MOVE(API_0P(M_F(name,_pop_move))) \
,SPLICE_BACK(M_F(name,_splice_back)) \ ,SPLICE_BACK(M_F(name,_splice_back)) \
@@ -293,7 +313,7 @@
return &((*v)->data); \ return &((*v)->data); \
} \ } \
\ \
M_P(type *, name, _push_raw, list_t v) \ M_P(type *, name, _push_back_raw, list_t v) \
{ \ { \
M_L1ST_CONTRACT(v); \ M_L1ST_CONTRACT(v); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
@@ -309,7 +329,7 @@
\ \
M_P(void, name, _push_back, list_t v, type const x) \ M_P(void, name, _push_back, list_t v, type const x) \
{ \ { \
type *data = M_F(name, _push_raw)M_R(v); \ type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return; \ return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \ M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
@@ -318,10 +338,15 @@
} \ } \
} \ } \
\ \
M_P(void, name, _push, list_t v, type const x) \
{ \
M_F(name, _push_back)M_R(v, x); \
} \
\
M_IF_METHOD(INIT, oplist)( \ M_IF_METHOD(INIT, oplist)( \
M_P(type *, name, _push_new, list_t v) \ M_P(type *, name, _push_new, list_t v) \
{ \ { \
type *data = M_F(name, _push_raw)M_R(v); \ type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return NULL; \ return NULL; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \ M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
@@ -347,10 +372,15 @@
M_L1ST_CONTRACT(v); \ M_L1ST_CONTRACT(v); \
} \ } \
\ \
M_P(void, name, _pop, type *data, list_t v) \
{ \
M_F(name, _pop_back)M_R(data, v); \
} \
\
M_P(void, name, _push_move, list_t v, type *x) \ M_P(void, name, _push_move, list_t v, type *x) \
{ \ { \
M_ASSERT (x != NULL); \ M_ASSERT (x != NULL); \
type *data = M_F(name, _push_raw)M_R(v); \ type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return; \ return; \
M_CALL_INIT_MOVE (oplist, *data, *x); \ M_CALL_INIT_MOVE (oplist, *data, *x); \
@@ -892,7 +922,7 @@
#define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ #define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \ { \
M_F(name, _subtype_ct) *data = M_F(name, _push_raw)M_R(v); \ M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return; \ return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \ M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
@@ -903,30 +933,30 @@
/* Definition of the emplace_back function for dual push list */ /* Definition of the emplace_back function for dual push list */
#define M_L1ST_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ #define M_L1ST_EMPLACE_STRONG_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \ { \
M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \ M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return; \ return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \ M_IF_EXCEPTION(struct M_F(name, _s) *next = v->first); \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \ M_ON_EXCEPTION( v->first = next->next, v->last = (v->last == next) ? NULL : v->last, M_CALL_DEL(oplist, next)) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \ } \
} }
/* Definition of the emplace_front function for dual push list */ /* Definition of the emplace_front function for dual push list */
#define M_L1ST_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ #define M_L1ST_EMPLACE_WEAK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \ { \
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ M_IF_EXCEPTION(struct M_F(name, _s) *front = v->last, *back = v->first); \
M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)M_R(v); \ M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)M_R(v); \
if (M_UNLIKELY (data == NULL) ) \ if (M_UNLIKELY (data == NULL) ) \
return; \ return; \
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->last); \
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \ M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \ M_ON_EXCEPTION( v->first = back, v->last = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \ } \
} }
@@ -948,8 +978,8 @@
/* Define the internal contract of an dual-push list */ /* Define the internal contract of an dual-push list */
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \ #define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
M_ASSERT (l != NULL); \ M_ASSERT (l != NULL); \
M_ASSERT ( (l->back == NULL && l->front == NULL) \ M_ASSERT ( (l->first == NULL && l->last == NULL) \
|| (l->back != NULL && l->front != NULL)); \ || (l->first != NULL && l->last != NULL)); \
} while (0) } while (0)
@@ -963,9 +993,9 @@
#define M_L1ST_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \ #define M_L1ST_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \
M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \ M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t, _back, _push_back_raw, _push_back, _push_back_move, _push_back_new, _pop_back, _front, _push_front_raw, _push_front, _push_front_move, _push_front_new) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_BACK_DEF) \ M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_STRONG_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_front, oplist, M_L1ST_EMPLACE_FRONT_DEF) \ M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_front, oplist, M_L1ST_EMPLACE_WEAK_DEF) \
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
@@ -978,13 +1008,12 @@
}; \ }; \
\ \
/* Dual Push singly linked list. \ /* Dual Push singly linked list. \
Support Push Back / Push Front / Pop back in O(1). \ Support Push Back / Push Front / Pop back or front in O(1). \
Doesn't support Pop front. \
This is done by keeping a pointer to both back & front \ This is done by keeping a pointer to both back & front \
*/ \ */ \
typedef struct M_F(name, _head_s) { \ typedef struct M_F(name, _head_s) { \
struct M_F(name,_s) *front; /* Pointer to the front node or NULL */ \ struct M_F(name,_s) *last; /* Pointer to the weak entry node or NULL */ \
struct M_F(name,_s) *back; /* Pointer to the back node or NULL */ \ struct M_F(name,_s) *first; /* Pointer to the strong entry node or NULL */ \
} list_t[1]; \ } list_t[1]; \
\ \
/* Define the iterator over a dual push singly linked list */ \ /* Define the iterator over a dual push singly linked list */ \
@@ -1007,30 +1036,32 @@
- oplist: oplist of the type of the elements of the container - oplist: oplist of the type of the elements of the container
- list_t: alias for type of the container - list_t: alias for type of the container
- it_t: alias for iterator of the container - it_t: alias for iterator of the container
- strong: name of the strong entry point (back or front)
- weak: name of the weak entry point (front or back)
*/ */
#define M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ #define M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t, strong, push_strong_raw, push_strong, push_strong_move, push_strong_new, pop_strong, weak, push_weak_raw, push_weak, push_weak_move, push_weak_new) \
\ \
M_INLINE void \ M_INLINE void \
M_F(name, _init)(list_t v) \ M_F(name, _init)(list_t v) \
{ \ { \
M_ASSERT( v != NULL); \ M_ASSERT( v != NULL); \
v->front = NULL; \ v->last = NULL; \
v->back = NULL; \ v->first = NULL; \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \ } \
\ \
M_P(void, name, _reset, list_t v) \ M_P(void, name, _reset, list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
struct M_F(name, _s) *it = v->back; \ struct M_F(name, _s) *it = v->first; \
while (it != NULL) { \ while (it != NULL) { \
struct M_F(name, _s) *next = it->next; \ struct M_F(name, _s) *next = it->next; \
M_CALL_CLEAR(oplist, it->data); \ M_CALL_CLEAR(oplist, it->data); \
M_CALL_DEL(oplist, it); \ M_CALL_DEL(oplist, it); \
it = next; \ it = next; \
} \ } \
v->front = NULL; \ v->last = NULL; \
v->back = NULL; \ v->first = NULL; \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \ } \
\ \
@@ -1040,14 +1071,14 @@
} \ } \
\ \
M_INLINE type * \ M_INLINE type * \
M_F(name, _back)(const list_t v) \ M_F(name, strong)(const list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_ASSERT (v->back != NULL); \ M_ASSERT (v->first != NULL); \
return &(v->back->data); \ return &(v->first->data); \
} \ } \
\ \
M_P(type *, name, _push_back_raw, list_t v) \ M_P(type *, name, push_strong_raw, list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
@@ -1055,52 +1086,51 @@
M_MEMORY_FULL(struct M_F(name, _s), 1); \ M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \ } \
type *ret = &next->data; \ type *ret = &next->data; \
next->next = v->back; \ next->next = v->first; \
v->back = next; \ v->first = next; \
/* Update front too if the list was empty */ \ /* Update weak entry too if the list was empty */ \
/* This C code should generate branchless code */ \ /* This C code should generate branchless code */ \
struct M_F(name, _s) *front = v->front; \ struct M_F(name, _s) *node = v->last; \
front = (front == NULL) ? next : front; \ node = (node == NULL) ? next : node; \
v->front = front; \ v->last = node; \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
return ret; \ return ret; \
} \ } \
\ \
/* Internal, for INIT_WITH */ \ M_P(void, name, push_strong, list_t v, type const x) \
M_P(type *, name, _push_raw, list_t d) \
{ \ { \
return M_F(name, _push_back_raw)M_R(d); \ type *data = M_F(name, push_strong_raw)M_R(v); \
} \
\
M_P(void, name, _push_back, list_t v, type const x) \
{ \
type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return; \ return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \ M_IF_EXCEPTION(struct M_F(name, _s) *next = v->first); \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \ M_ON_EXCEPTION( v->first = next->next, v->last = (v->last == next) ? NULL : v->last, M_CALL_DEL(oplist, next)) { \
M_CALL_INIT_SET(oplist, *data, x); \ M_CALL_INIT_SET(oplist, *data, x); \
} \ } \
} \ } \
\ \
M_IF_METHOD(INIT, oplist)( \ M_P(void, name, _push, list_t v, type const x) \
M_P(type *, name, _push_back_new, list_t v) \
{ \ { \
type *data = M_F(name, _push_back_raw)M_R(v); \ M_F(name, push_strong)M_R(v, x); \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_P(type *, name, push_strong_new, list_t v) \
{ \
type *data = M_F(name, push_strong_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return NULL; \ return NULL; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \ M_IF_EXCEPTION(struct M_F(name, _s) *next = v->first); \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \ M_ON_EXCEPTION( v->first = next->next, v->last = (v->last == next) ? NULL : v->last, M_CALL_DEL(oplist, next)) { \
M_CALL_INIT(oplist, *data); \ M_CALL_INIT(oplist, *data); \
} \ } \
return data; \ return data; \
} \ } \
, /* No INIT */ ) \ , /* No INIT */ ) \
\ \
M_P(void, name, _push_back_move, list_t v, type *x) \ M_P(void, name, push_strong_move, list_t v, type *x) \
{ \ { \
M_ASSERT (x != NULL); \ M_ASSERT (x != NULL); \
type *data = M_F(name, _push_back_raw)M_R(v); \ type *data = M_F(name, push_strong_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return; \ return; \
M_CALL_INIT_MOVE (oplist, *data, *x); \ M_CALL_INIT_MOVE (oplist, *data, *x); \
@@ -1108,55 +1138,60 @@
\ \
M_P(void, name, _push_move, list_t v, type *x) \ M_P(void, name, _push_move, list_t v, type *x) \
{ \ { \
M_F(name, _push_back_move)M_R(v, x); \ M_F(name, push_strong_move)M_R(v, x); \
} \ } \
\ \
M_P(void, name, _pop_back, type *data, list_t v) \ M_P(void, name, pop_strong, type *data, list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_ASSERT (v->back != NULL); \ M_ASSERT (v->first != NULL); \
struct M_F(name, _s) *tofree = v->back; \ struct M_F(name, _s) *tofree = v->first; \
if (data != NULL) { \ if (data != NULL) { \
M_DO_MOVE(oplist, *data, tofree->data); \ M_DO_MOVE(oplist, *data, tofree->data); \
} else { \ } else { \
M_CALL_CLEAR(oplist, tofree->data); \ M_CALL_CLEAR(oplist, tofree->data); \
} \ } \
v->back = tofree->next; \ v->first = tofree->next; \
M_CALL_DEL(oplist, tofree); \ M_CALL_DEL(oplist, tofree); \
/* Update front too if the list became empty */ \ /* Update weak entry too if the list became empty */ \
/* This C code shall generate branchless code */ \ /* This C code shall generate branchless code */ \
struct M_F(name, _s) *front = v->front; \ struct M_F(name, _s) *node = v->last; \
front = (front == tofree) ? NULL : front; \ node = (node == tofree) ? NULL : node; \
v->front = front; \ v->last = node; \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \ } \
\ \
M_P(void, name, _pop, type *data, list_t v) \
{ \
M_F(name, pop_strong)M_R(data, v); \
} \
\
M_P(void, name, _pop_move, type *data, list_t v) \ M_P(void, name, _pop_move, type *data, list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_ASSERT (v->back != NULL); \ M_ASSERT (v->first != NULL); \
M_ASSERT (data != NULL); \ M_ASSERT (data != NULL); \
struct M_F(name, _s) *tofree = v->back; \ struct M_F(name, _s) *tofree = v->first; \
M_CALL_INIT_MOVE (oplist, *data, tofree->data); \ M_CALL_INIT_MOVE (oplist, *data, tofree->data); \
v->back = tofree->next; \ v->first = tofree->next; \
M_CALL_DEL(oplist, tofree); \ M_CALL_DEL(oplist, tofree); \
/* Update front too if the list became empty */ \ /* Update weak entry too if the list became empty */ \
/* This C code shall generate branchless code */ \ /* This C code shall generate branchless code */ \
struct M_F(name, _s) *front = v->front; \ struct M_F(name, _s) *node = v->last; \
front = (front == tofree) ? NULL : front; \ node = (node == tofree) ? NULL : node; \
v->front = front; \ v->last = node; \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \ } \
\ \
M_INLINE type * \ M_INLINE type * \
M_F(name, _front)(list_t v) \ M_F(name, weak)(list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_ASSERT (v->front != NULL); \ M_ASSERT (v->last != NULL); \
return &(v->front->data); \ return &(v->last->data); \
} \ } \
\ \
M_P(type *, name, _push_front_raw, list_t v) \ M_P(type *, name, push_weak_raw, list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
@@ -1165,49 +1200,49 @@
} \ } \
type *ret = &next->data; \ type *ret = &next->data; \
next->next = NULL; \ next->next = NULL; \
if (M_LIKELY(v->front != NULL)) { \ if (M_LIKELY(v->last != NULL)) { \
v->front->next = next; \ v->last->next = next; \
} else { \ } else { \
/* Update back too as the list was empty */ \ /* Update strong entry too as the list was empty */ \
v->back = next; \ v->first = next; \
} \ } \
v->front = next; \ v->last = next; \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
return ret; \ return ret; \
} \ } \
\ \
M_P(void, name, _push_front, list_t v, type const x) \ M_P(void, name, push_weak, list_t v, type const x) \
{ \ { \
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ M_IF_EXCEPTION(struct M_F(name, _s) *last = v->last, *first = v->first); \
type *data = M_F(name, _push_front_raw)M_R(v); \ type *data = M_F(name, push_weak_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return; \ return; \
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->last); \
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \ M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \ M_ON_EXCEPTION( v->first = first, v->last = last, (last != NULL ? last : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \
M_CALL_INIT_SET(oplist, *data, x); \ M_CALL_INIT_SET(oplist, *data, x); \
} \ } \
} \ } \
\ \
M_P(void, name, _push_front_move, list_t v, type *x) \ M_P(void, name, push_weak_move, list_t v, type *x) \
{ \ { \
M_ASSERT (x != NULL); \ M_ASSERT (x != NULL); \
type *data = M_F(name, _push_front_raw)M_R(v); \ type *data = M_F(name, push_weak_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return; \ return; \
M_CALL_INIT_MOVE (oplist, *data, *x); \ M_CALL_INIT_MOVE (oplist, *data, *x); \
} \ } \
\ \
M_IF_METHOD(INIT, oplist)( \ M_IF_METHOD(INIT, oplist)( \
M_P(type *, name, _push_front_new, list_t v) \ M_P(type *, name, push_weak_new, list_t v) \
{ \ { \
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ M_IF_EXCEPTION(struct M_F(name, _s) *last = v->last, *first = v->first); \
type *data = M_F(name, _push_front_raw)M_R(v); \ type *data = M_F(name, push_weak_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \ if (M_UNLIKELY (data == NULL)) \
return NULL; \ return NULL; \
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->last); \
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \ M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \ M_ON_EXCEPTION( v->first = first, v->last = last, (last != NULL ? last : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \
M_CALL_INIT(oplist, *data); \ M_CALL_INIT(oplist, *data); \
} \ } \
return data; \ return data; \
@@ -1218,7 +1253,7 @@
M_F(name, _empty_p)(const list_t v) \ M_F(name, _empty_p)(const list_t v) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
return v->back == NULL; \ return v->first == NULL; \
} \ } \
\ \
M_INLINE void \ M_INLINE void \
@@ -1226,8 +1261,8 @@
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(l); \ M_L1ST_DUAL_PUSH_CONTRACT(l); \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_SWAP(struct M_F(name, _s) *, l->front, v->front); \ M_SWAP(struct M_F(name, _s) *, l->last, v->last); \
M_SWAP(struct M_F(name, _s) *, l->back, v->back); \ M_SWAP(struct M_F(name, _s) *, l->first, v->first); \
} \ } \
\ \
M_INLINE void \ M_INLINE void \
@@ -1235,7 +1270,7 @@
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_ASSERT (it != NULL); \ M_ASSERT (it != NULL); \
it->current = v->back; \ it->current = v->first; \
it->previous = NULL; \ it->previous = NULL; \
} \ } \
\ \
@@ -1305,7 +1340,7 @@
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_L1ST_DUAL_PUSH_CONTRACT(v); \
size_t size = 0; \ size_t size = 0; \
struct M_F(name, _s) *it = v->back; \ struct M_F(name, _s) *it = v->first; \
while (it != NULL) { \ while (it != NULL) { \
size ++; \ size ++; \
it = it->next; \ it = it->next; \
@@ -1324,19 +1359,19 @@
M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \ M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \
M_CALL_INIT_SET(oplist, next->data, x); \ M_CALL_INIT_SET(oplist, next->data, x); \
if (M_UNLIKELY (insertion_point->current == NULL)) { \ if (M_UNLIKELY (insertion_point->current == NULL)) { \
next->next = list->back; \ next->next = list->first; \
list->back = next; \ list->first = next; \
/* update front if list is empty */ \ /* update weak entry if list is empty */ \
struct M_F(name, _s) *front = list->front; \ struct M_F(name, _s) *node = list->last; \
front = (front == NULL) ? next : front; \ node = (node == NULL) ? next : node; \
list->front = front; \ list->last = node; \
} else { \ } else { \
next->next = insertion_point->current->next; \ next->next = insertion_point->current->next; \
insertion_point->current->next = next; \ insertion_point->current->next = next; \
/* update front if current == front */ \ /* update weak entry if current == front */ \
struct M_F(name, _s) *front = list->front; \ struct M_F(name, _s) *node = list->last; \
front = (front == insertion_point->current) ? next : front; \ node = (node == insertion_point->current) ? next : node; \
list->front = front; \ list->last = node; \
} \ } \
} \ } \
\ \
@@ -1348,14 +1383,14 @@
struct M_F(name, _s) *next = removing_point->current->next; \ struct M_F(name, _s) *next = removing_point->current->next; \
struct M_F(name, _s) *previous = removing_point->previous; \ struct M_F(name, _s) *previous = removing_point->previous; \
if (M_UNLIKELY (previous == NULL)) { \ if (M_UNLIKELY (previous == NULL)) { \
list->back = next; \ list->first = next; \
} else { \ } else { \
previous->next = next; \ previous->next = next; \
} \ } \
/* Update front */ \ /* Update weak entry */ \
struct M_F(name, _s) *front = list->front; \ struct M_F(name, _s) *node = list->last; \
front = (next == NULL) ? previous : front; \ node = (next == NULL) ? previous : node; \
list->front = front; \ list->last = node; \
/* Remove node */ \ /* Remove node */ \
M_CALL_CLEAR(oplist, removing_point->current->data); \ M_CALL_CLEAR(oplist, removing_point->current->data); \
M_CALL_DEL(oplist, removing_point->current); \ M_CALL_DEL(oplist, removing_point->current); \
@@ -1371,8 +1406,8 @@
struct M_F(name, _s) **update_list; \ struct M_F(name, _s) **update_list; \
if (M_UNLIKELY (list == org)) return; \ if (M_UNLIKELY (list == org)) return; \
M_F(name, _reset)M_R(list); \ M_F(name, _reset)M_R(list); \
update_list = &list->back; \ update_list = &list->first; \
it_org = org->back; \ it_org = org->first; \
M_ASSERT(*update_list == NULL); \ M_ASSERT(*update_list == NULL); \
M_ON_EXCEPTION(M_CALL_DEL(oplist, next) ) \ M_ON_EXCEPTION(M_CALL_DEL(oplist, next) ) \
while (it_org != NULL) { \ while (it_org != NULL) { \
@@ -1386,7 +1421,7 @@
update_list = &next->next; \ update_list = &next->next; \
it_org = it_org->next; \ it_org = it_org->next; \
/* so that even on exception, the object is still coherent */ \ /* so that even on exception, the object is still coherent */ \
list->front = next; \ list->last = next; \
*update_list = NULL; \ *update_list = NULL; \
M_IF_EXCEPTION(next = NULL); \ M_IF_EXCEPTION(next = NULL); \
} \ } \
@@ -1405,10 +1440,10 @@
M_F(name, _init_move)(list_t list, list_t org) \ M_F(name, _init_move)(list_t list, list_t org) \
{ \ { \
M_ASSERT (list != org); \ M_ASSERT (list != org); \
list->back = org->back; \ list->first = org->first; \
list->front = org->front; \ list->last = org->last; \
org->back = NULL; \ org->first = NULL; \
org->front = NULL; \ org->last = NULL; \
} \ } \
\ \
M_P(void, name, _move, list_t list, list_t org) \ M_P(void, name, _move, list_t list, list_t org) \
@@ -1420,6 +1455,7 @@
M_INLINE void \ M_INLINE void \
M_F(name, _splice_back)(list_t list1, list_t list2, it_t it) \ M_F(name, _splice_back)(list_t list1, list_t list2, it_t it) \
{ \ { \
/* FIXME back ==> strong */ \
M_L1ST_DUAL_PUSH_CONTRACT(list1); \ M_L1ST_DUAL_PUSH_CONTRACT(list1); \
M_L1ST_DUAL_PUSH_CONTRACT(list2); \ M_L1ST_DUAL_PUSH_CONTRACT(list2); \
M_ASSERT (it->current != NULL); \ M_ASSERT (it->current != NULL); \
@@ -1427,24 +1463,24 @@
struct M_F(name, _s) *current = it->current; \ struct M_F(name, _s) *current = it->current; \
struct M_F(name, _s) *next = current->next; \ struct M_F(name, _s) *next = current->next; \
if (it->previous == NULL) { \ if (it->previous == NULL) { \
list2->back = next; \ list2->first = next; \
} else { \ } else { \
it->previous->next = next; \ it->previous->next = next; \
} \ } \
/* Update the front of 'list2' if it was the last element */ \ /* Update the front of 'list2' if it was the last element */ \
struct M_F(name, _s) *front = list2->front; \ struct M_F(name, _s) *front = list2->last; \
front = (next == NULL) ? it->previous : front; \ front = (next == NULL) ? it->previous : front; \
list2->front = front; \ list2->last = front; \
/* Update 'it' to point to the next element */ \ /* Update 'it' to point to the next element */ \
it->current = next; \ it->current = next; \
/* Move the extracted 'current' into the list 'nv' */ \ /* Move the extracted 'current' into the list 'nv' */ \
current->next = list1->back; \ current->next = list1->first; \
list1->back = current; \ list1->first = current; \
/* Update the front field if the list 'nv' was empty */ \ /* Update the front field if the list 'nv' was empty */ \
/* This C code shall generate branchless code */ \ /* This C code shall generate branchless code */ \
front = list1->front; \ front = list1->last; \
front = (front == NULL) ? current : front; \ front = (front == NULL) ? current : front; \
list1->front = front; \ list1->last = front; \
M_L1ST_DUAL_PUSH_CONTRACT(list1); \ M_L1ST_DUAL_PUSH_CONTRACT(list1); \
M_L1ST_DUAL_PUSH_CONTRACT(list2); \ M_L1ST_DUAL_PUSH_CONTRACT(list2); \
} \ } \
@@ -1462,33 +1498,33 @@
M_ASSERT(current != NULL); \ M_ASSERT(current != NULL); \
struct M_F(name, _s) *next = current->next; \ struct M_F(name, _s) *next = current->next; \
if (opos->previous == NULL) { \ if (opos->previous == NULL) { \
olist->back = next; \ olist->first = next; \
} else { \ } else { \
opos->previous->next = next; \ opos->previous->next = next; \
} \ } \
/* Update the front of 'olist' if it was the last element */ \ /* Update the front of 'olist' if it was the last element */ \
struct M_F(name, _s) *front = olist->front; \ struct M_F(name, _s) *front = olist->last; \
front = (next == NULL) ? opos->previous : front; \ front = (next == NULL) ? opos->previous : front; \
olist->front = front; \ olist->last = front; \
/* Update 'opos' to point to the next element */ \ /* Update 'opos' to point to the next element */ \
opos->current = next; \ opos->current = next; \
/* opos->previous is still valid & doesn't need to be updated */ \ /* opos->previous is still valid & doesn't need to be updated */ \
/* Insert into 'nlist' */ \ /* Insert into 'nlist' */ \
struct M_F(name, _s) *npos_current = npos->current; \ struct M_F(name, _s) *npos_current = npos->current; \
if (M_UNLIKELY (npos_current == NULL)) { \ if (M_UNLIKELY (npos_current == NULL)) { \
current->next = nlist->back; \ current->next = nlist->first; \
nlist->back = current; \ nlist->first = current; \
/* update 'front' if the list was empty (branchless) */ \ /* update 'front' if the list was empty (branchless) */ \
front = nlist->front; \ front = nlist->last; \
front = (front == NULL) ? current : front; \ front = (front == NULL) ? current : front; \
nlist->front = front; \ nlist->last = front; \
} else { \ } else { \
current->next = npos_current->next; \ current->next = npos_current->next; \
npos_current->next = current; \ npos_current->next = current; \
/* update front if current == front (branchless) */ \ /* update front if current == front (branchless) */ \
front = nlist->front; \ front = nlist->last; \
front = (front == npos_current) ? current : front; \ front = (front == npos_current) ? current : front; \
nlist->front = front; \ nlist->last = front; \
} \ } \
/* Update 'npos' to point to 'current'. */ \ /* Update 'npos' to point to 'current'. */ \
npos->previous = npos_current; \ npos->previous = npos_current; \
@@ -1503,16 +1539,16 @@
M_L1ST_DUAL_PUSH_CONTRACT(list1); \ M_L1ST_DUAL_PUSH_CONTRACT(list1); \
M_L1ST_DUAL_PUSH_CONTRACT(list2); \ M_L1ST_DUAL_PUSH_CONTRACT(list2); \
M_ASSERT (list1 != list2); \ M_ASSERT (list1 != list2); \
if (M_LIKELY (list1->front != NULL)) { \ if (M_LIKELY (list1->last != NULL)) { \
list1->front->next = list2->back; \ list1->last->next = list2->first; \
list1->front = list2->front; \ list1->last = list2->last; \
} else { \ } else { \
/* list1 is empty */ \ /* list1 is empty */ \
list1->back = list2->back; \ list1->first = list2->first; \
list1->front = list2->front; \ list1->last = list2->last; \
} \ } \
list2->back = NULL; \ list2->first = NULL; \
list2->front = NULL; \ list2->last = NULL; \
M_L1ST_DUAL_PUSH_CONTRACT(list1); \ M_L1ST_DUAL_PUSH_CONTRACT(list1); \
M_L1ST_DUAL_PUSH_CONTRACT(list2); \ M_L1ST_DUAL_PUSH_CONTRACT(list2); \
} \ } \
@@ -1521,25 +1557,55 @@
M_F(name, _reverse)(list_t list) \ M_F(name, _reverse)(list_t list) \
{ \ { \
M_L1ST_DUAL_PUSH_CONTRACT(list); \ M_L1ST_DUAL_PUSH_CONTRACT(list); \
list->front = list->back; \ list->last = list->first; \
struct M_F(name, _s) *previous = NULL, *it = list->back, *next; \ struct M_F(name, _s) *previous = NULL, *it = list->first, *next; \
while (it != NULL) { \ while (it != NULL) { \
next = it->next; \ next = it->next; \
it->next = previous; \ it->next = previous; \
previous = it; \ previous = it; \
it = next; \ it = next; \
} \ } \
list->back = previous; \ list->first = previous; \
M_L1ST_DUAL_PUSH_CONTRACT(list); \ M_L1ST_DUAL_PUSH_CONTRACT(list); \
} \ } \
/* Deferred evaluation for the bi-push list definition,
so that all arguments are evaluated before further expansion */
#define M_L1ST_BIF_DEF_P1(arg) M_ID( M_L1ST_BIF_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_L1ST_BIF_DEF_P2(name, type, oplist, list_t, it_t) \
M_IF_OPLIST(oplist)(M_L1ST_BIF_DEF_P3, M_L1ST_BIF_DEF_FAILURE)(name, type, oplist, list_t, it_t)
/* Stop processing with a compilation failure */
#define M_L1ST_BIF_DEF_FAILURE(name, type, oplist, list_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_BIF_DEF): the given argument is not a valid oplist: " #oplist)
/* Internal bi-push list definition (like dual-push but inverts front & back)
- name: prefix to be used
- type: type of the elements of the array
- oplist: oplist of the type of the elements of the container
- list_t: alias for M_F(name, _t) [ type of the container ]
- it_t: alias for M_F(name, _it_t) [ iterator of the container ]
*/
#define M_L1ST_BIF_DEF_P3(name, type, oplist, list_t, it_t) \
M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t, _front, _push_front_raw, _push_front, _push_front_move, _push_front_new, _pop_front, _back, _push_back_raw, _push_back, _push_back_move, _push_back_new) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_front, oplist, M_L1ST_EMPLACE_STRONG_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_WEAK_DEF) \
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
#if M_USE_SMALL_NAME #if M_USE_SMALL_NAME
#define LIST_DEF M_LIST_DEF #define LIST_DEF M_LIST_DEF
#define LIST_DEF_AS M_LIST_DEF_AS #define LIST_DEF_AS M_LIST_DEF_AS
#define LIST_DUAL_PUSH_DEF M_LIST_DUAL_PUSH_DEF #define LIST_DUAL_PUSH_DEF M_LIST_DUAL_PUSH_DEF
#define LIST_DUAL_PUSH_DEF_AS M_LIST_DUAL_PUSH_DEF_AS #define LIST_DUAL_PUSH_DEF_AS M_LIST_DUAL_PUSH_DEF_AS
#define LIST_BIF_DEF M_LIST_BIF_DEF
#define LIST_BIF_DEF_AS M_LIST_BIF_DEF_AS
#define LIST_OPLIST M_LIST_OPLIST #define LIST_OPLIST M_LIST_OPLIST
#define LIST_BIF_OPLIST M_LIST_BIF_OPLIST
#define LIST_INIT_VALUE M_LIST_INIT_VALUE #define LIST_INIT_VALUE M_LIST_INIT_VALUE
#define LIST_DUAL_PUSH_INIT_VALUE M_LIST_DUAL_PUSH_INIT_VALUE #define LIST_DUAL_PUSH_INIT_VALUE M_LIST_DUAL_PUSH_INIT_VALUE
#endif #endif
+1 -1
View File
@@ -382,7 +382,7 @@ M_P(char *, m_str1ng, _fit2size, m_string_t v, size_t size_alloc)
alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc); alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc);
if (M_UNLIKELY_NOMEM (alloc <= size_alloc)) { if (M_UNLIKELY_NOMEM (alloc <= size_alloc)) {
/* Overflow in alloc computation */ /* Overflow in alloc computation */
M_MEMORY_FULL(char, alloc); M_MEMORY_FULL(char, size_alloc);
} }
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
//FIXME: old_alloc may not be NULL if ptr is NULL. //FIXME: old_alloc may not be NULL if ptr is NULL.
+28
View File
@@ -669,6 +669,34 @@ typedef int32_t m_tr33_index_t;
return ret; \ return ret; \
} \ } \
\ \
M_INLINE it_t \
M_F(name, _up)(it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
it_t i = { it.tree, it.tree->tab[it.index].parent }; \
return i; \
} \
\
M_INLINE it_t \
M_F(name, _down)(it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
it_t i = { it.tree, it.tree->tab[it.index].child }; \
return i; \
} \
\
M_INLINE it_t \
M_F(name, _left)(it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
it_t i = { it.tree, it.tree->tab[it.index].left }; \
return i; \
} \
\
M_INLINE it_t \
M_F(name, _right)(it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
it_t i = { it.tree, it.tree->tab[it.index].right }; \
return i; \
} \
\
M_INLINE bool \ M_INLINE bool \
M_F(name, _root_p)(const it_t it) { \ M_F(name, _root_p)(const it_t it) { \
M_TR33_IT_CONTRACT(it, true); \ M_TR33_IT_CONTRACT(it, true); \
+2 -2
View File
@@ -176,6 +176,8 @@
M_F(name, _MAX_TYPE) = M_NARGS(__VA_ARGS__) \ M_F(name, _MAX_TYPE) = M_NARGS(__VA_ARGS__) \
}; \ }; \
/* Define the variant */ \ /* Define the variant */ \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
typedef struct M_F(name, _s) { \ typedef struct M_F(name, _s) { \
enum M_F(name, _enum) type; \ enum M_F(name, _enum) type; \
union { \ union { \
@@ -183,8 +185,6 @@
} value; \ } value; \
} name_t[1]; \ } name_t[1]; \
\ \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
/* Define internal type for oplist */ \ /* Define internal type for oplist */ \
typedef name_t M_F(name, _ct); \ typedef name_t M_F(name, _ct); \
/* Save alias for the types of arguments */ \ /* Save alias for the types of arguments */ \
+39 -5
View File
@@ -82,11 +82,21 @@ static void g_f(int n)
g_count++; 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); assert (g_min <= n && n <= g_max);
g_count++; g_count++;
*d = n * n; *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) static void func_reduce(int *d, int n)
@@ -156,13 +166,17 @@ static void test_list(void)
g_min = 0; g_min = 0;
g_max = 99; g_max = 99;
g_count = 0; g_count = 0;
algo_list_transform(tmp, l, func_map); algo_list_transform(tmp, l, func_map, NULL);
assert(g_count == 101); assert(g_count == 101);
assert(list_int_size(tmp) == 101); assert(list_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) { for(int i = 0; i < 100; i++) {
assert(*list_int_get(tmp, (size_t) i) == i * i); assert(*list_int_get(tmp, (size_t) i) == i * i);
} }
assert(*list_int_get(tmp, 100) == 17 * 17); 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); int *p = algo_list_min(l);
@@ -305,19 +319,35 @@ static void test_array(void)
assert(g_count == 101); assert(g_count == 101);
int n; 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); assert(n == 100*99/2+17);
g_min = 0; g_min = 0;
g_max = 99; g_max = 99;
g_count = 0; 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(g_count == 101);
assert(n == (328350 + 17*17)); 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) { M_LET(tmp, array_int_t) {
g_count = 0; g_count = 0;
algo_array_transform(tmp, l, func_map); algo_array_transform(tmp, l, func_map, NULL);
assert(g_count == 101); assert(g_count == 101);
assert(array_int_size(tmp) == 101); assert(array_int_size(tmp) == 101);
for(int i = 0; i < 100; i++) { 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(l, 100) == 17);
assert(*array_int_get(tmp, 100) == 17 * 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); array_int_reset(tmp);
#define FT(d,x) ((d) = (x) + 1) #define FT(d,x) ((d) = (x) + 1)
+23
View File
@@ -893,6 +893,28 @@ static void test_coverage(void)
} }
/* Reported by florommel */
static void test_reserve_bug(void)
{
dict_int_t dict;
dict_int_init(dict);
/* NOTE: Remove the following line to make it not fail: */
dict_int_reserve(dict, 32);
int k = 0;
for (int n = 0; n < 100; n++) {
for (int i = 0; i < 3; i++) {
dict_int_set_at(dict, ++k, 42);
}
for (int i = 0; i < 3; i++) {
dict_int_erase(dict, k--);
}
k += 100; /* ensure fresh keys in the next iteration */
}
dict_int_clear(dict);
}
int main(void) int main(void)
{ {
test1(); test1();
@@ -905,6 +927,7 @@ int main(void)
test_it_oa(); test_it_oa();
test_oa_str1(); test_oa_str1();
test_oa_str2(); test_oa_str2();
test_reserve_bug();
testobj_final_check(); testobj_final_check();
test_coverage(); test_coverage();
exit(0); exit(0);
+42
View File
@@ -47,6 +47,8 @@ LIST_DEF_AS(list_double, ListDouble, ListDoubleIt, double)
LIST_DUAL_PUSH_DEF_AS(list_doubleDP, ListDoubleDP, ListDoubleDPIt, double) LIST_DUAL_PUSH_DEF_AS(list_doubleDP, ListDoubleDP, ListDoubleDPIt, double)
#define M_OPL_ListDoubleDP() LIST_OPLIST(list_doubleDP, M_BASIC_OPLIST) #define M_OPL_ListDoubleDP() LIST_OPLIST(list_doubleDP, M_BASIC_OPLIST)
LIST_BIF_DEF(list2f_double, double)
ListDouble g_array1 = LIST_INIT_VALUE(); ListDouble g_array1 = LIST_INIT_VALUE();
ListDoubleDP g_array2 = LIST_DUAL_PUSH_INIT_VALUE(); ListDoubleDP g_array2 = LIST_DUAL_PUSH_INIT_VALUE();
@@ -574,6 +576,45 @@ static void test_dual_push1(void)
list2_double_clear(list); list2_double_clear(list);
} }
static void test_bif(void)
{
list2f_double_t x;
list2f_double_init(x);
assert(list2f_double_empty_p(x));
list2f_double_push_front(x, 2.0);
list2f_double_push_front(x, 1.0);
list2f_double_push_back(x, 3.0);
assert(list2f_double_size(x) == 3);
assert(*list2f_double_front(x) == 1.0);
assert(*list2f_double_back(x) == 3.0);
list2f_double_it_t it;
double d = 1.0;
for(list2f_double_it(it, x); !list2f_double_end_p(it); list2f_double_next(it)){
assert(d == *list2f_double_cref(it));
d += 1.0;
}
list2f_double_pop_front(&d, x);
assert(d == 1.0);
list2f_double_reverse(x);
list2f_double_pop_front(&d, x);
assert(d == 3.0);
list2f_double_pop_front(&d, x);
assert(d == 2.0);
assert(list2f_double_empty_p(x));
list2f_double_clear(x);
M_LET( (y, (1.0, 2.0, 3.0, 4.0)), LIST_BIF_OPLIST(list2f_double, M_BASIC_OPLIST)) {
assert(list2f_double_size(y) == 4);
assert(*list2f_double_front(y) == 1.0);
assert(*list2f_double_back(y) == 4.0);
d = 1.0;
for(list2f_double_it(it, y); !list2f_double_end_p(it); list2f_double_next(it)){
assert( *list2f_double_cref(it) == d);
d += 1.0;
}
}
}
static void test_dual_it1(void) static void test_dual_it1(void)
{ {
list2_double_t list; list2_double_t list;
@@ -899,6 +940,7 @@ int main(void)
test_mpz(); test_mpz();
test_dual_push1(); test_dual_push1();
test_dual_it1(); test_dual_it1();
test_bif();
test_out_default_oplist(); test_out_default_oplist();
test_double(); test_double();
test_let_string(); test_let_string();
+11
View File
@@ -113,6 +113,17 @@ static void test_basic(void)
tree_get_str(s, t, false); tree_get_str(s, t, false);
assert(string_equal_str_p(s, "[{-1,[{0,[{1,[{3},{5,[{2}]},{4,[{9},{7,[{8}]},{10},{6}]}]}]}]}]")); assert(string_equal_str_p(s, "[{-1,[{0,[{1,[{3},{5,[{2}]},{4,[{9},{7,[{8}]},{10},{6}]}]}]}]}]"));
assert( *tree_cref(it7) == 7 );
assert( *tree_cref(tree_down(it7)) == 8 );
assert( *tree_cref(tree_up(it7)) == 4);
assert( *tree_cref(tree_left(it7)) == 9);
assert( *tree_cref(tree_right(it7)) == 10);
assert( *tree_cref(tree_down(root)) == 0);
assert( tree_end_p(tree_up(root)));
assert( tree_end_p(tree_left(root)));
assert( tree_end_p(tree_right(root)));
assert( *tree_down_ref(it7) == 8); assert( *tree_down_ref(it7) == 8);
assert( *tree_up_ref(it7) == 4); assert( *tree_up_ref(it7) == 4);
assert( *tree_left_ref(it7) == 9); assert( *tree_left_ref(it7) == 9);