Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46759b5f2c | ||
|
|
8c8a1e2822 | ||
|
|
ad646f5e04 | ||
|
|
9ecc031fd7 | ||
|
|
ea3c2c5019 | ||
|
|
a9dc2eef12 | ||
|
|
39a0a4f672 | ||
|
|
4ffa4a15ac | ||
|
|
2d5c9e71ae | ||
|
|
e802e22b7b | ||
|
|
3fbe8ec0b6 | ||
|
|
34085aa637 | ||
|
|
77033e2020 | ||
|
|
5c57ad1f51 | ||
|
|
27621db95d | ||
|
|
eab3f701a8 |
No files matched your search
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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); \
|
||||||
|
type_t tmp; \
|
||||||
|
M_CALL_INIT(type_oplist, tmp); \
|
||||||
for M_EACH(item, src, cont_oplist) { \
|
for M_EACH(item, src, cont_oplist) { \
|
||||||
type_t tmp; \
|
if (func(&tmp, *item, data)) { \
|
||||||
M_CALL_INIT(type_oplist, tmp); \
|
M_CALL_PUSH(cont_oplist, dst, tmp); \
|
||||||
func(&tmp, *item); \
|
} \
|
||||||
M_CALL_PUSH_MOVE(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; \
|
||||||
} \
|
} \
|
||||||
, ) \
|
, ) \
|
||||||
|
|
||||||
|
|||||||
@@ -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 --); \
|
||||||
|
|||||||
@@ -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)) \
|
||||||
|
|||||||
@@ -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); \
|
||||||
|
|||||||
@@ -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); \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -293,7 +293,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 +309,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 ); \
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
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 ); \
|
||||||
@@ -350,7 +350,7 @@
|
|||||||
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 +892,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 ); \
|
||||||
@@ -1066,12 +1066,6 @@
|
|||||||
return ret; \
|
return ret; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Internal, for INIT_WITH */ \
|
|
||||||
M_P(type *, name, _push_raw, list_t d) \
|
|
||||||
{ \
|
|
||||||
return M_F(name, _push_back_raw)M_R(d); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
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_back_raw)M_R(v); \
|
type *data = M_F(name, _push_back_raw)M_R(v); \
|
||||||
|
|||||||
+1
-1
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in new issue
Block a user