Merge pull request #134 from P-p-H-d/feature/new-memory-model

New memory model
This commit is contained in:
PpHd authored and GitHub committed 2025-05-08 22:14:17 +02:00
commit 02a39fce3f
77 files changed
+3839 -6840

No files matched your search

+2 -2
View File
@@ -34,10 +34,10 @@ DESTDIR=
# Package name & version.
PACKAGE=m_lib-$(VERSION)
VERSION=0.7.4
VERSION=0.8.0
# 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-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.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
HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.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
DOC1=LICENSE README.md
DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh
EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c example/ex-bptree02.c example/ex-i-list.c example/ex11-generic02.c example/ex11-small-name.c example/ex11-variant01.c
+754 -771
View File
File diff suppressed because it is too large. Load diff
+23 -1
View File
@@ -85,4 +85,26 @@ V0.7.2: * Rename m-mutex.h header in m-thread.h
V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated.
Use DICT_DEF2 / DICT_DEF2_AS
V0.8.0 : * Memory interface massive compatibility break to allow more efficient integration of custom allocators.
The prototypes of NEW / DEL REALLOC / FREE operators are incompatible:
* Add the old number of elements of the array as argument of REALLOC
* Add the number of elements of the array and its base type as arguments of FREE.
* Add the context argument (which shall be ignored in not specific build)
(You can ignore the new arguments which are only hints provided to memory functions).
Also impact M_MEMORY_NEW / M_MEMORY_DEL / M_MEMORY_REALLOC & M_MEMORY_FREE
M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated.
* m-buffer:
* non-thread safe queue & stack are moved into their dedicated header (m-queue)
* BUFFER_THREAD_UNSAFE policy is no longer supported.
* Disabling BUFFER_BLOCKING policy is no longer supported (default policy is now forced).
* _push / _pop now returns now void like other containers instead of a bool (it was undocumented)
* Remove MEMPOOL support from list & R/B tree
* m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove). Use new M_USE_CONTEXT interface to pass local pool context.
* M*LIB becomes stricter for the INIT_MOVE operator:
The Emulation layer using CLEAR+INIT_SET methods, when there is no INIT_MOVE operator, has been removed:
either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled.
If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method.
(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
+3 -3
View File
@@ -1,7 +1,7 @@
*Long term issues*
==========================================================
* TODO #34 : Pass old size arguments to memory allocator :ENHANCEMENT:
* DONE #34 : Pass old size arguments to memory allocator :ENHANCEMENT:
** State
@@ -53,7 +53,7 @@ function due to the copy of the object one per one. Each copied sub object
may throw an exception, so we always need to have the container in a correct
state so that it can be cleanup.
* TODO #32 : User specialization fields in the container :ENHANCEMENT:
* DONE #32 : User specialization fields in the container :ENHANCEMENT:
** State
Some methods of a contained object may need to have some options that
@@ -452,7 +452,7 @@ as DPRIORITY_QUEUE_DEF ?
NOTE: Needs for such container?
On hold until a user needs it.
* TODO #23 : Strict MOVE semantic to clarify :ENHANCEMENT:
* DONE #23 : Strict MOVE semantic to clarify :ENHANCEMENT:
** State
+4 -4
View File
@@ -43,12 +43,12 @@ static void my_array_free(void *ptr)
////////////////////////////////////////////////////////////
// Allocate for single object
# define M_MEMORY_ALLOC(type) my_alloc (sizeof (type))
# define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
# define M_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type))
# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr)
// Allocate for array of objects
# define M_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
# define M_MEMORY_FREE(ptr) my_array_free(ptr)
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
# define M_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr)
#include "m-list.h"
#include "m-array.h"
+4 -4
View File
@@ -23,8 +23,8 @@ static void my_free(void *ptr, size_t s)
}
// Allocate for single object
# define MY_MEMORY_ALLOC(type) my_alloc (sizeof (type))
# define MY_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr)
# define MY_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type))
# define MY_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr)
////////////////////////////////////////////////////////////
@@ -76,8 +76,8 @@ static void my_array_free(void *ptr)
}
// Allocate for array of objects
# define MY_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n)
# define MY_MEMORY_FREE(ptr) my_array_free(ptr)
# define MY_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n)
# define MY_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr)
////////////////////////////////////////////////////////////
+3 -1
View File
@@ -35,6 +35,7 @@ mpz_fast_hash(const mpz_t z)
#define M_OPL_mpz_t() \
(INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
INIT_MOVE(M_COPY_A1_DEFAULT) \
EQUAL( API( mpz_cmp, EQ(0), ARG1, ARG2)), \
CMP(mpz_cmp), \
HASH(mpz_fast_hash), \
@@ -77,7 +78,8 @@ mpfr_fast_hash (const mpfr_t f)
/* Define the OPLIST of a mpfr_t and register it globally */
#define M_OPL_mpfr_t() \
(INIT(mpfr_init), INIT_SET(API(mpfr_init_set, VOID, ARG1, ARG2, MPFR_RNDN)), SET(API(mpfr_set, VOID, ARG1, ARG2, MPFR_RNDN)), CLEAR(mpfr_clear), \
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \
INIT_MOVE(M_COPY_A1_DEFAULT) \
EQUAL( API( mpfr_cmp, EQ(0), ARG1, ARG2)), \
CMP(mpfr_cmp), \
HASH(mpfr_fast_hash), \
+1 -6
View File
@@ -8,22 +8,17 @@
#include "m-bptree.h"
#include "m-bstring.h"
#include "m-buffer.h"
#include "m-c-mempool.h"
#include "m-concurrent.h"
#include "m-deque.h"
#include "m-dict.h"
#include "m-funcobj.h"
#include "m-generic.h"
#include "m-genint.h"
#include "m-i-list.h"
#include "m-i-shared.h"
#include "m-list.h"
#include "m-mempool.h"
#include "m-prioqueue.h"
#include "m-rbtree.h"
#include "m-serial-bin.h"
#include "m-serial-json.h"
//#include "m-shared.h" // API incompatible with m-shared-ptr.h (exclusive)
#include "m-shared-ptr.h"
#include "m-snapshot.h"
#include "m-string.h"
@@ -70,4 +65,4 @@ M_WORKER_SPAWN_DEF2(worker, (filename, m_string_t) )
int main(void)
{
exit(0);
}
}
+188
View File
@@ -0,0 +1,188 @@
#include <stdlib.h>
// Define the memory context.
typedef int *context_t;
// Define the realloc / free that accepts the memory context.
static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context)
{
(void) context;
(void) old;
return realloc(ptr, new*base);
}
static void my_free(void *ptr, size_t old, size_t base, context_t context)
{
(void) context;
(void) old;
(void) base;
free(ptr);
}
// Request M*LIB to generate functions accepting a memory context parameter that will be passed to the memory functions
# define M_USE_CONTEXT context_t
// Overloaded memory functions to use the custom ones.
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), ctx)
# define M_MEMORY_FREE(ctx, type, ptr, o) my_free(ptr, o, sizeof (*ptr), ctx)
# define M_MEMORY_ALLOC(ctx, type) my_realloc(NULL, 0, 1, sizeof (type), ctx)
# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, 1, sizeof (*ptr), ctx)
// Now we can include M*LIB functions.
#include "m-string.h"
#include "m-bitset.h"
#include "m-bstring.h"
#include "m-genint.h"
#include "m-algo.h"
context_t my_pool = NULL;
extern int f(string_t, bitset_t b, bstring_t y);
int f(string_t x, bitset_t b, bstring_t y)
{
string_init(x);
string_set_str(my_pool, x, "Hello world");
string_clear(my_pool, x);
bitset_init(b);
bitset_push_back(my_pool, b, true);
bitset_clear(my_pool, b);
bstring_init(y);
bstring_push_back(my_pool, y, 0);
bstring_clear(my_pool, y);
return 0;
}
#include "m-array.h"
ARRAY_DEF(array, int)
ALGO_DEF(array, ARRAY_OPLIST(array, M_BASIC_OPLIST))
ARRAY_DEF(array_str, string_t)
ALGO_DEF(array_str, ARRAY_OPLIST(array_str, STRING_OPLIST))
#include "m-prioqueue.h"
PRIOQUEUE_DEF(prio, int)
PRIOQUEUE_DEF(prio_str, string_t)
ALGO_DEF(prio_str, PRIOQUEUE_OPLIST(prio_str, STRING_OPLIST))
#include "m-rbtree.h"
RBTREE_DEF(rbtree, int)
RBTREE_DEF(rbtree_str, string_t)
ALGO_DEF(rbtree_str, RBTREE_OPLIST(rbtree_str, STRING_OPLIST))
#include "m-list.h"
LIST_DEF(list, int)
ALGO_DEF(list, LIST_OPLIST(list, M_BASIC_OPLIST))
LIST_DEF(list_str, string_t)
ALGO_DEF(list_str, LIST_OPLIST(list_str, M_STRING_OPLIST))
LIST_DUAL_PUSH_DEF(list2, int)
LIST_DUAL_PUSH_DEF(list2_str, string_t)
ALGO_DEF(list2_str, LIST_OPLIST(list2_str, M_STRING_OPLIST))
#include "m-bptree.h"
BPTREE_DEF2(bptree, 5, int, int)
BPTREE_DEF2(bptree_str, 8, string_t, string_t)
ALGO_DEF(bptree_str, M_BPTREE_OPLIST2(bptree_str, M_STRING_OPLIST, M_STRING_OPLIST))
#include "m-dict.h"
DICT_DEF2(dict, int, int)
DICT_DEF2(dict_str, string_t, string_t)
ALGO_DEF(dict_str, DICT_OPLIST(dict_str, M_STRING_OPLIST, M_STRING_OPLIST))
DICT_SET_DEF(set, int)
DICT_SET_DEF(set_str, string_t)
ALGO_DEF(set_str, DICT_SET_OPLIST(set_str, M_STRING_OPLIST))
static inline bool oor_equal_p(int k, char n)
{
return k == INT_MIN + n;
}
static inline int oor_set(char n)
{
return INT_MIN + n;
}
DICT_OA_DEF2(dict_oa,
int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))),
int, M_BASIC_OPLIST)
DICT_OA_DEF2(dict2_str, string_t, string_t)
ALGO_DEF(dict2_str, DICT_OPLIST(dict2_str, M_STRING_OPLIST, M_STRING_OPLIST))
DICT_OASET_DEF(set_oa,
int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))) )
DICT_OASET_DEF(set2_str, string_t)
ALGO_DEF(set2_str, DICT_SET_OPLIST(set2_str, M_STRING_OPLIST))
#include "m-buffer.h"
BUFFER_DEF(buffer1, int, 10, M_BUFFER_QUEUE)
BUFFER_DEF(buffer2, int, 0, M_BUFFER_STACK)
M_QUEUE_MPMC_DEF(queue1, int, M_BUFFER_STACK)
M_QUEUE_SPSC_DEF(queue2, int, M_BUFFER_STACK)
BUFFER_DEF(buffer11, string_t, 10, M_BUFFER_QUEUE)
BUFFER_DEF(buffer22, string_t, 0, M_BUFFER_STACK)
M_QUEUE_MPMC_DEF(queue11, string_t, M_BUFFER_STACK)
M_QUEUE_SPSC_DEF(queue22, string_t, M_BUFFER_STACK)
#include "m-deque.h"
M_DEQUE_DEF(deque, int)
M_DEQUE_DEF(deque_str, string_t)
M_ALGO_DEF(deque_str, M_DEQUE_OPLIST(deque_str, M_STRING_OPLIST))
#include "m-snapshot.h"
M_SNAPSHOT_SPSC_DEF(snap1, int)
M_SNAPSHOT_SPMC_DEF(snap2, int)
M_SNAPSHOT_MPMC_DEF(snap3, string_t)
#include "m-tree.h"
M_TREE_DEF(tree, int)
M_TREE_DEF(tree_str, string_t)
#include "m-tuple.h"
M_TUPLE_DEF2(tuple1, (num, int) )
M_TUPLE_DEF2(tuple2, (num, int), (name, string_t) )
#include "m-variant.h"
M_VARIANT_DEF2(variant1, (num, int) )
M_VARIANT_DEF2(variant2, (num, int), (name, string_t) )
#include "m-worker.h"
M_WORKER_SPAWN_DEF2(worker_int, (in, int) )
M_WORKER_SPAWN_DEF2(worker_str, (str, string_t) )
#include "m-shared-ptr.h"
M_SHARED_PTR_DEF(shared_int, int)
M_SHARED_PTR_DEF(shared_str, string_t)
#include "m-queue.h"
M_QUEUE_DEF(queue_10, int, 10 )
M_STACK_DEF(stack_20, string_t, 20)
#include "m-serial-json.h"
#include "m-serial-bin.h"
int main(void)
{
return 0;
}
+24 -27
View File
@@ -171,7 +171,7 @@
typedef bool (*M_F(name, _eq_cb_ct))(type_t const, type_t const); \
typedef int (*M_F(name, _cmp_cb_ct))(type_t const, type_t const); \
typedef void (*M_F(name, _transform_cb_ct))(type_t *, type_t const); \
typedef void (*M_F(name, _apply_cb_ct))(type_t); \
typedef void (*M_F(name, _apply_cb_ct))(type_t M_IF_METHOD(IT_REF, cont_oplist)( , const) );
/* Define the function objects associated to the algorithms.
@@ -276,14 +276,14 @@
M_CALL_SPLICE_BACK(cont_oplist, (b ? l1 : l2), l, it); \
b = !b; \
} \
/* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \
M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); \
} \
\
/* Merge in empty 'l' the sorted container 'l1' and 'l2' */ \
M_INLINE void \
M_C3(name,sort_name,_merge)(container_t l, container_t l1, container_t l2 cmp_param(name)) \
{ \
/* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \
M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); \
it_t it; \
it_t it1; \
it_t it2; \
@@ -350,6 +350,7 @@
return; \
} \
/* Container length is greater than 2: split, sort & merge */ \
M_GLOBAL_CONTEXT(); \
M_CALL_INIT(cont_oplist, l1); \
M_CALL_INIT(cont_oplist, l2); \
M_C3(name,sort_name,_split)(l1, l2, l); \
@@ -357,6 +358,9 @@
M_F(name,sort_name)(l2 cmp_arg); \
M_C3(name,sort_name,_merge)(l, l1, l2 cmp_arg); \
/* l1 & l2 shall be empty now */ \
M_ASSERT( M_CALL_EMPTY_P(cont_oplist, l1)); \
M_ASSERT( M_CALL_EMPTY_P(cont_oplist, l2)); \
/* Normally nothing is done here */ \
M_CALL_CLEAR(cont_oplist, l2); \
M_CALL_CLEAR(cont_oplist, l1); \
} \
@@ -434,7 +438,7 @@
/* Compute the union of two ***sorted*** containers */ \
M_IF_METHOD(IT_INSERT, cont_oplist)( \
M_INLINE void \
M_C3(name,sort_name,_union)(container_t dst, const container_t src cmp_param(name)) \
M_C3(name,sort_name,_union)(M_P_EXPAND container_t dst, const container_t src cmp_param(name)) \
{ \
it_t itSrc; \
it_t itDst; \
@@ -479,7 +483,7 @@
/* Compute the intersection of two ***sorted*** containers */ \
M_IF_METHOD(IT_REMOVE, cont_oplist)( \
M_INLINE void \
M_C3(name,sort_name,_intersect)(container_t dst, const container_t src cmp_param(name)) \
M_C3(name,sort_name,_intersect)(M_P_EXPAND container_t dst, const container_t src cmp_param(name)) \
{ \
it_t itSrc; \
it_t itDst; \
@@ -688,9 +692,9 @@
#define M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
/* Fill all the container with value (overwritten) */ \
M_INLINE void \
M_F(name, _fill) (container_t l, type_t const value) \
M_P(void, name, _fill, container_t l, type_t const value) \
{ \
M_UNUSED_CONTEXT(); \
for M_EACH(item, l, cont_oplist) { \
M_CALL_SET(type_oplist, *item, value); \
} \
@@ -698,8 +702,7 @@
\
/* Fill the container with exactly 'n' occurrence of 'value' */ \
M_IF_METHOD(PUSH, cont_oplist)( \
M_INLINE void \
M_F(name, _fill_n) (container_t l, size_t n, type_t const value) \
M_P(void, name, _fill_n, container_t l, size_t n, type_t const value) \
{ \
M_CALL_RESET(cont_oplist, l); \
for(size_t i = 0; i < n; i++) { \
@@ -710,9 +713,9 @@
\
/* Fill the container with FOR('value'; 'value'+'inc') */ \
M_IF_METHOD(ADD, type_oplist)( \
M_INLINE void \
M_F(name, _fill_a) (container_t l, type_t const value, type_t const inc) \
M_P(void, name, _fill_a, container_t l, type_t const value, type_t const inc) \
{ \
M_UNUSED_CONTEXT(); \
type_t tmp; \
M_CALL_INIT_SET(type_oplist, tmp, value); \
for M_EACH(item, l, cont_oplist) { \
@@ -724,9 +727,9 @@
\
/* Fill the container with n occurences of FOR('value'; 'value'+'inc') */ \
M_IF_METHOD(PUSH, cont_oplist)( \
M_INLINE void \
M_F(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \
M_P(void, name, _fill_an, container_t l, size_t n, type_t const value, type_t const inc) \
{ \
M_UNUSED_CONTEXT(); \
type_t tmp; \
M_CALL_INIT_SET(type_oplist, tmp, value); \
M_CALL_RESET(cont_oplist, l); \
@@ -756,10 +759,7 @@
M_IF_METHOD(PUSH_MOVE, cont_oplist)( \
\
/* Apply func for all elements of the container src and push the result in dst */ \
M_INLINE void \
M_F(name, _transform) (container_t dst, \
container_t src, \
M_F(name, _transform_cb_ct) func) \
M_P(void, name, _transform, container_t dst, container_t src, M_F(name, _transform_cb_ct) func) \
{ \
M_ASSERT(dst != src); \
M_CALL_RESET(cont_oplist, dst); \
@@ -775,10 +775,10 @@
\
/* Reduce all elements of the container in dst in function of func */ \
M_IF_METHOD(SET, type_oplist)( \
M_INLINE void \
M_F(name, _reduce) (type_t *dest, container_t const l, \
M_P(void, name, _reduce, type_t *dest, container_t const l, \
M_F(name, _transform_cb_ct) func) \
{ \
M_UNUSED_CONTEXT(); \
bool initDone = false; \
for M_EACH(item, l, cont_oplist) { \
if (initDone) { \
@@ -793,12 +793,12 @@
\
/* Reduce all transformed elements of the container in dst in function of func */ \
M_IF_METHOD(INIT, type_oplist)( \
M_INLINE \
void M_F(name, _map_reduce) (type_t *dest, \
M_P(void, name, _map_reduce, type_t *dest, \
const container_t l, \
M_F(name, _transform_cb_ct) redFunc, \
M_F(name, _transform_cb_ct) mapFunc) \
{ \
M_UNUSED_CONTEXT(); \
bool initDone = false; \
type_t tmp; \
M_CALL_INIT(type_oplist, tmp); \
@@ -905,8 +905,7 @@
/* Define functions based on remove method */
#define M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \
\
M_INLINE void \
M_F(name, _uniq)(container_t l) \
M_P(void, name, _uniq, container_t l) \
{ \
it_t it1; \
it_t it2; \
@@ -927,8 +926,7 @@
} \
} \
\
M_INLINE void \
M_F(name, _remove_val)(container_t l, type_t const val) \
M_P(void, name, _remove_val, container_t l, type_t const val) \
{ \
it_t it1; \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
@@ -942,8 +940,7 @@
} \
} \
\
M_INLINE void \
M_F(name, _remove_if)(container_t l, M_F(name, _test_cb_ct) func) \
M_P(void, name, _remove_if, container_t l, M_F(name, _test_cb_ct) func) \
{ \
it_t it1; \
M_CALL_IT_FIRST(cont_oplist, it1, l); \
+162 -158
View File
@@ -80,6 +80,7 @@
/* OPLIST definition of a dynamic array */
/* FIXME: Do we want to export some methods as they are slow and
are not fit to be used for building other methods (like _it_remove)? */
#ifndef M_USE_CONTEXT
#define M_ARRA4_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)) \
,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_F(name, _init_set)),) \
@@ -106,7 +107,7 @@
,IT_REF(M_F(name,_ref)) \
,IT_CREF(M_F(name,_cref)) \
,M_IF_METHOD(INIT_SET, oplist)(IT_INSERT(M_F(name,_insert)) ,) \
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(IT_REMOVE(M_F(name,_remove)),) \
,IT_REMOVE(M_F(name,_remove)) \
,RESET(M_F(name,_reset)) \
,KEY_TYPE(size_t) \
,VALUE_TYPE(M_F(name, _subtype_ct)) \
@@ -115,12 +116,12 @@
,M_IF_METHOD(SET, oplist)(SET_KEY(M_F(name, _set_at)) ,) \
,GET_KEY(M_F(name, _get)) \
,M_IF_METHOD(INIT, oplist)(SAFE_GET_KEY(M_F(name, _safe_get)) ,) \
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(ERASE_KEY(M_F(name, _erase)),) \
,ERASE_KEY(M_F(name, _erase)) \
,GET_SIZE(M_F(name, _size)) \
,M_IF_METHOD(INIT_SET, oplist)(PUSH(M_F(name,_push_back)) ,) \
,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(POP(M_F(name,_pop_back)) ,) \
,M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist)(PUSH_MOVE(M_F(name,_push_move)) ,) \
,M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist)(POP_MOVE(M_F(name,_pop_move)) ,) \
,POP(M_F(name,_pop_back)) \
,PUSH_MOVE(M_F(name,_push_move)) \
,POP_MOVE(M_F(name,_pop_move)) \
,OPLIST(oplist) \
,M_IF_METHOD(CMP, oplist)(SORT(M_F(name, _special_sort)),) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \
@@ -132,11 +133,65 @@
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#else
#define M_ARRA4_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)) \
,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(API_0P(M_F(name, _init_set))),) \
,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_WITH_VAI)),) \
,M_IF_METHOD2(INIT_SET,SET, oplist)(SET(API_0P(M_F(name, _set))), ) \
,CLEAR(API_0P(M_F(name, _clear))) \
,INIT_MOVE(M_F(name, _init_move)) \
,MOVE(API_0P(M_F(name, _move))) \
,SWAP(M_F(name, _swap)) \
,TYPE(M_F(name,_ct)) , GENTYPE(struct M_F(name,_s)*) \
,NAME(name) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,EMPTY_P(M_F(name,_empty_p)) \
,IT_TYPE(M_F(name,_it_ct)), \
,IT_FIRST(M_F(name,_it)) \
,IT_LAST(M_F(name,_it_last)) \
,IT_END(M_F(name,_it_end)) \
,IT_SET(M_F(name,_it_set)) \
,IT_END_P(M_F(name,_end_p)) \
,IT_LAST_P(M_F(name,_last_p)) \
,IT_EQUAL_P(M_F(name,_it_equal_p)) \
,IT_NEXT(M_F(name,_next)) \
,IT_PREVIOUS(M_F(name,_previous)) \
,IT_REF(M_F(name,_ref)) \
,IT_CREF(M_F(name,_cref)) \
,M_IF_METHOD(INIT_SET, oplist)(IT_INSERT(API_0P(M_F(name,_insert))) ,) \
,IT_REMOVE(API_0P(M_F(name,_remove))) \
,RESET(API_0P(M_F(name,_reset))) \
,KEY_TYPE(size_t) \
,VALUE_TYPE(M_F(name, _subtype_ct)) \
,KEY_OPLIST(M_BASIC_OPLIST) \
,VALUE_OPLIST(oplist) \
,M_IF_METHOD(SET, oplist)(SET_KEY(API_0P(M_F(name, _set_at))) ,) \
,GET_KEY(M_F(name, _get)) \
,M_IF_METHOD(INIT, oplist)(SAFE_GET_KEY(API_0P(M_F(name, _safe_get))) ,) \
,ERASE_KEY(API_0P(M_F(name, _erase))) \
,GET_SIZE(M_F(name, _size)) \
,M_IF_METHOD(INIT_SET, oplist)(PUSH(API_0P(M_F(name,_push_back))) ,) \
,POP(API_0P(M_F(name,_pop_back))) \
,PUSH_MOVE(API_0P(M_F(name,_push_move))) \
,POP_MOVE(M_F(name,_pop_move)) \
,OPLIST(oplist) \
,M_IF_METHOD(CMP, oplist)(SORT(M_F(name, _special_sort)),) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#endif
/********************************** INTERNAL *********************************/
/* Define the internal contract of an array */
//TODO: Can be simplified in release build to speed up compilation speed.
#define M_ARRA4_CONTRACT(a) do { \
M_ASSERT (a != NULL); \
M_ASSERT (a->size <= a->alloc); \
@@ -173,7 +228,7 @@
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_ARRA4_DEF_CORE(name, type, oplist, array_t, it_t) \
M_ARRA4_DEF_IO(name, type, oplist, array_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, array_t, M_F(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF)
M_EMPLACE_QUEUE_DEF(name, array_t, _emplace_back, oplist, M_ARRA4_EMPLACE_DEF)
/* Define the types */
#define M_ARRA4_DEF_TYPE(name, type, oplist, array_t, it_t) \
@@ -212,40 +267,37 @@
M_ARRA4_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(name, _reset)(array_t v) \
M_P(void, name, _reset, array_t v) \
{ \
M_ARRA4_CONTRACT(v); \
M_UNUSED_CONTEXT(); \
for(size_t i = 0; i < v->size; i++) \
M_CALL_CLEAR(oplist, v->ptr[i]); \
v->size = 0; \
M_ARRA4_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(name, _clear)(array_t v) \
M_P(void, name, _clear, array_t v) \
{ \
M_ARRA4_CONTRACT(v); \
M_F(name, _reset)(v); \
M_CALL_FREE(oplist, v->ptr); \
M_F(name, _reset) M_R(v); \
M_CALL_FREE(oplist, type, v->ptr, v->alloc); \
/* This is so reusing the object implies an assertion failure */ \
v->alloc = 1; \
v->ptr = NULL; \
} \
\
M_IF_METHOD2(INIT_SET, SET, oplist)( \
M_INLINE void \
M_F(name, _set)(array_t d, const array_t s) \
M_P(void, name, _set, array_t d, const array_t s) \
{ \
M_ARRA4_CONTRACT(d); \
M_ARRA4_CONTRACT(s); \
if (M_UNLIKELY (d == s)) return; \
if (s->size > d->alloc) { \
const size_t alloc = s->size; \
type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, d->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
M_MEMORY_FULL(type, alloc); \
} \
d->ptr = ptr; \
d->alloc = alloc; \
@@ -264,13 +316,12 @@
M_ARRA4_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _init_set)(array_t d, const array_t s) \
M_P(void, name, _init_set, array_t d, const array_t s) \
{ \
M_ASSERT (d != s); \
M_ON_EXCEPTION(M_F(name, _clear)(d) ) { \
M_ON_EXCEPTION(M_F(name, _clear) M_R(d) ) { \
M_F(name, _init)(d); \
M_F(name, _set)(d, s); \
M_F(name, _set) M_R(d, s); \
} \
} \
, /* No SET & INIT_SET */) \
@@ -289,19 +340,18 @@
M_ARRA4_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _move)(array_t d, array_t s) \
M_P(void, name, _move, array_t d, array_t s) \
{ \
M_ASSERT (d != s); \
M_F(name, _clear)(d); \
M_F(name, _clear) M_R(d); \
M_F(name, _init_move)(d, s); \
} \
\
M_IF_METHOD(SET, oplist)( \
M_INLINE void \
M_F(name, _set_at)(array_t v, size_t i, type const x) \
M_P(void, name, _set_at, array_t v, size_t i, type const x) \
{ \
M_ARRA4_CONTRACT(v); \
M_UNUSED_CONTEXT(); \
M_ASSERT(v->size > 0 && v->ptr != NULL); \
M_ASSERT_INDEX(i, v->size); \
M_CALL_SET(oplist, v->ptr[i], x); \
@@ -317,22 +367,19 @@
return &v->ptr[v->size-1]; \
} \
\
M_INLINE type * \
M_F(name, _push_raw)(array_t v) \
M_P(type *, name, _push_raw, array_t v) \
{ \
M_ARRA4_CONTRACT(v); \
if (M_UNLIKELY (v->size >= v->alloc)) { \
M_ASSERT(v->size == v->alloc); \
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return NULL; \
M_MEMORY_FULL(type, -(size_t)1); \
} \
M_ASSERT (alloc > v->size); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return NULL; \
M_MEMORY_FULL(type, alloc); \
} \
v->ptr = ptr; \
v->alloc = alloc; \
@@ -346,10 +393,9 @@
} \
\
M_IF_METHOD(INIT_SET, oplist)( \
M_INLINE void \
M_F(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)(v); \
type *data = M_F(name, _push_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_IF_EXCEPTION( v->size --); \
@@ -359,10 +405,9 @@
, /* No INIT_SET */ ) \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _push_new)(array_t v) \
M_P(type *, name, _push_new, array_t v) \
{ \
type *data = M_F(name, _push_raw)(v); \
type *data = M_F(name, _push_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return NULL; \
M_IF_EXCEPTION( v->size --); \
@@ -372,21 +417,17 @@
} \
, /* No INIT */ ) \
\
M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \
M_INLINE void \
M_F(name, _push_move)(array_t v, type *x) \
M_P(void, name, _push_move, array_t v, type *x) \
{ \
M_ASSERT (x != NULL); \
type *data = M_F(name, _push_raw)(v); \
type *data = M_F(name, _push_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
M_CALL_INIT_MOVE (oplist, *data, *x); \
} \
, /* INIT_SET | INIT_MOVE */ ) \
\
M_IF_METHOD(INIT_SET, oplist)( \
M_INLINE void \
M_F(name, _push_at)(array_t v, size_t key, type const x) \
M_P(void, name, _push_at, array_t v, size_t key, type const x) \
{ \
M_ARRA4_CONTRACT(v); \
M_ASSERT_INDEX(key, v->size+1); \
@@ -394,14 +435,12 @@
M_ASSERT(v->size == v->alloc); \
size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \
if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
M_MEMORY_FULL(type, -(size_t)1); \
} \
M_ASSERT (alloc > v->size); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
M_MEMORY_FULL(type, alloc); \
} \
v->ptr = ptr; \
v->alloc = alloc; \
@@ -417,8 +456,7 @@
, /* No INIT_SET */ ) \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _resize)(array_t v, size_t size) \
M_P(void, name, _resize, array_t v, size_t size) \
{ \
M_ARRA4_CONTRACT(v); \
if (v->size > size) { \
@@ -430,10 +468,9 @@
/* Increase size of array */ \
if (size > v->alloc) { \
size_t alloc = size ; \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
M_MEMORY_FULL(type, alloc); \
} \
v->ptr = ptr; \
v->alloc = alloc; \
@@ -448,8 +485,7 @@
} \
, /* No INIT */ ) \
\
M_INLINE void \
M_F(name, _reserve)(array_t v, size_t alloc) \
M_P(void, name, _reserve, array_t v, size_t alloc) \
{ \
M_ARRA4_CONTRACT(v); \
/* NOTE: Reserve below needed size to perform a shrink to fit */ \
@@ -457,14 +493,13 @@
alloc = v->size; \
} \
if (M_UNLIKELY (alloc == 0)) { \
M_CALL_FREE(oplist, v->ptr); \
M_CALL_FREE(oplist, type, v->ptr, v->alloc); \
v->size = v->alloc = 0; \
v->ptr = NULL; \
} else { \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
M_MEMORY_FULL(type, alloc); \
} \
v->ptr = ptr; \
v->alloc = alloc; \
@@ -473,8 +508,7 @@
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _safe_get)(array_t v, size_t idx) \
M_P(type *, name, _safe_get, array_t v, size_t idx) \
{ \
M_ARRA4_CONTRACT(v); \
const size_t size = idx + 1; \
@@ -485,13 +519,11 @@
size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \
/* In case of overflow of size_t */ \
if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return NULL; \
M_MEMORY_FULL(type, -(size_t)1); \
} \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return NULL; \
M_MEMORY_FULL(type, alloc); \
} \
v->ptr = ptr; \
v->alloc = alloc; \
@@ -508,11 +540,10 @@
} \
, /* No INIT */) \
\
M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \
M_INLINE void \
M_F(name, _pop_back)(type *dest, array_t v) \
M_P(void, name, _pop_back, type *dest, array_t v) \
{ \
M_ARRA4_CONTRACT(v); \
M_UNUSED_CONTEXT(); \
M_ASSERT (v->ptr != NULL); \
M_ASSERT_INDEX(0, v->size); \
v->size--; \
@@ -523,9 +554,7 @@
} \
M_ARRA4_CONTRACT(v); \
} \
, /* SET | INIT_MOVE */ ) \
\
M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \
M_INLINE void \
M_F(name, _pop_move)(type *dest, array_t v) \
{ \
@@ -534,19 +563,18 @@
M_ASSERT_INDEX(0, v->size); \
M_ASSERT (dest != NULL); \
v->size--; \
M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \
M_CALL_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \
M_ARRA4_CONTRACT(v); \
} \
, /* INIT_SET | INIT_MOVE */ ) \
\
/* TODO: Factorize all INIT dependent methods within the same IF*/ \
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _pop_until)(array_t v, it_t pos) \
M_P(void, name, _pop_until, array_t v, it_t pos) \
{ \
M_ARRA4_CONTRACT(v); \
M_ASSERT (v == pos->array); \
M_ASSERT_INDEX(pos->index, v->size+1); \
M_F(name, _resize)(v, pos->index); \
M_F(name, _resize) M_R(v, pos->index); \
} \
, /* No INIT */ ) \
\
@@ -571,11 +599,10 @@
return v->alloc; \
} \
\
M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \
M_INLINE void \
M_F(name, _pop_at)(type *dest, array_t v, size_t i) \
M_P(void, name, _pop_at, type *dest, array_t v, size_t i) \
{ \
M_ARRA4_CONTRACT(v); \
M_UNUSED_CONTEXT(); \
M_ASSERT (v->size > 0 && v->ptr != NULL); \
M_ASSERT_INDEX(i, v->size); \
if (dest) \
@@ -587,19 +614,16 @@
M_ARRA4_CONTRACT(v); \
} \
\
M_INLINE bool \
M_F(name, _erase)(array_t a, size_t i) \
M_P(bool, name, _erase, array_t a, size_t i) \
{ \
M_ARRA4_CONTRACT(a); \
if (i >= a->size) return false; \
M_F(name, _pop_at)(NULL, a, i); \
M_F(name, _pop_at) M_R(NULL, a, i); \
return true; \
} \
, /* SET | INIT_MOVE */ ) \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _insert_v)(array_t v, size_t i, size_t num) \
M_P(void, name, _insert_v, array_t v, size_t i, size_t num) \
{ \
M_ARRA4_CONTRACT(v); \
M_ASSERT_INDEX(i, v->size+1); \
@@ -608,20 +632,17 @@
if (M_UNLIKELY_NOMEM (size <= v->size)) { \
/* Unlikely case of nothing to do */ \
if (num == 0) return; \
M_MEMORY_FULL(sizeof (type) * v->size); \
return ; \
M_MEMORY_FULL(type, v->size); \
} \
/* Test if alloc array is sufficient */ \
if (size > v->alloc) { \
size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \
if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return ; \
M_MEMORY_FULL(type, -(size_t)1); \
} \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \
type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * alloc); \
return; \
M_MEMORY_FULL(type, alloc); \
} \
v->ptr = ptr; \
v->alloc = alloc; \
@@ -637,10 +658,10 @@
} \
, /* No INIT */) \
\
M_INLINE void \
M_F(name, _remove_v)(array_t v, size_t i, size_t j) \
M_P(void, name, _remove_v, array_t v, size_t i, size_t j) \
{ \
M_ARRA4_CONTRACT(v); \
M_UNUSED_CONTEXT(); \
M_ASSERT(i < j && v->ptr != NULL); \
M_ASSERT_INDEX(i, v->size); \
M_ASSERT_INDEX(j, v->size+1); \
@@ -663,7 +684,6 @@
M_ARRA4_CONTRACT(v2); \
} \
\
M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist) ( \
M_INLINE void \
M_F(name, _swap_at)(array_t v, size_t i, size_t j) \
{ \
@@ -672,12 +692,11 @@
M_ASSERT_INDEX(i, v->size); \
M_ASSERT_INDEX(j, v->size); \
type tmp; \
M_DO_INIT_MOVE(oplist, tmp, v->ptr[i]); \
M_DO_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \
M_DO_INIT_MOVE(oplist, v->ptr[j], tmp); \
M_CALL_INIT_MOVE(oplist, tmp, v->ptr[i]); \
M_CALL_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \
M_CALL_INIT_MOVE(oplist, v->ptr[j], tmp); \
M_ARRA4_CONTRACT(v); \
} \
, /* INIT_SET | INIT_MOVE */ ) \
\
M_INLINE type * \
M_F(name, _get)(const array_t v, size_t i) \
@@ -797,22 +816,20 @@
} \
\
M_IF_METHOD(INIT_SET, oplist)( \
M_INLINE void \
M_F(name, _insert)(array_t a, it_t it, type const x) \
M_P(void, name, _insert, array_t a, it_t it, type const x) \
{ \
M_ASSERT (it != NULL && a == it->array); \
size_t index = M_F(name, _end_p)(it) ? 0 : it->index+1; \
M_F(name, _push_at)(a, index, x); \
M_F(name, _push_at)M_R(a, index, x); \
it->index = index; \
} \
, /* End of INIT_SET */ ) \
\
M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \
M_INLINE void \
M_F(name, _remove)(array_t a, it_t it) \
M_P(void, name, _remove, array_t a, it_t it) \
{ \
M_ASSERT (it != NULL && a == it->array); \
M_F(name, _pop_at)(NULL, a, it->index); \
M_F(name, _pop_at) M_R(NULL, a, it->index); \
/* NOTE: it->index will naturally point to the next element */ \
} \
, /* End of SET | INIT_SET */ ) \
@@ -870,25 +887,23 @@
k += n1+n2; \
for (;;) { \
if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \
M_DO_INIT_MOVE(oplist, *dest, *el1); \
M_CALL_INIT_MOVE(oplist, *dest, *el1); \
dest++; \
el1++; \
if (M_UNLIKELY(-- n1 == 0)) { \
if (n2 > 0) { \
memcpy (dest, el2, n2 * sizeof (type)); \
dest += n2; \
} \
M_ASSERT (n2 > 0); \
memcpy (dest, el2, n2 * sizeof (type)); \
dest += n2; \
break; \
} \
} else { \
M_DO_INIT_MOVE(oplist, *dest, *el2); \
M_CALL_INIT_MOVE(oplist, *dest, *el2); \
dest++; \
el2++; \
if (M_UNLIKELY(-- n2 == 0)) { \
if (n1 > 0) { \
memcpy (dest, el1, n1 * sizeof (type)); \
dest += n1; \
} \
M_ASSERT (n1 > 0); \
memcpy (dest, el1, n1 * sizeof (type)); \
dest += n1; \
break; \
} \
} \
@@ -902,19 +917,17 @@
M_ASSERT (org_tab == tab); \
} \
\
M_INLINE void \
M_F(name, _special_stable_sort)(array_t l) \
M_P(void, name, _special_stable_sort, array_t l) \
{ \
if (M_UNLIKELY (l->size < 2)) \
return; \
/* NOTE: if size is <= 4, no need to perform an allocation */ \
type *temp = M_CALL_REALLOC(oplist, type, NULL, l->size); \
type *temp = M_CALL_REALLOC(oplist, type, NULL, 0, l->size); \
if (M_UNLIKELY_NOMEM (temp == NULL)) { \
M_MEMORY_FULL(sizeof (type) * l->size); \
return ; \
M_MEMORY_FULL(type, l->size); \
} \
M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \
M_CALL_FREE(oplist, temp); \
M_CALL_FREE(oplist, type, temp, l->size); \
} \
,) /* IF SWAP & SET methods */ \
\
@@ -953,8 +966,7 @@
} \
, /* no HASH */ ) \
\
M_INLINE void \
M_F(name, _splice)(array_t a1, array_t a2) \
M_P(void, name, _splice, array_t a1, array_t a2) \
{ \
M_ARRA4_CONTRACT(a1); \
M_ARRA4_CONTRACT(a2); \
@@ -966,9 +978,9 @@
should have exhausted all memory before reaching such sizes. */ \
M_ASSERT_INDEX(a1->size, newSize); \
if (newSize > a1->alloc) { \
type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \
type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, a1->alloc, newSize); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (type) * newSize); \
M_MEMORY_FULL(type, newSize); \
} \
a1->ptr = ptr; \
a1->alloc = newSize; \
@@ -987,12 +999,10 @@
#define M_ARRA4_DEF_IO(name, type, oplist, array_t, it_t) \
\
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, array_t const array, \
bool append) \
M_P(void, name, _get_str, m_string_t str, array_t const array, bool append) \
{ \
M_ARRA4_CONTRACT(array); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
it_t it; \
for (M_F(name, _it)(it, array) ; \
!M_F(name, _end_p)(it); \
@@ -1000,9 +1010,9 @@
type const *item = M_F(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_F(name, _last_p)(it)) \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
} \
m_string_push_back (str, ']'); \
m_string_push_back M_R(str, ']'); \
} \
, /* no GET_STR */ ) \
\
@@ -1024,12 +1034,11 @@
, /* no OUT_STR */ ) \
\
M_IF_METHOD2(PARSE_STR, INIT, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(array_t array, const char str[], const char**endp) \
M_P(bool, name, _parse_str, array_t array, const char str[], const char**endp) \
{ \
M_ARRA4_CONTRACT(array); \
M_ASSERT (str != NULL); \
M_F(name,_reset)(array); \
M_F(name,_reset)M_R(array); \
int c = *str++; \
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
c = m_core_str_nospace(&str); \
@@ -1041,7 +1050,7 @@
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
c = m_core_str_nospace(&str); \
if (b == false || c == 0) { c = 0; break; } \
M_F(name, _push_back)(array, item); \
M_F(name, _push_back) M_R(array, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
exit: \
@@ -1052,12 +1061,11 @@
, /* no PARSE_STR & INIT */ ) \
\
M_IF_METHOD2(IN_STR, INIT, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(array_t array, FILE *file) \
M_P(bool, name, _in_str, array_t array, FILE *file) \
{ \
M_ARRA4_CONTRACT(array); \
M_ASSERT (file != NULL); \
M_F(name,_reset)(array); \
M_F(name,_reset)M_R(array); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
@@ -1069,7 +1077,7 @@
bool b = M_CALL_IN_STR(oplist, item, file); \
c = m_core_fgetc_nospace(file); \
if (b == false || c == EOF) { c = 0; break; } \
M_F(name, _push_back)(array, item); \
M_F(name, _push_back) M_R(array, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
M_ARRA4_CONTRACT(array); \
@@ -1078,46 +1086,44 @@
, /* no IN_STR & INIT */ ) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, const array_t array) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const array_t array) \
{ \
M_ARRA4_CONTRACT(array); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_return_code_t ret; \
m_serial_local_t local; \
ret = f->m_interface->write_array_start(local, f, array->size); \
ret = f->m_interface->write_array_start M_R(local, f, array->size); \
for (size_t i = 0; i < array->size; i++) { \
type const *item = M_F(name, _cget)(array, i); \
if (i != 0) { \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next M_R(local, f); \
} \
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end M_R(local, f); \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(array_t array, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, array_t array, m_serial_read_t f) \
{ \
M_ARRA4_CONTRACT(array); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_return_code_t ret; \
m_serial_local_t local; \
size_t estimated_size = 0; \
M_F(name,_reset)(array); \
M_F(name,_reset)M_R(array); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { \
return ret; \
} \
M_F(name, _reserve)(array, estimated_size); \
M_F(name, _reserve) M_R(array, estimated_size); \
M_QLET(1, item, type, oplist) { \
do { \
ret = M_CALL_IN_SERIAL(oplist, item, f); \
if (ret != M_SERIAL_OK_DONE) { break; } \
M_F(name, _push_back)(array, item); \
M_F(name, _push_back)M_R(array, item); \
ret = f->m_interface->read_array_next(local, f); \
} while (ret == M_SERIAL_OK_CONTINUE); \
} \
@@ -1128,11 +1134,9 @@
/* Definition of the emplace_back function for arrays */
#define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
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)(v); \
M_F(name, _subtype_ct) *data = M_F(name, _push_raw) M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_IF_EXCEPTION( v->size --); \
+1 -1
View File
@@ -146,7 +146,7 @@ using std::memory_order_seq_cst;
#endif
/* Non working C++ atomic header, nor working stdatomic.h found.
Write a compatible layer using mutex as slin as possible.
Write a compatible layer using mutex as slim as possible.
Supports only up to 64-bits atomic (sizeof long long to be more precise).
The locks are never properly cleared and remain active until
the end of the program.
+73 -54
View File
@@ -101,11 +101,10 @@ m_bitset_reset(m_bitset_t t)
}
/* Clear a bitset (DESTRUCTOR) */
M_INLINE void
m_bitset_clear(m_bitset_t t)
M_P(void, m_bitset, _clear, m_bitset_t t)
{
m_bitset_reset(t);
M_MEMORY_FREE(t->ptr);
M_MEMORY_FREE(m_context, m_b1tset_limb_ct, t->ptr, t->alloc);
// This is not really needed, but is safer
// This representation is invalid and will be detected by the contract.
// A C compiler should be able to optimize out theses initializations.
@@ -114,8 +113,7 @@ m_bitset_clear(m_bitset_t t)
}
/* Set a bitset to another one */
M_INLINE void
m_bitset_set(m_bitset_t d, const m_bitset_t s)
M_P(void, m_bitset, _set, m_bitset_t d, const m_bitset_t s)
{
M_B1TSET_CONTRACT(d);
M_B1TSET_CONTRACT(s);
@@ -124,10 +122,9 @@ m_bitset_set(m_bitset_t d, const m_bitset_t s)
if (M_LIKELY (s->size > 0)) {
// Test if enough space in target
if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) {
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, needAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(needAlloc);
return ;
M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc);
}
d->ptr = ptr;
d->alloc = needAlloc;
@@ -141,15 +138,14 @@ m_bitset_set(m_bitset_t d, const m_bitset_t s)
}
/* Initialize & set a bitset to another one (CONSTRUCTOR) */
M_INLINE void
m_bitset_init_set(m_bitset_t d, const m_bitset_t s)
M_P(void, m_bitset, _init_set, m_bitset_t d, const m_bitset_t s)
{
M_ASSERT (d != s);
// In case of exception, d remains initialized,
// but without any allocation done.
// Therefore it is safe, not to clear d on exception.
m_bitset_init(d);
m_bitset_set(d, s);
m_bitset_set M_R(d, s);
}
/* Initialize & move a bitset (CONSTRUCTOR) from another one (DESTRUCTOR) */
@@ -167,10 +163,9 @@ m_bitset_init_move(m_bitset_t d, m_bitset_t s)
}
/* Move a bitset from another one (DESTRUCTOR) */
M_INLINE void
m_bitset_move(m_bitset_t d, m_bitset_t s)
M_P(void, m_bitset, _move, m_bitset_t d, m_bitset_t s)
{
m_bitset_clear(d);
m_bitset_clear M_R(d);
m_bitset_init_move (d, s);
}
@@ -203,8 +198,7 @@ m_bitset_flip_at(m_bitset_t v, size_t i)
}
/* Push back the boolean 'x' in the bitset (increasing the bitset) */
M_INLINE void
m_bitset_push_back (m_bitset_t v, bool x)
M_P(void, m_bitset, _push_back, m_bitset_t v, bool x)
{
M_B1TSET_CONTRACT (v);
if (M_UNLIKELY (v->size >= M_B1TSET_FROM_ALLOC (v->alloc))) {
@@ -212,15 +206,13 @@ m_bitset_push_back (m_bitset_t v, bool x)
const size_t needAlloc = M_B1TSET_INC_ALLOC_SIZE(v->alloc);
// Check for integer overflow
if (M_UNLIKELY_NOMEM (needAlloc <= v->alloc)) {
M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct));
return;
M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc);
}
// Alloc memory
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, needAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc);
// Check if success
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct));
return;
M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc);
}
v->ptr = ptr;
v->alloc = needAlloc;
@@ -242,23 +234,20 @@ m_bitset_push_back (m_bitset_t v, bool x)
}
/* Resize the bitset to have exactly 'size' bits */
M_INLINE void
m_bitset_resize (m_bitset_t v, size_t size)
M_P(void, m_bitset, _resize, m_bitset_t v, size_t size)
{
M_B1TSET_CONTRACT (v);
// Check for overflow
if (M_UNLIKELY_NOMEM (size >= ((size_t)-1) - M_B1TSET_LIMB_BIT)) {
M_MEMORY_FULL((size_t) -1);
return;
M_MEMORY_FULL(char, -(size_t)1);
}
// Compute the needed allocation.
size_t newAlloc = M_B1TSET_TO_ALLOC (size);
if (newAlloc > v->alloc) {
// Allocate more limbs to store the bitset.
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc);
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct));
return;
M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc);
}
v->ptr = ptr;
v->alloc = newAlloc;
@@ -290,8 +279,7 @@ m_bitset_resize (m_bitset_t v, size_t size)
}
/* Reserve allocation in the bitset to accommodate at least 'size' bits without reallocation */
M_INLINE void
m_bitset_reserve (m_bitset_t v, size_t alloc)
M_P(void, m_bitset, _reserve, m_bitset_t v, size_t alloc)
{
M_B1TSET_CONTRACT (v);
size_t oldAlloc = M_B1TSET_TO_ALLOC (v->size);
@@ -302,15 +290,14 @@ m_bitset_reserve (m_bitset_t v, size_t alloc)
}
if (M_UNLIKELY (newAlloc == 0)) {
// Free all memory used by the bitsets
M_MEMORY_FREE (v->ptr);
M_MEMORY_FREE (m_context, m_b1tset_limb_ct, v->ptr, v->alloc);
v->size = v->alloc = 0;
v->ptr = NULL;
} else {
// Allocate more memory or reduce memory usage
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc);
m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc);
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct));
return;
M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc);
}
v->ptr = ptr;
v->alloc = newAlloc;
@@ -390,7 +377,7 @@ m_bitset_size(m_bitset_t v)
return v->size;
}
/* Return the capacity in limbs of the bitset */
/* Return the capacity in bits of the bitset */
M_INLINE size_t
m_bitset_capacity(m_bitset_t v)
{
@@ -456,12 +443,11 @@ m_b1tset_rshift(m_b1tset_limb_ct ptr[], size_t n, m_b1tset_limb_ct carry)
/* Insert a new bit at position 'key' of value 'value' in the bitset 'set'
shifting the set accordingly */
M_INLINE void
m_bitset_push_at(m_bitset_t set, size_t key, bool value)
M_P(void, m_bitset, _push_at, m_bitset_t set, size_t key, bool value)
{
M_B1TSET_CONTRACT (set);
// First push another value to extend the array to the right size
m_bitset_push_back(set, false);
m_bitset_push_back M_R(set, false);
M_ASSERT (set->ptr != NULL);
M_ASSERT_INDEX(key, set->size);
@@ -517,7 +503,7 @@ m_bitset_equal_p (const m_bitset_t set1, const m_bitset_t set2)
M_B1TSET_CONTRACT (set2);
if (set1->size != set2->size)
return false;
/* We won't compare each bit individualy,
/* We won't compare each bit individually,
but instead compare them per limb */
const size_t limbSize = (set1->size + M_B1TSET_LIMB_BIT -1) / M_B1TSET_LIMB_BIT;
for(size_t i = 0 ; i < limbSize;i++)
@@ -526,7 +512,7 @@ m_bitset_equal_p (const m_bitset_t set1, const m_bitset_t set2)
return true;
}
/* Initialize an iterator to the first bit of the biset */
/* Initialize an iterator to the first bit of the bitset */
M_INLINE void
m_bitset_it(m_bitset_it_t it, m_bitset_t set)
{
@@ -632,8 +618,7 @@ m_bitset_out_str(FILE *file, const m_bitset_t set)
}
/* Input the bitset from a formatted text in a FILE */
M_INLINE bool
m_bitset_in_str(m_bitset_t set, FILE *file)
M_P(bool, m_bitset, _in_str, m_bitset_t set, FILE *file)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(file != NULL);
@@ -643,7 +628,7 @@ m_bitset_in_str(m_bitset_t set, FILE *file)
c = fgetc(file);
while (c == '0' || c == '1') {
const bool b = (c == '1');
m_bitset_push_back (set, b);
m_bitset_push_back M_R(set, b);
c = fgetc(file);
}
M_B1TSET_CONTRACT (set);
@@ -651,8 +636,7 @@ m_bitset_in_str(m_bitset_t set, FILE *file)
}
/* Parse the bitset from a formatted text in a C string */
M_INLINE bool
m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr)
M_P(bool, m_bitset, _parse_str, m_bitset_t set, const char str[], const char **endptr)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(str != NULL);
@@ -664,7 +648,7 @@ m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr)
do {
if (M_UNLIKELY(c != '0' && c != '1')) goto exit;
const bool b = (c == '1');
m_bitset_push_back (set, b);
m_bitset_push_back M_R(set, b);
c = *str++;
} while (c != ']' && c != 0);
M_B1TSET_CONTRACT (set);
@@ -675,10 +659,9 @@ m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr)
}
/* Set the bitset from a formatted text in a C string */
M_INLINE bool
m_bitset_set_str(m_bitset_t dest, const char str[])
M_P(bool, m_bitset, _set_str, m_bitset_t dest, const char str[])
{
return m_bitset_parse_str(dest, str, NULL);
return m_bitset_parse_str M_R(dest, str, NULL);
}
/* Perform an AND operation between the bitsets,
@@ -851,6 +834,7 @@ m_bitset_popcount(const m_bitset_t set)
}
/* Oplist for a bitset */
#ifndef M_USE_CONTEXT
#define M_BITSET_OPLIST \
(INIT(m_bitset_init) \
,INIT_SET(m_bitset_init_set) \
@@ -885,6 +869,42 @@ m_bitset_popcount(const m_bitset_t set)
,IN_STR(m_bitset_in_str) \
,EQUAL(m_bitset_equal_p) \
)
#else
#define M_BITSET_OPLIST \
(INIT(m_bitset_init) \
,INIT_SET(API_0P(m_bitset_init_set)) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(API_0P(m_bitset_set)) \
,CLEAR(API_0P(m_bitset_clear)) \
,INIT_MOVE(m_bitset_init_move) \
,MOVE(API_0P(m_bitset_move)) \
,SWAP(m_bitset_swap) \
,TYPE(m_bitset_t) \
,SUBTYPE(bool) \
,EMPTY_P(m_bitset_empty_p), \
,GET_SIZE(m_bitset_size) \
,IT_TYPE(m_bitset_it_t) \
,IT_FIRST(m_bitset_it) \
,IT_SET(m_bitset_it_set) \
,IT_LAST(m_bitset_it_last) \
,IT_END(m_bitset_it_end) \
,IT_END_P(m_bitset_end_p) \
,IT_LAST_P(m_bitset_last_p) \
,IT_EQUAL_P(m_bitset_it_equal_p) \
,IT_NEXT(m_bitset_next) \
,IT_PREVIOUS(m_bitset_previous) \
,IT_CREF(m_bitset_cref) \
,RESET(m_bitset_reset) \
,PUSH(API_0P(m_bitset_push_back)) \
,POP(m_bitset_pop_back) \
,HASH(m_bitset_hash) \
,GET_STR(API_0P(m_bitset_get_str)) \
,OUT_STR(m_bitset_out_str) \
,PARSE_STR(API_0P(m_bitset_parse_str)) \
,IN_STR(API_0P(m_bitset_in_str)) \
,EQUAL(m_bitset_equal_p) \
)
#endif
/* Register the OPLIST as a global one */
#define M_OPL_m_bitset_t() M_BITSET_OPLIST
@@ -965,18 +985,17 @@ M_BEGIN_PROTECTED_CODE
/* Output to a m_string_t 'str' the formatted text representation of the bitset 'set'
or append it to the string (append=true) */
M_INLINE void
m_bitset_get_str(m_string_t str, const m_bitset_t set, bool append)
M_P(void, m_bitset, _get_str, m_string_t str, const m_bitset_t set, bool append)
{
M_B1TSET_CONTRACT (set);
M_ASSERT(str != NULL);
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "[");
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "[");
for(size_t i = 0; i < set->size; i++) {
const bool b = m_bitset_get (set, i);
const char c = b ? '1' : '0';
m_string_push_back (str, c);
m_string_push_back M_R(str, c);
}
m_string_push_back (str, ']');
m_string_push_back M_R(str, ']');
}
M_END_PROTECTED_CODE
+158 -85
View File
@@ -156,6 +156,7 @@
((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* OPLIST definition of a b+tree (global tree) */
#ifndef M_USE_CONTEXT
#define M_BPTR33_KEY_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -189,7 +190,40 @@
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#else
#define M_BPTR33_KEY_OPLIST_P3(name, oplist) \
(INIT(API_0P(M_F(name, _init))), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_INIT_VAI)), \
SET(API_0P(M_F(name, _set))), \
CLEAR(API_0P(M_F(name, _clear))), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(API_0P(M_F(name, _move))), \
SWAP(M_F(name, _swap)), \
NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
SUBTYPE(M_F(name, _subtype_ct)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name,_it_set)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_EQUAL_P(M_F(name,_it_equal_p)), \
IT_NEXT(M_F(name,_next)), \
IT_CREF(M_F(name,_cref)), \
RESET(API_0P(M_F(name,_reset))), \
PUSH(API_0P(M_F(name,_push))), \
GET_MIN(M_F(name,_min)), \
GET_MAX(M_F(name,_max)), \
M_IF_METHOD(GET_STR, oplist)(API_0P(GET_STR(M_F(name, _get_str))),), \
M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \
M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),), \
M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),), \
M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \
M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#endif
/* Deferred evaluation */
#define M_BPTR33_OPLIST2_P1(arg) M_BPTR33_OPLIST2_P2 arg
@@ -205,6 +239,7 @@
((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)))
/* Final definition of the oplist (associative array) */
#ifndef M_USE_CONTEXT
#define M_BPTR33_OPLIST2_P4(name, key_oplist, value_oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -233,7 +268,7 @@
VALUE_TYPE(M_F(name, _value_ct)), \
SET_KEY(M_F(name, _set_at)), \
GET_KEY(M_F(name, _get)), \
SAFE_GET_KEY(M_F(name, _safe_get)) \
SAFE_GET_KEY(M_F(name, _safe_get)), \
ERASE_KEY(M_F(name, _erase)), \
KEY_OPLIST(key_oplist), \
VALUE_OPLIST(value_oplist), \
@@ -245,7 +280,47 @@
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_F(name, _hash)),) \
)
#else
#define M_BPTR33_OPLIST2_P4(name, key_oplist, value_oplist) \
(INIT(API_0P(M_F(name, _init))), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_INIT_KEY_VAI)), \
SET(API_0P(M_F(name, _set))), \
CLEAR(API_0P(M_F(name, _clear))), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(API_0P(M_F(name, _move))), \
SWAP(M_F(name, _swap)), \
NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
SUBTYPE(M_F(name, _subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name,_it_set)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_EQUAL_P(M_F(name,_it_equal_p)), \
IT_NEXT(M_F(name,_next)), \
IT_CREF(M_F(name,_cref)), \
RESET(API_0P(M_F(name,_reset))), \
GET_MIN(M_F(name,_min)), \
GET_MAX(M_F(name,_max)), \
KEY_TYPE(M_F(name, _key_ct)), \
VALUE_TYPE(M_F(name, _value_ct)), \
SET_KEY(API_0P(M_F(name, _set_at))), \
GET_KEY(M_F(name, _get)), \
SAFE_GET_KEY(API_0P(M_F(name, _safe_get))), \
ERASE_KEY(API_0P(M_F(name, _erase))), \
KEY_OPLIST(key_oplist), \
VALUE_OPLIST(value_oplist), \
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \
M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_F(name, _out_str)),), \
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(API_0P(M_F(name, _in_str))),), \
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \
M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_F(name, _hash)),) \
)
#endif
/******************************** INTERNAL ***********************************/
@@ -343,6 +418,7 @@
M_BPTR33_DEF_IT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
M_BPTR33_DEF_EXT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist)
/* TODO: Check if key type has not disabled INIT_MOVE */
/* Define the types of a B+Tree */
#define M_BPTR33_DEF_TYPE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
@@ -406,23 +482,22 @@
\
/* Allocate a new node */ \
/* TODO: Can be specialized to alloc for leaf or for non leaf */ \
M_INLINE node_t M_F(name, _new_node)(void) \
M_INLINE node_t M_F(name, _new_node)(M_P_EXPAND_void) \
{ \
M_STATIC_ASSERT(N >= 2, M_LIB_ILLEGAL_PARAM, \
"Number of items per node shall be >= 2."); \
node_t n = M_CALL_NEW(key_oplist, struct M_F(name, _node_s)); \
if (M_UNLIKELY_NOMEM (n == NULL)) { \
M_MEMORY_FULL(sizeof (node_t)); \
M_ASSERT (0); \
M_MEMORY_FULL(node_t, 1); \
} \
n->next = NULL; \
n->num = 0; \
return n; \
} \
\
M_INLINE void M_F(name, _init)(tree_t b) \
M_P(void, name, _init, tree_t b) \
{ \
b->root = M_F(name, _new_node)(); \
b->root = M_F(name, _new_node)(M_R_EXPAND_void); \
b->size = 0; \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \
@@ -443,7 +518,7 @@
return num; \
} \
\
M_INLINE void M_F(name, _reset)(tree_t b) \
M_P(void, name, _reset, tree_t b) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
node_t next, n = b->root; \
@@ -486,19 +561,19 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
M_INLINE void M_F(name, _clear)(tree_t b) \
M_P(void, name, _clear, tree_t b) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
M_F(name, _reset)(b); \
M_F(name, _reset)M_R(b); \
/* Once the tree is clean, only the root remains */ \
M_CALL_DEL(key_oplist, b->root); \
b->root = NULL; \
} \
\
/* Copy recursively the node 'o' of root node 'root' */ \
M_INLINE node_t M_F(name, _copy_node)(const node_t o, const node_t root) \
M_P(node_t, name, _copy_node, const node_t o, const node_t root) \
{ \
node_t n = M_F(name, _new_node)(); \
node_t n = M_F(name, _new_node)(M_R_EXPAND_void); \
/* Set default number of keys and type to copy */ \
n->num = o->num; \
/* By default it is not linked to its brother. \
@@ -520,7 +595,7 @@
/* Copy recursively the associated nodes if it is not a leaf */ \
for(int i = 0; i <= num; i++) { \
M_ASSERT(o->kind.node[i] != root); \
n->kind.node[i] = M_F(name, _copy_node)(o->kind.node[i], root); \
n->kind.node[i] = M_F(name, _copy_node)M_R(o->kind.node[i], root); \
} \
/* The copied nodes don't have their next field correct */ \
/* Fix the next field for the copied nodes */ \
@@ -542,22 +617,22 @@
return n; \
} \
\
M_INLINE void M_F(name, _init_set)(tree_t b, const tree_t o) \
M_P(void, name, _init_set, tree_t b, const tree_t o) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, o); \
M_ASSERT (b != NULL); \
/* Just copy recursively the root node */ \
b->root = M_F(name, _copy_node)(o->root, o->root); \
b->root = M_F(name, _copy_node)M_R(o->root, o->root); \
b->size = o->size; \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
M_INLINE void M_F(name, _set)(tree_t b, const tree_t o) \
M_P(void, name, _set, tree_t b, const tree_t o) \
{ \
/* NOTE: We could reuse the already allocated nodes of 'b'. \
Not sure if it worth the effort */ \
M_F(name, _clear)(b); \
M_F(name, _init_set)(b, o); \
M_F(name, _clear)M_R(b); \
M_F(name, _init_set)M_R(b, o); \
} \
\
M_INLINE bool M_F(name, _empty_p)(const tree_t b) \
@@ -573,7 +648,7 @@
return b->size; \
} \
\
M_INLINE node_t M_F(name, _search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \
M_INLINE node_t M_F(name, _i_search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \
{ \
node_t n = b->root; \
int np = 0; \
@@ -607,7 +682,7 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
pit_t pit; \
/* Get the leaf node where the key can be */ \
node_t n = M_F(name, _search_for_leaf)(pit, b, key); \
node_t n = M_F(name, _i_search_for_leaf)(pit, b, key); \
int cmp = 0; \
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
/* Search in the leaf for key */ \
@@ -627,11 +702,11 @@
return M_CONST_CAST(value_t, M_F(name, _get)(b, key)); \
} \
\
M_INLINE int \
M_F(name, _search_and_insert_in_leaf)(node_t n, key_t const key \
M_P(int, name, _i_search_and_insert_in_leaf, node_t n, key_t const key \
M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \
{ \
M_ASSERT (M_F(name, _is_leaf)(n)); \
M_UNUSED_CONTEXT(); \
int i, num = M_F(name, _get_num)(n); \
M_ASSERT (num <= N); \
/* Search for the key in the node n (a leaf) for insertion */ \
@@ -659,10 +734,10 @@
return i; \
} \
\
M_INLINE int \
M_F(name, _search_and_insert_in_node)(node_t n, node_t l, key_t key) \
M_P(int, name, _i_search_and_insert_in_node, node_t n, node_t l, key_t key) \
{ \
M_ASSERT (!M_F(name, _is_leaf)(n)); \
M_UNUSED_CONTEXT(); \
int i, num = M_F(name, _get_num)(n); \
M_ASSERT (num <= N); \
/* Search for the key in the node n (not a leaf) for insertion */ \
@@ -682,16 +757,16 @@
return i; \
} \
\
M_INLINE void \
M_IF(isMap)(M_F(name, _set_at),M_F(name,_push))(tree_t b, key_t const key \
M_IF(isMap)(M_DEFERRED_COMMA value_t const value,)) \
M_IF(isMap)( \
M_P(void, name, _set_at, tree_t b, key_t const key, value_t const value) , \
M_P(void, name, _push, tree_t b, key_t const key) ) \
{ \
pit_t pit; \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
node_t leaf = M_F(name, _search_for_leaf)(pit, b, key); \
node_t leaf = M_F(name, _i_search_for_leaf)(pit, b, key); \
/* Insert key into the leaf.*/ \
/* NOTE: Even if there is N elements, we can still add one more.*/ \
int i = M_F(name, _search_and_insert_in_leaf)(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \
int i = M_F(name, _i_search_and_insert_in_leaf)M_R(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \
if (i < 0) { \
/* Nothing to do anymore. key already exists in the tree. \
value has been updated if needed */ \
@@ -713,7 +788,7 @@
/* leaf is full: need to slip the leaf in two */ \
int nnum = (N + 1) / 2; \
num = N + 1 - nnum; \
node_t nleaf = M_F(name, _new_node)(); \
node_t nleaf = M_F(name, _new_node)(M_R_EXPAND_void); \
/* Move half objects to the new node */ \
memmove(&nleaf->key[0], &leaf->key[num], sizeof(key_t)*(unsigned int)nnum); \
M_IF(isMap)(memmove(&nleaf->kind.value[0], &leaf->kind.value[num], sizeof(value_t)*(unsigned int)nnum);,) \
@@ -728,7 +803,7 @@
while (true) { \
if (pit->num == 0) { \
/* We reach root ==> Need to increase the height of the tree.*/ \
node_t parent = M_F(name, _new_node)(); \
node_t parent = M_F(name, _new_node)(M_R_EXPAND_void); \
parent->num = 1; \
/* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \
M_CALL_INIT_SET(key_oplist, parent->key[0], *key_ptr); \
@@ -741,7 +816,7 @@
/* Non root node. Get the parent node */ \
node_t parent = pit->parent[--pit->num]; \
/* Insert into parent (It is big enough to receive temporary one more) */ \
i = M_F(name, _search_and_insert_in_node)(parent, leaf, *key_ptr); \
i = M_F(name, _i_search_and_insert_in_node)M_R(parent, leaf, *key_ptr); \
parent->kind.node[i] = leaf; \
parent->kind.node[i+1] = nleaf; \
/* Test if parent node is full? */ \
@@ -754,7 +829,7 @@
int nnp = N / 2; \
int np = N - nnp; \
M_ASSERT (nnp > 0 && np > 0 && nnp+np+1 == N+1); \
node_t nparent = M_F(name, _new_node)(); \
node_t nparent = M_F(name, _new_node)(M_R_EXPAND_void); \
/* Move half items to new node (Like a classic B-TREE) \
and the median key to the grand-parent*/ \
memmove(&nparent->key[0], &parent->key[np+1], sizeof(key_t)*(unsigned int)nnp); \
@@ -772,7 +847,7 @@
} \
} \
\
M_INLINE value_t *M_F(name, _safe_get)(tree_t b, key_t const key) \
M_P(value_t *, name, _safe_get, tree_t b, key_t const key) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
/* Not optimized implementation */ \
@@ -781,7 +856,7 @@
M_IF(isMap)( \
value_t v; \
M_CALL_INIT(value_oplist, v); \
M_F(name, _set_at)(b, key, v); \
M_F(name, _set_at)M_R(b, key, v); \
M_CALL_CLEAR(value_oplist, v); \
, \
M_F(name, _push)(b, key); \
@@ -791,10 +866,10 @@
return ret; \
} \
\
M_INLINE int \
M_F(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \
M_P(int, name, _i_search_and_remove_in_leaf, node_t n, key_t const key) \
{ \
M_ASSERT(M_F(name, _is_leaf)(n)); \
M_UNUSED_CONTEXT(); \
const int num = M_F(name, _get_num)(n); \
for(int i = 0; i < num; i++) { \
const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
@@ -811,10 +886,11 @@
return -1; /* Not found */ \
} \
\
M_INLINE void M_F(name, _left_shift)(node_t parent, int k) \
M_P(void, name, _i_left_shift, node_t parent, int k) \
{ \
M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \
M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \
M_UNUSED_CONTEXT(); \
node_t left = parent->kind.node[k]; \
node_t right = parent->kind.node[k+1]; \
M_ASSERT (left != NULL && right != NULL); \
@@ -846,10 +922,11 @@
M_ASSERT (left->num != 0); \
} \
\
M_INLINE void M_F(name, _right_shift)(node_t parent, int k) \
M_P(void, name, _i_right_shift, node_t parent, int k) \
{ \
M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \
M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \
M_UNUSED_CONTEXT(); \
node_t left = parent->kind.node[k]; \
node_t right = parent->kind.node[k+1]; \
M_ASSERT (left != NULL && right != NULL); \
@@ -880,7 +957,7 @@
M_ASSERT (left->num != 0); \
} \
\
M_INLINE void M_F(name, _merge_node)(node_t parent, int k, bool leaf) \
M_P(void, name, _i_merge_node, node_t parent, int k, bool leaf) \
{ \
M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \
M_ASSERT (0 <= k && k < M_F(name, _get_num(parent))); \
@@ -916,7 +993,7 @@
/* We can also cache the index when we descend the tree. \
TODO: Bench if this is worth the effort.*/ \
M_INLINE int \
M_F(name, _search_for_node)(node_t parent, node_t child) \
M_F(name, _i_search_for_node)(node_t parent, node_t child) \
{ \
M_ASSERT (!M_F(name, _is_leaf)(parent)); \
int i = 0; \
@@ -928,12 +1005,12 @@
} \
} \
\
M_INLINE bool M_F(name, _erase)(tree_t b, key_t const key) \
M_P(bool, name, _erase, tree_t b, key_t const key) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
pit_t pit; \
node_t leaf = M_F(name, _search_for_leaf)(pit, b, key); \
int k = M_F(name, _search_and_remove_in_leaf)(leaf, key); \
node_t leaf = M_F(name, _i_search_for_leaf)(pit, b, key); \
int k = M_F(name, _i_search_and_remove_in_leaf)M_R(leaf, key); \
/* If key is not found ==> erase failed */ \
if (k < 0) return false; \
/* Remove one item from the B+TREE */ \
@@ -949,15 +1026,15 @@
/* Search for node 'leaf' in parent */ \
node_t parent = pit->parent[--pit->num]; \
M_ASSERT (parent != NULL); \
k = M_F(name, _search_for_node)(parent, leaf); \
k = M_F(name, _i_search_for_node)(parent, leaf); \
/* Look for the neighbour of the removed key. */ \
/* if we can steal one key from them to keep our node balanced */ \
if (k > 0 && M_F(name, _get_num)(parent->kind.node[k-1]) > N/2) { \
M_F(name, _left_shift)(parent, k-1); \
M_F(name, _i_left_shift)M_R(parent, k-1); \
return true; \
} else if (k < M_F(name, _get_num)(parent) \
&& M_F(name, _get_num)(parent->kind.node[k+1]) > N/2) { \
M_F(name, _right_shift)(parent, k); \
M_F(name, _i_right_shift)M_R(parent, k); \
return true; \
} \
/* Merge both nodes, removing 'k' from parent */ \
@@ -965,7 +1042,7 @@
k--; \
M_ASSERT(k >= 0 && k < M_F(name, _get_num)(parent)); \
/* Merge 'k' & 'k+1' & remove 'k' from parent */ \
M_F(name, _merge_node)(parent, k, pass1); \
M_F(name, _i_merge_node)M_R(parent, k, pass1); \
/* Check if we need to continue */ \
if (M_F(name, _get_num)(parent) >= N/2) \
return true; \
@@ -984,16 +1061,17 @@
} \
} \
\
M_INLINE bool M_F(name, _pop_at)(value_t *ptr, tree_t b, key_t const key) \
M_P(bool, name, _pop_at, value_t *ptr, tree_t b, key_t const key) \
{ \
if (ptr != NULL) { \
/* Not optimized tree parsing */ \
value_t *ref = M_F(name, _get)(b, key); \
if (ref == NULL) { \
return false; \
} \
M_CALL_SET(value_oplist, *ptr, *ref); \
} \
return M_F(name, _erase)(b, key); \
return M_F(name, _erase)M_R(b, key); \
} \
\
M_INLINE value_t * \
@@ -1046,13 +1124,12 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \
\
M_INLINE void \
M_F(name, _move)(tree_t b, tree_t ref) \
M_P(void, name, _move, tree_t b, tree_t ref) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \
M_ASSERT (b != ref); \
M_F(name,_clear)(b); \
M_F(name,_clear)M_R(b); \
M_F(name,_init_move)(b, ref); \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \
@@ -1161,7 +1238,7 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
M_ASSERT (it != NULL); \
pit_t pit; \
node_t n = M_F(name, _search_for_leaf)(pit, b, key); \
node_t n = M_F(name, _i_search_for_leaf)(pit, b, key); \
it->node = n; \
int i; \
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
@@ -1259,29 +1336,29 @@
, /* NO HASH METHOD */ ) \
\
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
M_INLINE void M_F(name, _get_str)(m_string_t str, \
const tree_t t1, bool append) { \
M_P(void, name, _get_str, m_string_t str, const tree_t t1, bool append) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT(str != NULL); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
bool commaToPrint = false; \
it_t it; \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)) { \
if (commaToPrint) \
m_string_push_back (str, M_GET_SEPARATOR key_oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR key_oplist); \
commaToPrint = true; \
subtype_t const *ref1 = M_F(name, _cref)(it); \
M_IF(isMap)( \
M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \
m_string_cat_cstr(str, ":"); \
m_string_cat_cstr M_R(str, ":"); \
M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \
, \
M_CALL_GET_STR(key_oplist, str, *ref1, true); \
); \
} \
m_string_push_back (str, ']'); \
m_string_push_back M_R(str, ']'); \
} \
, /* NO GET_STR */ ) \
\
@@ -1314,12 +1391,11 @@
, /* no out_str */ ) \
\
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(tree_t t1, const char str[], const char **endp) \
M_P(bool, name, _parse_str, tree_t t1, const char str[], const char **endp) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (str != NULL); \
M_F(name,_reset)(t1); \
M_F(name,_reset)M_R(t1); \
int c = *str++; \
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
c = *str++; \
@@ -1335,9 +1411,9 @@
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
c = m_core_str_nospace(&str); \
if (b == false || c == 0) { c = 0; break; } \
M_F(name, _set_at)(t1, key, value); \
M_F(name, _set_at)M_R(t1, key, value); \
, \
M_F(name, _push)(t1, key); \
M_F(name, _push)M_R(t1, key); \
) \
} while (c == M_GET_SEPARATOR key_oplist); \
} \
@@ -1349,12 +1425,11 @@
, /* no parse_str */ ) \
\
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \
M_INLINE bool \
M_F(name, _in_str)(tree_t t1, FILE *file) \
M_P(bool, name, _in_str, tree_t t1, FILE *file) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (file != NULL); \
M_F(name,_reset)(t1); \
M_F(name,_reset)M_R(t1); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
@@ -1371,9 +1446,9 @@
b = M_CALL_IN_STR(value_oplist,value, file); \
c = m_core_fgetc_nospace(file); \
if (b == false || c == EOF) { c = 0; break; } \
M_F(name, _set_at)(t1, key, value) \
M_F(name, _set_at)M_R(t1, key, value) \
, \
M_F(name, _push)(t1, key) \
M_F(name, _push)M_R(t1, key) \
); \
} while (c == M_GET_SEPARATOR key_oplist); \
} \
@@ -1383,8 +1458,7 @@
, /* no in_str */ ) \
\
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, tree_t const t1) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
@@ -1396,46 +1470,45 @@
/* Format is different between associative container \
& set container */ \
M_IF(isMap)( \
ret = f->m_interface->write_map_start(local, f, t1->size); \
ret = f->m_interface->write_map_start M_R(local, f, t1->size); \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_map_next(local, f); \
ret |= f->m_interface->write_map_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item->key_ptr); \
ret |= f->m_interface->write_map_value(local, f); \
ret |= f->m_interface->write_map_value M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(value_oplist, f, *item->value_ptr); \
first_done = true; \
} \
ret |= f->m_interface->write_map_end(local, f); \
ret |= f->m_interface->write_map_end M_R(local, f); \
, \
ret = f->m_interface->write_array_start(local, f, t1->size); \
ret = f->m_interface->write_array_start M_R(local, f, t1->size); \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \
first_done = true; \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end M_R(local, f); \
) \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, tree_t t1, m_serial_read_t f) \
{ \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
size_t estimated_size = 0; \
M_F(name,_reset)(t1); \
M_F(name,_reset)M_R(t1); \
M_QLET(1, key, key_t, key_oplist) \
M_IF(isMap)(M_QLET(2, value, value_t, value_oplist) , /*nothing*/) { \
M_IF(isMap)( \
@@ -1448,7 +1521,7 @@
if (ret != M_SERIAL_OK_CONTINUE) break; \
ret = M_CALL_IN_SERIAL(value_oplist, value, f); \
if (ret != M_SERIAL_OK_DONE) break; \
M_F(name, _set_at)(t1, key, value); \
M_F(name, _set_at)M_R(t1, key, value); \
} while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \
, /* queue style */ \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
@@ -1456,7 +1529,7 @@
do { \
ret = M_CALL_IN_SERIAL(key_oplist, key, f); \
if (ret != M_SERIAL_OK_DONE) break; \
M_F(name, _push)(t1, key); \
M_F(name, _push)M_R(t1, key); \
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
) /* End of IF isMap */ \
} \
+64 -55
View File
@@ -74,11 +74,10 @@ m_bstring_init(m_bstring_t s)
M_BSTRING_CONTRACT(s);
}
M_INLINE void
m_bstring_clear(m_bstring_t s)
M_P(void, m_bstring, _clear, m_bstring_t s)
{
M_BSTRING_CONTRACT(s);
M_MEMORY_FREE(s->ptr);
M_MEMORY_FREE(m_context, uint8_t, s->ptr, s->alloc);
s->offset = (size_t) -1;
}
@@ -138,8 +137,7 @@ m_bstring_empty_p(const m_bstring_t v)
allocations.
Return a pointer to the writable string.
*/
M_INLINE uint8_t *
m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
M_P(uint8_t *, m_bstr1ng, _fit2size, m_bstring_t v, size_t size_alloc, bool exact_alloc)
{
// Very unlikely overflow case
if (M_UNLIKELY_NOMEM (v->offset > v->offset + size_alloc)) {
@@ -166,7 +164,7 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
if (M_UNLIKELY_NOMEM (alloc < size_alloc)) {
goto allocation_error;
}
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, alloc);
uint8_t *ptr = M_MEMORY_REALLOC (m_context, uint8_t, v->ptr, v->alloc, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
goto allocation_error;
}
@@ -180,59 +178,56 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc)
}
return &v->ptr[v->offset];
allocation_error:
M_MEMORY_FULL(size_alloc);
// NOTE: Return is currently broken.
abort();
return NULL;
M_MEMORY_FULL(uint8_t, size_alloc);
}
/* Push the byte 'c' in the bstring 'v' */
M_INLINE void
m_bstring_push_back (m_bstring_t v, uint8_t c)
M_P(void, m_bstring, _push_back, m_bstring_t v, uint8_t c)
{
M_BSTRING_CONTRACT (v);
const size_t size = v->size;
uint8_t *ptr = m_bstr1ng_fit2size(v, size+1, false);
// To overflow size+1, we need to have exhausted all memory
// which is not possible.
uint8_t *ptr = m_bstr1ng_fit2size M_R(v, size+1, false);
ptr[size] = c;
v->size = size + 1;
M_BSTRING_CONTRACT (v);
}
/* Push the array of bytes from 'buffer' in the bstring 'v' */
M_INLINE void
m_bstring_push_back_bytes (m_bstring_t v, size_t n, const void *buffer)
M_P(void, m_bstring, _push_back_bytes, m_bstring_t v, size_t n, const void *buffer)
{
M_BSTRING_CONTRACT (v);
const size_t size = v->size;
M_ASSERT_INDEX (size, size + n);
uint8_t *ptr = m_bstr1ng_fit2size(v, size+n, false);
// If size+n overflows, it means we are giving two objects which sizes
// sum to be greater than the available memory. The memory should have exhausted before that.
// The case is not possible, or the given size of the buffer is "faked".
uint8_t *ptr = m_bstr1ng_fit2size M_R(v, size+n, false);
memcpy(&ptr[size], buffer, n);
v->size = size + n;
M_BSTRING_CONTRACT (v);
}
M_INLINE void
m_bstring_splice(m_bstring_t dst, m_bstring_t src)
M_P(void, m_bstring, _splice, m_bstring_t dst, m_bstring_t src)
{
M_BSTRING_CONTRACT (dst);
M_BSTRING_CONTRACT (src);
M_ASSERT(src != dst);
m_bstring_push_back_bytes(dst, m_bstring_size(src), m_bstr1ng_cstr(src));
m_bstring_push_back_bytes M_R(dst, m_bstring_size(src), m_bstr1ng_cstr(src));
m_bstring_reset(src);
}
M_INLINE void
m_bstring_init_set(m_bstring_t v, const m_bstring_t org)
M_P(void, m_bstring, _init_set, m_bstring_t v, const m_bstring_t org)
{
m_bstring_init(v);
m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org));
m_bstring_push_back_bytes M_R(v, m_bstring_size(org), m_bstr1ng_cstr(org));
}
M_INLINE void
m_bstring_set(m_bstring_t v, const m_bstring_t org)
M_P(void, m_bstring, _set, m_bstring_t v, const m_bstring_t org)
{
m_bstring_reset(v);
m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org));
m_bstring_push_back_bytes M_R(v, m_bstring_size(org), m_bstr1ng_cstr(org));
}
M_INLINE void
@@ -240,13 +235,13 @@ m_bstring_init_move(m_bstring_t v, m_bstring_t org)
{
M_BSTRING_CONTRACT (org);
memcpy(v, org, sizeof (m_bstring_t));
// Make org an invalid representation
org->offset = (size_t) -1;
}
M_INLINE void
m_bstring_move(m_bstring_t v, m_bstring_t org)
M_P(void, m_bstring, _move, m_bstring_t v, m_bstring_t org)
{
m_bstring_clear(v);
m_bstring_clear M_R(v);
m_bstring_init_move(v, org);
}
@@ -351,14 +346,16 @@ m_bstring_pop_front_bytes(size_t n, void *buffer, m_bstring_t v)
M_BSTRING_CONTRACT (v);
}
M_INLINE void
m_bstring_push_bytes_at (m_bstring_t v, size_t pos, size_t n, const void *buffer)
M_P(void, m_bstring, _push_bytes_at, m_bstring_t v, size_t pos, size_t n, const void *buffer)
{
M_BSTRING_CONTRACT (v);
const size_t size = v->size;
M_ASSERT_INDEX (pos, size+1); //pos == size ==> equivalent to _push_back_bytes
M_ASSERT_INDEX (size, size + n);
uint8_t *ptr = m_bstr1ng_fit2size(v, size+n, false);
// If size+n overflows, it means we are giving two objects which sizes
// sum to be greater than the available memory. The memory should have exhausted before that.
// The case is not possible.
uint8_t *ptr = m_bstr1ng_fit2size M_R(v, size+n, false);
memmove(&ptr[pos+n], &ptr[pos], size-pos);
memcpy(&ptr[pos], buffer, n);
v->size = size + n;
@@ -379,21 +376,19 @@ m_bstring_pop_bytes_at(size_t n, void *buffer, m_bstring_t v, size_t pos)
M_BSTRING_CONTRACT (v);
}
M_INLINE void
m_bstring_resize (m_bstring_t v, size_t n)
M_P(void, m_bstring, _resize, m_bstring_t v, size_t n)
{
M_BSTRING_CONTRACT (v);
const size_t size = v->size;
if (n > size) {
uint8_t *ptr = m_bstr1ng_fit2size(v, n, true);
uint8_t *ptr = m_bstr1ng_fit2size M_R(v, n, true);
memset(&ptr[size], 0, n-size);
}
v->size = n;
M_BSTRING_CONTRACT (v);
}
M_INLINE void
m_bstring_reserve (m_bstring_t v, size_t n)
M_P(void, m_bstring, _reserve, m_bstring_t v, size_t n)
{
M_BSTRING_CONTRACT (v);
const size_t size = v->size;
@@ -401,17 +396,16 @@ m_bstring_reserve (m_bstring_t v, size_t n)
n = v->offset + size;
}
if (n == 0) {
M_MEMORY_FREE(v->ptr);
M_MEMORY_FREE(m_context, uint8_t, v->ptr, v->alloc);
v->offset = 0;
v->size = 0;
v->alloc = 0;
v->ptr = NULL;
} else {
uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, n);
uint8_t *ptr = M_MEMORY_REALLOC (m_context, uint8_t, v->ptr, v->alloc, n);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(n);
M_MEMORY_FULL(uint8_t, n);
}
// The string cannot be fully embedded anymore.
v->ptr = ptr;
v->alloc = n;
}
@@ -423,6 +417,7 @@ m_bstring_view(const m_bstring_t v, size_t offset, size_t size_requested)
{
M_BSTRING_CONTRACT (v);
M_ASSERT_INDEX (offset+size_requested, v->size+1);
(void) size_requested;
return &m_bstr1ng_cstr(v)[offset];
}
@@ -434,6 +429,7 @@ m_bstring_acquire_access(m_bstring_t v, size_t offset, size_t size_requested)
{
M_BSTRING_CONTRACT (v);
M_ASSERT_INDEX (offset+size_requested, v->size+1);
(void) size_requested;
// Break canonical representation (this will generate assertion if a normal API is called now)
M_SWAP(size_t, v->size, v->alloc);
return &m_bstr1ng_cstr(v)[offset];
@@ -457,11 +453,14 @@ m_bstring_fwrite(FILE *f, const m_bstring_t v)
{
M_BSTRING_CONTRACT (v);
M_ASSERT (f != NULL);
if (M_UNLIKELY(m_bstring_size(v) == 0)) {
return 0;
}
M_ASSERT(m_bstr1ng_cstr(v) != NULL);
return fwrite(m_bstr1ng_cstr(v), 1, m_bstring_size(v), f);
}
M_INLINE bool
m_bstring_fread(m_bstring_t v, FILE *f, size_t num)
M_P(bool, m_bstring, _fread, m_bstring_t v, FILE *f, size_t num)
{
M_BSTRING_CONTRACT (v);
M_ASSERT (f != NULL);
@@ -470,7 +469,7 @@ m_bstring_fread(m_bstring_t v, FILE *f, size_t num)
if (M_UNLIKELY(num == 0)) {
return true;
}
uint8_t *ptr = m_bstr1ng_fit2size(v, num, true);
uint8_t *ptr = m_bstr1ng_fit2size M_R(v, num, true);
size_t n = fread(ptr, 1, num, f);
M_ASSERT (n <= num);
v->size = n;
@@ -485,8 +484,7 @@ m_bstring_fread(m_bstring_t v, FILE *f, size_t num)
and output it in the given serializer
See serialization for return code.
*/
M_INLINE m_serial_return_code_t
m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v)
M_P(m_serial_return_code_t, m_bstring, _out_serial, m_serial_write_t serial, const m_bstring_t v)
{
M_ASSERT (serial != NULL && serial->m_interface != NULL);
M_BSTRING_CONTRACT (v);
@@ -494,15 +492,15 @@ m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v)
m_serial_return_code_t ret;
size_t size = m_bstring_size(v);
uint8_t *ptr = m_bstr1ng_cstr(v);
ret = serial->m_interface->write_array_start(local, serial, size);
ret = serial->m_interface->write_array_start M_R(local, serial, size);
if (size > 0) {
ret |= serial->m_interface->write_integer(serial, ptr[0], 1);
ret |= serial->m_interface->write_integer M_R(serial, ptr[0], 1);
for(size_t i = 1; i < size; i++) {
ret |= serial->m_interface->write_array_next(local, serial);
ret |= serial->m_interface->write_integer(serial, ptr[i], 1);
ret |= serial->m_interface->write_array_next M_R(local, serial);
ret |= serial->m_interface->write_integer M_R(serial, ptr[i], 1);
}
}
ret |= serial->m_interface->write_array_end(local, serial);
ret |= serial->m_interface->write_array_end M_R(local, serial);
return ret;
}
@@ -510,8 +508,7 @@ m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v)
and set the converted value in the byte string 'v'.
See serialization for return code.
*/
M_INLINE m_serial_return_code_t
m_bstring_in_serial(m_bstring_t v, m_serial_read_t f)
M_P(m_serial_return_code_t, m_bstring, _in_serial, m_bstring_t v, m_serial_read_t f)
{
M_ASSERT (f != NULL && f->m_interface != NULL);
M_BSTRING_CONTRACT (v);
@@ -523,7 +520,7 @@ m_bstring_in_serial(m_bstring_t v, m_serial_read_t f)
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) {
return ret;
}
uint8_t *ptr = m_bstr1ng_fit2size(v, estimated_size, true);
uint8_t *ptr = m_bstr1ng_fit2size M_R(v, estimated_size, true);
do {
long long val;
ret = f->m_interface->read_integer(f, &val, 1);
@@ -537,15 +534,27 @@ m_bstring_in_serial(m_bstring_t v, m_serial_read_t f)
}
/* Define the OPLIST of a BYTE STRING */
#ifndef M_USE_CONTEXT
#define M_BSTRING_OPLIST \
(INIT(m_bstring_init),INIT_SET(m_bstring_init_set), SET(m_bstring_set), \
INIT_MOVE(m_bstring_init_move), MOVE(m_bstring_move), \
SWAP(m_bstring_swap), RESET(m_bstring_reset), \
EMPTY_P(m_bstring_empty_p), \
SWAP(m_bstring_swap), RESET(m_bstring_reset), EMPTY_P(m_bstring_empty_p), \
SUBTYPE(uint8_t), PUSH(m_bstring_push), \
CLEAR(m_bstring_clear), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \
CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \
OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(m_bstring_in_serial), \
)
#else
#define M_BSTRING_OPLIST \
(INIT(m_bstring_init),INIT_SET(API_0P(m_bstring_init_set)), SET(API_0P(m_bstring_set)), \
INIT_MOVE(m_bstring_init_move), MOVE(API_0P(m_bstring_move)), \
SWAP(m_bstring_swap), RESET(m_bstring_reset), EMPTY_P(m_bstring_empty_p), \
SUBTYPE(uint8_t), PUSH(API_0P(m_bstring_push)), \
CLEAR(API_0P(m_bstring_clear)), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \
CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \
OUT_SERIAL(API_0P(m_bstring_out_serial)), IN_SERIAL(API_0P(m_bstring_in_serial=) \
)
#endif
/********************************************************************************/
/* */
+189 -313
View File
@@ -1,5 +1,5 @@
/*
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface (Thread safe)
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
@@ -31,20 +31,12 @@
/* Define the different kind of policy a lock-based buffer can have:
* - the buffer can be either a queue (policy is FIFO) or a stack (policy is FILO),
* - if the push method is by default blocking (waiting for the buffer to has some space) or not, *** deprecated ***
* - if the pop method is by default blocking (waiting for the buffer to has some data) or not, *** deprecated ***
* - if both methods are blocking, *** deprecated ***
* - if it shall be thread safe or not (i.e. remove the mutex lock and atomic costs),
* - if the buffer has to be init with empty elements, or if it shall init an element when it is pushed (and moved when popped),
* - if the buffer has to overwrite the last element if the buffer is full,
* - if the pop of an element is not complete until the call to pop_release (preventing push until this call).
*/
typedef enum {
M_BUFFER_QUEUE = 0, M_BUFFER_STACK = 1,
M_BUFFER_BLOCKING_PUSH = 0, M_BUFFER_UNBLOCKING_PUSH = 2,
M_BUFFER_BLOCKING_POP = 0, M_BUFFER_UNBLOCKING_POP = 4,
M_BUFFER_BLOCKING = 0, M_BUFFER_UNBLOCKING = 6,
M_BUFFER_THREAD_SAFE = 0, M_BUFFER_THREAD_UNSAFE = 8,
M_BUFFER_PUSH_INIT_POP_MOVE = 16,
M_BUFFER_PUSH_OVERWRITE = 32,
M_BUFFER_DEFERRED_POP = 64
@@ -138,80 +130,6 @@ typedef enum {
#define M_BUFF3R_POLICY_P(policy, val) \
(((policy) & (val)) != 0)
/* Handle either atomic integer or normal integer in function of the policy
parameter of the buffer BUFFER_THREAD_UNSAFE (BUFFER_THREAD_SAFE is the
default). This enables avoiding to pay the cost of atomic operations if not
applicable.
*/
typedef union m_buff3r_number_s {
unsigned int u;
atomic_uint a;
#ifdef __cplusplus
// Not sure why, but C++ needs an explicit default constructor for this union.
m_buff3r_number_s() : u(0) {};
#endif
} m_buff3r_number_ct[1];
M_INLINE void
m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
atomic_init(&n->a, 0U);
else
n->u = 0UL;
}
M_INLINE unsigned int
m_buff3r_number_load(const m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
// Perform a memory acquire so that further usage of the buffer
// is synchronized.
return atomic_load_explicit(&n->a, memory_order_acquire);
else
return n->u;
}
M_INLINE void
m_buff3r_number_store(m_buff3r_number_ct n, unsigned int v, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
// This function is used in context where a relaxed access is sufficient.
atomic_store_explicit(&n->a, v, memory_order_relaxed);
else
n->u = v;
}
M_INLINE void
m_buff3r_number_set(m_buff3r_number_ct n, m_buff3r_number_ct v, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
// This function is used in context where a relaxed access is sufficient.
atomic_store_explicit(&n->a, atomic_load_explicit(&v->a, memory_order_relaxed), memory_order_relaxed);
else
n->u = v->u;
}
M_INLINE unsigned int
m_buff3r_number_inc(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
return atomic_fetch_add(&n->a, 1U);
else
return n->u ++;
}
M_INLINE unsigned int
m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
{
if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE))
return atomic_fetch_sub(&n->a, 1U);
else
return n->u --;
}
/********************************** INTERNAL *********************************/
/* Test if the size is only run-time or build time */
#define M_BUFF3R_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size))
@@ -230,7 +148,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
/* Contract of a buffer within a protected section */
#define M_BUFF3R_PROTECTED_CONTRACT(policy, buffer, size) do { \
M_ASSERT (m_buff3r_number_load(buffer->number[0], policy) <= M_BUFF3R_SIZE(size)); \
M_ASSERT (atomic_load_explicit(&buffer->number[0], memory_order_acquire) <= M_BUFF3R_SIZE(size)); \
} while (0)
@@ -258,7 +176,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
M_BUFF3R_DEF_TYPE(name, type, m_size, policy, oplist, buffer_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \
M_EMPLACE_QUEUE_DEF(name, buffer_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_BUFF3R_EMPLACE_QUEUE_GENE)
/* Define the type of a buffer */
#define M_BUFF3R_DEF_TYPE(name, type, m_size, policy, oplist, buffer_t) \
@@ -267,7 +185,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
by multiple writing threads. No need to align if there is no thread */ \
typedef union M_F(name, _el_s) { \
type x; \
char align[M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE) ? 1 : M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
char align[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
} M_F(name, _el_ct); \
\
typedef struct M_F(name, _s) { \
@@ -284,7 +202,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
size_t idx_cons; /* Index of the consumption threads */ \
/* number[0] := Number of elements in the buffer */ \
/* number[1] := [OPTION] Number of elements being deferred in the buffer */ \
m_buff3r_number_ct number[1 + M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)]; \
atomic_uint number[1 + M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)]; \
/* If fixed size, array of elements, otherwise pointer to element */ \
M_F(name, _el_ct) M_BUFF3R_IF_CTE_SIZE(m_size)(data[m_size], *data); \
} buffer_t[1]; \
@@ -300,29 +218,24 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
/* Define the core functionalities of a buffer */
#define M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \
\
M_INLINE void \
M_F(name, _init)(buffer_t v, size_t size) \
M_N(void, name, _init, buffer_t v, size_t size) \
{ \
M_ASSERT(size <= UINT_MAX); \
M_GLOBAL_CONTEXT(); \
M_BUFF3R_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = size); \
v->idx_prod = v->idx_cons = v->overwrite = 0; \
m_buff3r_number_init (v->number[0], policy); \
atomic_init (&v->number[0], 0U); \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_init (v->number[1], policy); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_init(v->mutexPush); \
m_mutex_init(v->mutexPop); \
m_cond_init(v->there_is_data); \
m_cond_init(v->there_is_room_for_data); \
} else { \
M_ASSERT(M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING)); \
} \
atomic_init (&v->number[1], 0U); \
m_mutex_init(v->mutexPush); \
m_mutex_init(v->mutexPop); \
m_cond_init(v->there_is_data); \
m_cond_init(v->there_is_room_for_data); \
\
M_BUFF3R_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \
v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, M_BUFF3R_SIZE(m_size)); \
v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, M_BUFF3R_SIZE(m_size)); \
if (M_UNLIKELY_NOMEM (v->data == NULL)) { \
M_MEMORY_FULL (M_BUFF3R_SIZE(m_size)*sizeof(M_F(name, _el_ct))); \
return; \
M_MEMORY_FULL (M_F(name, _el_ct), M_BUFF3R_SIZE(m_size)); \
} \
) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
@@ -334,17 +247,16 @@ M_F(name, _init)(buffer_t v, size_t size) \
} \
\
M_BUFF3R_IF_CTE_SIZE(m_size)( \
M_INLINE void \
M_C3(m_buff3r_,name,_init)(buffer_t v) \
M_N(void, name,_i_init, buffer_t v) \
{ \
M_F(name, _init)(v, m_size); \
} \
, ) \
\
M_INLINE void \
M_C3(m_buff3r_,name,_clear_obj)(buffer_t v) \
M_N(void, name, _i_clear_obj, buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
M_GLOBAL_CONTEXT(); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
M_CALL_CLEAR(oplist, v->data[i].x); \
@@ -359,73 +271,59 @@ M_F(name, _init)(buffer_t v, size_t size) \
} \
} \
v->idx_prod = v->idx_cons = 0; \
m_buff3r_number_store (v->number[0], 0U, policy); \
atomic_store_explicit (&v->number[0], 0U, memory_order_relaxed); \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_store(v->number[1], 0U, policy); \
atomic_store_explicit (&v->number[1], 0U, memory_order_relaxed); \
M_BUFF3R_CONTRACT(v,m_size); \
} \
\
M_INLINE void \
M_F(name, _clear)(buffer_t v) \
M_N(void, name, _clear, buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
M_C3(m_buff3r_,name,_clear_obj)(v); \
M_GLOBAL_CONTEXT(); \
M_F(name,_i_clear_obj)(v); \
M_BUFF3R_IF_CTE_SIZE(m_size)( , \
M_CALL_FREE(oplist, v->data); \
M_CALL_FREE(oplist, M_F(name, _el_ct), v->data, M_BUFF3R_SIZE(m_size)); \
v->data = NULL; \
) \
v->overwrite = 0; \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_clear(v->mutexPush); \
m_mutex_clear(v->mutexPop); \
m_cond_clear(v->there_is_data); \
m_cond_clear(v->there_is_room_for_data); \
} \
m_mutex_clear(v->mutexPush); \
m_mutex_clear(v->mutexPop); \
m_cond_clear(v->there_is_data); \
m_cond_clear(v->there_is_room_for_data); \
} \
\
M_INLINE void \
M_F(name, _reset)(buffer_t v) \
M_N(void, name, _reset, buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} \
M_GLOBAL_CONTEXT(); \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) \
M_C3(m_buff3r_,name,_clear_obj)(v); \
M_F(name,_i_clear_obj)(v); \
v->idx_prod = v->idx_cons = 0; \
m_buff3r_number_store (v->number[0], 0U, policy); \
atomic_store_explicit (&v->number[0], 0U, memory_order_relaxed); \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_store(v->number[1], 0U, policy); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
atomic_store_explicit(&v->number[1], 0U, memory_order_relaxed); \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
M_BUFF3R_CONTRACT(v,m_size); \
} \
\
M_INLINE void M_ATTR_DEPRECATED \
M_F(name, _clean)(buffer_t v) \
M_N(void, name, _init_set, buffer_t dest, const buffer_t src) \
{ \
M_F(name,_reset)(v); \
} \
\
M_INLINE void \
M_F(name, _init_set)(buffer_t dest, const buffer_t src) \
{ \
/* un-const 'src', so that we can lock it (semantically it is const) */ \
M_GLOBAL_CONTEXT(); \
/* un-const 'src', so that we can lock it (semantically it is const) */ \
M_F(name, _uptr_ct) vu; \
vu.cptr = src; \
M_F(name, _ptr) v = vu.ptr; \
M_ASSERT (dest != v); \
M_BUFF3R_CONTRACT(v,m_size); \
M_F(name, _init)(dest, M_BUFF3R_SIZE(m_size)); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
\
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
@@ -444,22 +342,20 @@ M_F(name, _init)(buffer_t v, size_t size) \
\
dest->idx_prod = v->idx_prod; \
dest->idx_cons = v->idx_cons; \
m_buff3r_number_set (dest->number[0], v->number[0], policy); \
atomic_store_explicit (&dest->number[0], atomic_load_explicit(&v->number[0], memory_order_relaxed), memory_order_relaxed); \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_set(dest->number[1], v->number[1], policy); \
atomic_store_explicit(&dest->number[1], atomic_load_explicit(&v->number[1], memory_order_relaxed), memory_order_relaxed); \
\
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
M_BUFF3R_CONTRACT(v,m_size); \
M_BUFF3R_CONTRACT(dest, m_size); \
} \
\
M_INLINE void \
M_F(name, _set)(buffer_t dest, const buffer_t src) \
M_N(void, name, _set, buffer_t dest, const buffer_t src) \
{ \
/* un-const 'src', so that we can lock it (semantically it is const) */ \
M_GLOBAL_CONTEXT(); \
/* un-const 'src', so that we can lock it (semantically it is const) */ \
M_F(name, _uptr_ct) vu; \
vu.cptr = src; \
M_F(name, _ptr) v = vu.ptr; \
@@ -467,24 +363,22 @@ M_F(name, _init)(buffer_t v, size_t size) \
M_BUFF3R_CONTRACT(v,m_size); \
\
if (dest == v) return; \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
/* Case of deadlock: A := B, B:=C, C:=A (all in //) \
Solution: order the lock by increasing memory */ \
if (dest < v) { \
m_mutex_lock(dest->mutexPush); \
m_mutex_lock(dest->mutexPop); \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} else { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
m_mutex_lock(dest->mutexPush); \
m_mutex_lock(dest->mutexPop); \
} \
/* Case of deadlock: A := B, B:=C, C:=A (all in //) \
Solution: order the lock by increasing memory */ \
if (dest < v) { \
m_mutex_lock(dest->mutexPush); \
m_mutex_lock(dest->mutexPop); \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
} else { \
m_mutex_lock(v->mutexPush); \
m_mutex_lock(v->mutexPop); \
m_mutex_lock(dest->mutexPush); \
m_mutex_lock(dest->mutexPop); \
} \
\
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
M_C3(m_buff3r_,name,_clear_obj)(dest); \
M_F(name,_i_clear_obj)(dest); \
\
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \
@@ -502,25 +396,22 @@ M_F(name, _init)(buffer_t v, size_t size) \
\
dest->idx_prod = v->idx_prod; \
dest->idx_cons = v->idx_cons; \
m_buff3r_number_set (dest->number[0], v->number[0], policy); \
atomic_store_explicit(&dest->number[0], atomic_load_explicit(&v->number[0], memory_order_relaxed), memory_order_relaxed); \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
m_buff3r_number_set(dest->number[1], v->number[1], policy); \
atomic_store_explicit(&dest->number[1], atomic_load_explicit(&v->number[1], memory_order_relaxed), memory_order_relaxed); \
\
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
/* It may be false, but it is not wrong! */ \
m_cond_broadcast(v->there_is_room_for_data); \
m_cond_broadcast(v->there_is_data); \
if (dest < v) { \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
m_mutex_unlock(dest->mutexPop); \
m_mutex_unlock(dest->mutexPush); \
} else { \
m_mutex_unlock(dest->mutexPop); \
m_mutex_unlock(dest->mutexPush); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
m_cond_broadcast(v->there_is_room_for_data); \
m_cond_broadcast(v->there_is_data); \
if (dest < v) { \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
m_mutex_unlock(dest->mutexPop); \
m_mutex_unlock(dest->mutexPush); \
} else { \
m_mutex_unlock(dest->mutexPop); \
m_mutex_unlock(dest->mutexPush); \
m_mutex_unlock(v->mutexPop); \
m_mutex_unlock(v->mutexPush); \
} \
M_BUFF3R_CONTRACT(v,m_size); \
M_BUFF3R_CONTRACT(dest, m_size); \
@@ -535,16 +426,16 @@ M_F(name, _init)(buffer_t v, size_t size) \
deferred pop has reached 0, not the number of items in the \
buffer is 0. */ \
if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \
return m_buff3r_number_load (v->number[1], policy) == 0; \
return atomic_load_explicit (&v->number[1], memory_order_relaxed) == 0; \
else \
return m_buff3r_number_load (v->number[0], policy) == 0; \
return atomic_load_explicit (&v->number[0], memory_order_relaxed) == 0; \
} \
\
M_INLINE bool \
M_F(name, _full_p)(const buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
return m_buff3r_number_load (v->number[0], policy) \
return atomic_load_explicit (&v->number[0], memory_order_relaxed) \
== M_BUFF3R_SIZE(m_size); \
} \
\
@@ -552,28 +443,23 @@ M_F(name, _init)(buffer_t v, size_t size) \
M_F(name, _size)(const buffer_t v) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
return m_buff3r_number_load (v->number[0], policy); \
return atomic_load_explicit (&v->number[0], memory_order_relaxed); \
} \
\
M_INLINE bool \
M_F(name, _push_blocking)(buffer_t v, type const data, bool blocking) \
M_N(bool, name, _push_blocking, buffer_t v, type const data, bool blocking) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
\
M_GLOBAL_CONTEXT(); \
/* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPush); \
while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
&& M_F(name, _full_p)(v)) { \
if (!blocking) { \
m_mutex_unlock(v->mutexPush); \
return false; \
} \
m_cond_wait(v->there_is_room_for_data, v->mutexPush); \
} \
} else if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
&& M_F(name, _full_p)(v)) \
return false; \
m_mutex_lock(v->mutexPush); \
while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \
&& M_F(name, _full_p)(v)) { \
if (!blocking) { \
m_mutex_unlock(v->mutexPush); \
return false; \
} \
m_cond_wait(v->there_is_room_for_data, v->mutexPush); \
} \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
\
size_t previousSize, idx = v->idx_prod; \
@@ -611,48 +497,42 @@ M_F(name, _init)(buffer_t v, size_t size) \
thread which has the push lock. As such, it is an atomic variable \
that performs a release memory barrier. */ \
/* Increment number of elements of the buffer */ \
previousSize = m_buff3r_number_inc (v->number[0], policy); \
previousSize = atomic_fetch_add (&v->number[0], 1U); \
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
previousSize = m_buff3r_number_inc (v->number[1], policy); \
previousSize = atomic_fetch_add (&v->number[1], 1U); \
} \
/* From this point, consumer may read the data in the table */ \
} \
\
/* Producer unlock (mutex unlock performs a release memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPush); \
/* If the number of items in the buffer was 0, some consumer \
may be waiting. Signal to them the availability of the data \
We cannot only signal one thread. */ \
if (previousSize == 0) { \
m_mutex_lock(v->mutexPop); \
m_cond_broadcast(v->there_is_data); \
m_mutex_unlock(v->mutexPop); \
} \
m_mutex_unlock(v->mutexPush); \
/* If the number of items in the buffer was 0, some consumer \
may be waiting. Signal to them the availability of the data \
We cannot only signal one thread. */ \
if (previousSize == 0) { \
m_mutex_lock(v->mutexPop); \
m_cond_broadcast(v->there_is_data); \
m_mutex_unlock(v->mutexPop); \
} \
\
M_BUFF3R_CONTRACT(v,m_size); \
return true; \
} \
\
M_INLINE bool \
M_F(name, _pop_blocking)(type *data, buffer_t v, bool blocking) \
M_N(bool, name, _pop_blocking, type *data, buffer_t v, bool blocking) \
{ \
M_BUFF3R_CONTRACT(v,m_size); \
M_ASSERT (data != NULL); \
\
M_GLOBAL_CONTEXT(); \
/* consumer lock (mutex lock performs an acquire memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_lock(v->mutexPop); \
while (M_F(name, _empty_p)(v)) { \
if (!blocking) { \
m_mutex_unlock(v->mutexPop); \
return false; \
} \
m_cond_wait(v->there_is_data, v->mutexPop); \
} \
} else if (M_F(name, _empty_p)(v)) \
return false; \
m_mutex_lock(v->mutexPop); \
while (M_F(name, _empty_p)(v)) { \
if (!blocking) { \
m_mutex_unlock(v->mutexPop); \
return false; \
} \
m_cond_wait(v->there_is_data, v->mutexPop); \
} \
M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \
\
/* POP data from the buffer and update INDEX */ \
@@ -661,7 +541,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *data, v->data[v->idx_cons].x); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons].x); \
M_CALL_INIT_MOVE (oplist, *data, v->data[v->idx_cons].x); \
} \
v->idx_cons = (v->idx_cons == M_BUFF3R_SIZE(m_size)-1) ? 0 : (v->idx_cons + 1); \
} else { \
@@ -670,7 +550,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *data, v->data[v->idx_prod].x); \
} else { \
M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod].x); \
M_CALL_INIT_MOVE (oplist, *data, v->data[v->idx_prod].x); \
} \
} \
\
@@ -681,24 +561,22 @@ M_F(name, _init)(buffer_t v, size_t size) \
/* Decrement number of elements in the buffer */ \
size_t previousSize; \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
previousSize = m_buff3r_number_dec (v->number[0], policy); \
previousSize = atomic_fetch_sub (&v->number[0], 1U); \
} else { \
m_buff3r_number_dec (v->number[1], policy); \
atomic_fetch_sub (&v->number[1], 1U); \
} \
/* Space may be reused by a producer thread from this point */ \
\
/* consumer unlock (mutex unlock performs a release memory barrier) */ \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \
m_mutex_unlock(v->mutexPop); \
/* If the number of items in the buffer was the max, some producer \
may be waiting. Signal to them the availability of the free room \
We cannot only signal one thread. */ \
if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \
&& previousSize == M_BUFF3R_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPush); \
} \
m_mutex_unlock(v->mutexPop); \
/* If the number of items in the buffer was the max, some producer \
may be waiting. Signal to them the availability of the free room \
We cannot only signal one thread. */ \
if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \
&& previousSize == M_BUFF3R_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
m_cond_broadcast(v->there_is_room_for_data); \
m_mutex_unlock(v->mutexPush); \
} \
\
M_BUFF3R_CONTRACT(v,m_size); \
@@ -706,18 +584,18 @@ M_F(name, _init)(buffer_t v, size_t size) \
} \
\
\
M_INLINE bool \
M_F(name, _push)(buffer_t v, type const data) \
M_N(void, name, _push, buffer_t v, type const data) \
{ \
return M_F(name, _push_blocking)(v, data, \
!M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_PUSH)); \
bool b = M_F(name, _push_blocking)(v, data, true); \
assert(b); \
(void) b; \
} \
\
M_INLINE bool \
M_F(name, _pop)(type *data, buffer_t v) \
M_N(void, name, _pop, type *data, buffer_t v) \
{ \
return M_F(name, _pop_blocking)(data, v, \
!M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_POP)); \
bool b = M_F(name, _pop_blocking)(data, v, true); \
assert(b); \
(void) b; \
} \
\
M_INLINE size_t \
@@ -738,7 +616,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
{ \
/* Decrement the effective number of elements in the buffer */ \
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
size_t previousSize = m_buff3r_number_dec (v->number[0], policy); \
size_t previousSize = atomic_fetch_sub (&v->number[0], 1U); \
if (previousSize == M_BUFF3R_SIZE(m_size)) { \
m_mutex_lock(v->mutexPush); \
m_cond_broadcast(v->there_is_room_for_data); \
@@ -798,7 +676,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
M_QU3UE_MPMC_DEF_TYPE(name, type, policy, oplist, buffer_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \
M_EMPLACE_QUEUE_DEF(name, buffer_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_BUFF3R_EMPLACE_QUEUE_GENE)
/* Define the type of a MPMC queue */
#define M_QU3UE_MPMC_DEF_TYPE(name, type, policy, oplist, buffer_t) \
@@ -833,10 +711,10 @@ M_F(name, _init)(buffer_t v, size_t size) \
/* Define the core functionalities of a MPMC queue */
#define M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \
M_INLINE bool \
M_F(name, _push)(buffer_t table, type const x) \
M_N(bool, name, _push, buffer_t table, type const x) \
{ \
M_QU3UE_MPMC_CONTRACT(table); \
M_GLOBAL_CONTEXT(); \
unsigned int idx = atomic_load_explicit(&table->ProdIdx, \
memory_order_relaxed); \
const unsigned int i = idx & (table->size -1); \
@@ -867,18 +745,18 @@ M_F(name, _init)(buffer_t v, size_t size) \
return true; \
} \
\
M_INLINE bool \
M_F(name, _pop)(type *ptr, buffer_t table) \
M_N(bool, name, _pop, type *ptr, buffer_t table) \
{ \
M_QU3UE_MPMC_CONTRACT(table); \
M_ASSERT (ptr != NULL); \
M_GLOBAL_CONTEXT(); \
unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \
memory_order_relaxed); \
const unsigned int i = (iC & (table->size -1)); \
const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \
memory_order_acquire); \
if (seq != 2 * iC) { \
/* Nothing in buffer to consumme (or unlikely preemption) */ \
/* Nothing in buffer to consume (or unlikely preemption) */ \
return false; \
} \
if (M_UNLIKELY (!atomic_compare_exchange_strong_explicit(&table->ConsoIdx, \
@@ -889,27 +767,25 @@ M_F(name, _init)(buffer_t v, size_t size) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *ptr, table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
M_CALL_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
} \
atomic_store_explicit(&table->Tab[i].seq, 2*iC + 1, memory_order_release); \
M_QU3UE_MPMC_CONTRACT(table); \
return true; \
} \
\
M_INLINE void \
M_F(name, _init)(buffer_t buffer, size_t size) \
M_N(void, name, _init, buffer_t buffer, size_t size) \
{ \
M_ASSERT (buffer != NULL); \
M_ASSERT( M_POWEROF2_P(size)); \
M_ASSERT (0 < size && size <= UINT_MAX); \
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \
M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \
M_GLOBAL_CONTEXT(); \
atomic_init(&buffer->ProdIdx, (unsigned int) size); \
atomic_init(&buffer->ConsoIdx, (unsigned int) size); \
buffer->size = (unsigned int) size; \
buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, size); \
buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \
if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \
M_MEMORY_FULL (size*sizeof(M_F(name, _el_ct) )); \
return; \
M_MEMORY_FULL (M_F(name, _el_ct), size); \
} \
for(unsigned int j = 0; j < (unsigned int) size; j++) { \
atomic_init(&buffer->Tab[j].seq, 2*j+1U); \
@@ -920,10 +796,10 @@ M_F(name, _init)(buffer_t v, size_t size) \
M_QU3UE_MPMC_CONTRACT(buffer); \
} \
\
M_INLINE void \
M_F(name, _clear)(buffer_t buffer) \
M_N(void, name, _clear, buffer_t buffer) \
{ \
M_QU3UE_MPMC_CONTRACT(buffer); \
M_GLOBAL_CONTEXT(); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < buffer->size; j++) { \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
@@ -940,7 +816,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
j = 0; \
} \
} \
M_CALL_FREE(oplist, buffer->Tab); \
M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, buffer->size); \
buffer->Tab = NULL; /* safer */ \
buffer->size = 3; \
} \
@@ -1033,7 +909,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \
M_EMPLACE_QUEUE_DEF(name, buffer_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_BUFF3R_EMPLACE_QUEUE_GENE)
/* Define the type of a SPSC queue */
#define M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \
@@ -1050,7 +926,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
atomic_uint consoIdx; /* Can only increase until overflow */ \
unsigned int size; \
M_F(name, _el_ct) *Tab; \
M_CACHELINE_ALIGN(align, atomic_uint, size_t, M_F(name, _el_ct) *); \
M_CACHELINE_ALIGN(align, atomic_uint, unsigned int, M_F(name, _el_ct) *); \
atomic_uint prodIdx; /* Can only increase until overflow */ \
} buffer_t[1]; \
\
@@ -1060,10 +936,10 @@ M_F(name, _init)(buffer_t v, size_t size) \
/* Define the core functionalities of a SPSC queue */
#define M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \
\
M_INLINE bool \
M_F(name, _push)(buffer_t table, type const x) \
M_N(bool, name, _push, buffer_t table, type const x) \
{ \
M_QU3UE_SPSC_CONTRACT(table); \
M_GLOBAL_CONTEXT(); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_relaxed); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
@@ -1081,10 +957,10 @@ M_F(name, _init)(buffer_t v, size_t size) \
return true; \
} \
\
M_INLINE bool \
M_F(name, _push_move)(buffer_t table, type *x) \
M_N(bool, name, _push_move, buffer_t table, type *x) \
{ \
M_QU3UE_SPSC_CONTRACT(table); \
M_GLOBAL_CONTEXT(); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_relaxed); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
@@ -1095,18 +971,18 @@ M_F(name, _init)(buffer_t v, size_t size) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_DO_MOVE(oplist, table->Tab[i].x, *x); \
} else { \
M_DO_INIT_MOVE(oplist, table->Tab[i].x, *x); \
M_CALL_INIT_MOVE(oplist, table->Tab[i].x, *x); \
} \
atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \
M_QU3UE_SPSC_CONTRACT(table); \
return true; \
} \
\
M_INLINE bool \
M_F(name, _pop)(type *ptr, buffer_t table) \
M_N(bool, name, _pop, type *ptr, buffer_t table) \
{ \
M_QU3UE_SPSC_CONTRACT(table); \
M_ASSERT (ptr != NULL); \
M_GLOBAL_CONTEXT(); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
memory_order_relaxed); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
@@ -1117,19 +993,19 @@ M_F(name, _init)(buffer_t v, size_t size) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, *ptr , table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
M_CALL_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \
} \
atomic_store_explicit(&table->consoIdx, r+1, memory_order_release); \
M_QU3UE_SPSC_CONTRACT(table); \
return true; \
} \
\
M_INLINE unsigned \
M_F(name, _push_bulk)(buffer_t table, unsigned n, type const x[]) \
M_N(unsigned, name, _push_bulk, buffer_t table, unsigned n, type const x[]) \
{ \
M_QU3UE_SPSC_CONTRACT(table); \
M_ASSERT (x != NULL); \
M_ASSERT (n <= table->size); \
M_GLOBAL_CONTEXT(); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_relaxed); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
@@ -1150,12 +1026,12 @@ M_F(name, _init)(buffer_t v, size_t size) \
return max; \
} \
\
M_INLINE unsigned \
M_F(name, _pop_bulk)(unsigned int n, type ptr[], buffer_t table) \
M_N(unsigned, name, _pop_bulk, unsigned n, type ptr[], buffer_t table) \
{ \
M_QU3UE_SPSC_CONTRACT(table); \
M_ASSERT (ptr != NULL); \
M_ASSERT (n <= table->size); \
M_GLOBAL_CONTEXT(); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
memory_order_relaxed); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
@@ -1168,7 +1044,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
M_CALL_SET(oplist, ptr[k], table->Tab[i].x); \
} else { \
M_DO_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \
M_CALL_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \
} \
} \
atomic_store_explicit(&table->consoIdx, r+max, memory_order_release); \
@@ -1176,10 +1052,10 @@ M_F(name, _init)(buffer_t v, size_t size) \
return max; \
} \
\
M_INLINE void \
M_F(name, _push_force)(buffer_t table, type const x) \
M_N(void, name, _push_force, buffer_t table, type const x) \
{ \
M_QU3UE_SPSC_CONTRACT(table); \
M_GLOBAL_CONTEXT(); \
unsigned int r = atomic_load_explicit(&table->consoIdx, \
memory_order_relaxed); \
unsigned int w = atomic_load_explicit(&table->prodIdx, \
@@ -1238,20 +1114,18 @@ M_F(name, _init)(buffer_t v, size_t size) \
return M_F(name, _size)(v) >= v->size; \
} \
\
M_INLINE void \
M_F(name, _init)(buffer_t buffer, size_t size) \
M_N(void, name, _init, buffer_t buffer, size_t size) \
{ \
M_ASSERT (buffer != NULL); \
M_ASSERT( M_POWEROF2_P(size)); \
M_ASSERT (0 < size && size <= UINT_MAX); \
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \
M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \
M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \
M_GLOBAL_CONTEXT(); \
atomic_init(&buffer->prodIdx, (unsigned int) size); \
atomic_init(&buffer->consoIdx, (unsigned int) size); \
buffer->size = (unsigned int) size; \
buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, size); \
buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \
if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \
M_MEMORY_FULL (size*sizeof(M_F(name, _el_ct) )); \
return; \
M_MEMORY_FULL (M_F(name, _el_ct), size); \
} \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < (unsigned int) size; j++) { \
@@ -1261,10 +1135,10 @@ M_F(name, _init)(buffer_t v, size_t size) \
M_QU3UE_SPSC_CONTRACT(buffer); \
} \
\
M_INLINE void \
M_F(name, _clear)(buffer_t buffer) \
M_N(void, name, _clear, buffer_t buffer) \
{ \
M_QU3UE_SPSC_CONTRACT(buffer); \
M_GLOBAL_CONTEXT(); \
if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \
for(unsigned int j = 0; j < buffer->size; j++) { \
M_CALL_CLEAR(oplist, buffer->Tab[j].x); \
@@ -1281,7 +1155,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
j = 0; \
} \
} \
M_CALL_FREE(oplist, buffer->Tab); \
M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, buffer->size); \
buffer->Tab = NULL; /* safer */ \
buffer->size = 3; \
} \
@@ -1303,7 +1177,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
/* OPLIST definition of a buffer */
#define M_BUFF3R_OPLIST_P3(name, oplist) \
(INIT(M_C3(m_buff3r_,name, _init)) \
(INIT(M_F(name, _i_init)) \
,INIT_SET(M_F(name, _init_set)) \
,SET(M_F(name, _set)) \
,CLEAR(M_F(name, _clear)) \
@@ -1319,8 +1193,18 @@ M_F(name, _init)(buffer_t v, size_t size) \
,GET_SIZE(M_F(name, _size)) \
)
/********************************** INTERNAL *********************************/
/* Same as M_EMPLACE_QUEUE_GENE but use M_GLOBAL_CONTEXT */
#define M_BUFF3R_EMPLACE_QUEUE_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_N(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_GET_TYPE oplist data; \
M_GLOBAL_CONTEXT(); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \
M_F(name, _push)(v, data); \
M_CALL_CLEAR(oplist, data); \
}
/********************************** INTERNAL *********************************/
#if M_USE_SMALL_NAME
#define BUFFER_DEF M_BUFFER_DEF
@@ -1334,14 +1218,6 @@ M_F(name, _init)(buffer_t v, size_t size) \
#define buffer_policy_e m_buffer_policy_e
#define BUFFER_QUEUE M_BUFFER_QUEUE
#define BUFFER_STACK M_BUFFER_STACK
#define BUFFER_BLOCKING_PUSH M_BUFFER_BLOCKING_PUSH
#define BUFFER_UNBLOCKING_PUSH M_BUFFER_UNBLOCKING_PUSH
#define BUFFER_BLOCKING_POP M_BUFFER_BLOCKING_POP
#define BUFFER_UNBLOCKING_POP M_BUFFER_UNBLOCKING_POP
#define BUFFER_BLOCKING M_BUFFER_BLOCKING
#define BUFFER_UNBLOCKING M_BUFFER_UNBLOCKING
#define BUFFER_THREAD_SAFE M_BUFFER_THREAD_SAFE
#define BUFFER_THREAD_UNSAFE M_BUFFER_THREAD_UNSAFE
#define BUFFER_PUSH_INIT_POP_MOVE M_BUFFER_PUSH_INIT_POP_MOVE
#define BUFFER_PUSH_OVERWRITE M_BUFFER_PUSH_OVERWRITE
#define BUFFER_DEFERRED_POP M_BUFFER_DEFERRED_POP
-835
View File
@@ -1,835 +0,0 @@
/*
* M*LIB - Concurrent memory pool allocator
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_CONCURRENT_MEMPOOL_H
#define MSTARLIB_CONCURRENT_MEMPOOL_H
#include "m-core.h"
#include "m-atomic.h"
#include "m-genint.h"
M_BEGIN_PROTECTED_CODE
/* Minimum number of nodes per group of nodes */
#define M_CMEMP00L_MIN_NODE_PER_GROUP 16
#define M_C_MEMPOOL_DEF(name, type_t) \
M_BEGIN_PROTECTED_CODE \
M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
M_END_PROTECTED_CODE
/* Classic internal Singly List without allocation */
#define M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \
\
typedef struct M_F(name, _slist_node_s) { \
struct M_F(name, _slist_node_s) *next; \
type_t data; \
} M_F(name, _slist_node_ct); \
\
typedef struct M_F(name, _slist_node_s) *M_F(name, _slist_ct)[1]; \
\
M_INLINE void \
M_F(name, _slist_init)(M_F(name, _slist_ct) list) \
{ \
*list = NULL; \
} \
\
M_INLINE void \
M_F(name, _slist_push)(M_F(name, _slist_ct) list, \
M_F(name, _slist_node_ct) *node) \
{ \
node->next = *list; \
*list = node; \
} \
\
M_INLINE M_F(name, _slist_node_ct) * \
M_F(name, _slist_pop)(M_F(name, _slist_ct) list) \
{ \
M_ASSERT (*list != NULL); \
M_F(name, _slist_node_ct) *node = *list; \
*list = node->next; \
M_IF_DEBUG(node->next = NULL;) \
return node; \
} \
\
M_INLINE bool \
M_F(name, _slist_empty_p)(M_F(name, _slist_ct) list) \
{ \
return *list == NULL; \
} \
\
M_INLINE void \
M_F(name, _slist_move)(M_F(name, _slist_ct) list, \
M_F(name, _slist_ct) src) \
{ \
*list = *src; \
*src = NULL; \
} \
\
M_INLINE void \
M_F(name, _slist_clear)(M_F(name, _slist_ct) list) \
{ \
M_F(name, _slist_node_ct) *it = *list, *next; \
while (it) { \
next = it->next; \
M_MEMORY_DEL(it); \
it = next; \
} \
*list = NULL; \
} \
/* Lock Free free queue list (not generic one) of lists without allocation
Based on Michael & Scott Lock Free Queue List algorithm.
Each list is considered empty if there is only one node within.
This LF Queue List doesn't try to prevent the ABA problem. It is up to the
caller to avoid recycling the nodes too fast.
Each list has its own unique NIL ptr in order to avoid issues when
migrating a node from a Q to another: in the following scenario,
- Thread 1 performs a PUSH of N in Q1 with Q1 empty (only node is NA)
NA.next is NIL.
- Thread 1 is interrupted just before the CAS on NA.next
- Thread 2 performs a successful push of NB in Q1. NA.next is set to NB.
- Thread 2 performs a successful pop of NA in Q1
- Thread 2 performs a successful push of NA in Q2. NA.next is set to NIL.
- Thread 1 is restored and will succeed as NA.next is once again NIL.
In order to prevent the last CAS to succeed, each queue uses its own NIL pointer.
It is a derived problem of the ABA problem.
*/
/* TODO: Optimize alignment to reduce memory consumption. NIL object can use []
to reduce memory consumption too (non compatible with C++ ...) */
#define M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \
\
typedef struct M_F(name, _lf_node_s) { \
M_ATTR_EXTENSION _Atomic(struct M_F(name, _lf_node_s) *) next; \
m_gc_atomic_ticket_ct cpt; \
M_F(name, _slist_ct) list; \
} M_F(name, _lf_node_t); \
\
typedef struct M_F(name, _lflist_s) { \
M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) head; \
char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) tail; \
char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \
M_F(name, _lf_node_t) nil; \
} M_F(name, _lflist_ct)[1]; \
\
M_INLINE void \
M_F(name, _lflist_init)(M_F(name, _lflist_ct) list, \
M_F(name, _lf_node_t) *node) \
{ \
atomic_init(&list->head, node); \
atomic_init(&list->tail, node); \
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
} \
\
M_INLINE bool \
M_F(name, _lflist_empty_p)(M_F(name, _lflist_ct) list) \
{ \
return atomic_load(&list->tail) == atomic_load(&list->head); \
} \
\
M_INLINE void \
M_F(name, _lflist_push)(M_F(name, _lflist_ct) list, \
M_F(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \
{ \
M_F(name, _lf_node_t) *tail; \
M_F(name, _lf_node_t) *next; \
\
atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \
m_core_backoff_reset(bkoff); \
while (true) { \
tail = atomic_load(&list->tail); \
next = atomic_load_explicit(&tail->next, memory_order_acquire); \
if (M_UNLIKELY(next != &list->nil)) { \
/* Tail was not pointing to the last node \
Try to swing Tail to the next node */ \
atomic_compare_exchange_weak_explicit(&list->tail, \
&tail, next, \
memory_order_release, \
memory_order_relaxed); \
} else { \
/* Try to link node at the end of the linked list */ \
if (atomic_compare_exchange_strong_explicit(&tail->next, \
&next, node, \
memory_order_release, \
memory_order_relaxed)) \
break; \
m_core_backoff_wait(bkoff); \
} \
} \
/* Enqueue is done. Try to swing Tail to the inserted node \
If it fails, someone else will do it or has already did it. */ \
atomic_compare_exchange_strong_explicit(&list->tail, &tail, node, \
memory_order_acq_rel, \
memory_order_relaxed); \
} \
\
M_INLINE M_F(name, _lf_node_t) * \
M_F(name, _lflist_pop)(M_F(name, _lflist_ct) list, m_core_backoff_ct bkoff) \
{ \
M_F(name, _lf_node_t) *head; \
M_F(name, _lf_node_t) *tail; \
M_F(name, _lf_node_t) *next; \
\
/* Reinitialize backoff */ \
m_core_backoff_reset(bkoff); \
while (true) { \
head = atomic_load(&list->head); \
tail = atomic_load(&list->tail); \
next = atomic_load(&head->next); \
/* Are head, tail, and next consistent?*/ \
if (M_LIKELY(head == \
atomic_load_explicit(&list->head, memory_order_relaxed))) \
{ \
/* Is queue empty or Tail falling behind? */ \
if (head == tail) { \
/* Is queue empty? */ \
if (next == &list->nil) \
return NULL; \
/* Tail is falling behind. Try to advance it */ \
atomic_compare_exchange_strong_explicit(&list->tail, &tail, \
next, \
memory_order_release, \
memory_order_relaxed); \
} else { \
/* Try to swing Head to the next node */ \
if (atomic_compare_exchange_strong_explicit(&list->head, \
&head, next, \
memory_order_release, \
memory_order_relaxed)) { \
break; \
} \
/* Failure: perform a random exponential backoff */ \
m_core_backoff_wait(bkoff); \
} \
} \
} \
/* dequeue returns an element that becomes the new dummy element (the new head), \
and the former dummy element (the former head) is removed: \
Since we want a link of free list, and we don't care about the content itself, \
provided that the node we return is older than the one we should return, \
Therefore, we return the previous dummy head. \
As such, it is not the original MSqueue algorithm. */ \
M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \
return head; \
} \
\
/* Dequeue a node if the node is old enough */ \
M_INLINE M_F(name, _lf_node_t) * \
M_F(name, _lflist_pop_if)(M_F(name, _lflist_ct) list, \
m_gc_ticket_ct age, m_core_backoff_ct bkoff) \
{ \
M_F(name, _lf_node_t) *head; \
M_F(name, _lf_node_t) *tail; \
M_F(name, _lf_node_t) *next; \
\
m_core_backoff_reset(bkoff); \
while (true) { \
head = atomic_load(&list->head); \
tail = atomic_load(&list->tail); \
next = atomic_load(&head->next); \
if (M_LIKELY(head == atomic_load_explicit(&list->head, memory_order_relaxed))) \
{ \
if (head == tail) { \
if (next == &list->nil) \
return NULL; \
atomic_compare_exchange_strong_explicit(&list->tail, &tail, next, \
memory_order_release, \
memory_order_relaxed); \
} else { \
/* Test if the node is old enough to be popped */ \
if (atomic_load_explicit(&next->cpt, memory_order_relaxed) >= age) \
return NULL; \
/* Try to swing Head to the next node */ \
if (atomic_compare_exchange_strong_explicit(&list->head, \
&head, next, \
memory_order_release, \
memory_order_relaxed)) { \
break; \
} \
m_core_backoff_wait(bkoff); \
} \
} \
} \
M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \
return head; \
} \
\
M_INLINE void \
M_F(name, _lflist_clear)(M_F(name, _lflist_ct) list) \
{ \
m_core_backoff_ct bkoff; \
m_core_backoff_init(bkoff); \
while (true) { \
M_F(name, _lf_node_t) *node = M_F(name, _lflist_pop)(list, bkoff); \
if (node == NULL) break; \
M_F(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \
memory_order_relaxed); \
M_F(name, _slist_clear)(node->list); \
M_MEMORY_DEL(node); \
node = next; \
} \
/* Dummy node to free too */ \
M_F(name, _lf_node_t) *dummy; \
dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \
M_F(name, _slist_clear)(dummy->list); \
M_MEMORY_DEL(dummy); \
} \
/* System node allocator: request memory to the system.
As such it is a non Lock-Free path. */
#define M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \
\
M_INLINE M_F(name, _lf_node_t) * \
M_F(name, _alloc_node)(unsigned int initial) \
{ \
M_F(name, _lf_node_t) * node; \
node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \
if (M_UNLIKELY_NOMEM (node == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \
return NULL; \
} \
atomic_init(&node->next, (M_F(name, _lf_node_t) *) 0); \
atomic_init(&node->cpt, 0UL); \
M_F(name, _slist_init)(node->list); \
for(unsigned i = 0; i < initial; i++) { \
M_F(name, _slist_node_ct) *n; \
n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \
if (M_UNLIKELY_NOMEM (n == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \
return NULL; \
} \
M_F(name, _slist_push)(node->list, n); \
} \
return node; \
} \
/* Concurrent Memory pool
The data structure is the following.
Each thread has its own pool of nodes (local) that only it can
access (it is a singly list). If there is no longer any node in this
pool, it requests a new pool to the lock free queue of pool (group of
nodes). If it fails, it requests a new pool to the system allocator
(and from there it is no longer lock free).
This memory pool can only be lock free if the initial state is
sufficiently dimensioned to avoid calling the system allocator during
the normal processing.
Then each thread pushes its deleted node into another pool of nodes,
where the node is logically deleted (no contain of the node is destroyed
at this point and the node can be freely accessed by other threads).
Once the thread mempool is put to sleep, the age of the pool of logical
deleted nodes is computed and this pool is move to the Lock Free Queue
List of pools to be reclaimed. Then A Garbage Collector is performed
on this Lock Free Queue list to reclaim all pools that are sufficiently
aged (taking into account the grace period of the pool) to be moved back
to the Lock Free Queue of the free pools.
Each pool of nodes can be in the following state:
* FREE state if it is present in the Lock Free Queue of free pools.
* EMPTY state if it is present in the Lock Free Queue of empty pools
which means that the nodes present in it has been USED directly by a thread,
* TO_BE_RECLAIMED state if it is present in the Lock Free Queue of TBR pools
A pool of nodes will go to the following state:
FREE --> EMPTY --> TO_BE_RECLAIMED
^ |
+----------------------+
The ABA problem is taken into account as a node cannot be reused in the
same queue without performing a full cycle of its state. Moreover
it can only move from TO_BE_RECLAIMED to FREE if and only if a grace
period is finished (and then we are sure that no thread references any
older node).
Each thread has its own backoff structure (with local pseudo-random
generator).
The grace period is detected through a global age counter (ticket)
that is incremented each time a thread is awaken / sleep.
Each thread has its own age that is set to the global ticket on sleep/awaken.
The age of the pool to be reclaimed is also set to this global age counter.
To ensure that the grace period is finished, it tests if all threads
are younger than the age of the pool to be reclaimed.
From a performance point of view, this puts a bottleneck on the global
age counter that is shared and incremented by all threads. However,
the sleep/awaken operations are much less frequent than other operations.
Thus, it shall not have a huge impact on the performance if the user
code is intelligent with the sleep/awaken operations.
As such it won't support more than ULONG_MAX sleep for all threads.
*/
#define M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \
\
typedef struct M_F(name, _lfmp_thread_s) { \
M_F(name, _slist_ct) free; \
M_F(name, _slist_ct) to_be_reclaimed; \
M_CACHELINE_ALIGN(align1, M_F(name, _slist_ct), M_F(name, _slist_ct)); \
} M_F(name, _lfmp_thread_ct); \
\
M_INLINE void \
M_F(name, _lfmp_thread_init)(M_F(name, _lfmp_thread_ct) *t) \
{ \
M_F(name, _slist_init)(t->free); \
M_F(name, _slist_init)(t->to_be_reclaimed); \
} \
\
M_INLINE void \
M_F(name, _lfmp_thread_clear)(M_F(name, _lfmp_thread_ct) *t) \
{ \
M_ASSERT(M_F(name, _slist_empty_p)(t->to_be_reclaimed)); \
M_F(name, _slist_clear)(t->free); \
M_F(name, _slist_clear)(t->to_be_reclaimed); \
} \
/* NOTE: once a node is deleted, its data are kept readable until the future GC */
#define M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \
\
typedef struct M_F(name, _s) { \
unsigned initial; \
M_F(name, _lfmp_thread_ct) *thread_data; \
M_F(name, _lflist_ct) free; \
M_F(name, _lflist_ct) to_be_reclaimed; \
M_F(name, _lflist_ct) empty; \
m_cmemp00l_list_ct mempool_node; \
struct m_gc_s *gc_mem; \
} M_F(name, _t)[1]; \
\
/* Garbage collect of the nodes of the mempool on sleep */ \
M_INLINE void \
M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_cmemp00l_list_ct *data, \
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \
{ \
/* Get back the mempool from the node */ \
struct M_F(name, _s) *mempool = \
M_TYPE_FROM_FIELD(struct M_F(name, _s), data, m_cmemp00l_list_ct, mempool_node); \
\
/* Move the local nodes of the mempool to be reclaimed to the thread into the global pool */ \
if (!M_F(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \
M_F(name, _lf_node_t) *node; \
/* Get a new empty group of nodes */ \
node = M_F(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \
if (M_UNLIKELY (node == NULL)) { \
/* Fail to get an empty group of node. \
Alloc a new one from the system */ \
node = M_F(name, _alloc_node)(0); \
M_ASSERT(node != NULL); \
} \
M_ASSERT(M_F(name, _slist_empty_p)(node->list)); \
M_F(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \
atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); \
M_F(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \
} \
\
/* Perform a GC of the freelist of nodes */ \
while (true) { \
M_F(name, _lf_node_t) *node; \
node = M_F(name, _lflist_pop_if)(mempool->to_be_reclaimed, \
min_ticket, gc_mem->thread_data[id].bkoff); \
if (node == NULL) break; \
M_F(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \
} \
} \
\
M_INLINE void \
M_F(name, _init)(M_F(name, _t) mem, m_gc_t gc_mem, \
unsigned init_node_count, unsigned init_group_count) \
{ \
const size_t max_thread = gc_mem->max_thread; \
/* Initialize the thread data of the mempool */ \
mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, max_thread); \
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \
M_MEMORY_FULL(max_thread * sizeof(M_F(name, _lfmp_thread_ct))); \
return; \
} \
for(unsigned i = 0; i < max_thread;i++) { \
M_F(name, _lfmp_thread_init)(&mem->thread_data[i]); \
} \
/* Preallocate some group of nodes for the mempool */ \
mem->initial = M_MAX(M_CMEMP00L_MIN_NODE_PER_GROUP, init_node_count); \
M_F(name, _lflist_init)(mem->free, M_F(name, _alloc_node)(init_node_count)); \
M_F(name, _lflist_init)(mem->to_be_reclaimed, M_F(name, _alloc_node)(init_node_count)); \
M_F(name, _lflist_init)(mem->empty, M_F(name, _alloc_node)(0)); \
for(unsigned i = 1; i < init_group_count; i++) { \
M_F(name, _lflist_push)(mem->free, M_F(name, _alloc_node)(init_node_count), \
gc_mem->thread_data[0].bkoff); \
M_F(name, _lflist_push)(mem->empty, M_F(name, _alloc_node)(0), \
gc_mem->thread_data[0].bkoff); \
} \
/* Register the mempool in the GC */ \
mem->mempool_node.gc_on_sleep = M_C3(m_cmemp00l_,name,_gc_on_sleep); \
mem->mempool_node.next = gc_mem->mempool_list; \
gc_mem->mempool_list = &mem->mempool_node; \
mem->gc_mem = gc_mem; \
} \
\
M_INLINE void \
M_F(name, _clear)(M_F(name, _t) mem) \
{ \
const unsigned max_thread = mem->gc_mem->max_thread; \
for(unsigned i = 0; i < max_thread;i++) { \
M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \
} \
M_MEMORY_FREE(mem->thread_data); \
mem->thread_data = NULL; \
M_F(name, _lflist_clear)(mem->empty); \
M_F(name, _lflist_clear)(mem->free); \
M_ASSERT(M_F(name, _lflist_empty_p)(mem->to_be_reclaimed)); \
M_F(name, _lflist_clear)(mem->to_be_reclaimed); \
/* TODO: Unregister from the GC? */ \
} \
\
M_INLINE type_t * \
M_F(name, _new)(M_F(name, _t) mem, m_gc_tid_t id) \
{ \
M_F(name, _slist_node_ct) *snode; \
M_F(name, _lf_node_t) *node; \
while (true) { \
/* Fast & likely path where we access the thread pool of nodes */ \
if (M_LIKELY(!M_F(name, _slist_empty_p)(mem->thread_data[id].free))) { \
snode = M_F(name, _slist_pop)(mem->thread_data[id].free); \
return &snode->data; \
} \
/* Request a group node to the freelist of groups */ \
node = M_F(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \
if (M_UNLIKELY (node == NULL)) { \
/* Request a new group to the system. Non Lock Free path */ \
M_ASSERT(mem->initial > 0); \
node = M_F(name, _alloc_node)(mem->initial); \
M_ASSERT(node != NULL); \
M_ASSERT(!M_F(name, _slist_empty_p)(node->list)); \
} \
M_F(name, _slist_move)(mem->thread_data[id].free, node->list); \
/* Push back the empty group */ \
M_ASSERT (M_F(name, _slist_empty_p)(node->list)); \
M_F(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \
} \
} \
\
M_INLINE void \
M_F(name, _del)(M_F(name, _t) mem, type_t *d, m_gc_tid_t id) \
{ \
M_F(name, _slist_node_ct) *snode; \
M_ASSERT( d != NULL); \
snode = M_TYPE_FROM_FIELD(M_F(name, _slist_node_ct), d, type_t, data); \
M_F(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \
} \
/***********************************************************************/
/* Define the ID of a thread */
typedef unsigned int m_gc_tid_t;
/* Define the age of a node */
/* TODO: Compute if sufficient (worst cast ULONG_MAX is 32 bits) */
typedef unsigned long m_gc_ticket_ct;
typedef atomic_ulong m_gc_atomic_ticket_ct;
/* Define the Linked List of mempools that are registered in the GC */
struct m_gc_s;
typedef struct m_cmemp00l_list_s {
struct m_cmemp00l_list_s *next;
void (*gc_on_sleep)(struct m_gc_s *gc_mem,
struct m_cmemp00l_list_s *data, m_gc_tid_t id,
m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket);
void *data;
} m_cmemp00l_list_ct;
/* Define the Garbage collector thread data */
typedef struct m_gc_lfmp_thread_s {
m_gc_atomic_ticket_ct ticket;
m_core_backoff_ct bkoff;
M_CACHELINE_ALIGN(align1, atomic_ulong, m_core_backoff_ct);
} m_gc_lfmp_thread_ct;
/* Define the Garbage collector coordinator */
typedef struct m_gc_s {
m_gc_atomic_ticket_ct ticket;
m_gc_tid_t max_thread;
m_genint_t thread_alloc;
m_gc_lfmp_thread_ct *thread_data;
m_cmemp00l_list_ct *mempool_list;
} m_gc_t[1];
M_INLINE void
m_gc_init(m_gc_t gc_mem, size_t max_thread)
{
M_ASSERT(gc_mem != NULL);
M_ASSERT(max_thread > 0 && max_thread < INT_MAX);
atomic_init(&gc_mem->ticket, 0UL);
m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread);
gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, max_thread);
if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) {
M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct));
return;
}
for(unsigned i = 0; i < max_thread;i++) {
atomic_init(&gc_mem->thread_data[i].ticket, ULONG_MAX);
m_core_backoff_init(gc_mem->thread_data[i].bkoff);
}
gc_mem->max_thread = (unsigned int) max_thread;
gc_mem->mempool_list = NULL;
}
M_INLINE void
m_gc_clear(m_gc_t gc_mem)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
for(m_gc_tid_t i = 0; i < gc_mem->max_thread;i++) {
m_core_backoff_clear(gc_mem->thread_data[i].bkoff);
}
M_MEMORY_FREE(gc_mem->thread_data);
gc_mem->thread_data = NULL;
m_genint_clear(gc_mem->thread_alloc);
}
M_INLINE m_gc_tid_t
m_gc_attach_thread(m_gc_t gc_mem)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
unsigned id = m_genint_pop(gc_mem->thread_alloc);
return M_ASSIGN_CAST(m_gc_tid_t, id);
}
M_INLINE void
m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
M_ASSERT(id < gc_mem->max_thread);
M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX);
m_genint_push(gc_mem->thread_alloc, id);
}
M_INLINE void
m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id)
{
M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0);
M_ASSERT(id < gc_mem->max_thread);
M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX);
m_gc_ticket_ct t = atomic_fetch_add(&gc_mem->ticket, 1UL) + 1;
atomic_store(&gc_mem->thread_data[id].ticket, t);
}
M_INLINE m_gc_ticket_ct
m_cmemp00l_gc_min_ticket(m_gc_t gc_mem)
{
m_gc_ticket_ct min = atomic_load(&gc_mem->thread_data[0].ticket);
for(m_gc_tid_t i = 1; i < gc_mem->max_thread; i++) {
m_gc_ticket_ct t = atomic_load(&gc_mem->thread_data[i].ticket);
min = M_MIN(t, min);
}
return min;
}
M_INLINE void
m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id)
{
/* Increase life time of the thread */
m_gc_ticket_ct t = atomic_fetch_add(&gc_mem->ticket, 1UL);
atomic_store(&gc_mem->thread_data[id].ticket, t+1);
const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem);
/* Iterate over all registered mempools */
m_cmemp00l_list_ct *it = gc_mem->mempool_list;
while (it) {
/* Perform a garbage collect of the mempool */
it->gc_on_sleep(gc_mem, it, id, t, min_ticket);
/* Next mempool to scan for GC */
it = it->next;
}
/* Sleep the thread */
atomic_store(&gc_mem->thread_data[id].ticket, ULONG_MAX);
}
/***********************************************************************/
/* */
/* Variable Length Array MEMPOOL */
/* */
/***********************************************************************/
M_CMEMP00L_DEF_SINGLY_LIST(m_vlapool, char)
M_CMEMP00L_DEF_LF_QUEUE(m_vlapool, char)
M_CMEMP00L_DEF_SYSTEM_ALLOC(m_vlapool, char)
typedef struct m_vlapool_lfmp_thread_s {
m_vlapool_slist_ct to_be_reclaimed;
M_CACHELINE_ALIGN(align1, m_vlapool_slist_ct);
} m_vlapool_lfmp_thread_ct;
M_INLINE void
m_vlapool_lfmp_thread_init(m_vlapool_lfmp_thread_ct *t)
{
m_vlapool_slist_init(t->to_be_reclaimed);
}
M_INLINE void
m_vlapool_lfmp_thread_clear(m_vlapool_lfmp_thread_ct *t)
{
M_ASSERT(m_vlapool_slist_empty_p(t->to_be_reclaimed));
m_vlapool_slist_clear(t->to_be_reclaimed);
}
typedef struct m_vlapool_s {
m_vlapool_lflist_ct to_be_reclaimed;
m_vlapool_lflist_ct empty;
m_vlapool_lfmp_thread_ct *thread_data;
m_cmemp00l_list_ct mvla_node;
struct m_gc_s *gc_mem;
} m_vlapool_t[1];
/* Garbage collect of the nodes of the vla mempool on sleep */
M_INLINE void
m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_cmemp00l_list_ct *data,
m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket)
{
/* Get back the mempool from the node */
struct m_vlapool_s *vlapool =
M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_cmemp00l_list_ct, mvla_node);
/* Move the local nodes of the vlapool to be reclaimed to the thread into the global pool */
if (!m_vlapool_slist_empty_p(vlapool->thread_data[id].to_be_reclaimed)) {
m_vlapool_lf_node_t *node;
/* Get a new empty group of nodes */
node = m_vlapool_lflist_pop(vlapool->empty, gc_mem->thread_data[id].bkoff);
if (M_UNLIKELY (node == NULL)) {
/* Fail to get an empty group of node.
Alloc a new one from the system */
node = m_vlapool_alloc_node(0);
M_ASSERT(node != NULL);
}
M_ASSERT(m_vlapool_slist_empty_p(node->list));
m_vlapool_slist_move(node->list, vlapool->thread_data[id].to_be_reclaimed);
atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed);
m_vlapool_lflist_push(vlapool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff);
}
/* Perform a GC of the freelist of nodes */
while (true) {
m_vlapool_lf_node_t *node;
node = m_vlapool_lflist_pop_if(vlapool->to_be_reclaimed,
min_ticket, gc_mem->thread_data[id].bkoff);
if (node == NULL) break;
// No reuse of VLA nodes. Free physically the node back to the system
m_vlapool_slist_clear(node->list);
// Add back the empty group of nodes
m_vlapool_slist_init(node->list);
m_vlapool_lflist_push(vlapool->empty, node, gc_mem->thread_data[id].bkoff);
}
}
M_INLINE void
m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem)
{
const size_t max_thread = gc_mem->max_thread;
/* Initialize the thread data of the vlapool */
mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, max_thread);
if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) {
M_MEMORY_FULL(max_thread * sizeof(m_vlapool_lfmp_thread_ct));
return;
}
for(unsigned i = 0; i < max_thread;i++) {
m_vlapool_lfmp_thread_init(&mem->thread_data[i]);
}
/* Initialize the lists */
m_vlapool_lflist_init(mem->to_be_reclaimed, m_vlapool_alloc_node(0));
m_vlapool_lflist_init(mem->empty, m_vlapool_alloc_node(0));
/* Register the mempool in the GC */
mem->mvla_node.gc_on_sleep = m_cmemp00l_vlapool_on_sleep;
mem->mvla_node.next = gc_mem->mempool_list;
gc_mem->mempool_list = &mem->mvla_node;
mem->gc_mem = gc_mem;
}
M_INLINE void
m_vlapool_clear(m_vlapool_t mem)
{
const unsigned max_thread = mem->gc_mem->max_thread;
for(unsigned i = 0; i < max_thread;i++) {
m_vlapool_lfmp_thread_clear(&mem->thread_data[i]);
}
M_MEMORY_FREE(mem->thread_data);
mem->thread_data = NULL;
m_vlapool_lflist_clear(mem->empty);
M_ASSERT(m_vlapool_lflist_empty_p(mem->to_be_reclaimed));
m_vlapool_lflist_clear(mem->to_be_reclaimed);
/* TODO: Unregister from the GC? */
}
M_INLINE void *
m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size)
{
M_ASSERT(mem != NULL && mem->gc_mem != NULL);
M_ASSERT(id < mem->gc_mem->max_thread);
M_ASSERT( atomic_load(&mem->gc_mem->thread_data[id].ticket) != ULONG_MAX);
// Nothing to do with theses parameters yet
(void) mem;
(void) id;
// Ensure the size is big enough to also represent a node
size += offsetof(struct m_vlapool_slist_node_s, data);
// Simply wrap around a system call to get the memory
char *ptr = M_MEMORY_REALLOC(char, NULL, size);
return (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data));
}
M_INLINE void
m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
{
M_ASSERT(mem != NULL && mem->gc_mem != NULL);
M_ASSERT(id < mem->gc_mem->max_thread);
M_ASSERT(atomic_load(&mem->gc_mem->thread_data[id].ticket) != ULONG_MAX);
M_ASSERT(d != NULL);
// Get back the pointer to a struct m_vlapool_slist_node_s.
d = M_ASSIGN_CAST(void *, M_ASSIGN_CAST(char *, d) - offsetof(struct m_vlapool_slist_node_s, data));
m_vlapool_slist_node_ct *snode = M_ASSIGN_CAST(m_vlapool_slist_node_ct *, d);
// Push the logically free memory into the list of the nodes to be reclaimed.
m_vlapool_slist_push(mem->thread_data[id].to_be_reclaimed, snode);
}
M_END_PROTECTED_CODE
#if M_USE_SMALL_NAME
#define C_MEMPOOL_DEF M_C_MEMPOOL_DEF
#endif
#endif
-907
View File
@@ -1,907 +0,0 @@
/*
* M*LIB - Basic Protected Concurrent module over container.
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_CONCURRENT_H
#define MSTARLIB_CONCURRENT_H
#include "m-core.h"
#include "m-thread.h"
#include "m-atomic.h"
/* Define a protected concurrent container and its associated functions
based on the given container.
USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */
#define M_CONCURRENT_DEF(name, ...) \
M_CONCURRENT_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
/* Define a protected concurrent container and its associated functions
based on the given container as the given name name_t
USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define M_CONCURRENT_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_C0NCURRENT_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
(name, __VA_ARGS__, name_t ))) \
M_END_PROTECTED_CODE
/* Define a protected concurrent container and its associated functions
based on its given container. Operations that perform only read of the container
can be done in parallel.
USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */
#define M_CONCURRENT_RP_DEF(name, ...) \
M_CONCURRENT_RP_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
/* Define a protected concurrent container and its associated functions
as the given name name_t
based on its given container. Operations that perform only read of the container
can be done in parallel.
USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */
#define M_CONCURRENT_RP_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_C0NCURRENT_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
(name, __VA_ARGS__, name_t ))) \
M_END_PROTECTED_CODE
/* Define the oplist of a protected concurrent container given its name and its oplist.
USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */
#define M_CONCURRENT_OPLIST(...) \
M_C0NCURRENT_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
/* Deferred evaluation for the oplist definition,
so that all arguments are evaluated before further expansion */
#define M_C0NCURRENT_OPLIST_P1(arg) M_C0NCURRENT_OPLIST_P2 arg
/* Validation of the given oplist */
#define M_C0NCURRENT_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(M_C0NCURRENT_OPLIST_P3, M_C0NCURRENT_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define M_C0NCURRENT_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* OPLIST definition
GET_KEY is not present as its interface is not compatible with a concurrent
container (_get returns a pointer to an internal data, data that may be
destroyed by another thread).
*/
#define M_C0NCURRENT_OPLIST_P3(name, oplist) \
(M_IF_METHOD(INIT, oplist)(INIT(M_F(name, _init)),) \
,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_F(name, _init_set)),) \
,M_IF_METHOD(SET, oplist)(SET(M_F(name, _set)),) \
,M_IF_METHOD(CLEAR, oplist)(CLEAR(M_F(name, _clear)),) \
,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_F(name, _init_move)),) \
,M_IF_METHOD(MOVE, oplist)(MOVE(M_F(name, _move)),) \
,M_IF_METHOD(SWAP,oplist)(SWAP(M_F(name, _swap)),) \
,NAME(name) \
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,OPLIST(oplist) \
,M_IF_METHOD(EMPTY_P, oplist)(EMPTY_P(M_F(name,_empty_p)),) \
,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_F(name,_size)),) \
,M_IF_METHOD(RESET, oplist)(RESET(M_F(name,_reset)),) \
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \
,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \
,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \
,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_OPLIST(M_GET_VALUE_OPLIST oplist), ) \
,M_IF_METHOD(SET_KEY, oplist)(SET_KEY(M_F(name, _set_at)),) \
,M_IF_METHOD(ERASE_KEY, oplist)(ERASE_KEY(M_F(name, _erase)),) \
,M_IF_METHOD(PUSH, oplist)(PUSH(M_F(name,_push)),) \
,M_IF_METHOD(POP, oplist)(POP(M_F(name,_pop)),) \
,M_IF_METHOD(PUSH_MOVE, oplist)(PUSH_MOVE(M_F(name,_push_move)),) \
,M_IF_METHOD(POP_MOVE, oplist)(POP_MOVE(M_F(name,_pop_move)),) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
/******************************** INTERNAL ***********************************/
/* Internal contract
NOTE: Can't check too much without locking the container itself
*/
#define M_C0NCURRENT_CONTRACT(c) do { \
M_ASSERT ((c) != NULL); \
M_ASSERT ((c)->self == (c)); \
} while (0)
/* Deferred evaluation for the concurrent definition,
so that all arguments are evaluated before further expansion */
#define M_C0NCURRENT_DEF_P1(arg) M_ID( M_C0NCURRENT_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_C0NCURRENT_DEF_P2(name, type, oplist, concurrent_t) \
M_IF_OPLIST(oplist)(M_C0NCURRENT_DEF_P3, M_C0NCURRENT_DEF_FAILURE)(name, type, oplist, concurrent_t)
/* Stop processing with a compilation failure */
#define M_C0NCURRENT_DEF_FAILURE(name, type, oplist, concurrent_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
/* Internal concurrent definition
- name: prefix to be used
- type: type of the sub container
- oplist: oplist of the type of the sub container
- concurrent_t: alias for M_F(name, _t) [ type of the container ]
*/
#define M_C0NCURRENT_DEF_P3(name, type, oplist, concurrent_t) \
M_C0NCURRENT_DEF_TYPE(name, type, oplist, concurrent_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_C0NCURRENT_DEF_CORE(name, type, oplist, concurrent_t) \
M_C0NCURRENT_DEF_COMMON(name, type, oplist, concurrent_t)
/* Define the type of a concurrent container */
#define M_C0NCURRENT_DEF_TYPE(name, type, oplist, concurrent_t) \
\
/* Define a concurrent container using a lock */ \
typedef struct M_F(name, _s) { \
struct M_F(name, _s) *self; \
m_mutex_t lock; \
m_cond_t there_is_data; /* condition raised when there is data */ \
type data; \
} concurrent_t[1]; \
\
/* Define alias for pointer types */ \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* Internal types for oplist */ \
typedef concurrent_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
\
/* Cannot define iterator as it cannot be reliable in a concurrent type */ \
/* Define the internal services used for the lock strategy */
#define M_C0NCURRENT_DEF_CORE(name, type, oplist, concurrent_t) \
\
/* Initial the fields of the concurrent object not associated to the \
sub-container. */ \
M_INLINE void \
M_F(name, _internal_init)(concurrent_t out) \
{ \
m_mutex_init(out->lock); \
m_cond_init(out->there_is_data); \
out->self = out; \
M_C0NCURRENT_CONTRACT(out); \
} \
\
/* Clear the fields of the concurrent object not associated to the \
sub-container. */ \
M_INLINE void \
M_F(name, _internal_clear)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_mutex_clear(out->lock); \
m_cond_clear(out->there_is_data); \
out->self = NULL; \
} \
\
/* Get the read lock. Multiple threads can get it, but only for reading. \
write lock is exclusive. \
NOTE: This instance doesn't implement the read/write strategy, \
and only get the lock */ \
M_INLINE void \
M_F(name, _read_lock)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_mutex_lock (out->self->lock); \
} \
\
/* Free the read lock. See above. \
NOTE: This instance doesn't implement the read/write strategy, \
and only get the lock */ \
M_INLINE void \
M_F(name, _read_unlock)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_mutex_unlock (out->self->lock); \
} \
\
/* Wait for a thread pushing some data in the container. \
CONSTRAINT: the read lock shall be get before calling this service */ \
M_INLINE void \
M_F(name, _read_wait)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_cond_wait(out->self->there_is_data, out->self->lock); \
} \
\
/* Get the write lock. Only one threads can get it, and no other threads \
can get the read lock too. \
NOTE: This instance doesn't implement the read/write strategy, \
and only get the lock */ \
M_INLINE void \
M_F(name, _write_lock)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_mutex_lock (out->lock); \
} \
\
/* Free the write lock. \
NOTE: This instance doesn't implement the read/write strategy, \
and only get the lock */ \
M_INLINE void \
M_F(name, _write_unlock)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_mutex_unlock (out->lock); \
} \
\
/* Wait for a thread pushing some data in the container. \
CONSTRAINT: the write lock shall be get before calling this service */ \
M_INLINE void \
M_F(name, _write_wait)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_cond_wait(out->self->there_is_data, out->self->lock); \
} \
\
/* Wait to all threads that some data are available in the container. \
CONSTRAINT: the write lock shall be get before calling this service */ \
M_INLINE void \
M_F(name, _write_signal)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
/* We need to signal this to ALL waiting threads as multiple threads \
may wait on a some data of this container. */ \
m_cond_broadcast(out->there_is_data); \
} \
/* Internal definition of the functions commons to concurrent and rp-concurrent
- name: prefix to be used
- type: type of the sub container
- oplist: oplist of the type of the sub container
- concurrent_t: alias for M_F(name, _t) [ type of the container ]
A function is defined only if the underlying container exports the needed
services. It is usually one service declared per service exported.
*/
#define M_C0NCURRENT_DEF_COMMON(name, type, oplist, concurrent_t) \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _init)(concurrent_t out) \
{ \
M_F(name, _internal_init)(out); \
M_CALL_INIT(oplist, out->data); \
M_C0NCURRENT_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(INIT_SET, oplist)( \
M_INLINE void \
M_F(name, _init_set)(concurrent_t out, concurrent_t const src) \
{ \
M_C0NCURRENT_CONTRACT(src); \
M_ASSERT (out != src); \
M_F(name, _internal_init)(out); \
M_F(name, _read_lock)(src); \
M_CALL_INIT_SET(oplist, out->data, src->data); \
M_F(name, _read_unlock)(src); \
M_C0NCURRENT_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(SET, oplist)( \
M_INLINE void \
M_F(name, _set)(concurrent_t out, concurrent_t const src) \
{ \
M_C0NCURRENT_CONTRACT(out); \
if (M_UNLIKELY (out == src)) return; \
/* Need to order the locks in a total way to avoid lock deadlock. \
Indeed, two call to _set can be done in two threads with : \
T1: A := B \
T2: B := A \
If we lock first the mutex of out, then the src, it could be possible \
in the previous scenario that both mutexes are locked: T1 has locked A \
and T2 has locked B, and T1 is waiting for locking B, and T2 is waiting \
for locking A, resulting in a deadlock. \
To avoid this problem, we **always** lock the mutex which address is \
the lowest. */ \
if (out < src) { \
M_F(name, _write_lock)(out); \
M_F(name, _read_lock)(src); \
} else { \
M_F(name, _read_lock)(src); \
M_F(name, _write_lock)(out); \
} \
M_CALL_SET(oplist, out->data, src->data); \
if (out < src) { \
M_F(name, _read_unlock)(src); \
M_F(name, _write_unlock)(out); \
} else { \
M_F(name, _write_unlock)(out); \
M_F(name, _read_unlock)(src); \
} \
M_C0NCURRENT_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(CLEAR, oplist)( \
M_INLINE void \
M_F(name, _clear)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
/* No need to lock. A clear is supposed to be called when all operations \
of the container in other threads are terminated */ \
M_CALL_CLEAR(oplist, out->data); \
M_F(name, _internal_clear)(out); \
} \
,) \
\
M_IF_METHOD(INIT_MOVE, oplist)( \
M_INLINE void \
M_F(name, _init_move)(concurrent_t out, concurrent_t src) \
{ \
M_C0NCURRENT_CONTRACT(src); \
M_ASSERT (out != src); \
/* No need to lock 'src' ? */ \
M_F(name, _internal_init)(out); \
M_CALL_INIT_MOVE(oplist, out->data, src->data); \
M_F(name, _internal_clear)(src); \
M_C0NCURRENT_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(MOVE, oplist)( \
M_INLINE void \
M_F(name, _move)(concurrent_t out, concurrent_t src) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_C0NCURRENT_CONTRACT(src); \
/* No need to lock 'src' ? */ \
M_F(name, _write_lock)(out); \
M_CALL_MOVE(oplist, out->data, src->data); \
M_F(name, _write_unlock)(out); \
M_F(name, _internal_clear)(src); \
M_C0NCURRENT_CONTRACT(out); \
} \
,) \
\
M_IF_METHOD(SWAP, oplist)( \
M_INLINE void \
M_F(name, _swap)(concurrent_t out, concurrent_t src) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_C0NCURRENT_CONTRACT(src); \
if (M_UNLIKELY (out == src)) return; \
/* See comment above */ \
if (out < src) { \
M_F(name, _write_lock)(out); \
M_F(name, _write_lock)(src); \
} else { \
M_F(name, _write_lock)(src); \
M_F(name, _write_lock)(out); \
} \
M_CALL_SWAP(oplist, out->data, src->data); \
if (out < src) { \
M_F(name, _write_unlock)(src); \
M_F(name, _write_unlock)(out); \
} else { \
M_F(name, _write_unlock)(out); \
M_F(name, _write_unlock)(src); \
} \
} \
,) \
\
M_IF_METHOD(RESET, oplist)( \
M_INLINE void \
M_F(name, _reset)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
M_CALL_RESET(oplist, out->data); \
M_F(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(EMPTY_P, oplist)( \
M_INLINE bool \
M_F(name, _empty_p)(concurrent_t const out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _read_lock)(out); \
bool b = M_CALL_EMPTY_P(oplist, out->data); \
M_F(name, _read_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(GET_SIZE, oplist)( \
M_INLINE size_t \
M_F(name, _size)(concurrent_t const out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _read_lock)(out); \
size_t r = M_CALL_GET_SIZE(oplist, out->data); \
M_F(name, _read_unlock)(out); \
return r; \
} \
,) \
\
M_IF_METHOD(SET_KEY, oplist)( \
M_INLINE void \
M_F(name, _set_at)(concurrent_t out, M_GET_KEY_TYPE oplist const key, M_GET_VALUE_TYPE oplist const data) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
M_CALL_SET_KEY(oplist, out->data, key, data); \
M_F(name, _write_signal)(out); \
M_F(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(GET_KEY, oplist)( \
M_INLINE bool \
M_F(name, _get_copy)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT (out_data != NULL); \
M_F(name, _read_lock)(out); \
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \
if (p != NULL) { \
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
} \
M_F(name, _read_unlock)(out); \
return p != NULL; \
} \
,) \
\
M_IF_METHOD(SAFE_GET_KEY, oplist)( \
M_INLINE void \
M_F(name, _safe_get_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT (out_data != NULL); \
M_F(name, _write_lock)(out); \
M_GET_VALUE_TYPE oplist *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \
M_ASSERT (p != NULL); \
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
M_F(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(ERASE_KEY, oplist)( \
M_INLINE bool \
M_F(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \
/* We suppose that the container has 'infinite' capacity, so \
we won't signal that a free space has been created */ \
M_F(name, _write_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(PUSH, oplist)( \
M_INLINE void \
M_F(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
M_CALL_PUSH(oplist, out->data, data); \
M_F(name, _write_signal)(out); \
M_F(name, _write_unlock)(out); \
} \
\
M_EMPLACE_QUEUE_DEF(name, concurrent_t, M_F(name, _emplace), M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \
,) \
\
M_IF_METHOD(POP, oplist)( \
M_INLINE void \
M_F(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
M_CALL_POP(oplist, p, out->data); \
/* See comment above */ \
M_F(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(PUSH_MOVE, oplist)( \
M_INLINE void \
M_F(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
M_CALL_PUSH_MOVE(oplist, out->data, data); \
M_F(name, _write_signal)(out); \
M_F(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(POP_MOVE, oplist)( \
M_INLINE void \
M_F(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
M_CALL_POP_MOVE(oplist, p, out->data); \
/* See comment above */ \
M_F(name, _write_unlock)(out); \
} \
,) \
\
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, concurrent_t const out, bool a) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _read_lock)(out); \
M_CALL_GET_STR(oplist, str, out->data, a); \
M_F(name, _read_unlock)(out); \
} \
,) \
\
M_IF_METHOD(OUT_STR, oplist)( \
M_INLINE void \
M_F(name, _out_str)(FILE *f, concurrent_t const out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _read_lock)(out); \
M_CALL_OUT_STR(oplist, f, out->data); \
M_F(name, _read_unlock)(out); \
} \
,) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(concurrent_t out, const char str[], const char **e) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \
M_F(name, _write_signal)(out); \
M_F(name, _write_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(concurrent_t out, FILE *f) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
bool b = M_CALL_IN_STR(oplist, out->data, f); \
M_F(name, _write_signal)(out); \
M_F(name, _write_unlock)(out); \
return b; \
} \
,) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, concurrent_t const out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _read_lock)(out); \
m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, f, out->data); \
M_F(name, _read_unlock)(out); \
return r; \
} \
,) \
\
M_IF_METHOD(IN_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(concurrent_t out, m_serial_read_t f) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _write_lock)(out); \
m_serial_return_code_t r = M_CALL_IN_SERIAL(oplist, out->data, f); \
M_F(name, _write_signal)(out); \
M_F(name, _write_unlock)(out); \
return r; \
} \
,) \
\
M_IF_METHOD(EQUAL, oplist)( \
M_INLINE bool \
M_F(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \
{ \
M_C0NCURRENT_CONTRACT(out1); \
M_C0NCURRENT_CONTRACT(out2); \
if (M_UNLIKELY (out1 == out2)) return true; \
/* See comment above on mutual mutexes */ \
if (out1 < out2) { \
M_F(name, _read_lock)(out1); \
M_F(name, _read_lock)(out2); \
} else { \
M_F(name, _read_lock)(out2); \
M_F(name, _read_lock)(out1); \
} \
bool b = M_CALL_EQUAL(oplist, out1->data, out2->data); \
if (out1 < out2) { \
M_F(name, _read_unlock)(out2); \
M_F(name, _read_unlock)(out1); \
} else { \
M_F(name, _read_unlock)(out1); \
M_F(name, _read_unlock)(out2); \
} \
return b; \
} \
,) \
\
M_IF_METHOD(GET_KEY, oplist)( \
M_INLINE bool \
M_F(name, _get_blocking)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key, bool blocking) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT (out_data != NULL); \
bool ret = false; \
M_F(name, _read_lock)(out); \
while (true) { \
M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \
if (p != NULL) { \
M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \
ret = true; \
break; \
} \
if (blocking == false) break; \
/* No data: wait for a write to signal some data */ \
M_F(name, _read_wait)(out); \
} \
M_F(name, _read_unlock)(out); \
return ret; \
} \
,) \
\
M_IF_METHOD2(POP, EMPTY_P, oplist)( \
M_INLINE bool \
M_F(name, _pop_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT (p != NULL); \
bool ret = false; \
M_F(name, _write_lock)(out); \
while (true) { \
if (!M_CALL_EMPTY_P(oplist, out->data)) { \
M_CALL_POP(oplist, p, out->data); \
ret = true; \
break; \
} \
if (blocking == false) break; \
/* No data: wait for a write to signal some data */ \
M_F(name, _write_wait)(out); \
} \
M_F(name, _write_unlock)(out); \
return ret; \
} \
,) \
\
M_IF_METHOD2(POP_MOVE, EMPTY_P, oplist)( \
M_INLINE bool \
M_F(name, _pop_move_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT (p != NULL); \
bool ret = false; \
M_F(name, _write_lock)(out); \
while (true) { \
if (!M_CALL_EMPTY_P(oplist, out->data)) { \
M_CALL_POP_MOVE(oplist, p, out->data); \
ret = true; \
break; \
} \
if (blocking == false) break; \
/* No data: wait for a write to signal some data */ \
M_F(name, _write_wait)(out); \
} \
M_F(name, _write_unlock)(out); \
return ret; \
} \
,) \
\
M_IF_METHOD(HASH, oplist)( \
M_INLINE size_t \
M_F(name, _hash)(concurrent_t const out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_F(name, _read_lock)(out); \
size_t h = M_CALL_HASH(oplist, out->data); \
M_F(name, _read_unlock)(out); \
/* The hash is unchanged by the concurrent container */ \
return h; \
} \
,) \
/******************************** INTERNAL ***********************************/
/* Deferred evaluation for the RP concurrent definition,
so that all arguments are evaluated before further expansion */
#define M_C0NCURRENT_RP_DEF_P1(arg) M_ID( M_C0NCURRENT_RP_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_C0NCURRENT_RP_DEF_P2(name, type, oplist, concurrent_t) \
M_IF_OPLIST(oplist)(M_C0NCURRENT_RP_DEF_P3, M_C0NCURRENT_RP_DEF_FAILURE)(name, type, oplist, concurrent_t)
/* Stop processing with a compilation failure */
#define M_C0NCURRENT_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_RP_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
/* Internal RP concurrent definition
- name: prefix to be used
- type: type of the sub container
- oplist: oplist of the type of the sub container
- concurrent_t: alias for M_F(name, _t) [ type of the container ]
*/
#define M_C0NCURRENT_RP_DEF_P3(name, type, oplist, concurrent_t) \
M_C0NCURRENT_RP_DEF_TYPE(name, type, oplist, concurrent_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_C0NCURRENT_RP_DEF_CORE(name, type, oplist, concurrent_t) \
M_C0NCURRENT_DEF_COMMON(name, type, oplist, concurrent_t)
/* Define the type of a RP concurrent container */
#define M_C0NCURRENT_RP_DEF_TYPE(name, type, oplist, concurrent_t) \
\
typedef struct M_F(name, _s) { \
struct M_F(name, _s) *self; \
m_mutex_t lock; \
atomic_uint num_reader; /* number of reader threads */ \
atomic_uint num_waiting_writer; /* number of waiting writer threads */ \
m_cond_t there_is_data; /* condition raised when there is data */ \
type data; \
} concurrent_t[1]; \
\
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
typedef type M_F(name, _subtype_ct); \
/* Define the internal services for the lock strategy of a RP container */
#define M_C0NCURRENT_RP_DEF_CORE(name, type, oplist, concurrent_t) \
\
M_INLINE void \
M_F(name, _internal_init)(concurrent_t out) \
{ \
m_mutex_init(out->lock); \
atomic_init(&out->num_reader, 0); \
atomic_init(&out->num_waiting_writer, 0); \
m_cond_init(out->there_is_data); \
out->self = out; \
M_C0NCURRENT_CONTRACT(out); \
} \
\
M_INLINE void \
M_F(name, _internal_clear)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_mutex_clear(out->lock); \
m_cond_clear(out->there_is_data); \
out->self = NULL; \
} \
\
M_INLINE void \
M_F(name, _read_lock)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
struct M_F(name, _s) *self = out->self; \
m_core_backoff_ct backoff; \
m_core_backoff_init(backoff); \
while (true) { \
unsigned int num = atomic_load(&self->num_reader); \
/* To avoid reader threads that starve writer threads \
Disable sharing of lock for reader threads if some writer thread \
waits */ \
/* Otherwise try to reuse the lock opened by another reader thread */ \
if (num != 0 \
&& atomic_load(&self->num_waiting_writer) == 0 \
&& atomic_compare_exchange_strong(&self->num_reader, &num, num+1)) { \
break; \
} \
/* Otherwise try to get the lock ourself */ \
if (m_mutex_trylock(self->lock)) { \
atomic_store(&self->num_reader, 1); \
break; \
} \
/* Perform exponential backoff to avoid monopolizing the memory bus */ \
m_core_backoff_wait(backoff); \
} \
m_core_backoff_clear(backoff); \
} \
\
M_INLINE void \
M_F(name, _read_unlock)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
struct M_F(name, _s) *self = out->self; \
unsigned int num = atomic_fetch_sub(&self->num_reader, 1); \
if (num == 1) { \
/* We are the last reader thread: release the lock */ \
m_mutex_unlock(self->lock); \
} \
} \
\
M_INLINE void \
M_F(name, _write_lock)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
atomic_fetch_add(&out->num_waiting_writer, 1); \
m_mutex_lock (out->lock); \
atomic_fetch_sub(&out->num_waiting_writer, 1); \
M_ASSERT(atomic_load(&out->num_reader) == 0); \
} \
\
M_INLINE void \
M_F(name, _write_unlock)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT(atomic_load(&out->num_reader) == 0); \
m_mutex_unlock (out->lock); \
} \
\
M_INLINE void \
M_F(name, _read_wait)(const concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
struct M_F(name, _s) *self = out->self; \
m_cond_wait(self->there_is_data, self->lock); \
} \
\
M_INLINE void \
M_F(name, _write_wait)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
m_cond_wait(out->there_is_data, out->lock); \
} \
\
M_INLINE void \
M_F(name, _write_signal)(concurrent_t out) \
{ \
M_C0NCURRENT_CONTRACT(out); \
M_ASSERT(atomic_load(&out->num_reader) == 0); \
m_cond_broadcast(out->there_is_data); \
} \
/******************************** INTERNAL ***********************************/
#if M_USE_SMALL_NAME
#define CONCURRENT_DEF M_CONCURRENT_DEF
#define CONCURRENT_DEF_AS M_CONCURRENT_DEF_AS
#define CONCURRENT_RP_DEF M_CONCURRENT_RP_DEF
#define CONCURRENT_RP_DEF_AS M_CONCURRENT_RP_DEF_AS
#define CONCURRENT_OPLIST M_CONCURRENT_OPLIST
#endif
#endif
+227 -149
View File
@@ -70,8 +70,8 @@
/* Define M*LIB version */
#define M_CORE_VERSION_MAJOR 0
#define M_CORE_VERSION_MINOR 7
#define M_CORE_VERSION_PATCHLEVEL 4
#define M_CORE_VERSION_MINOR 8
#define M_CORE_VERSION_PATCHLEVEL 0
/* M_ASSUME is equivalent to M_ASSERT, but gives hints to compiler
about how to optimize the code if NDEBUG is defined.
@@ -363,48 +363,122 @@ M_BEGIN_PROTECTED_CODE
explicit cast) */
/* Define allocators for object:
* void *M_MEMORY_ALLOC(type): Return a pointer to a new object of type 'type'
* void *M_MEMORY_ALLOC(ctx, type):
* Return a pointer to a new object of type 'type'
* It returns NULL in case of memory allocation failure.
* void M_MEMORY_DEL(ptr): Free the object associated to the pointer.
* void M_MEMORY_DEL(ctx, ptr):
* Free the object associated to the pointer.
* By default, 'context' does nothing.
* 'context' is the context parameter given to the memory functions to identify where to create the object.
* It exists only if M_USE_CONTEXT has been globally defined.
*/
#ifndef M_MEMORY_ALLOC
#ifdef __cplusplus
# include <cstdlib>
# define M_MEMORY_ALLOC(type) ((type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ptr) std::free(ptr)
# define M_MEMORY_ALLOC(ctx, type) ((type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ctx, ptr) std::free(ptr)
#else
# define M_MEMORY_ALLOC(type) malloc (sizeof (type))
# define M_MEMORY_DEL(ptr) free(ptr)
# define M_MEMORY_ALLOC(ctx, type) malloc (sizeof (type))
# define M_MEMORY_DEL(ctx, ptr) free(ptr)
#endif
#endif
/* Define allocators for array
* void *M_MEMORY_REALLOC(type, ptr, n): Return a pointer to a new array of 'n' object of type 'type'
* If ptr is NULL, it creates a new array.
* If ptr is not null, it reallocates the given array to the new size.
* void *M_MEMORY_REALLOC(context, type, ptr, o, n, perm):
* Return a pointer to a new array of 'n' object of type 'type'.
* If ptr is NULL, it creates a new array of type 'type' and size 'n'
* If ptr is not null, it reallocates the given array of type 'type' and size 'o' to the new size.
* It returns NULL in case of memory allocation failure.
* void M_MEMORY_FREE(ptr): Free the object associated to the array.
* void M_MEMORY_FREE(type, ptr, o):
* Free the object associated to the array of type 'type' at base 'ptr' of size 'o'.
* By default, 'o' size and 'context' do nothing.
* 'context' is the context parameter given to the memory functions to identify where to create the object.
* It exists only if M_USE_CONTEXT has been globally defined.
*/
#ifndef M_MEMORY_REALLOC
#ifdef __cplusplus
# include <cstdlib>
# define M_MEMORY_REALLOC(type, ptr, n) \
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) \
((type*) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : std::realloc ((ptr), (n)*sizeof (type))))
# define M_MEMORY_FREE(ptr) std::free(ptr)
# define M_MEMORY_FREE(ctx, type, ptr, o) std::free(ptr)
#else
# define M_MEMORY_REALLOC(type, ptr, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(ptr) free(ptr)
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(ctx, type, ptr, o) free(ptr)
#endif
#endif
/* This macro is called on memory allocation failure.
* By default, it raises a fatal error.
* By default, it raises a fatal error and abort execution.
* It shall never continue execution.
* NOTE: Can be overloaded by user code.
*/
#ifndef M_MEMORY_FULL
#define M_MEMORY_FULL(size) \
M_RAISE_FATAL("Cannot allocate %zu bytes of memory at (%s:%s:%d).\n", \
(size_t) (size), __FILE__, __func__, __LINE__)
#define M_MEMORY_FULL(type, number) \
M_RAISE_FATAL("Cannot allocate %zu objects of type '%s' (size '%zu') at (%s:%s:%d).\n", \
(size_t) (number), M_AS_STR(type), sizeof (type), \
__FILE__, __func__, __LINE__)
#endif
// Default global memory context is to consider the global context as '0' if it is not defined.
#ifndef M_USE_GLOBAL_CONTEXT
#define M_USE_GLOBAL_CONTEXT 0
#endif
/* In order to support local context for memory functions, the prototypes and usages of some functions are modified
* so that they can accept a first argument 'm_context' which is the memory context parameter.
*
* For some functions, there is no meaning of a local memory context parameter:
* for all data shared between threads, only a global memory context has any meaning.
* For such cases, the memory context parameter is globally requested to the user through M_USE_GLOBAL_POOL or set to 0.
*
* This is controlled through M_USE_CONTEXT parameter that define the type of the memory context parameter
* to be used globally for all M*LIB. There is no possibility to support only some containers and not others.
*
* Several macros are defined **globally** to support such features and being internally used by M*LIB containers.
* They expand to nothing if the memory context parameter is not requested:
* * M_P_EXPAND: expand to the first parameter 'm_context' of type M_USE_CONTEXT for a function that may use memory context.
* * M_P_EXPAND_void: same but assume that there is no argument in the initial function.
* * M_R_EXPAND: expand to the first parameter 'm_context' (followed by a comma)
* * M_R_EXPAND_void: same but assume that there is no argument
* * M_R: add the parameter m_context to the function call if needed,
* * M_P: define the prototype of a function that may have the parameter m_context.
* * M_N: define the prototype of a function that don't need the parameter m_context.
* * M_UNUSED_CONTEXT: avoid warning of unused m_context argument
* * M_GLOBAL_CONTEXT: define m_context to zero, meaning it is a global memory context.
*/
#ifndef M_USE_CONTEXT
// Memory context parameter not used for memory function.
# define M_P_EXPAND
# define M_P_EXPAND_void void
# define M_R_EXPAND
# define M_R_EXPAND_void
# define M_R
# define M_UNUSED_CONTEXT()
# define M_GLOBAL_CONTEXT()
#else
// Memory context parameter is used for function using memory. (local definition to the function).
// Expand to a prototype to a function that may not trigger exception
# define M_P_EXPAND M_USE_CONTEXT m_context,
# define M_P_EXPAND_void M_USE_CONTEXT m_context
# define M_R_EXPAND m_context ,
# define M_R_EXPAND_void m_context
# define M_R(...) (m_context, __VA_ARGS__)
# define M_UNUSED_CONTEXT() (void) m_context
# define M_GLOBAL_CONTEXT() M_USE_CONTEXT m_context = { M_USE_GLOBAL_CONTEXT }; (void) m_context
#endif
// M_P: Expand to a prototype of a function that may trigger exception / accept memory context
// M_N: Expand to a prototype of a function that may not trigger exception or accept memory context
// If not user defined M_F or memory context, no overloaded M_INLINE,
// simplify the definition of M_P/M_N to provide faster compile time.
// (faster build: 0.54s instead of 0.80s in extreme expanding)
#if !defined(M_USE_CONTEXT) && !defined(M_F) && !defined(M_USE_FINE_GRAINED_LINKAGE) && !defined(M_USE_DEF) && !defined(M_USE_DECL)
# define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__)
# define M_N(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__)
#else
# define M_P(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(M_P_EXPAND __VA_ARGS__)
# define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__)
#endif
@@ -439,6 +513,7 @@ M_BEGIN_PROTECTED_CODE
* NOTE: Can be overriden by user if it needs to keep finer access
* on the assertions.
*/
//TODO: If NDEBUG, simply do nothing "no expression", to speed up compilation speed.
#ifndef M_ASSERT
#define M_ASSERT(expr) assert(expr)
#endif
@@ -449,6 +524,7 @@ M_BEGIN_PROTECTED_CODE
* NOTE: Can be overriden by user if it needs to keep finer access
* on the assertions.
*/
//TODO: If NDEBUG, simply do nothing "no expression", to speed up compilation speed.
#ifndef M_ASSERT_SLOW
# if defined(M_USE_ADDITIONAL_CHECKS) && M_USE_ADDITIONAL_CHECKS
# define M_ASSERT_SLOW(n) assert(n)
@@ -2771,7 +2847,7 @@ M_INLINE char m_core_str_nospace(const char **str)
/* Transform a C variable into a m_string_t (needs m-string.h) */
#define M_GET_STRING_ARG(str, x, append) \
(append ? m_string_cat_printf : m_string_printf) (str, M_PRINTF_FORMAT(x), M_CORE_PRINTF_ARG(x))
(append ? m_string_cat_printf : m_string_printf) M_R(str, M_PRINTF_FORMAT(x), M_CORE_PRINTF_ARG(x))
/* No use of GET_STR if no inclusion of m-string */
#define M_GET_STR_METHOD_FOR_DEFAULT_TYPE /* */
@@ -3455,8 +3531,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_X_DEL_DEL(a) ,a,
#define M_X_REALLOC_REALLOC(a) ,a,
#define M_X_FREE_FREE(a) ,a,
#define M_X_MEMPOOL_MEMPOOL(a) ,a,
#define M_X_MEMPOOL_LINKAGE_MEMPOOL_LINKAGE(a) ,a,
#define M_X_SIZE_SIZE(a) ,a,
#define M_X_CONTEXT_CONTEXT(a) ,a,
#define M_X_POLICY_POLICY(a) ,a,
@@ -3476,7 +3550,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
/* Get the given method */
#define M_GET_INIT(...) M_GET_METHOD(INIT, M_INIT_DEFAULT, __VA_ARGS__)
#define M_GET_INIT_SET(...) M_GET_METHOD(INIT_SET, M_SET_DEFAULT, __VA_ARGS__)
#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_NO_DEF_INIT_MOVE, __VA_ARGS__)
#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_SET_DEFAULT, __VA_ARGS__)
#define M_GET_INIT_WITH(...) M_GET_METHOD(INIT_WITH, M_NO_DEF_INIT_WITH, __VA_ARGS__)
#define M_GET_SET(...) M_GET_METHOD(SET, M_SET_DEFAULT, __VA_ARGS__)
#define M_GET_MOVE(...) M_GET_METHOD(MOVE, M_NO_DEF_MOVE, __VA_ARGS__)
@@ -3544,12 +3618,10 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_GET_PROPERTIES(...) M_GET_METHOD(PROPERTIES, (), __VA_ARGS__)
#define M_GET_EMPLACE_TYPE(...) M_GET_METHOD(EMPLACE_TYPE, , __VA_ARGS__)
// As attribute customization
#define M_GET_NEW(...) M_GET_METHOD(NEW, M_NEW_DEFAULT, __VA_ARGS__)
#define M_GET_DEL(...) M_GET_METHOD(DEL, M_DEL_DEFAULT, __VA_ARGS__)
#define M_GET_REALLOC(...) M_GET_METHOD(REALLOC, M_REALLOC_DEFAULT, __VA_ARGS__)
#define M_GET_FREE(...) M_GET_METHOD(FREE, M_FREE_DEFAULT, __VA_ARGS__)
#define M_GET_MEMPOOL(...) M_GET_METHOD(MEMPOOL, M_NO_DEF_MEMPOOL, __VA_ARGS__)
#define M_GET_MEMPOOL_LINKAGE(...) M_GET_METHOD(MEMPOOL_LINKAGE, , __VA_ARGS__)
#define M_GET_NEW(...) M_GET_METHOD(NEW, M_MEMORY_ALLOC, __VA_ARGS__)
#define M_GET_DEL(...) M_GET_METHOD(DEL, M_MEMORY_DEL, __VA_ARGS__)
#define M_GET_REALLOC(...) M_GET_METHOD(REALLOC, M_MEMORY_REALLOC, __VA_ARGS__)
#define M_GET_FREE(...) M_GET_METHOD(FREE, M_MEMORY_FREE, __VA_ARGS__)
#define M_GET_SIZE(...) M_GET_METHOD(SIZE, 0, __VA_ARGS__)
#define M_GET_CONTEXT(...) M_GET_METHOD(CONTEXT, 0, __VA_ARGS__)
#define M_GET_POLICY(...) M_GET_METHOD(POLICY, 0, __VA_ARGS__)
@@ -3564,7 +3636,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_CALL_MOVE(oplist, ...) M_APPLY_API(M_GET_MOVE oplist, oplist, __VA_ARGS__)
#define M_CALL_SWAP(oplist, ...) M_APPLY_API(M_GET_SWAP oplist, oplist, __VA_ARGS__)
#define M_CALL_CLEAR(oplist, ...) M_APPLY_API(M_GET_CLEAR oplist, oplist, __VA_ARGS__)
#define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, __VA_ARGS__)
#define M_CALL_HASH(oplist, ...) M_APPLY_API(M_GET_HASH oplist, oplist, __VA_ARGS__)
#define M_CALL_EQUAL(oplist, ...) M_APPLY_API(M_GET_EQUAL oplist, oplist, __VA_ARGS__)
#define M_CALL_CMP(oplist, ...) M_APPLY_API(M_GET_CMP oplist, oplist, __VA_ARGS__)
@@ -3622,12 +3693,11 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_CALL_OOR_EQUAL(oplist, ...) M_APPLY_API(M_GET_OOR_EQUAL oplist, oplist, __VA_ARGS__)
//#define M_CALL_PROPERTIES(oplist, ...) M_APPLY_API(M_GET_PROPERTIES oplist, oplist, __VA_ARGS__)
//#define M_CALL_EMPLACE_TYPE(oplist, ...) M_APPLY_API(M_GET_EMPLACE_TYPE oplist, oplist, __VA_ARGS__)
// As attribute customization
#define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, __VA_ARGS__)
#define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, __VA_ARGS__)
#define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, __VA_ARGS__)
#define M_CALL_MEMPOOL(oplist, ...) M_APPLY_API(M_GET_MEMPOOL oplist, oplist, __VA_ARGS__)
#define M_CALL_MEMPOOL_LINKAGE(oplist, ...) M_APPLY_API(M_GET_MEMPOOL_LINKAGE oplist, oplist, __VA_ARGS__)
// m_context is always added here!
#define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, m_context, __VA_ARGS__)
#define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, m_context, __VA_ARGS__)
//#define M_CALL_SIZE(oplist, ...) M_APPLY_API(M_GET_SIZE oplist, oplist, __VA_ARGS__)
//#define M_CALL_CONTEXT(oplist, ...) M_APPLY_API(M_GET_CONTEXT oplist, oplist, __VA_ARGS__)
//#define M_CALL_POLICY(oplist, ...) M_APPLY_API(M_GET_POLICY oplist, oplist, __VA_ARGS__)
@@ -3661,6 +3731,14 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_OPLAPI_5(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, __VA_ARGS__)
#define M_OPLAPI_6(method, oplist, x, ...) , M_DELAY3(method)(&x, &__VA_ARGS__)
#define M_OPLAPI_7(method, oplist, x, ...) , M_DELAY3(method)(oplist, &x, &__VA_ARGS__)
#define M_OPLAPI_0P(method, oplist, ...) , M_DELAY3(method)(m_context, __VA_ARGS__)
#define M_OPLAPI_1P(method, oplist, ...) , M_DELAY3(method)(oplist, m_context, __VA_ARGS__)
#define M_OPLAPI_2P(method, oplist, ...) , M_DELAY3(method)(m_context, & __VA_ARGS__)
#define M_OPLAPI_3P(method, oplist, ...) , M_DELAY3(method)(oplist, m_context, &__VA_ARGS__)
#define M_OPLAPI_4P(method, oplist, x, ...) , x = M_DELAY3(method)(m_context, __VA_ARGS__)
#define M_OPLAPI_5P(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, m_context, __VA_ARGS__)
#define M_OPLAPI_6P(method, oplist, x, ...) , M_DELAY3(method)(m_context, &x, &__VA_ARGS__)
#define M_OPLAPI_7P(method, oplist, x, ...) , M_DELAY3(method)(oplist, m_context, &x, &__VA_ARGS__)
/* API transformation support for indirection */
#define M_OPLAPI_INDIRECT_0 M_OPLAPI_ERROR
#define M_OPLAPI_INDIRECT_API_0(...) M_OPLAPI_0
@@ -3679,6 +3757,22 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_OPLAPI_EXTRACT_API_6(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_7(...) M_OPLAPI_7
#define M_OPLAPI_EXTRACT_API_7(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_0P(...) M_OPLAPI_0P
#define M_OPLAPI_EXTRACT_API_0P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_1P(...) M_OPLAPI_1P
#define M_OPLAPI_EXTRACT_API_1P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_2P(...) M_OPLAPI_2P
#define M_OPLAPI_EXTRACT_API_2P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_3P(...) M_OPLAPI_3P
#define M_OPLAPI_EXTRACT_API_3P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_4P(...) M_OPLAPI_4P
#define M_OPLAPI_EXTRACT_API_4P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_5P(...) M_OPLAPI_5P
#define M_OPLAPI_EXTRACT_API_5P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_6P(...) M_OPLAPI_6P
#define M_OPLAPI_EXTRACT_API_6P(...) __VA_ARGS__
#define M_OPLAPI_INDIRECT_API_7P(...) M_OPLAPI_7P
#define M_OPLAPI_EXTRACT_API_7P(...) __VA_ARGS__
/* Generic API transformation.
@@ -3776,7 +3870,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
"The " #operator " operator has no method associated in the given OPLIST."),\
(return_type) 0)
#define M_NO_DEF_INIT_MOVE(...) M_NO_DEFAULT(INIT_MOVE, void)
#define M_NO_DEF_INIT_WITH(...) M_NO_DEFAULT(INIT_WITH, void)
#define M_NO_DEF_MOVE(...) M_NO_DEFAULT(MOVE, void)
#define M_NO_DEF_SWAP(...) M_NO_DEFAULT(SWAP, void)
@@ -3817,7 +3910,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_NO_DEF_IN_SERIAL(...) M_NO_DEFAULT(IN_SERIAL, m_serial_return_code_t)
#define M_NO_DEF_OOR_SET(...) M_NO_DEFAULT(OOR_SET, void)
#define M_NO_DEF_OOR_EQUAL(...) M_NO_DEFAULT(OOR_EQUAL, bool)
#define M_NO_DEF_MEMPOOL(...) M_NO_DEFAULT(MEMPOOL, void)
/* Create a type with an invalid static assertion.
Creating a type allowed the macro into something not too bad
@@ -3940,10 +4032,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
#define M_EMPTY_DEFAULT(...) ((void)1)
#define M_TRUE_DEFAULT(...) true
#define M_FALSE_DEFAULT(...) false
#define M_NEW_DEFAULT(a) M_MEMORY_ALLOC(a)
#define M_DEL_DEFAULT(a) M_MEMORY_DEL(a)
#define M_REALLOC_DEFAULT(t,p,s) M_MEMORY_REALLOC(t,p,s)
#define M_FREE_DEFAULT(a) M_MEMORY_FREE(a)
#define M_EQUAL_DEFAULT(a,b) ((a) == (b))
#define M_CMP_DEFAULT(a,b) ((a) < (b) ? -1 : (a) > (b))
#define M_ADD_DEFAULT(a,b,c) ((a) = (b) + (c))
@@ -3965,9 +4053,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
/* NOTE: Theses operators are NOT compatible with the '[1]' tricks
if the variable is defined as a parameter of a function
(sizeof (a) is not portable). */
#define M_MOVE_DEFAULT(a,b) (M_CHECK_SAME(a, b), M_MEMCPY_DEFAULT(a, b), memset(&(b), 0, sizeof (a)))
#define M_MEMCPY_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcpy(&(a), &(b), sizeof (a)))
#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
#define M_RESET_DEFAULT(a) (memset(&(a), 0, sizeof (a)))
#define M_MEMCMP1_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)) == 0)
#define M_MEMCMP2_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)))
#define M_SWAP_DEFAULT(el1, el2) do { \
@@ -3978,28 +4064,35 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
memcpy(&(el2), &_tmp, sizeof (el1)); \
} while (0)
/* Default oplist for plain structure */
#define M_POD_OPLIST \
(INIT(M_RESET_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \
INIT_MOVE(M_SET_DEFAULT) )
/* NOTE: Theses operators are to be used with the '[1]' tricks
if the variable is defined as a parameter of a function
(sizeof (a) is not portable). */
#define M_MOVE_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b))
#define M_MEMCPY_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_MEMSET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0])))
#define M_COPY_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcpy(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_RESET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0])))
#define M_MEMCMP1_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0],b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0)
#define M_MEMCMP2_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0])))
#define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a[0]), sizeof (a[0])) )
#define M_SWAP_A1_DEFAULT(a, b) do { \
char _tmp[sizeof (a[0])]; \
M_CHECK_SAME(a[0], b[0]); \
memcpy(&_tmp, &(a[0]), sizeof (a[0])); \
memcpy(&(a[0]), &(b[0]), sizeof (a[0])); \
memcpy(&(b[0]), &_tmp, sizeof (a[0])); \
} while (0)
/* Default oplist for plain structure */
#define M_POD_OPLIST \
(INIT(M_MEMSET_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT), SET(M_MEMCPY_DEFAULT), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), \
HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT))
/* Default oplist for a structure defined with an array of size 1 */
/* Default oplist for a structure defined with an array of size 1.
MOVE operator is not defined since the object may need to release some data */
#define M_A1_OPLIST \
(INIT(M_MEMSET_A1_DEFAULT), INIT_SET(M_MEMCPY_A1_DEFAULT), SET(M_MEMCPY_A1_DEFAULT), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_A1_DEFAULT), CMP(M_MEMCMP2_A1_DEFAULT), \
HASH(M_HASH_A1_DEFAULT))
(INIT(M_RESET_A1_DEFAULT), INIT_SET(M_COPY_A1_DEFAULT), SET(M_COPY_A1_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
EQUAL(M_MEMCMP1_A1_DEFAULT), CMP(M_MEMCMP2_A1_DEFAULT), HASH(M_HASH_A1_DEFAULT), SWAP(M_SWAP_A1_DEFAULT), \
INIT_MOVE(M_COPY_A1_DEFAULT) )
/* Oplist for a type that does nothing and shall not be instanciated */
@@ -4024,7 +4117,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
# define M_BASIC_OPLIST \
(INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_BASIC), CMP(M_CMP_BASIC), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \
RESET(M_INIT_BASIC), PROPERTIES( (NOCLEAR(1)) ), \
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
@@ -4037,7 +4130,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
# define M_BASIC_OPLIST \
(INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_BASIC), CMP(M_CMP_BASIC), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \
RESET(M_INIT_BASIC), PROPERTIES( (NOCLEAR(1)) ), \
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
@@ -4050,7 +4143,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
# define M_BASIC_OPLIST \
(INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_BASIC), CMP(M_CMP_BASIC), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \
RESET(M_INIT_BASIC), PROPERTIES( (NOCLEAR(1)) ), \
ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \
MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \
@@ -4081,7 +4174,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
(INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \
SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \
HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \
TYPE(type), OPLIST(init), \
IN_STR(API_1(M_ENUM_FSCAN)), OUT_STR(M_ENUM_FPRINT), \
@@ -4094,7 +4187,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
(INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \
SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \
HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \
TYPE(type), OPLIST(init), \
IN_SERIAL(API_1(M_ENUM_IN_SERIAL)), OUT_SERIAL(M_ENUM_OUT_SERIAL), \
@@ -4149,7 +4242,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
#define M_ENUM_IN_SERIAL(oplist, var, serial) \
( var = (M_GET_TYPE oplist)(true ? m_core_in_serial_enum(serial) : 0), (serial)->tmp.r)
#define M_ENUM_GET_STR(str, var, append) \
((append ? m_string_cat_printf : m_string_printf) (str, "%lld", (long long) (var) ))
((append ? m_string_cat_printf : m_string_printf) M_R(str, "%lld", (long long) (var) ))
#define M_ENUM_PARSE(oplist, var, str, endptr) \
( var = (M_GET_TYPE oplist) (true ? m_core_parse1_enum(str) : 0), m_core_parse2_enum(str, endptr))
@@ -4157,32 +4250,29 @@ m_core_parse2_enum (const char str[], const char **endptr)
/* Default oplist for standard types of pointers.
*/
#define M_PTR_OPLIST \
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \
CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), \
INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \
SWAP(M_SWAP_DEFAULT) )
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
EQUAL(M_EQUAL_DEFAULT), SWAP(M_SWAP_DEFAULT) \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) )
/* Default oplist for complex objects with "classic" names for methods.
/* Default oplist for complex objects (using [1] trick) with "classic" names for methods.
*/
#define M_CLASSIC_OPLIST(name) ( \
INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
SET(M_F(name, _set)), \
CLEAR(M_F(name, _clear)), \
TYPE(M_F(name, _t)) )
INIT(M_F(name, _init)), INIT_SET(M_F(name, _init_set)), SET(M_F(name, _set)), CLEAR(M_F(name, _clear)), \
INIT_MOVE(M_COPY_A1_DEFAULT), TYPE(M_F(name, _t)) )
/* OPLIST for 'const char *' string (with NO memory allocation).
/* Default oplist for 'const char *' string (with NO memory allocation).
*/
#define M_CSTR_EQUAL(a,b) (strcmp((a),(b)) == 0)
#define M_CSTR_OUT_STR(file, str) fprintf(file, "%s", str)
#define M_CSTR_OPLIST (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), \
SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
HASH(m_core_cstr_hash), EQUAL(M_CSTR_EQUAL), \
CMP(strcmp), TYPE(const char *), \
OUT_STR(M_CSTR_OUT_STR) )
#define M_CSTR_OPLIST \
(INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \
HASH(m_core_cstr_hash), EQUAL(M_CSTR_EQUAL), CMP(strcmp), SWAP(M_SWAP_DEFAULT), \
INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT), TYPE(const char *), \
OUT_STR(M_CSTR_OUT_STR) )
/****************************************************************************/
/* From an oplist (...) return ... (Like M_ID but for OPLIST) */
#define M_OPFLAT(...) __VA_ARGS__
@@ -4267,13 +4357,6 @@ m_core_parse2_enum (const char str[], const char **endptr)
so that the first argument becomes a pointer to the destination (OBSOLETE MACRO) */
#define M_IPTR(...) ( & __VA_ARGS__ )
/* Perform an INIT_MOVE if present, or emulate it using INIT_SET/CLEAR */
#define M_DO_INIT_MOVE(oplist, dest, src) do { \
M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_INIT_MOVE(oplist, (dest), (src)), \
M_CALL_INIT_SET(oplist, (dest), (src)) ; \
M_CALL_CLEAR(oplist, (src) )); \
} while (0)
/* Perform a MOVE if present, or emulate it using CLEAR/INIT_MOVE
if possible, or with SET/CLEAR otherwise */
#define M_DO_MOVE(oplist, dest, src) do { \
@@ -4422,7 +4505,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__)
// Stop with a failure (invalid oplist)
#define M_LETI2_FAILURE(cont, oplist, ...) \
M_STATIC_ASSERT(false, M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist))
M_STATIC_ASSERT(false, M_LIB_NOT_AN_OPLIST, "the last argument of M_LET is not a valid oplist or a registered type: " M_AS_STR(oplist))
// 4. Map all variables to their own LET
#define M_LETI3(cont, oplist, ...) \
for(bool cont = true; cont ; /* unused */) \
@@ -4526,7 +4609,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
for( init; cont ; cont = false) \
M_DEFER_TRY_INJECT_POST(cont, clear) \
for( (void) 0; cont; cont = false)
/* If exceptions are activated, M_CHAIN_OBJ enables support for chaining
initialization at the begining of a constructor for the fields of the constructed
@@ -4656,12 +4739,12 @@ m_core_parse2_enum (const char str[], const char **endptr)
so it reverses the final order.
*/
#define M_INIT_VAI(oplist, dest, ...) \
(void)(M_GET_INIT oplist (dest) , \
M_MAP2_C(M_INIT_VAI_FUNC, (dest, M_GET_PUSH oplist) , __VA_ARGS__) \
M_IF_METHOD(REVERSE, oplist)(M_DEFERRED_COMMA M_GET_REVERSE oplist (dest), ) \
(void)(M_CALL_INIT(oplist, dest) , \
M_MAP2_C(M_INIT_VAI_FUNC, (dest, oplist) , __VA_ARGS__) \
M_IF_METHOD(REVERSE, oplist)(M_DEFERRED_COMMA M_CALL_REVERSE(oplist, dest), ) \
)
#define M_INIT_VAI_FUNC(d, a) \
M_PAIR_2 d (M_PAIR_1 d, a)
M_CALL_PUSH(M_PAIR_2 d, M_PAIR_1 d, a)
/* Initialize the container 'dest' as per 'oplist' INIT operator
@@ -5010,11 +5093,11 @@ m_core_parse2_enum (const char str[], const char **endptr)
#define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(isSet, name, name_t, key_oplist, val_oplist) \
M_ID( M_C(M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF, isSet)(name, name_t, key_oplist, val_oplist) )
#define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF0(name, name_t, key_oplist, val_oplist) \
M_EMPLACE_ASS_ARRAY_DEF(name, name_t, M_F(name, _emplace), key_oplist, val_oplist, M_EMPLACE_ASS_ARRA1_BOTH_GENE, M_EMPLACE_ASS_ARRA1_KEY_GENE, M_EMPLACE_ASS_ARRA1_VAL_GENE) \
M_EMPLACE_QUEUE_DEF(name, name_t, M_F(name, _get_emplace), key_oplist, M_EMPLACE_GET_GENE)
M_EMPLACE_ASS_ARRAY_DEF(name, name_t, _emplace, key_oplist, val_oplist, M_EMPLACE_ASS_ARRA1_BOTH_GENE, M_EMPLACE_ASS_ARRA1_KEY_GENE, M_EMPLACE_ASS_ARRA1_VAL_GENE) \
M_EMPLACE_QUEUE_DEF(name, name_t, _get_emplace, key_oplist, M_EMPLACE_GET_GENE)
#define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF1(name, name_t, key_oplist, val_oplist) \
M_EMPLACE_QUEUE_DEF(name, name_t, M_F(name, _emplace), key_oplist, M_EMPLACE_QUEUE_GENE) \
M_EMPLACE_QUEUE_DEF(name, name_t, M_F(name, _get_emplace), key_oplist, M_EMPLACE_GET_GENE)
M_EMPLACE_QUEUE_DEF(name, name_t, _emplace, key_oplist, M_EMPLACE_QUEUE_GENE) \
M_EMPLACE_QUEUE_DEF(name, name_t, _get_emplace, key_oplist, M_EMPLACE_GET_GENE)
/* Definition of the emplace_back function for associative arrays.
@@ -5025,39 +5108,36 @@ m_core_parse2_enum (const char str[], const char **endptr)
one for value only.
*/
#define M_EMPLACE_ASS_ARRA1_BOTH_GENE(name, name_t, function_name, key_oplist, val_oplist, key_init_func, val_init_func, key_emplace_type, val_emplace_type) \
M_INLINE void \
function_name(name_t v \
M_P(void, name, function_name, name_t v \
M_EMPLACE_LIST_TYPE_VAR(akey, key_emplace_type) \
M_EMPLACE_LIST_TYPE_VAR(aval, val_emplace_type) \
){ \
M_F(name, _key_ct) key; \
M_EMPLACE_CALL_FUNC(akey, key_init_func, key_oplist, key, key_emplace_type); \
M_F(name, _value_ct) *val; \
val = M_F(name, _safe_get)(v, key); \
val = M_F(name, _safe_get)M_R(v, key); \
M_CALL_CLEAR(val_oplist, *val); \
M_EMPLACE_CALL_FUNC(aval, val_init_func, val_oplist, *val, val_emplace_type); \
M_CALL_CLEAR(key_oplist, key); \
} \
#define M_EMPLACE_ASS_ARRA1_KEY_GENE(name, name_t, function_name, key_oplist, val_oplist, key_init_func, val_init_func, key_emplace_type, val_emplace_type) \
M_INLINE void \
function_name(name_t v \
M_P(void, name, function_name, name_t v \
M_EMPLACE_LIST_TYPE_VAR(akey, key_emplace_type) \
, M_F(name, _value_ct) const val \
){ \
M_F(name, _key_ct) key; \
M_EMPLACE_CALL_FUNC(akey, key_init_func, key_oplist, key, key_emplace_type); \
M_F(name, _set_at)(v, key, val); \
M_F(name, _set_at)M_R(v, key, val); \
M_CALL_CLEAR(key_oplist, key); \
} \
#define M_EMPLACE_ASS_ARRA1_VAL_GENE(name, name_t, function_name, key_oplist, val_oplist, key_init_func, val_init_func, key_emplace_type, val_emplace_type) \
M_INLINE void \
function_name(name_t v, M_F(name, _key_ct) const key \
M_P(void, name, function_name, name_t v, M_F(name, _key_ct) const key \
M_EMPLACE_LIST_TYPE_VAR(aval, val_emplace_type) \
){ \
M_F(name, _value_ct) *val; \
val = M_F(name, _safe_get)(v, key); \
val = M_F(name, _safe_get)M_R(v, key); \
M_CALL_CLEAR(val_oplist, *val); \
M_EMPLACE_CALL_FUNC(aval, val_init_func, val_oplist, *val, val_emplace_type); \
} \
@@ -5068,13 +5148,12 @@ m_core_parse2_enum (const char str[], const char **endptr)
This definition is far from being efficient but works for the current interface.
*/
#define M_EMPLACE_QUEUE_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
function_name(name_t v \
M_P(void, name, function_name, name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_GET_TYPE oplist data; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \
M_F(name, _push)(v, data); \
M_F(name, _push) M_R(v, data); \
M_CALL_CLEAR(oplist, data); \
}
@@ -5084,9 +5163,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
This definition is far from being efficient but works for the current interface.
*/
#define M_EMPLACE_GET_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE M_F(name, _value_ct) * \
function_name(name_t const v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(M_F(name, _value_ct) *, name, function_name, name_t const v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_GET_TYPE oplist data; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \
@@ -5111,6 +5188,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
* each time it is called with a pseudo random wait.
* It is used to avoid too many threads trying to grab some atomic
* variables at the same times (it makes the threads waits randomly).
* Initialization is cheap.
*/
typedef struct m_core_backoff_s {
unsigned int count; // Number of times it has been run
@@ -5184,7 +5262,7 @@ struct m_string_s;
* - OK & done (object is fully parsed),
* - OK & continue parsing (object is partially parsed)
* - Fail parsing
* - Fail parsing with given arguments (give explicit size)
* - Fail parsing with given arguments (give explicit size) but a retry will succeed.
*/
typedef enum m_serial_return_code_e {
M_SERIAL_OK_DONE = 0, M_SERIAL_OK_CONTINUE = 1, M_SERIAL_FAIL = 2, M_SERIAL_FAIL_RETRY = 4
@@ -5264,7 +5342,7 @@ typedef struct m_serial_read_interface_s {
m_serial_return_code_t (*read_boolean)(m_serial_read_t,bool *);
m_serial_return_code_t (*read_integer)(m_serial_read_t, long long *, const size_t size_of_type);
m_serial_return_code_t (*read_float)(m_serial_read_t, long double *, const size_t size_of_type);
m_serial_return_code_t (*read_string)(m_serial_read_t, struct m_string_s *);
m_serial_return_code_t (*read_string)(M_P_EXPAND m_serial_read_t, struct m_string_s *);
m_serial_return_code_t (*read_array_start)(m_serial_local_t, m_serial_read_t, size_t *);
m_serial_return_code_t (*read_array_next)(m_serial_local_t, m_serial_read_t);
m_serial_return_code_t (*read_map_start)(m_serial_local_t, m_serial_read_t, size_t *);
@@ -5294,22 +5372,22 @@ typedef struct m_serial_write_s {
* All function pointers shall be not null.
*/
typedef struct m_serial_write_interface_s {
m_serial_return_code_t (*write_boolean)(m_serial_write_t,const bool data);
m_serial_return_code_t (*write_integer)(m_serial_write_t,const long long data, const size_t size_of_type);
m_serial_return_code_t (*write_float)(m_serial_write_t, const long double data, const size_t size_of_type);
m_serial_return_code_t (*write_string)(m_serial_write_t,const char data[], size_t len);
m_serial_return_code_t (*write_array_start)(m_serial_local_t, m_serial_write_t, const size_t number_of_elements);
m_serial_return_code_t (*write_array_next)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_array_end)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_map_start)(m_serial_local_t, m_serial_write_t, const size_t number_of_elements);
m_serial_return_code_t (*write_map_value)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_map_next)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_map_end)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_tuple_start)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_tuple_id)(m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index);
m_serial_return_code_t (*write_tuple_end)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_variant_start)(m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index);
m_serial_return_code_t (*write_variant_end)(m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_boolean)(M_P_EXPAND m_serial_write_t,const bool data);
m_serial_return_code_t (*write_integer)(M_P_EXPAND m_serial_write_t,const long long data, const size_t size_of_type);
m_serial_return_code_t (*write_float)(M_P_EXPAND m_serial_write_t, const long double data, const size_t size_of_type);
m_serial_return_code_t (*write_string)(M_P_EXPAND m_serial_write_t,const char data[], size_t len);
m_serial_return_code_t (*write_array_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const size_t number_of_elements);
m_serial_return_code_t (*write_array_next)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_array_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_map_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const size_t number_of_elements);
m_serial_return_code_t (*write_map_value)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_map_next)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_map_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_tuple_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_tuple_id)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index);
m_serial_return_code_t (*write_tuple_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
m_serial_return_code_t (*write_variant_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index);
m_serial_return_code_t (*write_variant_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t);
} m_serial_write_interface_t;
@@ -5319,23 +5397,23 @@ typedef struct m_serial_write_interface_s {
*/
#define M_OUT_SERIAL_DEFAULT_ARG(serial, x) \
_Generic(((void)0,(x)), \
bool: (serial)->m_interface->write_boolean(serial, M_AS_TYPE(bool, (x))), \
char: (serial)->m_interface->write_integer(serial, M_AS_TYPE(char,(x)), sizeof (x)), \
signed char: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed char,(x)), sizeof (x)), \
unsigned char: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned char,(x)), sizeof (x)), \
signed short: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed short,(x)), sizeof (x)), \
unsigned short: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned short,(x)), sizeof (x)), \
signed int: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed int,(x)), sizeof (x)), \
unsigned int: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned int,(x)), sizeof (x)), \
long int: (serial)->m_interface->write_integer(serial, M_AS_TYPE(long,(x)), sizeof (x)), \
unsigned long int: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned long,(x)), sizeof (x)), \
long long int: (serial)->m_interface->write_integer(serial, M_AS_TYPE(long long,(x)), sizeof (x)), \
unsigned long long int: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned long long,(x)), sizeof (x)), \
float: (serial)->m_interface->write_float(serial, M_AS_TYPE(float,(x)), sizeof (x)), \
double: (serial)->m_interface->write_float(serial, M_AS_TYPE(double,(x)), sizeof (x)), \
long double: (serial)->m_interface->write_float(serial, M_AS_TYPE(long double,(x)), sizeof (x)), \
const char *: (serial)->m_interface->write_string(serial, M_AS_TYPE(const char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \
char *: (serial)->m_interface->write_string(serial, M_AS_TYPE(char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \
bool: (serial)->m_interface->write_boolean M_R(serial, M_AS_TYPE(bool, (x))), \
char: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(char,(x)), sizeof (x)), \
signed char: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(signed char,(x)), sizeof (x)), \
unsigned char: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned char,(x)), sizeof (x)), \
signed short: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(signed short,(x)), sizeof (x)), \
unsigned short: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned short,(x)), sizeof (x)), \
signed int: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(signed int,(x)), sizeof (x)), \
unsigned int: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned int,(x)), sizeof (x)), \
long int: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(long,(x)), sizeof (x)), \
unsigned long int: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned long,(x)), sizeof (x)), \
long long int: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(long long,(x)), sizeof (x)), \
unsigned long long int: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned long long,(x)), sizeof (x)), \
float: (serial)->m_interface->write_float M_R(serial, M_AS_TYPE(float,(x)), sizeof (x)), \
double: (serial)->m_interface->write_float M_R(serial, M_AS_TYPE(double,(x)), sizeof (x)), \
long double: (serial)->m_interface->write_float M_R(serial, M_AS_TYPE(long double,(x)), sizeof (x)), \
const char *: (serial)->m_interface->write_string M_R(serial, M_AS_TYPE(const char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \
char *: (serial)->m_interface->write_string M_R(serial, M_AS_TYPE(char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \
const void *: M_SERIAL_FAIL /* unsupported */, \
void *: M_SERIAL_FAIL /* unsupported */)
+141 -118
View File
@@ -99,8 +99,15 @@
M_D3QU3_DEF_TYPE(name, type, oplist, deque_t, it_t, node_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_D3QU3_DEF_CORE(name, type, oplist, deque_t, it_t, node_t) \
M_EMPLACE_QUEUE_DEF(name, deque_t, M_F(name, _emplace_back), oplist, M_D3QUE_EMPLACE_BACK_DEF) \
M_EMPLACE_QUEUE_DEF(name, deque_t, M_F(name, _emplace_front), oplist, M_D3QUE_EMPLACE_FRONT_DEF)
M_EMPLACE_QUEUE_DEF(name, deque_t, _emplace_back, oplist, M_D3QUE_EMPLACE_BACK_DEF) \
M_EMPLACE_QUEUE_DEF(name, deque_t, _emplace_front, oplist, M_D3QUE_EMPLACE_FRONT_DEF)
// OPLIST for the node deletion
#ifdef M_USE_CONTEXT
#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(M_F(name, _node_list_i_del)))
#else
#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API(M_F(name, _node_list_i_del), NONE, ARG2)))
#endif
/* Define the types.
It is a linked list of buckets of the types,
@@ -116,7 +123,7 @@
\
typedef struct M_F(name, _node_s) { \
M_ILIST_INTERFACE(M_F(name, _node_list), struct M_F(name, _node_s)); \
size_t size; \
size_t size, capacity; \
type data[M_MIN_FLEX_ARRAY_SIZE]; \
} node_t; \
\
@@ -124,10 +131,13 @@
M_GET_REALLOC for the allocation). But we want to delete the nodes \
automatically with the intrusive list used for storing the nodes: \
so we register as a DEL operator the FREE operator of the oplist. \
The interfaces are compatible. \
*/ \
/* FIXME: How can I separate public types and private implementation? */ \
M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \
M_P(void, name, _node_list_i_del, node_t *ptr) \
{ \
M_CALL_FREE(oplist, char, ptr, sizeof(node_t) + ptr->capacity * sizeof(type)); \
} \
M_ILIST_DEF(M_F(name, _node_list), node_t, M_D3QU3_NODE_DEL_OPLIST(name) ) \
\
/* Define an internal iterator */ \
typedef struct M_F(name, _it2_s) { \
@@ -170,27 +180,22 @@
#define M_D3QU3_DEF_CORE(name, type, oplist, deque_t, it_t, node_t) \
\
/* Allocate a new node for a deque */ \
M_INLINE node_t* \
M_C3(m_d3qu3_,name,_new_node)(deque_t d) \
M_P(node_t*, name, _i_new_node, deque_t d) \
{ \
size_t def = d->default_size; \
/* Test for overflow of the size computation */ \
if (M_UNLIKELY_NOMEM (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \
M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \
abort(); \
return NULL; \
M_MEMORY_FULL(char, sizeof(node_t)+def * sizeof(type)); \
} \
/* Alloc a new node with dynamic size */ \
node_t*n = (node_t*) (void*) \
M_CALL_REALLOC(oplist, char, NULL, \
sizeof(node_t) + def * sizeof(type) ); \
M_CALL_REALLOC(oplist, char, NULL, 0, sizeof(node_t) + def * sizeof(type) ); \
if (M_UNLIKELY_NOMEM (n==NULL)) { \
M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \
abort(); \
return NULL; \
M_MEMORY_FULL(char, sizeof(node_t)+def * sizeof(type)); \
} \
/* Initialize the node */ \
n->size = def; \
n->capacity = def; \
M_F(name, _node_list_init_field)(n); \
/* Increase the next bucket allocation */ \
/* Do not increase it too much if there are few items */ \
@@ -200,13 +205,12 @@
return n; \
} \
\
M_INLINE void \
M_F(name, _init)(deque_t d) \
M_P(void, name, _init, deque_t d) \
{ \
M_F(name, _node_list_init)(d->list); \
d->default_size = M_USE_DEQUE_DEFAULT_SIZE; \
d->count = 0; \
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
node_t *n = M_F(name,_i_new_node)M_R(d); \
M_F(name, _node_list_push_back)(d->list, n); \
d->front->node = n; \
d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \
@@ -215,10 +219,10 @@
M_D3QU3_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _reset)(deque_t d) \
M_P(void, name, _reset, deque_t d) \
{ \
M_D3QU3_CONTRACT(d); \
M_UNUSED_CONTEXT(); \
node_t *min_node = NULL; \
for(node_t *n = d->front->node; \
n != NULL ; \
@@ -240,31 +244,29 @@
M_D3QU3_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _clear)(deque_t d) \
M_P(void, name, _clear, deque_t d) \
{ \
M_D3QU3_CONTRACT(d); \
M_F(name, _reset)(d); \
/* We have registered the delete operator to clear all objects */ \
M_F(name, _node_list_clear)(d->list); \
/* It is safer to clean some variables */ \
M_F(name, _reset)M_R(d); \
/* We have registered the delete operator to clear all node objects */ \
M_F(name, _node_list_clear)M_R(d->list); \
/* It is safer to clean some variables to mark d as invalid */ \
d->front->node = NULL; \
d->back->node = NULL; \
d->count = 0; \
} \
\
M_INLINE type * \
M_F(name, _push_back_raw)(deque_t d) \
M_P(type *, name, _push_back_raw, deque_t d) \
{ \
M_D3QU3_CONTRACT(d); \
node_t *n = d->back->node; \
size_t index = d->back->index; \
if (M_UNLIKELY (n->size <= index)) { \
/* try to get an already allocated node */ \
/* Cannot fit in the current node, try to get another allocated node */ \
n = M_F(name, _node_list_next_obj)(d->list, n); \
if (n == NULL) { \
/* No node exists, allocate a new one */ \
n = M_C3(m_d3qu3_,name,_new_node)(d); \
/* No another node exists: allocate a new one */ \
n = M_F(name,_i_new_node)M_R(d); \
M_F(name, _node_list_push_back)(d->list, n); \
} \
d->back->node = n; \
@@ -278,27 +280,24 @@
return ret; \
} \
\
/* Internal, for INIT_WITH */ \
M_INLINE type * \
M_F(name, _push_raw)(deque_t d) \
/* Internal, for generic INIT_WITH */ \
M_P(type *, name, _push_raw, deque_t d) \
{ \
return M_F(name, _push_back_raw)(d); \
return M_F(name, _push_back_raw)M_R(d); \
} \
\
M_INLINE void \
M_F(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)(d); \
type *p = M_F(name, _push_back_raw)M_R(d); \
M_ON_EXCEPTION(d->back->index --, d->count--) { \
M_CALL_INIT_SET(oplist, *p, x); \
} \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _push_back_new)(deque_t d) \
M_P(type *, name, _push_back_new, deque_t d) \
{ \
type *p = M_F(name, _push_back_raw)(d); \
type *p = M_F(name, _push_back_raw)M_R(d); \
M_ON_EXCEPTION(d->back->index --, d->count--) { \
M_CALL_INIT(oplist, *p); \
} \
@@ -306,16 +305,14 @@
} \
, ) \
\
M_INLINE void \
M_F(name, _push_back_move)(deque_t d, type *x) \
M_P(void, name, _push_back_move, deque_t d, type *x) \
{ \
M_ASSERT (x != NULL); \
type *p = M_F(name, _push_back_raw)(d); \
M_DO_INIT_MOVE (oplist, *p, *x); \
type *p = M_F(name, _push_back_raw)M_R(d); \
M_CALL_INIT_MOVE (oplist, *p, *x); \
} \
\
M_INLINE type* \
M_F(name, _push_front_raw)(deque_t d) \
M_P(type *, name, _push_front_raw, deque_t d) \
{ \
M_D3QU3_CONTRACT(d); \
node_t *n = d->front->node; \
@@ -325,7 +322,7 @@
if (M_UNLIKELY (n->size <= index)) { \
n = M_F(name, _node_list_previous_obj)(d->list, n); \
if (n == NULL) { \
n = M_C3(m_d3qu3_,name,_new_node)(d); \
n = M_F(name,_i_new_node)M_R(d); \
M_F(name, _node_list_push_front)(d->list, n); \
} \
d->front->node = n; \
@@ -338,20 +335,18 @@
return ret; \
} \
\
M_INLINE void \
M_F(name, _push_front)(deque_t d, type const x) \
M_P(void, name, _push_front, deque_t d, type const x) \
{ \
type *p = M_F(name, _push_front_raw)(d); \
type *p = M_F(name, _push_front_raw)M_R(d); \
M_ON_EXCEPTION(d->front->index ++, d->count--) { \
M_CALL_INIT_SET(oplist, *p, x); \
} \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _push_front_new)(deque_t d) \
M_P(type *, name, _push_front_new, deque_t d) \
{ \
type *p = M_F(name, _push_front_raw)(d); \
type *p = M_F(name, _push_front_raw)M_R(d); \
M_ON_EXCEPTION(d->front->index ++, d->count--) { \
M_CALL_INIT(oplist, *p); \
} \
@@ -359,19 +354,18 @@
} \
,) \
\
M_INLINE void \
M_F(name, _push_front_move)(deque_t d, type *x) \
M_P(void, name, _push_front_move, deque_t d, type *x) \
{ \
M_ASSERT (x != NULL); \
type *p = M_F(name, _push_front_raw)(d); \
M_DO_INIT_MOVE (oplist, *p, *x); \
type *p = M_F(name, _push_front_raw)M_R(d); \
M_CALL_INIT_MOVE (oplist, *p, *x); \
} \
\
M_INLINE void \
M_F(name, _pop_back)(type *ptr, deque_t d) \
M_P(void, name, _pop_back, type *ptr, deque_t d) \
{ \
M_D3QU3_CONTRACT(d); \
M_ASSERT(d->count > 0); \
M_UNUSED_CONTEXT(); \
node_t *n = d->back->node; \
size_t index = d->back->index; \
index --; \
@@ -391,34 +385,35 @@
index = n->size-1; \
} \
if (ptr != NULL) \
M_DO_MOVE(oplist, *ptr, n->data[index]); else \
M_CALL_CLEAR(oplist, n->data[index]); \
M_DO_MOVE(oplist, *ptr, n->data[index]); \
else \
M_CALL_CLEAR(oplist, n->data[index]); \
d->count --; \
d->back->index = index; \
M_D3QU3_CONTRACT(d); \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _pop_back_move)(type *ptr, deque_t d) \
M_P(void, name, _pop_back_move, type *ptr, deque_t d) \
{ \
M_ASSERT(ptr != NULL); \
/* Note: Lazy implementation. Can be improved if needed */ \
M_CALL_INIT(oplist, *ptr); \
M_F(name, _pop_back)(ptr, d); \
M_F(name, _pop_back)M_R(ptr, d); \
} \
, ) \
\
M_INLINE void \
M_F(name, _pop_front)(type *ptr, deque_t d) \
M_P(void, name, _pop_front, type *ptr, deque_t d) \
{ \
M_D3QU3_CONTRACT(d); \
M_ASSERT(d->count > 0); \
M_UNUSED_CONTEXT(); \
node_t *n = d->front->node; \
size_t index = d->front->index; \
if (ptr != NULL) \
M_DO_MOVE(oplist, *ptr, n->data[index]); else \
M_CALL_CLEAR(oplist, n->data[index]); \
M_DO_MOVE(oplist, *ptr, n->data[index]); \
else \
M_CALL_CLEAR(oplist, n->data[index]); \
index++; \
if (M_UNLIKELY (n->size <= index)) { \
/* If there is a previous node, \
@@ -451,13 +446,12 @@
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _pop_front_move)(type *ptr, deque_t d) \
M_P(void, name, _pop_front_move, type *ptr, deque_t d) \
{ \
M_ASSERT(ptr != NULL); \
/* Note: Lazy implementation */ \
M_CALL_INIT(oplist, *ptr); \
M_F(name, _pop_front)(ptr, d); \
M_F(name, _pop_front)M_R(ptr, d); \
} \
,) \
\
@@ -663,8 +657,7 @@
return M_CONST_CAST(type, &it->node->data[it->index]); \
} \
\
M_INLINE void \
M_F(name, _remove)(deque_t d, it_t it) \
M_P(void, name, _remove, deque_t d, it_t it) \
{ \
M_D3QU3_CONTRACT(d); \
M_ASSERT (it != NULL && it->node != NULL); \
@@ -711,7 +704,7 @@
/* Node deletion */ \
M_ASSERT(d->count > 1); \
M_F(name, _node_list_unlink)(n); \
M_CALL_FREE(oplist, n); \
M_CALL_FREE(oplist, char, n, sizeof(node_t) + n->capacity * sizeof(type) ); \
} else { \
memmove(&n->data[it->index], &n->data[it->index+1], \
sizeof(type) * (it->node->size - it->index - 1)); \
@@ -726,14 +719,13 @@
M_D3QU3_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _init_set)(deque_t d, const deque_t src) \
M_P(void, name, _init_set, deque_t d, const deque_t src) \
{ \
M_D3QU3_CONTRACT(src); \
M_ASSERT (d != NULL); \
M_F(name, _node_list_init)(d->list); \
d->default_size = M_USE_DEQUE_DEFAULT_SIZE + src->count; \
node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \
node_t *n = M_F(name,_i_new_node)M_R(d); \
d->count = src->count; \
d->default_size /= 2; \
M_F(name, _node_list_push_back)(d->list, n); \
@@ -753,15 +745,14 @@
M_D3QU3_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _set)(deque_t d, deque_t const src) \
M_P(void, name, _set, deque_t d, deque_t const src) \
{ \
if (M_UNLIKELY (src == d)) \
return; \
/* TODO: Reuse memory of d! */ \
M_ON_EXCEPTION( M_F(name, _init)(d) ) { \
M_F(name, _clear)(d); \
M_F(name, _init_set)(d, src); \
M_F(name, _clear)M_R(d); \
M_F(name, _init_set)M_R(d, src); \
} \
} \
\
@@ -781,12 +772,11 @@
M_D3QU3_CONTRACT(d); \
} \
\
M_INLINE void \
M_F(name, _move)(deque_t d, deque_t src) \
M_P(void, name, _move, deque_t d, deque_t src) \
{ \
M_D3QU3_CONTRACT(d); \
M_D3QU3_CONTRACT(src); \
M_F(name, _clear)(d); \
M_F(name, _clear)M_R(d); \
M_F(name, _init_move)(d, src); \
M_D3QU3_CONTRACT(d); \
} \
@@ -832,10 +822,10 @@
return M_CONST_CAST(type, M_F(name, _get)(d, key)); \
} \
\
M_INLINE void \
M_F(name, _set_at)(deque_t d, size_t key, type const x) \
M_P(void, name, _set_at, deque_t d, size_t key, type const x) \
{ \
M_D3QU3_CONTRACT(d); \
M_UNUSED_CONTEXT(); \
M_ASSERT_INDEX (key, d->count); \
type *p = M_F(name, _get)(d, key); \
M_CALL_SET(oplist, *p, x); \
@@ -895,11 +885,10 @@
, /* NO SWAP */) \
\
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, deque_t const deque, bool append) \
M_P(void, name, _get_str, m_string_t str, deque_t const deque, bool append) \
{ \
M_D3QU3_CONTRACT(deque); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
it_t it; \
for (M_F(name, _it)(it, deque) ; \
!M_F(name, _end_p)(it); \
@@ -907,9 +896,9 @@
type const *item = M_F(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_F(name, _last_p)(it)) \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
} \
m_string_push_back (str, ']'); \
m_string_push_back M_R(str, ']'); \
} \
, /* no GET_STR */ ) \
\
@@ -934,12 +923,11 @@
, /* no OUT_STR */ ) \
\
M_IF_METHOD2(PARSE_STR, INIT, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(deque_t deque, const char str[], const char **endp) \
M_P(bool, name, _parse_str, deque_t deque, const char str[], const char **endp) \
{ \
M_D3QU3_CONTRACT(deque); \
M_ASSERT (str != NULL); \
M_F(name,_reset)(deque); \
M_F(name,_reset)M_R(deque); \
int c = *str++; \
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
c = *str++; \
@@ -950,7 +938,7 @@
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
c = m_core_str_nospace(&str); \
if (b == false || c == 0) { c = 0; break; } \
M_F(name, _push_back)(deque, item); \
M_F(name, _push_back)M_R(deque, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
exit: \
@@ -961,12 +949,11 @@
, /* no PARSE_STR */ ) \
\
M_IF_METHOD2(IN_STR, INIT, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(deque_t deque, FILE *file) \
M_P(bool, name, _in_str, deque_t deque, FILE *file) \
{ \
M_D3QU3_CONTRACT(deque); \
M_ASSERT (file != NULL); \
M_F(name,_reset)(deque); \
M_F(name,_reset)M_R(deque); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
@@ -978,7 +965,7 @@
bool b = M_CALL_IN_STR(oplist, item, file); \
c = m_core_fgetc_nospace(file); \
if (b == false || c == EOF) { c = 0; break; } \
M_F(name, _push_back)(deque, item); \
M_F(name, _push_back)M_R(deque, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
M_D3QU3_CONTRACT(deque); \
@@ -987,47 +974,45 @@
, /* no IN_STR */ ) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, const deque_t deque) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const deque_t deque) \
{ \
M_D3QU3_CONTRACT(deque); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
bool first_done = false; \
ret = f->m_interface->write_array_start(local, f, deque->count); \
ret = f->m_interface->write_array_start M_R(local, f, deque->count); \
M_F(name, _it_ct) it; \
for (M_F(name, _it)(it, deque) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
type const *item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
first_done = true; \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end M_R(local, f); \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(deque_t deque, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, deque_t deque, m_serial_read_t f) \
{ \
M_D3QU3_CONTRACT(deque); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
size_t estimated_size = 0; \
M_F(name,_reset)(deque); \
M_F(name,_reset)M_R(deque); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
M_QLET(1, item, type, oplist) { \
do { \
ret = M_CALL_IN_SERIAL(oplist, item, f); \
if (ret != M_SERIAL_OK_DONE) { break; } \
M_F(name, _push_back)(deque, item); \
M_F(name, _push_back)M_R(deque, item); \
ret = f->m_interface->read_array_next(local, f); \
} while (ret == M_SERIAL_OK_CONTINUE); \
} \
@@ -1037,11 +1022,9 @@
/* Definition of the emplace_back function for deque */
#define M_D3QUE_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
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)(v); \
M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \
M_ON_EXCEPTION(v->back->index --, v->count--) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \
@@ -1050,11 +1033,9 @@
/* Definition of the emplace_front function for deque */
#define M_D3QUE_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
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_front_raw)(v); \
M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)M_R(v); \
M_ON_EXCEPTION(v->front->index ++, v->count--) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \
@@ -1076,6 +1057,7 @@
((M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* OPLIST definition of a deque */
#ifndef M_USE_CONTEXT
#define M_D3QU3_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)) \
,INIT_SET(M_F(name, _init_set)) \
@@ -1116,7 +1098,48 @@
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#else
#define M_D3QU3_OPLIST_P3(name, oplist) \
(INIT(API_0P(M_F(name, _init))) \
,INIT_SET(API_0P(M_F(name, _init_set))) \
,INIT_WITH(API_1(M_INIT_WITH_VAI)) \
,SET(API_0P(M_F(name, _set))) \
,CLEAR(API_0P(M_F(name, _clear))) \
,INIT_MOVE(M_F(name, _init_move)) \
,MOVE(API_0P(M_F(name, _move))) \
,SWAP(M_F(name, _swap)) \
,NAME(name) \
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,EMPTY_P(M_F(name,_empty_p)) \
,IT_TYPE(M_F(name,_it_ct)) \
,IT_FIRST(M_F(name,_it)) \
,IT_LAST(M_F(name,_it_last)) \
,IT_END(M_F(name,_it_end)) \
,IT_SET(M_F(name,_it_set)) \
,IT_END_P(M_F(name,_end_p)) \
,IT_LAST_P(M_F(name,_last_p)) \
,IT_EQUAL_P(M_F(name,_it_equal_p)) \
,IT_NEXT(M_F(name,_next)) \
,IT_PREVIOUS(M_F(name,_previous)) \
,IT_REF(M_F(name,_ref)) \
,IT_CREF(M_F(name,_cref)) \
,IT_REMOVE(API_0P(M_F(name,_remove))) \
,RESET(API_0P(M_F(name,_reset))) \
,GET_SIZE(M_F(name, _size)) \
,PUSH(API_0P(M_F(name,_push_back))) \
,POP(API_0P(M_F(name,_pop_front))) \
,OPLIST(oplist) \
,M_IF_METHOD(GET_STR, oplist)(API_0P(GET_STR(M_F(name, _get_str))),) \
,M_IF_METHOD(PARSE_STR, oplist)(API_0P(PARSE_STR(M_F(name, _parse_str))),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#endif
/********************************* INTERNAL **********************************/
+216 -173
View File
@@ -27,7 +27,6 @@
#include "m-array.h"
/* Define a dictionary associating the key key_type to the value value_type and its associated functions.
USAGE:
DICT_DEF2(name, key_type, key_oplist, value_type, value_oplist)
@@ -155,14 +154,14 @@
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
// Define the maximum index
// Define the maximum index type (implying the maximum allowed size)
#ifdef M_USE_DICT_LARGE_INDEX
typedef uint64_t m_index_t;
#else
typedef uint32_t m_index_t;
#endif
// Define a pair index / hash
// Define a pair index of the cell where the (key,value) is stored / hash of the key.
typedef struct {
m_index_t index;
m_index_t hash;
@@ -296,7 +295,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
m_index_t count, count_delete; \
m_index_t upper_limit, lower_limit; \
m_index_t mask; \
m_index_t freelist_first_data, freelist_count; \
m_index_t freelist_first_data, freelist_count, freelist_cap; \
m_indexhash_t *index; \
M_F(name, _freelist_ct) *data; \
} dict_t[1]; \
@@ -328,8 +327,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
map->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (m_index_t) ((double) size * M_D1CT_OA_LOWER_BOUND) ; \
} \
\
M_INLINE void \
M_F(name, _init)(dict_t map) \
M_P(void, name, _init, dict_t map) \
{ \
M_ASSERT (map != NULL); \
map->mask = M_D1CT_INITIAL_SIZE-1; \
@@ -337,17 +335,16 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
map->count_delete = 0; \
M_C3(m_d1ct_,name,_update_limit)(map, M_D1CT_INITIAL_SIZE); \
/* The first 2 buckets are reserved for (empty) and (deleted) access. Allocation could be avoided */ \
map->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), NULL, (size_t) 1+2+map->upper_limit); \
map->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), NULL, 0, (size_t) 1+2+map->upper_limit); \
if (M_UNLIKELY_NOMEM (map->data == NULL)) { \
M_MEMORY_FULL( (2+M_D1CT_INITIAL_SIZE) * sizeof (M_F(name, _freelist_ct))); \
return ; \
M_MEMORY_FULL(M_F(name, _freelist_ct), 2+M_D1CT_INITIAL_SIZE); \
} \
map->freelist_first_data = 0; \
map->freelist_count = 2; \
map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, (size_t)(0+M_D1CT_INITIAL_SIZE)); \
map->freelist_cap = 1+2+map->upper_limit; \
map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, 0, (size_t)(0+M_D1CT_INITIAL_SIZE)); \
if (M_UNLIKELY_NOMEM (map->index == NULL)) { \
M_MEMORY_FULL( (2+M_D1CT_INITIAL_SIZE) * sizeof (m_indexhash_t)); \
return ; \
M_MEMORY_FULL(m_indexhash_t, 2+M_D1CT_INITIAL_SIZE); \
} \
/* Populate the initial table with the 'empty' representation which is 0 */ \
for(m_index_t i = 0; i < M_D1CT_INITIAL_SIZE; i++) { \
@@ -357,8 +354,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
M_D1CT_CONTRACT(map); \
} \
\
M_INLINE void \
M_F(name,_clear)(dict_t map) \
M_P(void, name,_clear, dict_t map) \
{ \
M_D1CT_CONTRACT(map); \
/* Clear objects */ \
@@ -371,8 +367,8 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
M_CALL_CLEAR(value_oplist, map->data[d].pair.value); \
} \
} \
M_CALL_FREE(key_oplist, map->index); \
M_CALL_FREE(key_oplist, map->data); \
M_CALL_FREE(key_oplist, m_indexhash_t, map->index, map->mask+1); \
M_CALL_FREE(key_oplist, M_F(name, _freelist_ct), map->data, map->freelist_cap); \
/* Mark the dictionary as cleared */ \
map->data = NULL; \
map->index = NULL; \
@@ -383,7 +379,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
{ \
M_D1CT_CONTRACT(org); \
memcpy(map, org, sizeof (dict_t)); \
/* Mark the original dictionary as cleared */ \
/* Mark the original dictionary as cleared (invalid representation) */ \
org->data = NULL; \
org->index = NULL; \
} \
@@ -451,8 +447,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
} \
} \
\
M_INLINE void \
M_C3(m_d1ct_,name,_resize_up)(dict_t h, m_index_t newSize, bool updateLimit) \
M_P(void, name, _i_resize_up, dict_t h, m_index_t newSize, bool updateLimit) \
{ \
/* NOTE: Contract may not be fulfilled here */ \
m_index_t oldSize = h->mask+1; \
@@ -466,21 +461,19 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
if (newSize > oldSize) { \
/* h->data is not always the same size than h->index: it may be bigger \
if there is some erase of items: h->index will shrink, but not h->data \
To have an estimate of the size, we look at the maximum index of it: \
if it is bigger than our new size, then we don't need to reallocate */ \
/* We need to allocate '2' for the dummy first two entries in the table (not used), \
then we can have at maximum only up to 'upper_limit+1' data */ \
if (1+2+h->upper_limit > h->freelist_count) { \
h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, (size_t) 1+2+h->upper_limit); \
if (1+2+h->upper_limit > h->freelist_cap) { \
h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, h->freelist_cap, (size_t) 1+2+h->upper_limit); \
if (M_UNLIKELY_NOMEM (h->data == NULL) ) { \
M_MEMORY_FULL((2+newSize)*sizeof (M_F(name, _freelist_ct))); \
return ; \
M_MEMORY_FULL(M_F(name, _freelist_ct), 2+newSize); \
} \
h->freelist_cap = 1+2+h->upper_limit; \
} \
m_indexhash_t *index = M_MEMORY_REALLOC(m_indexhash_t, h->index,(size_t) 0+newSize); \
m_indexhash_t *index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \
if (M_UNLIKELY_NOMEM (index == NULL) ) { \
M_MEMORY_FULL(newSize*sizeof(m_indexhash_t)); \
return ; \
M_MEMORY_FULL(m_indexhash_t, newSize); \
} \
h->index = index; \
\
@@ -511,7 +504,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
h->index[p].hash = hash; \
} else { \
m_indexhash_t t = { ind, hash }; \
m_array_index_push_back(tmp, t); \
m_array_index_push_back M_R(tmp, t); \
} \
} \
} \
@@ -521,7 +514,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
which contains what we weren't be able to fit in the first pass */ \
while (m_array_index_size(tmp) > 0) { \
m_indexhash_t ind; \
m_array_index_pop_back(&ind, tmp); \
m_array_index_pop_back M_R(&ind, tmp); \
m_index_t p = ind.hash & mask; \
/* NOTE: since the first pass, the bucket might be free now */ \
m_index_t s = 1; \
@@ -533,14 +526,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
h->index[p].hash = ind.hash; \
} \
\
m_array_index_clear(tmp); \
m_array_index_clear M_R(tmp); \
h->mask = newSize-1; \
h->count_delete = h->count; \
M_IF_DEBUG( M_C3(m_d1ct_,name,_control_after_resize)(h); ) \
} \
\
M_INLINE void \
M_C3(m_d1ct_,name,_resize_down)(dict_t h, m_index_t newSize) \
M_P(void, name, _i_resize_down, dict_t h, m_index_t newSize) \
{ \
/* NOTE: Contract may not be fulfilled here */ \
m_index_t oldSize = h->mask+1; \
@@ -563,7 +555,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
h->index[p].hash = hash; \
} else { \
m_indexhash_t t = { ind, hash }; \
m_array_index_push_back(tmp, t); \
m_array_index_push_back M_R(tmp, t); \
} \
} \
} \
@@ -583,7 +575,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
/* Pass 3: scan failed moved entries and move them back */ \
while (m_array_index_size(tmp) > 0) { \
m_indexhash_t ind; \
m_array_index_pop_back(&ind, tmp); \
m_array_index_pop_back M_R(&ind, tmp); \
m_index_t p = ind.hash & mask; \
m_index_t s = 1; \
while (h->index[p].index != 0) { \
@@ -594,12 +586,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
h->index[p].hash = ind.hash; \
} \
\
m_array_index_clear(tmp); \
m_array_index_clear M_R(tmp); \
h->count_delete = h->count; \
if (newSize != oldSize) { \
h->mask = newSize-1; \
M_C3(m_d1ct_,name,_update_limit)(h, newSize); \
h->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, (size_t)0+newSize); \
h->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \
M_ASSERT (h->index != NULL); \
/* FIXME: What to do for h->data ? */ \
} \
@@ -607,10 +599,9 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
M_D1CT_CONTRACT(h); \
} \
\
M_INLINE void \
M_IF(isSet)(M_F(name, _push), M_F(name, _set_at)) \
(dict_t map, key_type const key \
M_IF(isSet)(, M_DEFERRED_COMMA value_type const value)) \
M_IF(isSet)( \
M_P(void, name, _push, dict_t map, key_type const key) , \
M_P(void, name, _set_at, dict_t map, key_type const key, value_type const value)) \
{ \
M_D1CT_CONTRACT(map); \
const m_index_t mask = map->mask; \
@@ -653,16 +644,15 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
if (map->count > newSize/2) { \
newSize += newSize; \
if (M_UNLIKELY_NOMEM (newSize <= map->mask+1)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, (size_t)-1); \
} \
} \
M_C3(m_d1ct_,name,_resize_up)(map, newSize, true); \
M_F(name,_i_resize_up)M_R(map, newSize, true); \
} \
M_D1CT_CONTRACT(map); \
} \
\
M_INLINE value_type * \
M_F(name, _safe_get)(dict_t map, key_type const key) \
M_P(value_type *, name, _safe_get, dict_t map, key_type const key) \
{ \
M_D1CT_CONTRACT(map); \
const m_index_t mask = map->mask; \
@@ -712,18 +702,17 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
if (map->count > newSize/2) { \
newSize += newSize; \
if (M_UNLIKELY_NOMEM (newSize <= map->mask+1)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, (size_t)-1); \
} \
} \
M_C3(m_d1ct_,name,_resize_up)(map, newSize, true); \
M_F(name,_i_resize_up)M_R(map, newSize, true); \
} \
M_D1CT_CONTRACT(map); \
/* bucket index won't move even if resize is done */ \
return &map->data[d].pair.M_IF(isSet)(key, value); \
} \
\
M_INLINE bool \
M_F(name, _erase)(dict_t map, key_type const key) \
M_P(bool, name, _erase, dict_t map, key_type const key) \
{ \
M_D1CT_CONTRACT(map); \
\
@@ -754,7 +743,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
M_ASSERT (map->count >= 1); \
map->count--; \
if (M_UNLIKELY (map->count < map->lower_limit)) { \
M_C3(m_d1ct_,name,_resize_down)(map, (map->mask+1) >> 1); \
M_F(name,_i_resize_down)M_R(map, (map->mask+1) >> 1); \
} \
M_D1CT_CONTRACT(map); \
return true; \
@@ -879,40 +868,36 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
#define M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) \
\
\
M_INLINE void \
M_F(name, _init_set)(dict_t map, const dict_t org) \
M_P(void, name, _init_set, dict_t map, const dict_t org) \
{ \
dict_it_t it; \
M_ASSERT (map != org); \
M_F(name, _init)(map); \
M_F(name, _init)M_R(map); \
/* Naive implementation. No need to optimize such access */ \
for (M_F(name,_it)(it, org); !M_F(name,_end_p)(it); M_F(name,_next)(it)){ \
M_IF(isSet)( \
M_F(name,_push)(map, * M_F(name,_ref)(it) ) \
, M_F(name,_set_at)(map, M_F(name,_ref)(it)->key, M_F(name,_ref)(it)->value) \
M_F(name,_push)M_R(map, * M_F(name,_ref)(it) ) \
, M_F(name,_set_at)M_R(map, M_F(name,_ref)(it)->key, M_F(name,_ref)(it)->value) \
); \
} \
} \
\
M_INLINE void \
M_F(name, _set)(dict_t map, const dict_t org) \
M_P(void, name, _set, dict_t map, const dict_t org) \
{ \
if (M_LIKELY (map != org)) { \
/* Naive implementation. No need to optimize such access */ \
M_F(name, _clear)(map); \
M_F(name, _init_set)(map, org); \
M_F(name, _clear)M_R(map); \
M_F(name, _init_set)M_R(map, org); \
} \
} \
\
M_INLINE void \
M_F(name, _move)(dict_t map, dict_t org) \
M_P(void, name, _move, dict_t map, dict_t org) \
{ \
M_ASSERT (map != org); \
M_F(name,_clear)(map); \
M_F(name,_clear)M_R(map); \
M_F(name,_init_move)(map, org); \
} \
\
\
M_INLINE void \
M_F(name, _swap)(dict_t d1, dict_t d2) \
{ \
@@ -923,13 +908,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
memcpy( d2, tmp, sizeof (dict_t)); \
} \
\
M_INLINE void \
M_F(name, _reset)(dict_t d) \
M_P(void, name, _reset, dict_t d) \
{ \
if (d->count == 0) return; \
/* Naive algorithm. Not work optimizing it */ \
M_F(name, _clear)(d); \
M_F(name, _init)(d); \
M_F(name, _clear)M_R(d); \
M_F(name, _init)M_R(d); \
} \
\
M_INLINE value_type const * \
@@ -952,14 +936,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
return map->count; \
} \
\
M_INLINE void \
M_F(name,_reserve)(dict_t dict, size_t capacity) \
M_P(void, name,_reserve, dict_t dict, size_t capacity) \
{ \
if (capacity == 0) { \
/* Perform a shrink to fit: copy everything to a new dict properly, and move it back */ \
dict_t tmp; \
M_F(name, _init_set)(tmp, dict); \
M_F(name, _move)(dict, tmp); \
M_F(name, _init_set)M_R(tmp, dict); \
M_F(name, _move)M_R(dict, tmp); \
return; \
} \
/* Get the size which will allow to fit this capacity \
@@ -970,11 +953,11 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
M_ASSERT (M_POWEROF2_P(size)); \
/* Test for overflow of the computation */ \
if (M_UNLIKELY_NOMEM (size < capacity)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, (size_t)-1); \
} \
if (size > dict->mask+1) { \
dict->upper_limit = (M_F(name, _index_ct)) ((double) size * M_D1CT_OA_UPPER_BOUND) - 1; \
M_C3(m_d1ct_,name,_resize_up)(dict, size, false); \
M_F(name,_i_resize_up)M_R(dict, size, false); \
} \
} \
\
@@ -1009,28 +992,27 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
, /* no value equal */ ) \
\
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, const dict_t dict, const bool append) \
M_P(void, name, _get_str, m_string_t str, const dict_t dict, const bool append) \
{ \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "{"); \
(append ? m_string_cat_cstr : m_string_set_cstr)M_R(str, "{"); \
dict_it_t it; \
bool print_comma = false; \
for (M_F(name, _it)(it, dict) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
if (print_comma) \
m_string_push_back (str, ','); \
m_string_push_back M_R(str, ','); \
const it_deref_t *item = M_F(name, _cref)(it); \
M_IF(isSet)( \
M_CALL_GET_STR(key_oplist, str, *item, true); \
, \
M_CALL_GET_STR(key_oplist, str, item->key, true); \
m_string_push_back (str, ':'); \
m_string_push_back M_R(str, ':'); \
M_CALL_GET_STR(value_oplist, str, item->value, true); \
) \
print_comma = true; \
} \
m_string_push_back (str, '}'); \
m_string_push_back M_R(str, '}'); \
} \
, /* no GET_STR */ ) \
\
@@ -1062,11 +1044,10 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
, /* no OUT_STR */ ) \
\
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(dict_t dict, const char str[], const char **endp) \
M_P(bool, name, _parse_str, dict_t dict, const char str[], const char **endp) \
{ \
M_ASSERT (str != NULL); \
M_F(name, _reset)(dict); \
M_F(name, _reset)M_R(dict); \
int c = m_core_str_nospace(&str); \
if (M_UNLIKELY (c != '{')) { c = 0; goto exit; } \
c = m_core_str_nospace(&str); \
@@ -1080,7 +1061,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \
M_IF(isSet)( \
if (b == false) { c = 0; break; } \
M_F(name, _push)(dict, key); \
M_F(name, _push)M_R(dict, key); \
, /* is a map */ \
c = m_core_str_nospace(&str); \
if (b == false || c != ':') { c = 0; break; } \
@@ -1088,7 +1069,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
str--; \
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
if (b == false) { c = 0; break; } \
M_F(name, _set_at)(dict, key, value); \
M_F(name, _set_at)M_R(dict, key, value); \
) \
c = m_core_str_nospace(&str); \
} while (c == ','); \
@@ -1100,11 +1081,10 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
, /* no PARSE_STR */ ) \
\
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \
M_INLINE bool \
M_F(name, _in_str)(dict_t dict, FILE *file) \
M_P(bool, name, _in_str, dict_t dict, FILE *file) \
{ \
M_ASSERT (file != NULL); \
M_F(name, _reset)(dict); \
M_F(name, _reset)M_R(dict); \
int c = m_core_fgetc_nospace(file); \
if (M_UNLIKELY (c != '{')) return false; \
c = m_core_fgetc_nospace(file); \
@@ -1120,7 +1100,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
bool b = M_CALL_IN_STR(key_oplist, key, file); \
M_IF(isSet)( \
if (M_UNLIKELY (b == false)) { c = 0; break; } \
M_F(name, _push)(dict, key); \
M_F(name, _push)M_R(dict, key); \
, /* is map */ \
c = m_core_fgetc_nospace(file); \
if (M_UNLIKELY (b == false || c != ':')) { c = 0; break; } \
@@ -1129,7 +1109,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
ungetc(c, file); \
b = M_CALL_IN_STR(value_oplist, value, file); \
if (M_UNLIKELY (b == false)) { c = 0; break; } \
M_F(name, _set_at)(dict, key, value); \
M_F(name, _set_at)M_R(dict, key, value); \
) \
c = m_core_fgetc_nospace(file); \
} while (c == ','); \
@@ -1139,8 +1119,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
, /* no IN_STR */ ) \
\
M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, dict_t const t1) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, dict_t const t1) \
{ \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
@@ -1151,45 +1130,44 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
/* Format is different between associative container \
& set container */ \
M_IF(isSet)( \
ret = f->m_interface->write_array_start(local, f, M_F(name, _size)(t1)); \
ret = f->m_interface->write_array_start M_R(local, f, M_F(name, _size)(t1)); \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \
first_done = true; \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end M_R(local, f); \
, \
ret = f->m_interface->write_map_start(local, f, M_F(name, _size)(t1)); \
ret = f->m_interface->write_map_start M_R(local, f, M_F(name, _size)(t1)); \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_map_next(local, f); \
ret |= f->m_interface->write_map_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(key_oplist, f, item->key); \
ret |= f->m_interface->write_map_value(local, f); \
ret |= f->m_interface->write_map_value M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(value_oplist, f, item->value); \
first_done = true; \
} \
ret |= f->m_interface->write_map_end(local, f); \
ret |= f->m_interface->write_map_end M_R(local, f); \
) \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(dict_t t1, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, dict_t t1, m_serial_read_t f) \
{ \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
size_t estimated_size = 0; \
M_F(name,_reset)(t1); \
M_F(name,_reset)M_R(t1); \
M_QLET(1, key, key_type, key_oplist) \
M_IF(isSet)(,M_QLET(2, value, value_type, value_oplist)) { \
M_IF(isSet)( \
@@ -1198,7 +1176,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
do { \
ret = M_CALL_IN_SERIAL(key_oplist, key, f); \
if (ret != M_SERIAL_OK_DONE) break; \
M_F(name, _push)(t1, key); \
M_F(name, _push)M_R(t1, key); \
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
, /* is map */ \
ret = f->m_interface->read_map_start(local, f, &estimated_size); \
@@ -1210,7 +1188,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
if (ret != M_SERIAL_OK_CONTINUE) break; \
ret = M_CALL_IN_SERIAL(value_oplist, value, f); \
if (ret != M_SERIAL_OK_DONE) break; \
M_F(name, _set_at)(t1, key, value); \
M_F(name, _set_at)M_R(t1, key, value); \
} while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \
) /* End of IF isSet */ \
} \
@@ -1219,8 +1197,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
, /* no in_serial */ ) \
\
M_IF(isSet)( \
M_INLINE void \
M_F(name, _splice)(dict_t d1, dict_t d2) \
M_P(void, name, _splice, dict_t d1, dict_t d2) \
{ \
dict_it_t it; \
M_ASSERT(d1 != d2); \
@@ -1229,14 +1206,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
uses the same order than d1 */ \
for (M_F(name, _it)(it, d2); !M_F(name, _end_p)(it); M_F(name, _next)(it)){ \
const it_deref_t *item = M_F(name, _cref)(it); \
M_F(name, _push)(d1, *item); \
M_F(name, _push)M_R(d1, *item); \
} \
M_F(name, _reset)(d2); \
M_F(name, _reset)M_R(d2); \
} \
, \
M_IF_METHOD(ADD, value_oplist)( \
M_INLINE void \
M_F(name, _splice)(dict_t d1, dict_t d2) \
M_P(void, name, _splice, dict_t d1, dict_t d2) \
{ \
dict_it_t it; \
/* NOTE: Despite using set_at, the accessing of the item in d1 \
@@ -1246,12 +1222,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
const struct M_F(name, _pair_s) *item = M_F(name, _cref)(it); \
value_type *ptr = M_F(name, _get)(d1, item->key); \
if (ptr == NULL) { \
M_F(name, _set_at)(d1, item->key, item->value); \
M_F(name, _set_at)M_R(d1, item->key, item->value); \
} else { \
M_CALL_ADD(value_oplist, *ptr, *ptr, item->value); \
} \
} \
M_F(name, _reset)(d2); \
M_F(name, _reset)M_R(d2); \
} \
, /* NO UPDATE */) ) \
\
@@ -1277,6 +1253,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
/* Define the oplist of a dictionary
NOTE: IT_REF is not exported so that the contained appears as not modifiable
by algorithm.*/
#ifndef M_USE_CONTEXT
#define M_D1CT_OPLIST_P4(name, key_oplist, value_oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -1316,6 +1293,46 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
,M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_F(name, _equal_p)),) \
)
#else
#define M_D1CT_OPLIST_P4(name, key_oplist, value_oplist) \
(INIT(API_0P(M_F(name, _init))), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_INIT_KEY_VAI)), \
SET(API_0P(M_F(name, _set))), \
CLEAR(API_0P(M_F(name, _clear))), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(API_0P(M_F(name, _move))), \
SWAP(M_F(name, _swap)), \
RESET(API_0P(M_F(name, _reset))), \
NAME(name), TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
SUBTYPE(M_F(name, _subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name, _it_set)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_LAST_P(M_F(name,_last_p)), \
IT_NEXT(M_F(name,_next)), \
IT_CREF(M_F(name,_cref)) \
,KEY_TYPE(M_F(name, _key_ct)) \
,VALUE_TYPE(M_F(name, _value_ct)) \
,SET_KEY(API_0P(M_F(name, _set_at))) \
,GET_KEY(M_F(name, _get)) \
,SAFE_GET_KEY(API_0P(M_F(name, _safe_get))) \
,ERASE_KEY(API_0P(M_F(name, _erase))) \
,KEY_OPLIST(key_oplist) \
,VALUE_OPLIST(value_oplist) \
,GET_SIZE(M_F(name, _size)) \
,M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(API_0P(GET_STR(M_F(name, _get_str))),) \
,M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(API_0P(PARSE_STR(M_F(name, _parse_str))),) \
,M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \
,M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \
,M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \
,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_F(name, _equal_p)),) \
)
#endif
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
@@ -1332,6 +1349,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
/* Define the oplist of a set
Note: IT_REF is not exported so that the contained appears as not modifiable
*/
#ifndef M_USE_CONTEXT
#define M_D1CT_SET_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -1372,6 +1390,47 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST)
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
,EQUAL(M_F(name, _equal_p)), \
)
#else
#define M_D1CT_SET_OPLIST_P3(name, oplist) \
(INIT(API_0P(M_F(name, _init))), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_INIT_VAI)), \
SET(API_0P(M_F(name, _set))), \
CLEAR(API_0P(M_F(name, _clear))), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(API_0P(M_F(name, _move))), \
SWAP(M_F(name, _swap)), \
RESET(API_0P(M_F(name, _reset))), \
NAME(name), TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
SUBTYPE(M_F(name, _subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
PUSH(API_0P(M_F(name,_push))), \
KEY_TYPE(M_F(name, _key_ct)), \
VALUE_TYPE(M_F(name, _key_ct)), \
GET_KEY(M_F(name, _get)), \
SAFE_GET_KEY(API_0P(M_F(name, _safe_get))), \
ERASE_KEY(API_0P(M_F(name, _erase))), \
KEY_OPLIST(oplist), \
VALUE_OPLIST(oplist), \
GET_SIZE(M_F(name, _size)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name, _it_set)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_LAST_P(M_F(name,_last_p)), \
IT_NEXT(M_F(name,_next)), \
IT_CREF(M_F(name,_cref)) \
,OPLIST(oplist) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \
,EQUAL(M_F(name, _equal_p)), \
)
#endif
/******************************** INTERNAL ***********************************/
@@ -1445,8 +1504,8 @@ enum m_d1ct_oa_element_e {
\
/* NOTE: We don't want a real oplist for this sub type */ \
M_ARRAY_DEF(M_F(name, _array_pair), M_F(name, _pair_ct), \
(INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \
INIT_SET(M_MEMCPY_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \
(INIT(M_NOTHING_DEFAULT), SET(M_SET_DEFAULT), \
INIT_SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \
\
typedef struct M_F(name,_s) { \
size_t mask, count, count_delete; \
@@ -1477,18 +1536,16 @@ enum m_d1ct_oa_element_e {
dict->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (size_t) ((double) size * coeff_down) ; \
} \
\
M_INLINE void \
M_F(name, _init)(dict_t dict) \
M_P(void, name, _init, dict_t dict) \
{ \
M_ASSERT(0 <= (coeff_down) && (coeff_down)*2 < (coeff_up) && (coeff_up) < 1); \
dict->mask = M_D1CT_INITIAL_SIZE-1; \
dict->count = 0; \
dict->count_delete = 0; \
M_C3(m_d1ct_,name,_update_limit)(dict, M_D1CT_INITIAL_SIZE); \
dict->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), NULL, M_D1CT_INITIAL_SIZE); \
dict->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), NULL, 0, M_D1CT_INITIAL_SIZE); \
if (M_UNLIKELY_NOMEM (dict->data == NULL)) { \
M_MEMORY_FULL(sizeof (M_F(name, _pair_ct)) * M_D1CT_INITIAL_SIZE); \
return ; \
M_MEMORY_FULL(M_F(name, _pair_ct), M_D1CT_INITIAL_SIZE); \
} \
/* Populate the initial table with the 'empty' representation */ \
for(size_t i = 0; i < M_D1CT_INITIAL_SIZE; i++) { \
@@ -1498,8 +1555,7 @@ enum m_d1ct_oa_element_e {
M_D1CT_OA_CONTRACT(dict); \
} \
\
M_INLINE void \
M_F(name, _clear)(dict_t dict) \
M_P(void, name, _clear, dict_t dict) \
{ \
M_D1CT_OA_CONTRACT(dict); \
for(size_t i = 0; i <= dict->mask; i++) { \
@@ -1509,7 +1565,7 @@ enum m_d1ct_oa_element_e {
M_CALL_CLEAR(value_oplist, dict->data[i].value); \
} \
} \
M_CALL_FREE(key_oplist, dict->data); \
M_CALL_FREE(key_oplist, M_F(name, _pair_ct), dict->data, dict->mask+1); \
/* Not really needed, but safer */ \
dict->mask = 0; \
dict->data = NULL; \
@@ -1557,8 +1613,7 @@ enum m_d1ct_oa_element_e {
} \
) \
\
M_INLINE void M_ATTR_COLD_FUNCTION \
M_C3(m_d1ct_,name,_resize_up)(dict_t h, size_t newSize, bool updateLimit) \
M_P(void, name, _i_resize_up, dict_t h, size_t newSize, bool updateLimit) \
{ \
size_t oldSize = h->mask+1; \
M_ASSERT (newSize >= oldSize); \
@@ -1566,10 +1621,9 @@ enum m_d1ct_oa_element_e {
M_F(name, _pair_ct) *data = h->data; \
/* resize can be called just to delete the items */ \
if (newSize > oldSize) { \
data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, newSize); \
data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, oldSize, newSize); \
if (M_UNLIKELY_NOMEM (data == NULL) ) { \
M_MEMORY_FULL(sizeof (M_F(name, _pair_ct)) * newSize); \
return ; \
M_MEMORY_FULL(M_F(name, _pair_ct), newSize); \
} \
\
/* First mark the extended space as empty */ \
@@ -1595,7 +1649,7 @@ enum m_d1ct_oa_element_e {
Reserve a little bit of array to avoid reallocation if possible */ \
M_F(name, _array_pair_ct) tmp; \
M_F(name, _array_pair_init)(tmp); \
M_F(name, _array_pair_reserve)(tmp, oldSize >> 2); \
M_F(name, _array_pair_reserve)M_R(tmp, oldSize >> 2); \
const size_t mask = (newSize -1); \
\
for(size_t i = 0 ; i < oldSize; i++) { \
@@ -1605,12 +1659,12 @@ enum m_d1ct_oa_element_e {
if (p != i) { \
if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \
|| M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED))) { \
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} else { \
M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw) (tmp); \
M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \
M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \
M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \
} \
M_CALL_OOR_SET(key_oplist, data[i].key, M_D1CT_OA_EMPTY); \
} \
@@ -1635,7 +1689,7 @@ enum m_d1ct_oa_element_e {
M_F(name, _array_pair_pop_move)(&data[p], tmp); \
} \
\
M_F(name, _array_pair_clear) (tmp); \
M_F(name, _array_pair_clear)M_R(tmp); \
h->mask = newSize-1; \
h->count_delete = h->count; \
if (updateLimit == true) { \
@@ -1646,10 +1700,9 @@ enum m_d1ct_oa_element_e {
M_D1CT_OA_CONTRACT(h); \
} \
\
M_INLINE void M_ATTR_HOT_FUNCTION \
M_IF(isSet)(M_F(name, _push), M_F(name,_set_at)) \
(dict_t dict, key_type const key \
M_IF(isSet)(, M_DEFERRED_COMMA value_type const value) ) \
M_IF(isSet)( \
M_P(void, name, _push, dict_t dict, key_type const key) , \
M_P(void, name, _set_at, dict_t dict, key_type const key, value_type const value)) \
{ \
M_D1CT_OA_CONTRACT(dict); \
/* NOTE: key can not be the representation of empty or deleted */ \
@@ -1693,16 +1746,15 @@ enum m_d1ct_oa_element_e {
if (dict->count > (dict->mask / 2)) { \
newSize += newSize; \
if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, -(size_t)1); \
} \
} \
M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \
M_F(name,_i_resize_up)M_R(dict, newSize, true); \
} \
M_D1CT_OA_CONTRACT(dict); \
} \
\
M_INLINE value_type * M_ATTR_HOT_FUNCTION \
M_F(name,_safe_get)(dict_t dict, key_type const key) \
M_P(value_type *, name,_safe_get, dict_t dict, key_type const key) \
{ \
M_D1CT_OA_CONTRACT(dict); \
/* NOTE: key can not be the representation of empty or deleted */ \
@@ -1747,24 +1799,18 @@ enum m_d1ct_oa_element_e {
if (dict->count > (dict->mask / 2)) { \
newSize += newSize; \
if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, (size_t)-1); \
} \
} \
M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \
M_F(name,_i_resize_up)M_R(dict, newSize, true); \
/* data is now invalid */ \
return M_F(name, _get)(dict, key); \
} \
M_D1CT_OA_CONTRACT(dict); \
return &data[p].M_IF(isSet)(key, value); \
} \
M_INLINE M_ATTR_DEPRECATED value_type * \
M_F(name,_get_at)(dict_t dict, key_type const key) \
{ \
return M_F(name,_safe_get)(dict, key); \
} \
\
M_INLINE void M_ATTR_COLD_FUNCTION \
M_C3(m_d1ct_,name,_resize_down)(dict_t h, size_t newSize) \
M_P(void, name, _i_resize_down, dict_t h, size_t newSize) \
{ \
size_t oldSize = h->mask+1; \
M_ASSERT (newSize <= oldSize && M_POWEROF2_P(newSize)); \
@@ -1787,12 +1833,12 @@ enum m_d1ct_oa_element_e {
if (p != i) { \
if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \
|| M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) { \
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} else { \
M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw) (tmp); \
M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \
M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \
M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \
} \
M_CALL_OOR_SET(key_oplist, data[i].key, M_D1CT_OA_EMPTY); \
} \
@@ -1810,8 +1856,8 @@ enum m_d1ct_oa_element_e {
M_ASSERT (s <= h->mask); \
} while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \
} \
M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \
M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \
} \
} \
/* Pass 3: scan moved entries and move them back */ \
@@ -1828,12 +1874,12 @@ enum m_d1ct_oa_element_e {
M_F(name, _array_pair_pop_move)(&data[p], tmp); \
} \
\
M_F(name, _array_pair_clear) (tmp); \
M_F(name, _array_pair_clear) M_R(tmp); \
h->count_delete = h->count; \
if (newSize != oldSize) { \
h->mask = newSize-1; \
M_C3(m_d1ct_,name,_update_limit)(h, newSize); \
h->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, newSize); \
h->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, oldSize, newSize); \
M_ASSERT (h->data != NULL); \
} \
M_IF_DEBUG (M_ASSERT (M_C3(m_d1ct_,name,_control_after_resize)(h));) \
@@ -1841,8 +1887,7 @@ enum m_d1ct_oa_element_e {
M_D1CT_OA_CONTRACT(h); \
} \
\
M_INLINE bool \
M_F(name,_erase)(dict_t dict, key_type const key) \
M_P(bool, name,_erase, dict_t dict, key_type const key) \
{ \
M_D1CT_OA_CONTRACT(dict); \
/* NOTE: key can't be the representation of empty or deleted */ \
@@ -1871,7 +1916,7 @@ enum m_d1ct_oa_element_e {
M_ASSERT (dict->count >= 1); \
dict->count--; \
if (M_UNLIKELY (dict->count < dict->lower_limit)) { \
M_C3(m_d1ct_,name,_resize_down)(dict, (dict->mask+1) >> 1); \
M_F(name,_i_resize_down)M_R(dict, (dict->mask+1) >> 1); \
} \
M_D1CT_OA_CONTRACT(dict); \
return true; \
@@ -2027,13 +2072,13 @@ enum m_d1ct_oa_element_e {
#define M_USE_MAX_PREFETCH 16
#endif
// WIP. Only if isSet is true for the time being
// WIP. Only if isSet is false for the time being
#define M_D1CT_OA_DEF_BULK(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t, it_deref_t) \
\
M_INLINE void \
M_F(name, _bulk_get)(unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type const key[M_VLA(n)], value_type def) \
M_P(void, name, _bulk_get, unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type const key[M_VLA(n)], value_type def) \
{ \
M_D1CT_OA_CONTRACT (dict); \
M_UNUSED_CONTEXT(); \
size_t h[M_USE_MAX_PREFETCH]; \
M_F(name, _pair_ct) *data = dict->data; \
const size_t mask = dict->mask; \
@@ -2063,8 +2108,7 @@ M_F(name, _bulk_get)(unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type
} \
} \
\
M_INLINE void \
M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], key_type const key[M_VLA(n)]) \
M_P(void, name, _bulk_set, dict_t dict, unsigned n, value_type const val[M_VLA(n)], key_type const key[M_VLA(n)]) \
{ \
M_D1CT_OA_CONTRACT (dict); \
size_t h[M_USE_MAX_PREFETCH]; \
@@ -2112,10 +2156,10 @@ M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], ke
if (dict->count > (dict->mask / 2)) { \
newSize += newSize; \
if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, (size_t)-1); \
} \
} \
M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \
M_F(name,_i_resize_up)M_R(dict, newSize, true); \
} \
next: \
(void)0; \
@@ -2124,9 +2168,8 @@ M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], ke
} \
\
\
M_INLINE void \
M_F(name, _bulk_update)(dict_t dict, unsigned n, value_type val[M_VLA(n)], key_type const key[M_VLA(n)], value_type def, \
void (*update)(dict_t dict, key_type const key, value_type *storeval, value_type *newval)) \
M_P(void, name, _bulk_update, dict_t dict, unsigned n, value_type val[M_VLA(n)], key_type const key[M_VLA(n)], value_type def, \
void (*update)(dict_t dict, key_type const key, value_type *storedval, value_type *newval)) \
{ \
M_D1CT_OA_CONTRACT (dict); \
size_t h[M_USE_MAX_PREFETCH]; \
@@ -2175,10 +2218,10 @@ M_F(name, _bulk_update)(dict_t dict, unsigned n, value_type val[M_VLA(n)], key_t
if (dict->count > (dict->mask / 2)) { \
newSize += newSize; \
if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \
M_MEMORY_FULL((size_t)-1); \
M_MEMORY_FULL(char, (size_t)-1); \
} \
} \
M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \
M_F(name,_i_resize_up)M_R(dict, newSize, true); \
} \
next: \
(void)0; \
+5 -8
View File
@@ -103,16 +103,14 @@ typedef struct m_genint_s {
* meaning it can be used to index global unique resources shared
* for all threads.
*/
M_INLINE void
m_genint_init(m_genint_t s, unsigned int n)
M_P(void, m_genint, _init, m_genint_t s, unsigned int n)
{
M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC);
const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE;
const unsigned int index = n % M_GEN1NT_LIMBSIZE;
atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc);
atomic_ullong *ptr = M_MEMORY_REALLOC (m_context, atomic_ullong, NULL, 0, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(alloc);
return;
M_MEMORY_FULL(atomic_ullong, alloc);
}
s->n = n;
s->data = ptr;
@@ -126,11 +124,10 @@ m_genint_init(m_genint_t s, unsigned int n)
}
/* Clear an integer generator (Destructor) */
M_INLINE void
m_genint_clear(m_genint_t s)
M_P(void, m_genint, _clear, m_genint_t s)
{
M_GEN1NT_CONTRACT(s);
M_MEMORY_FREE(s->data);
M_MEMORY_FREE(m_context, atomic_ullong, s->data, s->max+1);
s->data = NULL;
}
+6 -10
View File
@@ -210,8 +210,7 @@ typedef struct m_il1st_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
M_INLINE void \
M_F(name, _reset)(list_t list) \
M_P(void, name, _reset, list_t list) \
{ \
M_IL1ST_CONTRACT(name, list); \
for(struct m_il1st_head_s *it = list->name.next, *next ; \
@@ -232,11 +231,10 @@ typedef struct m_il1st_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
M_INLINE void \
M_F(name, _clear)(list_t list) \
M_P(void, name, _clear, list_t list) \
{ \
/* Nothing to do more than clean the list itself */ \
M_F(name, _reset)(list); \
M_F(name, _reset)M_R(list); \
/* For safety purpose (create invalid representation of object) */ \
list->name.next = NULL; \
list->name.prev = NULL; \
@@ -267,10 +265,9 @@ typedef struct m_il1st_head_s {
M_IL1ST_CONTRACT(name, list); \
} \
\
M_INLINE void \
M_F(name, _move)(list_t list, list_t ref) \
M_P(void, name, _move, list_t list, list_t ref) \
{ \
M_F(name, _clear)(list); \
M_F(name, _clear)M_R(list); \
M_F(name, _init_move)(list, ref); \
} \
\
@@ -511,8 +508,7 @@ typedef struct m_il1st_head_s {
return M_CONST_CAST(type, ptr); \
} \
\
M_INLINE void \
M_F(name, _remove)(list_t list, it_t it) \
M_P(void, name, _remove, list_t list, it_t it) \
{ \
M_IL1ST_CONTRACT(name, list); \
M_IL1ST_NODE_CONTRACT(it->current); \
-255
View File
@@ -1,255 +0,0 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_I_SHARED_PTR_H
#define MSTARLIB_I_SHARED_PTR_H
#include "m-core.h"
#include "m-atomic.h"
M_BEGIN_PROTECTED_CODE
/* Define the oplist of a intrusive shared pointer.
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
#define M_ISHARED_PTR_OPLIST(...) \
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
/* Interface to add to a structure to allow intrusive support.
name: name of the intrusive shared pointer.
type: name of the type of the structure (aka. struct test_s) - not used currently.
NOTE: There can be only one interface of this kind in a type! */
#define M_ISHARED_PTR_INTERFACE(name, type) \
atomic_int M_F(name, _cpt)
/* Value of the interface field for static initialization (Uses C99 designated element). */
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
.M_F(name, _cpt) = M_ATOMIC_VAR_INIT(0)
/* Value of the interface field for static initialization (Uses C89 designated element). */
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
M_ATOMIC_VAR_INIT(0)
/* Define the intrusive shared pointer type and its M_INLINE functions.
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
#define M_ISHARED_PTR_DEF(name, ...) \
M_ISHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
/* Define the intrusive shared pointer type and its M_INLINE functions
as the name name_t
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
#define M_ISHARED_PTR_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
(name, __VA_ARGS__ , name_t ))) \
M_END_PROTECTED_CODE
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
// Deferred evaluation
#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_PTR_OPLIST_P2 arg
/* Validation of the given oplist */
#define M_ISHAR3D_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_OPLIST_P3, M_ISHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define M_ISHAR3D_PTR_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
// Define the oplist
#define M_ISHAR3D_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_INIT_DEFAULT), \
INIT_SET(API_4(M_F(name, _init_set))), \
SET(M_F(name, _set) M_IPTR), \
CLEAR(M_F(name, _clear)), \
RESET(M_F(name, _reset) M_IPTR), \
NAME(name), \
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
OPLIST(oplist), \
SUBTYPE(M_F(name, _subtype_ct)) \
)
/******************************** INTERNAL ***********************************/
// Deferred evaluation
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_DEF_P3, M_ISHAR3D_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
/* Stop processing with a compilation failure */
#define M_ISHAR3D_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \
M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
/* Define the types */
#define M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
\
/* The shared pointer is only a pointer to the type */ \
typedef type *shared_t; \
\
/* Define internal types for oplist */ \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
\
M_INLINE shared_t \
M_F(name, _init)(type *ptr) \
{ \
/* Initialize the type referenced by the pointer */ \
if (M_LIKELY (ptr != NULL)) { \
atomic_init(&ptr->M_F(name, _cpt), 2); \
} \
return ptr; \
} \
\
M_INLINE shared_t \
M_F(name, _init_set)(shared_t shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
int n = atomic_fetch_add(&(shared->M_F(name, _cpt)), 2); \
(void) n; \
} \
return shared; \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_IF_DISABLED_METHOD(NEW, oplist) \
( \
/* This function is only for static object */ \
M_INLINE shared_t \
M_F(name, _init_once)(type *shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
/* Pretty much like atomic_add, except the first one increment by 1, others by 2 */ \
int o = atomic_load(&(shared->M_F(name, _cpt))); \
int n; \
do { \
n = o + 1 + (o != 0); \
} while (!atomic_compare_exchange_strong(&(shared->M_F(name, _cpt)), &o, n)); \
if (o == 0) { \
/* Partial initialization: _cpt is odd */ \
/* Call the INIT function once */ \
M_CALL_INIT(oplist, *shared); \
/* Finish initialization: _cpt is even */ \
atomic_fetch_add(&(shared->M_F(name, _cpt)), 1); \
} else if ( (o&1) != 0) { \
/* Not fully initialized yet: wait for initialization */ \
m_core_backoff_ct bkoff; \
m_core_backoff_init(bkoff); \
/* Wait for _cpt to be _even */ \
while ((atomic_load(&(shared->M_F(name, _cpt)))&1) != 0 ) { \
m_core_backoff_wait(bkoff); \
} \
} \
M_ASSERT( (atomic_load(&(shared->M_F(name, _cpt)))&1) == 0); \
} \
return shared; \
} \
, \
/* This function is only for dynamic object */ \
M_INLINE shared_t \
M_F(name, _init_new)(void) \
{ \
type *ptr = M_CALL_NEW(oplist, type); \
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
M_MEMORY_FULL(sizeof(type)); \
return NULL; \
} \
M_CALL_INIT(oplist, *ptr); \
atomic_init (&ptr->M_F(name, _cpt), 2); \
return ptr; \
} \
/* End of NEW */) \
, /* End of INIT */) \
\
M_INLINE void \
M_F(name, _clear)(shared_t shared) \
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_F(name, _cpt)), 2) == 2) { \
M_CALL_CLEAR(oplist, *shared); \
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
} \
} \
} \
\
M_INLINE void \
M_F(name, _clear_ptr)(shared_t *shared) \
{ \
M_ASSERT(shared != NULL); \
M_F(name, _clear)(*shared); \
*shared = NULL; \
} \
\
M_INLINE void \
M_F(name, _reset)(shared_t *shared) \
{ \
M_F(name, _clear)(*shared); \
*shared = NULL; \
} \
\
M_INLINE void \
M_F(name, _set)(shared_t *ptr, shared_t shared) \
{ \
M_ASSERT (ptr != NULL); \
if (M_LIKELY (*ptr != shared)) { \
M_F(name, _clear)(*ptr); \
*ptr = M_F(name, _init_set)(shared); \
} \
} \
\
M_END_PROTECTED_CODE
/******************************** INTERNAL ***********************************/
#if M_USE_SMALL_NAME
#define ISHARED_PTR_OPLIST M_ISHARED_PTR_OPLIST
#define ISHARED_PTR_INTERFACE M_ISHARED_PTR_INTERFACE
#define ISHARED_PTR_STATIC_DESIGNATED_INIT M_ISHARED_PTR_STATIC_DESIGNATED_INIT
#define ISHARED_PTR_STATIC_INIT M_ISHARED_PTR_STATIC_INIT
#define ISHARED_PTR_DEF M_ISHARED_PTR_DEF
#define ISHARED_PTR_DEF_AS M_ISHARED_PTR_DEF_AS
#endif
#endif
+171 -202
View File
@@ -86,6 +86,8 @@
/********************************** INTERNAL ************************************/
//TODO: Provide an update scheme for mempool using new memory allocator context.
/* Deferred evaluation for the oplist definition,
so that all arguments are evaluated before further expansion */
#define M_L1ST_OPLIST_P1(arg) M_L1ST_OPLIST_P2 arg
@@ -99,6 +101,7 @@
((M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* OPLIST definition of a list and list_dual_push */
#ifndef M_USE_CONTEXT
#define M_L1ST_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -142,6 +145,51 @@
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#else
#define M_L1ST_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_INIT_WITH_VAI)), \
SET(API_0P(M_F(name, _set))), \
CLEAR(API_0P(M_F(name, _clear))), \
MOVE(API_0P(M_F(name, _move))), \
INIT_MOVE(M_F(name, _init_move)), \
SWAP(M_F(name, _swap)), \
NAME(name), \
TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)**), \
SUBTYPE(M_F(name,_subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_END(M_F(name,_it_end)), \
IT_SET(M_F(name,_it_set)), \
IT_END_P(M_F(name,_end_p)), \
IT_EQUAL_P(M_F(name,_it_equal_p)), \
IT_LAST_P(M_F(name,_last_p)), \
IT_NEXT(M_F(name,_next)), \
IT_REF(M_F(name,_ref)), \
IT_CREF(M_F(name,_cref)), \
IT_INSERT(API_0P(M_F(name, _insert))), \
IT_REMOVE(API_0P(M_F(name,_remove))), \
RESET(API_0P(M_F(name,_reset))), \
PUSH(API_0P(M_F(name,_push_back))), \
POP(API_0P(M_F(name,_pop_back))), \
PUSH_MOVE(API_0P(M_F(name,_push_move))), \
POP_MOVE(API_0P(M_F(name,_pop_move))) \
,SPLICE_BACK(M_F(name,_splice_back)) \
,SPLICE_AT(M_F(name,_splice_at)) \
,REVERSE(M_F(name,_reverse)) \
,OPLIST(oplist) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \
,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \
,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#endif
/* Deferred evaluation for the list definition,
so that all arguments are evaluated before further expansion */
@@ -155,29 +203,6 @@
#define M_L1ST_DEF_FAILURE(name, type, oplist, list_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DEF): the given argument is not a valid oplist: " #oplist)
/* Define allocation functions. If MEMPOOL, we need to define it */
#define M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \
M_IF_METHOD(MEMPOOL, oplist)( \
\
MEMPOOL_DEF(M_F(name, _mempool), struct M_F(name, _s)) \
M_GET_MEMPOOL_LINKAGE oplist M_F(name, _mempool_t) M_GET_MEMPOOL oplist; \
M_INLINE struct M_F(name, _s) *M_C3(m_l1st_,name,_new)(void) { \
return M_F(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
} \
M_INLINE void M_C3(m_l1st_,name,_del)(struct M_F(name, _s) *ptr) { \
M_F(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
} \
\
, /* No mempool allocation */ \
\
M_INLINE struct M_F(name, _s) *M_C3(m_l1st_,name,_new)(void) { \
return M_CALL_NEW(oplist, struct M_F(name, _s)); \
} \
M_INLINE void M_C3(m_l1st_,name,_del)(struct M_F(name, _s) *ptr) { \
M_CALL_DEL(oplist, ptr); \
} \
) \
/* Internal list definition
- name: prefix to be used
@@ -190,9 +215,8 @@
#define M_L1ST_DEF_P3(name, type, oplist, list_t, it_t) \
M_L1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_DEF) \
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
@@ -242,8 +266,7 @@
*v = NULL; \
} \
\
M_INLINE void \
M_F(name, _reset)(list_t v) \
M_P(void,name, _reset, list_t v) \
{ \
M_L1ST_CONTRACT(v); \
struct M_F(name, _s) *it = *v; \
@@ -251,16 +274,15 @@
while (it != NULL) { \
struct M_F(name, _s) *next = it->next; \
M_CALL_CLEAR(oplist, it->data); \
M_C3(m_l1st_,name,_del)(it); \
M_CALL_DEL(oplist, it); \
it = next; \
} \
M_L1ST_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(name, _clear)(list_t v) \
M_P(void, name, _clear, list_t v) \
{ \
M_F(name, _reset)(v); \
M_F(name, _reset)M_R(v); \
} \
\
M_INLINE type * \
@@ -271,15 +293,12 @@
return &((*v)->data); \
} \
\
M_INLINE type * \
M_F(name, _push_raw)(list_t v) \
M_P(type *, name, _push_raw, list_t v) \
{ \
M_L1ST_CONTRACT(v); \
struct M_F(name, _s) *next; \
next = M_C3(m_l1st_,name,_new)(); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
return NULL; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
type *ret = &next->data; \
next->next = *v; \
@@ -288,35 +307,32 @@
return ret; \
} \
\
M_INLINE void \
M_F(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)(v); \
type *data = M_F(name, _push_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \
M_ON_EXCEPTION( *v = next->next, M_CALL_DEL(oplist, next)) { \
M_CALL_INIT_SET(oplist, *data, x); \
} \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _push_new)(list_t v) \
M_P(type *, name, _push_new, list_t v) \
{ \
type *data = M_F(name, _push_raw)(v); \
type *data = M_F(name, _push_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return NULL; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \
M_ON_EXCEPTION( *v = next->next, M_CALL_DEL(oplist, next)) { \
M_CALL_INIT(oplist, *data); \
} \
return data; \
} \
, /* No INIT */) \
\
M_INLINE void \
M_F(name, _pop_back)(type *data, list_t v) \
M_P(void, name, _pop_back, type *data, list_t v) \
{ \
M_L1ST_CONTRACT(v); \
M_ASSERT(*v != NULL); \
@@ -327,29 +343,27 @@
} \
struct M_F(name, _s) *tofree = *v; \
*v = (*v)->next; \
M_C3(m_l1st_,name,_del)(tofree); \
M_CALL_DEL(oplist, tofree); \
M_L1ST_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(name, _push_move)(list_t v, type *x) \
M_P(void, name, _push_move, list_t v, type *x) \
{ \
M_ASSERT (x != NULL); \
type *data = M_F(name, _push_raw)(v); \
type *data = M_F(name, _push_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
M_CALL_INIT_MOVE (oplist, *data, *x); \
} \
\
M_INLINE void \
M_F(name, _pop_move)(type *data, list_t v) \
M_P(void, name, _pop_move, type *data, list_t v) \
{ \
M_L1ST_CONTRACT(v); \
M_ASSERT(*v != NULL && data != NULL); \
M_DO_INIT_MOVE (oplist, *data, (*v)->data); \
M_CALL_INIT_MOVE (oplist, *data, (*v)->data); \
struct M_F(name, _s) *tofree = *v; \
*v = (*v)->next; \
M_C3(m_l1st_,name,_del)(tofree); \
M_CALL_DEL(oplist, tofree); \
M_L1ST_CONTRACT(v); \
} \
\
@@ -490,19 +504,16 @@
return M_CONST_CAST(type, M_F(name, _get)(l,i)); \
} \
\
M_INLINE void \
M_F(name, _insert)(list_t list, it_t insertion_point, \
type const x) \
M_P(void, name, _insert, list_t list, it_t insertion_point, type const x) \
{ \
M_L1ST_CONTRACT(list); \
M_ASSERT (insertion_point != NULL); \
M_ASSERT(M_F(name, _sublist_p)(list, insertion_point)); \
struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
M_ASSERT (M_F(name, _sublist_p)(list, insertion_point)); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
return; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \
M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \
M_CALL_INIT_SET(oplist, next->data, x); \
struct M_F(name, _s) *current = insertion_point->current; \
if (M_UNLIKELY (current == NULL)) { \
@@ -518,13 +529,12 @@
M_L1ST_CONTRACT(list); \
} \
\
M_INLINE void \
M_F(name, _remove)(list_t list, it_t removing_point) \
M_P(void, name, _remove, list_t list, it_t removing_point) \
{ \
M_L1ST_CONTRACT(list); \
M_ASSERT (removing_point != NULL); \
M_ASSERT (removing_point->current != NULL); \
M_ASSERT(M_F(name, _sublist_p)(list, removing_point)); \
M_ASSERT (M_F(name, _sublist_p)(list, removing_point)); \
struct M_F(name, _s) *next = removing_point->current->next; \
if (M_UNLIKELY (removing_point->previous == NULL)) { \
*list = next; \
@@ -532,13 +542,12 @@
removing_point->previous->next = next; \
} \
M_CALL_CLEAR(oplist, removing_point->current->data); \
M_C3(m_l1st_,name,_del) (removing_point->current); \
M_CALL_DEL(oplist, removing_point->current); \
removing_point->current = next; \
M_L1ST_CONTRACT(list); \
} \
\
M_INLINE void \
M_F(name, _init_set)(list_t list, const list_t org) \
M_P(void, name, _init_set, list_t list, const list_t org) \
{ \
M_L1ST_CONTRACT(org); \
struct M_F(name, _s) *m_volatile next = NULL; \
@@ -546,15 +555,14 @@
struct M_F(name, _s) **update_list; \
update_list = list; \
it_org = *org; \
/* On exceptions, free node and clear list*/ \
/* If exceptions, always keep list as a valid list */ \
M_IF_EXCEPTION(*update_list = NULL); \
M_ON_EXCEPTION(M_C3(m_l1st_,name,_del)(next), M_F(name, _clear)(list) ) \
/* On exceptions, free node and clear list*/ \
M_ON_EXCEPTION(M_CALL_DEL(oplist, next), M_F(name, _clear)(list) ) \
while (it_org != NULL) { \
next = M_C3(m_l1st_,name,_new)(); \
next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
*update_list = NULL; \
return; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
M_CALL_INIT_SET(oplist, next->data, it_org->data); \
*update_list = next; \
@@ -566,13 +574,12 @@
M_L1ST_CONTRACT(list); \
} \
\
M_INLINE void \
M_F(name, _set)(list_t list, const list_t org) \
M_P(void, name, _set, list_t list, const list_t org) \
{ \
if (M_UNLIKELY (list == org)) return; \
M_ON_EXCEPTION(M_F(name, _init)(list) ) { \
M_F(name, _clear)(list); \
M_F(name, _init_set)(list, org); \
M_F(name, _clear)M_R(list); \
M_F(name, _init_set)M_R(list, org); \
} \
} \
\
@@ -585,11 +592,10 @@
*org = NULL; /* safer */ \
} \
\
M_INLINE void \
M_F(name, _move)(list_t list, list_t org) \
M_P(void, name, _move, list_t list, list_t org) \
{ \
M_ASSERT (list != org); \
M_F(name, _clear)(list); \
M_F(name, _clear)M_R(list); \
M_F(name, _init_move)(list, org); \
} \
\
@@ -699,12 +705,10 @@
#define M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) \
\
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, const list_t list, \
bool append) \
M_P(void, name, _get_str, m_string_t str, const list_t list, bool append) \
{ \
M_ASSERT (str != NULL && list != NULL); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
it_t it; \
for (M_F(name, _it)(it, list) ; \
!M_F(name, _end_p)(it); \
@@ -712,9 +716,9 @@
type const *item = M_F(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
if (!M_F(name, _last_p)(it)) \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
} \
m_string_push_back (str, ']'); \
m_string_push_back M_R(str, ']'); \
} \
, /* no str */ ) \
\
@@ -738,11 +742,10 @@
, /* no out_str */ ) \
\
M_IF_METHOD2(PARSE_STR, INIT, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(list_t list, const char str[], const char **endp) \
M_P(bool, name, _parse_str, list_t list, const char str[], const char **endp) \
{ \
M_ASSERT (str != NULL && list != NULL); \
M_F(name,_reset)(list); \
M_F(name,_reset)M_R(list); \
bool success = false; \
int c = *str++; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -755,7 +758,7 @@
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
c = m_core_str_nospace(&str); \
if (b == false || c == 0) { c = 0; break; } \
M_F(name, _push_back)(list, item); \
M_F(name, _push_back)M_R(list, item); \
} while (c == M_GET_SEPARATOR oplist); \
success = (c == ']'); \
} \
@@ -767,11 +770,10 @@
, /* no PARSE_STR & INIT */ ) \
\
M_IF_METHOD2(IN_STR, INIT, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(list_t list, FILE *file) \
M_P(bool, name, _in_str, list_t list, FILE *file) \
{ \
M_ASSERT (file != NULL && list != NULL); \
M_F(name,_reset)(list); \
M_F(name,_reset)M_R(list); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
@@ -783,7 +785,7 @@
bool b = M_CALL_IN_STR(oplist, item, file); \
c = m_core_fgetc_nospace(file); \
if (b == false || c == EOF) { c = 0; break; } \
M_F(name, _push_back)(list, item); \
M_F(name, _push_back)M_R(list, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
M_F(name, _reverse)(list); \
@@ -792,18 +794,17 @@
, /* no IN_STR & INIT */ ) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, const list_t list) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const list_t list) \
{ \
M_ASSERT (list != NULL); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_return_code_t ret; \
m_serial_local_t local; \
bool first_done = false; \
ret = f->m_interface->write_array_start(local, f, (size_t)-1); \
ret = f->m_interface->write_array_start M_R(local, f, (size_t)-1); \
if (ret == M_SERIAL_FAIL_RETRY) { \
size_t n = M_F(name, _size)(list); \
ret = f->m_interface->write_array_start(local, f, n); \
ret = f->m_interface->write_array_start M_R(local, f, n); \
} \
it_t it; \
for (M_F(name, _it)(it, list) ; \
@@ -811,32 +812,31 @@
M_F(name, _next)(it)){ \
type const *item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
first_done = true; \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end M_R(local, f); \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(list_t list, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, list_t list, m_serial_read_t f) \
{ \
M_ASSERT (list != NULL); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_return_code_t ret; \
m_serial_local_t local; \
size_t estimated_size = 0; \
M_F(name,_reset)(list); \
M_F(name,_reset)M_R(list); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
M_QLET(1, item, type, oplist) { \
do { \
ret = M_CALL_IN_SERIAL(oplist, item, f); \
if (ret != M_SERIAL_OK_DONE) { break; } \
M_F(name, _push_back)(list, item); \
M_F(name, _push_back)M_R(list, item); \
ret = f->m_interface->read_array_next(local, f); \
} while (ret == M_SERIAL_OK_CONTINUE); \
} \
@@ -890,15 +890,13 @@
/* Definition of the emplace_back function for single list */
#define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
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)(v); \
M_F(name, _subtype_ct) *data = M_F(name, _push_raw)M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \
M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \
M_ON_EXCEPTION( *v = next->next, M_CALL_DEL(oplist, next)) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \
}
@@ -906,15 +904,13 @@
/* 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) \
M_INLINE void \
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)(v); \
M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \
}
@@ -922,17 +918,15 @@
/* 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) \
M_INLINE void \
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_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)(v); \
M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)M_R(v); \
if (M_UNLIKELY (data == NULL) ) \
return; \
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
} \
}
@@ -969,10 +963,9 @@
#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_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \
M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_BACK_DEF) \
M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_front, oplist, M_L1ST_EMPLACE_FRONT_DEF) \
M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
@@ -1026,15 +1019,14 @@
M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(name, _reset)(list_t v) \
M_P(void, name, _reset, list_t v) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(v); \
struct M_F(name, _s) *it = v->back; \
while (it != NULL) { \
struct M_F(name, _s) *next = it->next; \
M_CALL_CLEAR(oplist, it->data); \
M_C3(m_l1st_,name,_del)(it); \
M_CALL_DEL(oplist, it); \
it = next; \
} \
v->front = NULL; \
@@ -1042,10 +1034,9 @@
M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(name, _clear)(list_t v) \
M_P(void, name, _clear, list_t v) \
{ \
M_F(name, _reset)(v); \
M_F(name, _reset)M_R(v); \
} \
\
M_INLINE type * \
@@ -1056,20 +1047,18 @@
return &(v->back->data); \
} \
\
M_INLINE type * \
M_F(name, _push_back_raw)(list_t v) \
M_P(type *, name, _push_back_raw, list_t v) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(v); \
struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
return NULL; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
type *ret = &next->data; \
next->next = v->back; \
v->back = next; \
/* Update front too if the list was empty */ \
/* This C code shall generate branchless code */ \
/* This C code should generate branchless code */ \
struct M_F(name, _s) *front = v->front; \
front = (front == NULL) ? next : front; \
v->front = front; \
@@ -1078,57 +1067,51 @@
} \
\
/* Internal, for INIT_WITH */ \
M_INLINE type * \
M_F(name, _push_raw)(list_t d) \
M_P(type *, name, _push_raw, list_t d) \
{ \
return M_F(name, _push_back_raw)(d); \
return M_F(name, _push_back_raw)M_R(d); \
} \
\
M_INLINE void \
M_F(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)(v); \
type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \
M_CALL_INIT_SET(oplist, *data, x); \
} \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _push_back_new)(list_t v) \
M_P(type *, name, _push_back_new, list_t v) \
{ \
type *data = M_F(name, _push_back_raw)(v); \
type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return NULL; \
M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \
M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \
M_CALL_INIT(oplist, *data); \
} \
return data; \
} \
, /* No INIT */ ) \
\
M_INLINE void \
M_F(name, _push_back_move)(list_t v, type *x) \
M_P(void, name, _push_back_move, list_t v, type *x) \
{ \
M_ASSERT (x != NULL); \
type *data = M_F(name, _push_back_raw)(v); \
type *data = M_F(name, _push_back_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
M_CALL_INIT_MOVE (oplist, *data, *x); \
} \
\
M_INLINE void \
M_F(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)(v, x); \
M_F(name, _push_back_move)M_R(v, x); \
} \
\
M_INLINE void \
M_F(name, _pop_back)(type *data, list_t v) \
M_P(void, name, _pop_back, type *data, list_t v) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(v); \
M_ASSERT (v->back != NULL); \
@@ -1139,7 +1122,7 @@
M_CALL_CLEAR(oplist, tofree->data); \
} \
v->back = tofree->next; \
M_C3(m_l1st_,name,_del)(tofree); \
M_CALL_DEL(oplist, tofree); \
/* Update front too if the list became empty */ \
/* This C code shall generate branchless code */ \
struct M_F(name, _s) *front = v->front; \
@@ -1148,16 +1131,15 @@
M_L1ST_DUAL_PUSH_CONTRACT(v); \
} \
\
M_INLINE void \
M_F(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_ASSERT (v->back != NULL); \
M_ASSERT (data != NULL); \
struct M_F(name, _s) *tofree = v->back; \
M_DO_INIT_MOVE (oplist, *data, tofree->data); \
M_CALL_INIT_MOVE (oplist, *data, tofree->data); \
v->back = tofree->next; \
M_C3(m_l1st_,name,_del)(tofree); \
M_CALL_DEL(oplist, tofree); \
/* Update front too if the list became empty */ \
/* This C code shall generate branchless code */ \
struct M_F(name, _s) *front = v->front; \
@@ -1174,14 +1156,12 @@
return &(v->front->data); \
} \
\
M_INLINE type * \
M_F(name, _push_front_raw)(list_t v) \
M_P(type *, name, _push_front_raw, list_t v) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(v); \
struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \
struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
return NULL; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
type *ret = &next->data; \
next->next = NULL; \
@@ -1196,41 +1176,38 @@
return ret; \
} \
\
M_INLINE void \
M_F(name, _push_front)(list_t v, type const x) \
M_P(void, name, _push_front, list_t v, type const x) \
{ \
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \
type *data = M_F(name, _push_front_raw)(v); \
type *data = M_F(name, _push_front_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \
M_CALL_INIT_SET(oplist, *data, x); \
} \
} \
\
M_INLINE void \
M_F(name, _push_front_move)(list_t v, type *x) \
M_P(void, name, _push_front_move, list_t v, type *x) \
{ \
M_ASSERT (x != NULL); \
type *data = M_F(name, _push_front_raw)(v); \
type *data = M_F(name, _push_front_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return; \
M_DO_INIT_MOVE (oplist, *data, *x); \
M_CALL_INIT_MOVE (oplist, *data, *x); \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE type * \
M_F(name, _push_front_new)(list_t v) \
M_P(type *, name, _push_front_new, list_t v) \
{ \
M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \
type *data = M_F(name, _push_front_raw)(v); \
type *data = M_F(name, _push_front_raw)M_R(v); \
if (M_UNLIKELY (data == NULL)) \
return NULL; \
M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \
M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \
M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \
M_CALL_INIT(oplist, *data); \
} \
return data; \
@@ -1336,18 +1313,15 @@
return size; \
} \
\
M_INLINE void \
M_F(name, _insert)(list_t list, it_t insertion_point, \
type const x) \
M_P(void, name, _insert, list_t list, it_t insertion_point, type const x) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(list); \
M_ASSERT (insertion_point != NULL); \
struct M_F(name, _s) *m_volatile next = M_C3(m_l1st_,name,_new)(); \
struct M_F(name, _s) *m_volatile next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
return; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \
M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \
M_CALL_INIT_SET(oplist, next->data, x); \
if (M_UNLIKELY (insertion_point->current == NULL)) { \
next->next = list->back; \
@@ -1366,8 +1340,7 @@
} \
} \
\
M_INLINE void \
M_F(name, _remove)(list_t list, it_t removing_point) \
M_P(void, name, _remove, list_t list, it_t removing_point) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(list); \
M_ASSERT (removing_point != NULL); \
@@ -1385,12 +1358,11 @@
list->front = front; \
/* Remove node */ \
M_CALL_CLEAR(oplist, removing_point->current->data); \
M_C3(m_l1st_,name,_del) (removing_point->current); \
M_CALL_DEL(oplist, removing_point->current); \
removing_point->current = next; \
} \
\
M_INLINE void \
M_F(name, _set)(list_t list, const list_t org) \
M_P(void, name, _set, list_t list, const list_t org) \
{ \
M_L1ST_DUAL_PUSH_CONTRACT(list); \
M_L1ST_DUAL_PUSH_CONTRACT(org); \
@@ -1398,16 +1370,15 @@
struct M_F(name, _s) *it_org; \
struct M_F(name, _s) **update_list; \
if (M_UNLIKELY (list == org)) return; \
M_F(name, _reset)(list); \
M_F(name, _reset)M_R(list); \
update_list = &list->back; \
it_org = org->back; \
M_ASSERT(*update_list == NULL); \
M_ON_EXCEPTION(M_C3(m_l1st_,name,_del)(next) ) \
M_ON_EXCEPTION(M_CALL_DEL(oplist, next) ) \
while (it_org != NULL) { \
next = M_C3(m_l1st_,name,_new)(); \
next = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (next == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
return; \
M_MEMORY_FULL(struct M_F(name, _s), 1); \
} \
M_CALL_INIT_SET(oplist, next->data, it_org->data); \
/* Link new node to the previous one*/ \
@@ -1421,13 +1392,12 @@
} \
} \
\
M_INLINE void \
M_F(name, _init_set)(list_t list, const list_t org) \
M_P(void, name, _init_set, list_t list, const list_t org) \
{ \
M_ASSERT (list != org); \
M_ON_EXCEPTION( M_F(name, _clear)(list)) { \
M_F(name, _init)(list); \
M_F(name, _set)(list, org); \
M_F(name, _set) M_R(list, org); \
} \
} \
\
@@ -1441,10 +1411,9 @@
org->front = NULL; \
} \
\
M_INLINE void \
M_F(name, _move)(list_t list, list_t org) \
M_P(void, name, _move, list_t list, list_t org) \
{ \
M_F(name, _clear)(list); \
M_F(name, _clear)M_R(list); \
M_F(name, _init_move)(list, org); \
} \
\
-206
View File
@@ -1,206 +0,0 @@
/*
* M*LIB - MEMPOOL module
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_MEMPOOL_H
#define MSTARLIB_MEMPOOL_H
#include "m-core.h"
/* Fast, fixed size, thread unsafe allocator based on memory regions.
No oplist is needed.
USAGE:
MEMPOOL_DEF(name, type)
Example:
MEMPOOL_DEF(mempool_uint, unsigned int)
...
mempool_uint_t m;
mempool_uint_init(m);
unsigned int *ptr = mempool_uint_alloc(m);
*ptr = 17;
mempool_uint_free(m, ptr);
mempool_uint_clear(m); // Give back memory to system
*/
#define M_MEMPOOL_DEF(name, type) \
M_MEMPOOL_DEF_AS(name, M_F(name,_t), type)
/* Fast, fixed Size, thread unsafe allocator based on memory region.
USAGE:
MEMPOOL_DEF_AS(name, name_t, type)
*/
#define M_MEMPOOL_DEF_AS(name, name_t, type) \
M_BEGIN_PROTECTED_CODE \
M_M3MPOOL_DEF_P2(name, type, name_t ) \
M_END_PROTECTED_CODE
/* User shall be able to customize the size of the region segment and/or
the minimum number of elements.
The default is the number of elements that fits in 16KB, or 256
is the size of the type is too big.
*/
#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT
#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \
M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U)
#endif
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
/*
Technically, it uses a list of memory regions, where multiple
allocations are performed in each region. However, it
can not use m-list since it may be expanded from LIST_DEF
(recursive dependency problem). */
#define M_M3MPOOL_DEF_P2(name, type, name_t) \
M_M3MPOOL_DEF_TYPE(name, type, name_t) \
M_M3MPOOL_DEF_CORE(name, type, name_t)
/* Define the types of the mempool */
#define M_M3MPOOL_DEF_TYPE(name, type, name_t) \
\
/* Define the type of element in a segment of the mempool. \
Either it is the basic type or a pointer to another one. */ \
typedef union M_F(name,_union_s) { \
type t; \
union M_F(name,_union_s) *next; \
} M_F(name,_union_ct); \
\
/* Define a segment of a mempool. \
It is an array of basic type, each segment is in a linked list */ \
typedef struct M_F(name,_segment_s) { \
unsigned int count; \
struct M_F(name,_segment_s) *next; \
M_F(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \
} M_F(name,_segment_ct); \
\
/* Define a mempool. \
It is a pointer to the first free object within the segments \
and the segments themselves */ \
typedef struct M_F(name, _s) { \
M_F(name,_union_ct) *free_list; \
M_F(name,_segment_ct) *current_segment; \
} name_t[1]; \
/* Define the core functions of the mempool */
#define M_M3MPOOL_DEF_CORE(name, type, name_t) \
\
M_INLINE void \
M_F(name,_init)(name_t mem) \
{ \
mem->free_list = NULL; \
mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \
if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \
M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \
return; \
} \
mem->current_segment->next = NULL; \
mem->current_segment->count = 0; \
M_M3MPOOL_CONTRACT(mem, type); \
} \
\
M_INLINE void \
M_F(name,_clear)(name_t mem) \
{ \
M_M3MPOOL_CONTRACT(mem, type); \
M_F(name,_segment_ct) *segment = mem->current_segment; \
while (segment != NULL) { \
M_F(name,_segment_ct) *next = segment->next; \
M_MEMORY_DEL (segment); \
segment = next; \
} \
/* Clean pointers to be safer */ \
mem->free_list = NULL; \
mem->current_segment = NULL; \
} \
\
M_INLINE type * \
M_F(name,_alloc)(name_t mem) \
{ \
M_M3MPOOL_CONTRACT(mem, type); \
/* Test if one object is in the free list */ \
M_F(name,_union_ct) *ret = mem->free_list; \
if (ret != NULL) { \
/* Yes, so return it, and pop it from the free list */ \
mem->free_list = ret->next; \
return &ret->t; \
} \
/* No cheap free object exist. Test within a segment */ \
M_F(name,_segment_ct) *segment = mem->current_segment; \
M_ASSERT(segment != NULL); \
unsigned int count = segment->count; \
/* If segment is full, allocate a new one from the system */ \
if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \
M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \
if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \
M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \
return NULL; \
} \
new_segment->next = segment; \
new_segment->count = 0; \
mem->current_segment = new_segment; \
segment = new_segment; \
count = 0; \
} \
/* Return the object as the last element of the current segment */ \
ret = &segment->tab[count]; \
segment->count = count + 1; \
M_M3MPOOL_CONTRACT(mem, type); \
return &ret->t; \
} \
\
M_INLINE void \
M_F(name,_free)(name_t mem, type *ptr) \
{ \
M_M3MPOOL_CONTRACT(mem, type); \
/* NOTE: Unsafe cast: suppose that the given pointer \
was allocated by the previous alloc function. */ \
M_F(name,_union_ct) *ret = (M_F(name,_union_ct) *)(uintptr_t)ptr; \
/* Add the object back in the free list */ \
ret->next = mem->free_list; \
mem->free_list = ret; \
/* NOTE: the objects are NOT given back to the system until the mempool \
is fully cleared */ \
M_M3MPOOL_CONTRACT(mem, type); \
} \
/* MEMPOOL contract. We only control the current segment. */
#define M_M3MPOOL_CONTRACT(mempool, type) do { \
M_ASSERT((mempool) != NULL); \
M_ASSERT((mempool)->current_segment != NULL); \
M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \
} while (0)
/********************************** INTERNAL *********************************/
#if M_USE_SMALL_NAME
#define MEMPOOL_DEF M_MEMPOOL_DEF
#define MEMPOOL_DEF_AS M_MEMPOOL_DEF_AS
#endif
#endif
-28
View File
@@ -1,28 +0,0 @@
/*
* M*LIB - Thin Mutex & Thread wrapper (compatibility layer)
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(__GNUC__) && __GNUC__ >= 4
#warning "m-mutex.h is an obsolete header. Use m-thread.h instead."
#endif
#include "m-thread.h"
+66 -45
View File
@@ -25,7 +25,6 @@
#ifndef MSTARLIB_PRIOQUEUE_H
#define MSTARLIB_PRIOQUEUE_H
#include "m-core.h"
#include "m-array.h" /* Priority queue are built upon array */
/* Priority queue based on binary heap implementation */
@@ -72,6 +71,7 @@
((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* Define oplist of a priority queue */
#ifndef M_USE_CONTEXT
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)) \
,INIT_SET(M_F(name, _init_set)) \
@@ -106,7 +106,42 @@
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \
)
#else
#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)) \
,INIT_SET(API_0P(M_F(name, _init_set))) \
,INIT_WITH(API_1(M_INIT_VAI)) \
,SET(API_0P(M_F(name, _set))) \
,CLEAR(API_0P(M_F(name, _clear))) \
,INIT_MOVE(M_F(name, _init_move)) \
,MOVE(API_0P(M_F(name, _move))) \
,SWAP(M_F(name, _swap)) \
,NAME(name) \
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,RESET(API_0P(M_F(name,_reset))) \
,PUSH(API_0P(M_F(name,_push))) \
,POP(API_0P(M_F(name,_pop))) \
,OPLIST(oplist) \
,EMPTY_P(M_F(name, _empty_p)) \
,GET_SIZE(M_F(name, _size)) \
,IT_TYPE(M_F(name, _it_ct)) \
,IT_FIRST(M_F(name,_it)) \
,IT_END(M_F(name,_it_end)) \
,IT_SET(M_F(name,_it_set)) \
,IT_END_P(M_F(name,_end_p)) \
,IT_EQUAL_P(M_F(name,_it_equal_p)) \
,IT_LAST_P(M_F(name,_last_p)) \
,IT_NEXT(M_F(name,_next)) \
,IT_CREF(M_F(name,_cref)) \
,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \
,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \
,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \
,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \
,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \
,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \
)
#endif
/********************************** INTERNAL *********************************/
@@ -137,7 +172,7 @@
M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \
M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \
M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
M_EMPLACE_QUEUE_DEF(name, prioqueue_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE)
/* Define the types */
#define M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \
@@ -167,22 +202,19 @@
M_F(name, _array_init)(p->array); \
} \
\
M_INLINE void \
M_F(name, _init_set)(prioqueue_t p, prioqueue_t const o) \
M_P(void, name, _init_set, prioqueue_t p, prioqueue_t const o) \
{ \
M_F(name, _array_init_set)(p->array, o->array); \
M_F(name, _array_init_set) M_R(p->array, o->array); \
} \
\
M_INLINE void \
M_F(name, _set)(prioqueue_t p, prioqueue_t const o) \
M_P(void, name, _set, prioqueue_t p, prioqueue_t const o) \
{ \
M_F(name, _array_set)(p->array, o->array); \
M_F(name, _array_set) M_R(p->array, o->array); \
} \
\
M_INLINE void \
M_F(name, _clear)(prioqueue_t p) \
M_P(void, name, _clear, prioqueue_t p) \
{ \
M_F(name, _array_clear)(p->array); \
M_F(name, _array_clear) M_R(p->array); \
} \
\
M_INLINE void \
@@ -191,10 +223,9 @@
M_F(name, _array_init_move)(p->array, o->array); \
} \
\
M_INLINE void \
M_F(name, _move)(prioqueue_t p, prioqueue_t o) \
M_P(void, name, _move, prioqueue_t p, prioqueue_t o) \
{ \
M_F(name, _array_move)(p->array, o->array); \
M_F(name, _array_move) M_R(p->array, o->array); \
} \
\
M_INLINE void \
@@ -203,10 +234,9 @@
M_F(name, _array_swap)(p->array, o->array); \
} \
\
M_INLINE void \
M_F(name, _reset)(prioqueue_t p) \
M_P(void, name, _reset, prioqueue_t p) \
{ \
M_F(name, _array_reset)(p->array); \
M_F(name, _array_reset)M_R(p->array); \
} \
\
M_INLINE size_t \
@@ -249,11 +279,10 @@
return M_F(name, _array_size)(p->array); \
} \
\
M_INLINE void \
M_F(name, _push)(prioqueue_t p, type const x) \
M_P(void, name, _push, prioqueue_t p, type const x) \
{ \
/* Push back the new element at the end of the array */ \
M_F(name, _array_push_back)(p->array, x); \
M_F(name, _array_push_back) M_R(p->array, x); \
\
/* Reorder the array by swapping with its parent \
* until it reaches the right position */ \
@@ -273,14 +302,13 @@
return M_F(name, _array_cget)(p->array, 0); \
} \
\
M_INLINE void \
M_F(name, _pop)(type *x, prioqueue_t p) \
M_P(void, name, _pop, type *x, prioqueue_t p) \
{ \
/* Swap the front element with the last element */ \
size_t size = M_F(name, _array_size)(p->array)-1; \
M_F(name, _array_swap_at) (p->array, 0, size); \
/* Swap the new last element */ \
M_F(name, _array_pop_back)(x, p->array); \
M_F(name, _array_pop_back) M_R(x, p->array); \
\
/* Reorder the heap */ \
size_t i = 0; \
@@ -323,8 +351,7 @@
return i; \
} \
\
M_INLINE bool \
M_F(name, _erase)(prioqueue_t p, type const x) \
M_P(bool, name, _erase, prioqueue_t p, type const x) \
{ \
/* First pass: search for an item EQUAL to x */ \
size_t size = M_F(name, _array_size)(p->array); \
@@ -335,7 +362,7 @@
/* Swap the found item and the last element */ \
size--; \
M_F(name, _array_swap_at) (p->array, i, size); \
M_F(name, _array_pop_back)(NULL, p->array); \
M_F(name, _array_pop_back) M_R(NULL, p->array); \
/* Move back the last swapped element to its right position in the heap */ \
while (true) { \
size_t child = M_F(name, _i_lchild)(i); \
@@ -352,8 +379,7 @@
return true; \
} \
\
M_INLINE void \
M_F(name, _update)(prioqueue_t p, type const xold, type const xnew) \
M_P(void, name, _update, prioqueue_t p, type const xold, type const xnew) \
{ \
/* NOTE: xold can be the same pointer than xnew */ \
/* First pass: search for an item EQUAL to x */ \
@@ -364,7 +390,7 @@
/* Test if the position of the old data is further or nearer than the new */ \
int cmp = M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), xnew); \
/* Set the found item to the new element */ \
M_F(name, _array_set_at) (p->array, i, xnew); \
M_F(name, _array_set_at) M_R(p->array, i, xnew); \
if (cmp < 0) { \
/* Move back the updated element to its new position, further in the heap */ \
while (true) { \
@@ -467,42 +493,37 @@
,/* No OUT_STR */) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(prioqueue_t p, FILE *file) \
M_P(bool, name, _in_str, prioqueue_t p, FILE *file) \
{ \
return M_F(name, _array_in_str)(p->array, file); \
return M_F(name, _array_in_str)M_R(p->array, file); \
} \
,/* No IN_STR */) \
\
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, const prioqueue_t p, bool append) \
M_P(void, name, _get_str, m_string_t str, const prioqueue_t p, bool append) \
{ \
M_F(name, _array_get_str)(str, p->array, append); \
M_F(name, _array_get_str)M_R(str, p->array, append); \
} \
,/* No GET_STR */) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \
M_P(bool, name, _parse_str, prioqueue_t p, const char str[], const char **endp) \
{ \
return M_F(name, _array_parse_str)(p->array, str, endp); \
return M_F(name, _array_parse_str)M_R(p->array, str, endp); \
} \
,/* No PARSE_STR */) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const prioqueue_t p) \
{ \
return M_F(name, _array_out_serial)(f, p->array); \
return M_F(name, _array_out_serial) M_R(f, p->array); \
} \
,/* No OUT_SERIAL */) \
\
M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, prioqueue_t p, m_serial_read_t f) \
{ \
return M_F(name, _array_in_serial)(p->array, f); \
return M_F(name, _array_in_serial)M_R(p->array, f); \
} \
,/* No in_SERIAL */) \
+323
View File
@@ -0,0 +1,323 @@
/*
* M*LIB - Fixed size (Bounded) QUEUE & STACK interface (Not Thread safe)
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_QUEUE_H
#define MSTARLIB_QUEUE_H
#include "m-core.h"
/* Define a fixed size queue.
If size is 0, then the size will only be defined at run-time when initializing the queue,
otherwise the size will be a compile time constant embedded in the structure.
USAGE: QUEUE_DEF(name, type, size_of_QUEUE_or_0[, oplist]) */
#define M_QUEUE_DEF(name, ... ) M_QUEUE_DEF_AS(name, M_F(name, _t), __VA_ARGS__)
/* Define a fixed size queue
as the provided type name_t.
USAGE: QUEUE_DEF_AS(name, name_t, type, size_of_QUEUE_or_0[, oplist of type]) */
#define M_QUEUE_DEF_AS(name, name_t, type, ... ) \
M_BEGIN_PROTECTED_CODE \
M_QUEU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t, 0), \
(name, type, __VA_ARGS__, name_t, 0))) \
M_END_PROTECTED_CODE
/* Define a fixed size stack.
If size is 0, then the size will only be defined at run-time when initializing the stack,
otherwise the size will be a compile time constant embedded in the structure.
USAGE: STACK_DEF(name, type, size_of_stack_or_0[, oplist]) */
#define M_STACK_DEF(name, ... ) M_STACK_DEF_AS(name, M_F(name, _t), __VA_ARGS__)
/* Define a fixed size stack
as the provided type name_t.
USAGE: QUEUE_DEF_AS(name, name_t, type, size_of_stack_or_0[, oplist of type]) */
#define M_STACK_DEF_AS(name, name_t, type, ... ) \
M_BEGIN_PROTECTED_CODE \
M_QUEU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t, 1), \
(name, type, __VA_ARGS__, name_t, 1))) \
M_END_PROTECTED_CODE
/* Define the oplist of a fixed size queue given its name and its oplist.
USAGE: QUEUE_OPLIST(name[, oplist of the type]) */
#define M_QUEUE_OPLIST(...) \
M_QUEU3_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define M_QUEU3_OPLIST_P1(arg) M_QUEU3_OPLIST_P2 arg
/* Validation of the given oplist */
#define M_QUEU3_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(M_QUEU3_OPLIST_P3, M_QUEU3_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define M_QUEU3_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_BUFFER_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
/* OPLIST definition of a buffer */
#define M_QUEU3_OPLIST_P3(name, oplist) \
(INIT(API_0P(M_F(name, _i_init))) \
,INIT_SET(API_0P(M_F(name, _init_set))) \
,SET(API_0P(M_F(name, _set))) \
,CLEAR(API_0P(M_F(name, _clear))) \
,NAME(name) \
,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \
,SUBTYPE(M_F(name, _subtype_ct)) \
,RESET(API_0P(M_F(name,_reset))) \
,PUSH(API_0P(M_F(name,_push))) \
,POP(API_0P(M_F(name,_pop))) \
,OPLIST(oplist) \
,EMPTY_P(M_F(name, _empty_p)), \
,FULL_P(M_F(name, _full_p)), \
,GET_SIZE(M_F(name, _size)) \
)
/* Test if the size is only run-time or build time */
#define M_QUEU3_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size))
/* Return the size (run time or build time).
NOTE: It assumed that the queue variable name is 'v' */
#define M_QUEU3_SIZE(v, m_size) \
M_QUEU3_IF_CTE_SIZE(m_size) (m_size, v->capacity)
/* Contract of a queue. */
#define M_QUEU3_CONTRACT(queue, size) do { \
M_ASSERT (queue != NULL); \
M_ASSERT (queue->data != NULL); \
}while (0)
/* Deferred evaluation for the definition,
so that all arguments are evaluated before further expansion */
#define M_QUEU3_DEF_P1(arg) M_ID( M_QUEU3_DEF_P2 arg )
/* Validate the value oplist before going further */
#define M_QUEU3_DEF_P2(name, type, m_size, oplist, queue_t, stack_mode) \
M_IF_OPLIST(oplist)(M_QUEU3_DEF_P3, M_QUEU3_DEF_FAILURE)(name, type, m_size, oplist, queue_t, stack_mode)
/* Stop processing with a compilation failure */
#define M_QUEU3_DEF_FAILURE(name, type, m_size, oplist, queue_t, stack_mode) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_QUEUE_DEF/M_STACK_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist))
/* Define the queue type using mutex lock and its functions.
- name: main prefix of the container
- type: type of an element of the queue
- m_size: constant to 0 if variable runtime size, or else the fixed size of the queue
- oplist: the oplist of the type of an element of the queue
- queue_t: name of the queue
*/
#define M_QUEU3_DEF_P3(name, type, m_size, oplist, queue_t, stack_mode) \
M_QUEU3_DEF_TYPE(name, type, m_size, oplist, queue_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_QUEU3_DEF_CORE(name, type, m_size, oplist, queue_t, stack_mode) \
M_EMPLACE_QUEUE_DEF(name, queue_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE)
/* Define the type of a queue */
#define M_QUEU3_DEF_TYPE(name, type, m_size, oplist, queue_t) \
\
typedef struct M_F(name, _s) { \
unsigned idx_prod; /* Index of the production threads */ \
M_QUEU3_IF_CTE_SIZE(m_size)( ,unsigned capacity;) /* Capacity of the queue */ \
unsigned idx_cons; /* Index of the consumption threads */ \
unsigned number; /* Number of elements in the queue */ \
/* If fixed size, array of elements, otherwise pointer to element */ \
type M_QUEU3_IF_CTE_SIZE(m_size)(data[m_size], *data); \
} queue_t[1]; \
\
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
/* Internal types used by the oplist */ \
typedef type M_F(name, _subtype_ct); \
typedef queue_t M_F(name, _ct); \
/* Define the core functionalities of a queue */
#define M_QUEU3_DEF_CORE(name, type, m_size, oplist, queue_t, stack_mode) \
\
M_P(void, name, _init, queue_t v, size_t size) \
{ \
M_ASSERT(size <= UINT_MAX); \
M_UNUSED_CONTEXT(); \
M_QUEU3_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = (unsigned) size); \
v->idx_prod = v->idx_cons = v->number = 0; \
\
M_QUEU3_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \
v->data = M_CALL_REALLOC(oplist, type, NULL, 0, M_QUEU3_SIZE(v, m_size)); \
if (M_UNLIKELY_NOMEM (v->data == NULL)) { \
M_MEMORY_FULL (type, M_QUEU3_SIZE(v, m_size)); \
} \
) \
for(size_t i = 0; i < size; i++) { \
M_CALL_INIT(oplist, v->data[i]); \
} \
M_QUEU3_CONTRACT(v,m_size); \
} \
\
M_QUEU3_IF_CTE_SIZE(m_size)( \
M_P(void, name,_i_init, queue_t v) \
{ \
M_F(name, _init)M_R(v, m_size); \
} \
, ) \
\
M_P(void, name, _i_clear_obj, queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
M_UNUSED_CONTEXT(); \
for(size_t i = 0; i < M_QUEU3_SIZE(v, m_size); i++) { \
M_CALL_CLEAR(oplist, v->data[i]); \
} \
v->idx_prod = v->idx_cons = v->number = 0; \
M_QUEU3_CONTRACT(v,m_size); \
} \
\
M_P(void, name, _clear, queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
M_UNUSED_CONTEXT(); \
M_F(name,_i_clear_obj)M_R(v); \
M_QUEU3_IF_CTE_SIZE(m_size)( , \
M_CALL_FREE(oplist, type, v->data, M_QUEU3_SIZE(v, m_size)); \
v->data = NULL; \
) \
} \
\
M_N(void, name, _reset, queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
v->idx_prod = v->idx_cons = v->number = 0; \
M_QUEU3_CONTRACT(v,m_size); \
} \
\
M_P(void, name, _init_set, queue_t dest, const queue_t src) \
{ \
M_ASSERT (dest != src); \
M_QUEU3_CONTRACT(src,m_size); \
M_F(name, _init) M_R(dest, M_QUEU3_SIZE(src, m_size)); \
for(size_t i = 0; i < M_QUEU3_SIZE(src, m_size); i++) { \
M_CALL_SET(oplist, dest->data[i], src->data[i]); \
} \
dest->idx_prod = src->idx_prod; \
dest->idx_cons = src->idx_cons; \
dest->number = src->number; \
M_QUEU3_CONTRACT(dest, m_size); \
} \
\
M_P(void, name, _set, queue_t dest, const queue_t src) \
{ \
M_F(name, _clear) M_R(dest); \
M_F(name, _init_set) M_R(dest, src); \
} \
\
M_INLINE bool \
M_F(name, _empty_p)(const queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
return v->number == 0; \
} \
\
M_INLINE bool \
M_F(name, _full_p)(const queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
return v->number == M_QUEU3_SIZE(v, m_size); \
} \
\
M_INLINE size_t \
M_F(name, _size)(const queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
return v->number; \
} \
\
M_P(bool, name, _push, queue_t v, type const data) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
M_UNUSED_CONTEXT(); \
if (M_F(name, _full_p)(v)) \
return false; \
\
unsigned idx = v->idx_prod; \
M_CALL_SET(oplist, v->data[idx], data); \
idx++; \
M_IF(stack_mode)(, idx = (idx == M_QUEU3_SIZE(v, m_size)) ? 0 : idx); \
v->idx_prod = idx; \
\
v->number++; \
\
M_QUEU3_CONTRACT(v,m_size); \
return true; \
} \
\
M_P(bool, name, _pop, type *data, queue_t v) \
{ \
M_QUEU3_CONTRACT(v,m_size); \
M_ASSERT (data != NULL); \
M_UNUSED_CONTEXT(); \
if (M_F(name, _empty_p)(v)) \
return false; \
\
/* POP data from the queue and update INDEX */ \
M_IF(stack_mode)( \
/* STACK queue */ \
v->idx_prod --; \
M_CALL_SET(oplist, *data, v->data[v->idx_prod]); \
, \
/* FIFO queue */ \
M_CALL_SET(oplist, *data, v->data[v->idx_cons]); \
v->idx_cons = (v->idx_cons == M_QUEU3_SIZE(v, m_size)-1) ? 0 : (v->idx_cons + 1); \
) \
v->number--; \
\
M_QUEU3_CONTRACT(v,m_size); \
return true; \
} \
\
M_INLINE size_t \
M_F(name, _capacity)(const queue_t v) \
{ \
(void) v; /* may be unused */ \
return M_QUEU3_SIZE(v, m_size); \
} \
#if M_USE_SMALL_NAME
#define QUEUE_DEF M_QUEUE_DEF
#define QUEUE_DEF_AS M_QUEUE_DEF_AS
#define STACK_DEF M_STACK_DEF
#define STACK_DEF_AS M_STACK_DEF_AS
#define QUEUE_OPLIST M_QUEUE_OPLIST
#endif
#endif
+90 -94
View File
@@ -71,6 +71,7 @@
/* OPLIST definition of a rbtree
NOTE: IT_REF is not exported so that the container appears as not modifiable
by algorithm.*/
#ifndef M_USE_CONTEXT
#define M_RBTR33_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -110,7 +111,46 @@
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#else
#define M_RBTR33_OPLIST_P3(name, oplist) \
(INIT(M_F(name, _init)), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_INIT_EMPLACE_VAI)), \
SET(API_0P(M_F(name, _set))), \
CLEAR(API_0P(M_F(name, _clear))), \
INIT_MOVE(M_F(name, _init_move)), \
MOVE(API_0P(M_F(name, _move))), \
SWAP(M_F(name, _swap)), \
NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
SUBTYPE(M_F(name, _subtype_ct)), \
EMPTY_P(M_F(name,_empty_p)), \
GET_SIZE(M_F(name, _size)), \
IT_TYPE(M_F(name, _it_ct)), \
IT_FIRST(M_F(name,_it)), \
IT_SET(M_F(name,_it_set)), \
IT_LAST(M_F(name,_it_last)), \
IT_END(M_F(name,_it_end)), \
IT_END_P(M_F(name,_end_p)), \
IT_LAST_P(M_F(name,_last_p)), \
IT_EQUAL_P(M_F(name,_it_equal_p)), \
IT_NEXT(M_F(name,_next)), \
IT_PREVIOUS(M_F(name,_previous)), \
IT_CREF(M_F(name,_cref)), \
IT_REMOVE(M_F(name,_remove)), \
RESET(API_0P(M_F(name,_reset))), \
PUSH(API_0P(M_F(name,_push))), \
GET_MIN(M_F(name,_min)), \
GET_MAX(M_F(name,_max)), \
M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),), \
M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \
M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),), \
M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),), \
M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \
M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \
M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \
)
#endif
/********************************** INTERNAL *********************************/
@@ -176,11 +216,10 @@ typedef enum {
*/
#define M_RBTR33_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \
M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \
M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \
M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE)
M_EMPLACE_QUEUE_DEF(name, tree_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE)
/* Define the types associated to a R/B Tree */
#define M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \
@@ -215,33 +254,6 @@ typedef enum {
typedef tree_t M_F(name, _ct); \
typedef it_t M_F(name, _it_ct); \
/* Define the mempool encapsulation */
#define M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \
/* Link with fast memory allocator if requested */ \
M_IF_METHOD(MEMPOOL, oplist)( \
/* Definition of the memory pool of this kind of node */ \
MEMPOOL_DEF(M_F(name, _mempool), node_t) \
/* Definition of the global variable used to reference this pool */ \
M_GET_MEMPOOL_LINKAGE oplist M_F(name, _mempool_t) M_GET_MEMPOOL oplist; \
/* Allocator function */ \
M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \
return M_F(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \
} \
/* Deallocator function */ \
M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
M_F(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \
} \
\
, /* No mempool allocation */ \
/* Classic Allocator function (common case) */ \
M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \
return M_CALL_NEW(oplist, node_t); \
} \
/* Classic deallocator function (common case) */ \
M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \
M_CALL_DEL(oplist, ptr); \
} ) \
/* Define the core functions */
#define M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \
\
@@ -254,8 +266,7 @@ typedef enum {
M_RBTR33_CONTRACT(tree); \
} \
\
M_INLINE void \
M_F(name, _reset)(tree_t tree) \
M_P(void, name, _reset, tree_t tree) \
{ \
M_RBTR33_CONTRACT(tree); \
node_t *stack[M_RBTR33_MAX_STACK]; \
@@ -289,7 +300,7 @@ typedef enum {
M_ASSERT (n == stack[cpt - 1]); \
/* Clear the bottom left node */ \
M_CALL_CLEAR(oplist, n->data); \
M_C3(m_rbtr33_,name,_del) (n); \
M_CALL_DEL(oplist, n); \
M_ASSERT((stack[cpt-1] = NULL) == NULL); \
/* Go up to the parent */ \
cpt--; \
@@ -299,15 +310,13 @@ typedef enum {
tree->size = 0; \
} \
\
M_INLINE void \
M_F(name, _clear)(tree_t tree) \
M_P(void, name, _clear, tree_t tree) \
{ \
/* Nothing more than clean the tree as everything is cleared */ \
M_F(name, _reset)(tree); \
M_F(name, _reset) M_R(tree); \
} \
\
M_INLINE void \
M_F(name, _push)(tree_t tree, type const data) \
M_P(void, name, _push, tree_t tree, type const data) \
{ \
M_RBTR33_CONTRACT(tree); \
node_t *tab[M_RBTR33_MAX_STACK]; \
@@ -316,10 +325,9 @@ typedef enum {
node_t *n = tree->node; \
/* If there is no root node, create a new node */ \
if (n == NULL) { \
n = M_C3(m_rbtr33_,name,_new)(); \
n = M_CALL_NEW(oplist, node_t); \
if (M_UNLIKELY_NOMEM (n == NULL)) { \
M_MEMORY_FULL(sizeof (node_t)); \
return; \
M_MEMORY_FULL(node_t, 1); \
} \
/* Copy the data in the root node */ \
M_CALL_INIT_SET(oplist, n->data, data); \
@@ -357,10 +365,9 @@ typedef enum {
return; \
} \
/* Create new node to store the data */ \
n = M_C3(m_rbtr33_,name,_new)(); \
n = M_CALL_NEW(oplist, node_t); \
if (M_UNLIKELY_NOMEM (n == NULL) ) { \
M_MEMORY_FULL (sizeof (node_t)); \
return; \
M_MEMORY_FULL (node_t, 1); \
} \
/* Copy the data and mark the node as red */ \
M_CALL_INIT_SET(oplist, n->data, data); \
@@ -684,41 +691,37 @@ typedef enum {
} \
\
/* Create a copy of the given node (recursively) */ \
M_INLINE node_t * \
M_C3(m_rbtr33_,name,_copy_node)(const node_t *o) \
M_P(node_t *, name, _i_copy_node, const node_t *o) \
{ \
if (o == NULL) return NULL; \
node_t *n = M_C3(m_rbtr33_,name,_new)(); \
if (M_UNLIKELY(o == NULL)) return NULL; \
node_t *n = M_CALL_NEW(oplist, node_t); \
if (M_UNLIKELY_NOMEM (n == NULL) ) { \
M_MEMORY_FULL (sizeof (node_t)); \
return NULL; \
M_MEMORY_FULL (node_t, 1); \
} \
M_CALL_INIT_SET(oplist, n->data, o->data); \
n->child[0] = M_C3(m_rbtr33_,name,_copy_node)(o->child[0]); \
n->child[1] = M_C3(m_rbtr33_,name,_copy_node)(o->child[1]); \
n->child[0] = M_F(name,_i_copy_node)M_R(o->child[0]); \
n->child[1] = M_F(name,_i_copy_node)M_R(o->child[1]); \
M_RBTR33_COPY_COLOR (n, o); \
return n; \
} \
\
M_INLINE void \
M_F(name, _init_set)(tree_t tree, const tree_t ref) \
M_P(void, name, _init_set, tree_t tree, const tree_t ref) \
{ \
M_RBTR33_CONTRACT (ref); \
M_ASSERT (tree != NULL && tree != ref); \
tree->size = ref->size; \
/* Copy the root node recursively */ \
tree->node = M_C3(m_rbtr33_,name,_copy_node)(ref->node); \
tree->node = M_F(name,_i_copy_node)M_R(ref->node); \
M_RBTR33_CONTRACT (tree); \
} \
\
M_INLINE void \
M_F(name, _set)(tree_t tree, const tree_t ref) \
M_P(void, name, _set, tree_t tree, const tree_t ref) \
{ \
M_RBTR33_CONTRACT (tree); \
M_RBTR33_CONTRACT (ref); \
if (tree == ref) return; \
M_F(name,_clear)(tree); \
M_F(name,_init_set)(tree, ref); \
M_F(name,_clear)M_R(tree); \
M_F(name,_init_set)M_R(tree, ref); \
} \
\
M_INLINE void \
@@ -728,18 +731,18 @@ typedef enum {
M_ASSERT (tree != NULL && tree != ref); \
tree->size = ref->size; \
tree->node = ref->node; \
/* Mark ref as an invalid representation */ \
ref->node = NULL; \
ref->size = 0; \
ref->size = 1; \
M_RBTR33_CONTRACT (tree); \
} \
\
M_INLINE void \
M_F(name, _move)(tree_t tree, tree_t ref) \
M_P(void, name, _move, tree_t tree, tree_t ref) \
{ \
M_RBTR33_CONTRACT (tree); \
M_RBTR33_CONTRACT (ref); \
M_ASSERT (tree != ref); \
M_F(name,_clear)(tree); \
M_F(name,_clear)M_R(tree); \
M_F(name,_init_move)(tree, ref); \
M_RBTR33_CONTRACT (tree); \
} \
@@ -801,8 +804,7 @@ typedef enum {
} \
) \
\
M_INLINE bool \
M_F(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \
M_P(bool, name, _pop_at, type *data_ptr, tree_t tree, type const key) \
{ \
M_RBTR33_CONTRACT (tree); \
node_t *tab[M_RBTR33_MAX_STACK]; \
@@ -955,24 +957,22 @@ typedef enum {
M_DO_MOVE(oplist, *data_ptr, n->data); \
else \
M_CALL_CLEAR(oplist, n->data); \
M_C3(m_rbtr33_,name,_del) (n); \
M_CALL_DEL(oplist, n); \
tree->size --; \
M_RBTR33_CONTRACT (tree); \
return true; \
} \
\
M_INLINE void M_F(name,_remove)(tree_t t, it_t it) \
M_P(void, name,_remove, tree_t t, it_t it) \
{ \
/* Not optimum: another search in the tree is performed */ \
type data; \
M_CALL_INIT_SET(oplist, data, *M_F(name,_cref)(it)); \
type const *data = M_F(name,_cref)(it); \
M_F(name,_next)(it); \
M_F(name, _pop_at)(NULL, t, data); \
/* We have changed the tree: the iterator is partialy invalid */ \
M_F(name, _pop_at)M_R(NULL, t, *data); \
/* We have changed the tree: the iterator is partially invalid */ \
if (!M_F(name, _end_p)(it)) { \
M_F(name, _it_from)(it, t, *M_F(name,_cref)(it)); \
} \
M_CALL_CLEAR(oplist, data); \
} \
\
M_IF_METHOD(EQUAL, oplist)( \
@@ -1022,24 +1022,24 @@ typedef enum {
/* Define the I/O functions */
#define M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void M_F(name, _get_str)(m_string_t str, \
tree_t const t1, bool append) { \
M_P(void, name, _get_str, m_string_t str, tree_t const t1, bool append) \
{ \
M_RBTR33_CONTRACT(t1); \
M_ASSERT(str != NULL); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
/* NOTE: The print is really naive, and not really efficient */ \
bool commaToPrint = false; \
it_t it1; \
M_F(name, _it)(it1, t1); \
while (!M_F(name, _end_p)(it1)) { \
if (commaToPrint) \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
commaToPrint = true; \
type const *ref1 = M_F(name, _cref)(it1); \
M_CALL_GET_STR(oplist, str, *ref1, true); \
M_F(name, _next)(it1); \
} \
m_string_push_back (str, ']'); \
m_string_push_back M_R(str, ']'); \
} \
, /* NO GET_STR */ ) \
\
@@ -1066,12 +1066,11 @@ typedef enum {
, /* no out_str */ ) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \
M_P(bool, name, _parse_str, tree_t rbtree, const char str[], const char **endp) \
{ \
M_RBTR33_CONTRACT(rbtree); \
M_ASSERT (str != NULL); \
M_F(name,_reset)(rbtree); \
M_F(name,_reset)M_R(rbtree); \
int c = m_core_str_nospace(&str); \
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
c = m_core_str_nospace(&str); \
@@ -1082,7 +1081,7 @@ typedef enum {
bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \
c = m_core_str_nospace(&str); \
if (b == false || c == 0) { c= 0 ; break; }; \
M_F(name, _push)(rbtree, item); \
M_F(name, _push)M_R(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
exit: \
@@ -1092,12 +1091,11 @@ typedef enum {
, /* no parse_str */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(tree_t rbtree, FILE *file) \
M_P(bool, name, _in_str, tree_t rbtree, FILE *file) \
{ \
M_RBTR33_CONTRACT(rbtree); \
M_ASSERT (file != NULL); \
M_F(name,_reset)(rbtree); \
M_F(name,_reset)M_R(rbtree); \
int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \
@@ -1109,7 +1107,7 @@ typedef enum {
bool b = M_CALL_IN_STR(oplist, item, file); \
c = m_core_fgetc_nospace(file); \
if (b == false || c == EOF) { c = 0; break; } \
M_F(name, _push)(rbtree, item); \
M_F(name, _push)M_R(rbtree, item); \
} while (c == M_GET_SEPARATOR oplist); \
} \
return c == ']'; \
@@ -1117,8 +1115,7 @@ typedef enum {
, /* no in_str */ ) \
\
M_IF_METHOD(OUT_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, tree_t const t1) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, tree_t const t1) \
{ \
M_RBTR33_CONTRACT(t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
@@ -1127,38 +1124,37 @@ typedef enum {
M_F(name, _subtype_ct) const *item; \
bool first_done = false; \
it_t it; \
ret = f->m_interface->write_array_start(local, f, t1->size); \
ret = f->m_interface->write_array_start M_R(local, f, t1->size); \
for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \
M_F(name, _next)(it)){ \
item = M_F(name, _cref)(it); \
if (first_done) \
ret |= f->m_interface->write_array_next(local, f); \
ret |= f->m_interface->write_array_next M_R(local, f); \
ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \
first_done = true; \
} \
ret |= f->m_interface->write_array_end(local, f); \
ret |= f->m_interface->write_array_end M_R(local, f); \
return ret & M_SERIAL_FAIL; \
} \
, /* no OUT_SERIAL */ ) \
\
M_IF_METHOD(IN_SERIAL, oplist)( \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \
M_P(m_serial_return_code_t, name, _in_serial, tree_t t1, m_serial_read_t f) \
{ \
M_RBTR33_CONTRACT(t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \
m_serial_return_code_t ret; \
size_t estimated_size = 0; \
M_F(name,_reset)(t1); \
M_F(name,_reset)M_R(t1); \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \
if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \
M_QLET(1, key, type, oplist) { \
do { \
ret = M_CALL_IN_SERIAL(oplist, key, f); \
if (ret != M_SERIAL_OK_DONE) { break; } \
M_F(name, _push)(t1, key); \
M_F(name, _push)M_R(t1, key); \
ret = f->m_interface->read_array_next(local, f); \
} while (ret == M_SERIAL_OK_CONTINUE); \
} \
+29 -29
View File
@@ -111,9 +111,9 @@ m_ser1al_bin_read_size(FILE *f, size_t *size)
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_boolean, m_serial_write_t serial, const bool data)
{
M_UNUSED_CONTEXT();
FILE *f = (FILE *)serial->data[0].p;
size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f);
return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail();
@@ -121,9 +121,9 @@ m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data)
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_integer, m_serial_write_t serial,const long long data, const size_t size_of_type)
{
M_UNUSED_CONTEXT();
size_t n;
FILE *f = (FILE *)serial->data[0].p;
@@ -146,9 +146,9 @@ m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const s
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type)
{
M_UNUSED_CONTEXT();
size_t n;
FILE *f = (FILE *)serial->data[0].p;
@@ -168,9 +168,9 @@ m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t length)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_string, m_serial_write_t serial, const char data[], size_t length)
{
M_UNUSED_CONTEXT();
M_ASSERT_SLOW(length == strlen(data) );
FILE *f = (FILE *)serial->data[0].p;
M_ASSERT(f != NULL && data != NULL);
@@ -188,9 +188,9 @@ m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t len
Initialize 'local' so that it can be used to serialize the array
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
M_UNUSED_CONTEXT();
(void) local; //Unused
if (number_of_elements == (size_t)-1) return M_SERIAL_FAIL_RETRY;
FILE *f = (FILE *)serial->data[0].p;
@@ -200,9 +200,9 @@ m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial,
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_next, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // Unused
(void) serial; // Unused
return M_SERIAL_OK_CONTINUE;
@@ -210,9 +210,9 @@ m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial)
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // Unused
(void) serial; // Unused
return M_SERIAL_OK_CONTINUE;
@@ -220,9 +220,9 @@ m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial)
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_map_value, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_CONTINUE;
@@ -232,9 +232,9 @@ m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial)
Initialize 'local' so that it can serial the tuple
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_CONTINUE;
@@ -242,9 +242,9 @@ m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) serial;
(void) field_name;
@@ -255,9 +255,9 @@ m_ser1al_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, con
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_DONE;
@@ -268,9 +268,9 @@ m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
M_UNUSED_CONTEXT();
(void) field_name;
(void) max;
(void) local;
@@ -281,9 +281,9 @@ m_ser1al_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) serial;
return M_SERIAL_OK_DONE;
@@ -399,15 +399,15 @@ m_ser1al_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz
/* Read from the stream 'serial' a string.
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_bin_read_string(m_serial_read_t serial, struct m_string_s *s){
M_P(m_serial_return_code_t, m_ser1al_bin, _read_string, m_serial_read_t serial, struct m_string_s *s)
{
FILE *f = (FILE*) serial->data[0].p;
M_ASSERT(f != NULL && s != NULL);
// First read the number of non null characters
size_t length;
if (m_ser1al_bin_read_size(f, &length) != true) return m_core_serial_fail();
// Use of internal string interface to dimension the string
char *p = m_str1ng_fit2size(s, length + 1);
char *p = m_str1ng_fit2size M_R(s, length + 1);
m_str1ng_set_size(s, length);
// Read the characters excluding the final null one.
// NOTE: fread supports length == 0.
+72 -87
View File
@@ -36,9 +36,9 @@ M_BEGIN_PROTECTED_CODE
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_boolean(m_serial_write_t serial, const bool data)
M_P(m_serial_return_code_t, m_ser1al_json, _write_boolean, m_serial_write_t serial, const bool data)
{
M_UNUSED_CONTEXT();
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%s", data ? "true" : "false");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
@@ -46,9 +46,9 @@ m_ser1al_json_write_boolean(m_serial_write_t serial, const bool data)
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
M_P(m_serial_return_code_t, m_ser1al_json, _write_integer, m_serial_write_t serial,const long long data, const size_t size_of_type)
{
M_UNUSED_CONTEXT();
(void) size_of_type; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%lld", data);
@@ -57,9 +57,9 @@ m_ser1al_json_write_integer(m_serial_write_t serial,const long long data, const
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
M_P(m_serial_return_code_t, m_ser1al_json, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type)
{
M_UNUSED_CONTEXT();
(void) size_of_type; // Ignored
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "%Lf", data);
@@ -68,9 +68,9 @@ m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t length)
M_P(m_serial_return_code_t, m_ser1al_json, _write_string, m_serial_write_t serial, const char data[], size_t length)
{
M_UNUSED_CONTEXT();
M_ASSERT(length == (m_str1ng_size_t) length);
M_ASSERT_SLOW(length == strlen(data) );
FILE *f = (FILE *)serial->data[0].p;
@@ -92,9 +92,9 @@ m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t le
Initialize 'local' so that it can be used to serialize the array
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
M_P(m_serial_return_code_t, m_ser1al_json, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) number_of_elements; // Ignored
FILE *f = (FILE *)serial->data[0].p;
@@ -104,9 +104,9 @@ m_ser1al_json_write_array_start(m_serial_local_t local, m_serial_write_t serial,
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_array_next, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, ",");
@@ -115,9 +115,9 @@ m_ser1al_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_array_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "]");
@@ -130,9 +130,9 @@ m_ser1al_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
Initialize 'local' so that it can be used to serialize the map
(local is an unique serialization object of the map).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
M_P(m_serial_return_code_t, m_ser1al_json, _write_map_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) number_of_elements; // Ignored
FILE *f = (FILE *)serial->data[0].p;
@@ -142,9 +142,9 @@ m_ser1al_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, c
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_map_value, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, ":");
@@ -153,9 +153,9 @@ m_ser1al_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_map_next, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, ",");
@@ -164,9 +164,9 @@ m_ser1al_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
/* End the writing of a map into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_map_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "}");
@@ -177,9 +177,9 @@ m_ser1al_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
Initialize 'local' so that it can serial the tuple
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "{");
@@ -188,9 +188,9 @@ m_ser1al_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) max; // Ignored
FILE *f = (FILE *)serial->data[0].p;
@@ -200,9 +200,9 @@ m_ser1al_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, co
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "}");
@@ -214,9 +214,9 @@ m_ser1al_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
(void) max; // argument not used
FILE *f = (FILE *)serial->data[0].p;
@@ -233,9 +233,9 @@ m_ser1al_json_write_variant_start(m_serial_local_t local, m_serial_write_t seria
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_end, m_serial_local_t local, m_serial_write_t serial)
{
M_UNUSED_CONTEXT();
(void) local; // argument not used
FILE *f = (FILE *)serial->data[0].p;
int n = fprintf(f, "}");
@@ -344,12 +344,12 @@ m_ser1al_json_read_float(m_serial_read_t serial, long double *r, const size_t si
/* Read from the stream 'serial' a string.
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_json_read_string(m_serial_read_t serial, struct m_string_s *s){
M_P(m_serial_return_code_t, m_ser1al_json, _read_string, m_serial_read_t serial, struct m_string_s *s)
{
FILE *f = (FILE*) serial->data[0].p;
int n = m_core_fscanf(f, " "); // Skip any leading spaces.
(void) n; // Unused return value.
return m_string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
return m_string_in_str M_R(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Start reading from the stream 'serial' an array.
@@ -587,40 +587,37 @@ typedef m_serial_read_t m_serial_json_read_t;
/* Write the boolean 'data' into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_boolean(m_serial_write_t serial, const bool data)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_boolean, m_serial_write_t serial, const bool data)
{
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%s", data ? "true" : "false");
//TODO: Simplify code.
int n = m_string_cat_printf M_R(f, "%s", data ? "true" : "false");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_integer, m_serial_write_t serial, const long long data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%lld", data);
int n = m_string_cat_printf M_R(f, "%lld", data);
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type)
{
(void) size_of_type; // Ignored
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%Lf", data);
int n = m_string_cat_printf M_R(f, "%Lf", data);
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
/* Write the null-terminated string 'data'into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_t length)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_string, m_serial_write_t serial, const char data[], size_t length)
{
M_ASSERT(length == (m_str1ng_size_t) length);
M_ASSERT_SLOW(length == strlen(data) );
@@ -633,7 +630,7 @@ m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1;
v2->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31;
v2->u.heap.ptr = (char*)ptr;
m_string_get_str(f, v2, true);
m_string_get_str M_R(f, v2, true);
return M_SERIAL_OK_DONE;
}
@@ -643,35 +640,32 @@ m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_
Initialize 'local' so that it can be used to serialize the array
(local is an unique serialization object of the array).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '[');
m_string_push_back M_R(f, '[');
return M_SERIAL_OK_CONTINUE;
}
/* Write an array separator between elements of an array into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_array_next(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_array_next, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ',');
m_string_push_back M_R(f, ',');
return M_SERIAL_OK_CONTINUE;
}
/* End the writing of an array into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_array_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_array_end, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ']');
m_string_push_back M_R(f, ']');
return M_SERIAL_OK_CONTINUE;
}
@@ -681,46 +675,42 @@ m_ser1al_str_json_write_array_end(m_serial_local_t local, m_serial_write_t seria
Initialize 'local' so that it can be used to serialize the map
(local is an unique serialization object of the map).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements)
{
(void) local; // argument not used
(void) number_of_elements; // Ignored
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '{');
m_string_push_back M_R(f, '{');
return M_SERIAL_OK_CONTINUE;
}
/* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_map_value(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_value, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ':');
m_string_push_back M_R(f, ':');
return M_SERIAL_OK_CONTINUE;
}
/* Write a map separator between elements of a map into the serial stream 'serial' if needed.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_map_next(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_next, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, ',');
m_string_push_back M_R(f, ',');
return M_SERIAL_OK_CONTINUE;
}
/* End the writing of a map into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_end, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '}');
m_string_push_back M_R(f, '}');
return M_SERIAL_OK_CONTINUE;
}
@@ -728,35 +718,32 @@ m_ser1al_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial)
Initialize 'local' so that it can serial the tuple
(local is an unique serialization object of the tuple).
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '{');
m_string_push_back M_R(f, '{');
return M_SERIAL_OK_CONTINUE;
}
/* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // Ignored
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
int n = m_string_cat_printf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
int n = m_string_cat_printf M_R(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
}
/* End the write of a tuple into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '}');
m_string_push_back M_R(f, '}');
return M_SERIAL_OK_CONTINUE;
}
@@ -765,8 +752,7 @@ m_ser1al_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t seria
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise
Otherwise, the field 'field_name[index]' will be filled.
Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index)
{
(void) local; // argument not used
(void) max; // argument not used
@@ -774,22 +760,21 @@ m_ser1al_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t s
int n;
if (index >= 0) {
M_ASSERT (index < max);
n = m_string_cat_printf(f, "{\"%s\":", field_name[index]);
n = m_string_cat_printf M_R(f, "{\"%s\":", field_name[index]);
return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail();
} else {
n = m_string_cat_printf(f, "{}");
n = m_string_cat_printf M_R(f, "{}");
return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
}
/* End Writing a variant into the serial stream 'serial'.
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial)
M_P(m_serial_return_code_t, m_ser1al_str_json, _write_variant_end, m_serial_local_t local, m_serial_write_t serial)
{
(void) local; // argument not used
struct m_string_s *f = (struct m_string_s *)serial->data[0].p;
m_string_push_back(f, '}');
m_string_push_back M_R(f, '}');
return M_SERIAL_OK_CONTINUE;
}
@@ -933,12 +918,12 @@ m_ser1al_str_json_read_float(m_serial_read_t serial, long double *r, const size_
/* Read from the stream 'serial' a string.
Set 's' with the string if succeeds
Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */
M_INLINE m_serial_return_code_t
m_ser1al_str_json_read_string(m_serial_read_t serial, struct m_string_s *s){
M_P(m_serial_return_code_t, m_ser1al_str_json, _read_string, m_serial_read_t serial, struct m_string_s *s)
{
const char **f = &serial->data[0].cstr;
m_ser1al_str_json_skip(f);
const char *e;
bool b = m_string_parse_str(s, *f, &e);
bool b = m_string_parse_str M_R(s, *f, &e);
serial->data[0].cstr = e;
return b ? M_SERIAL_OK_DONE : m_core_serial_fail();
}
+46 -19
View File
@@ -613,12 +613,12 @@ extern shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type
M_IF_METHOD(INIT, oplist)( \
fattr shared_t *M_F(name, _new)(void) \
{ \
M_GLOBAL_CONTEXT(); \
shared_t *out = M_CALL_NEW(oplist, shared_t); \
if (M_UNLIKELY_NOMEM( out == NULL)) { \
M_MEMORY_FULL(sizeof (shared_t)); \
abort(); \
M_MEMORY_FULL(shared_t, 1); \
} \
M_ON_EXCEPTION( M_CALL_FREE(oplist, out) ) \
M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \
M_CALL_INIT(oplist, out->data); \
M_F(name, _init_lock)(out); \
return out; \
@@ -629,13 +629,13 @@ M_IF_METHOD(INIT_SET, oplist)( \
fattr shared_t *M_F(name, _clone)(const shared_t *src) \
{ \
M_ASSERT(src != NULL); \
M_GLOBAL_CONTEXT(); \
shared_t *out = M_CALL_NEW(oplist, shared_t); \
if (M_UNLIKELY_NOMEM( out == NULL)) { \
M_MEMORY_FULL(sizeof (shared_t)); \
abort(); \
M_MEMORY_FULL(shared_t, 1); \
} \
M_F(name, _read_lock)(src); \
M_ON_EXCEPTION( M_F(name, _read_unlock)(src), M_CALL_FREE(oplist, out) ) \
M_ON_EXCEPTION( M_F(name, _read_unlock)(src), M_CALL_DEL(oplist, out) ) \
M_CALL_INIT_SET(oplist, out->data, src->data); \
M_F(name, _read_unlock)(src); \
M_F(name, _init_lock)(out); \
@@ -646,12 +646,12 @@ M_IF_METHOD(INIT_SET, oplist)( \
fattr shared_t *M_F(name, _new_from)(type const src); ) \
fattr shared_t *M_F(name, _new_from)(type const src) \
{ \
M_GLOBAL_CONTEXT(); \
shared_t *out = M_CALL_NEW(oplist, shared_t); \
if (M_UNLIKELY_NOMEM( out == NULL)) { \
M_MEMORY_FULL(sizeof (shared_t)); \
abort(); \
M_MEMORY_FULL(shared_t, 1); \
} \
M_ON_EXCEPTION( M_CALL_FREE(oplist, out) ) \
M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \
M_CALL_INIT_SET(oplist, out->data, src); \
M_F(name, _init_lock)(out); \
return out; \
@@ -663,6 +663,7 @@ M_IF_METHOD(SET, oplist)( \
{ \
M_ASSERT(out != NULL); \
M_ASSERT(src != NULL); \
M_GLOBAL_CONTEXT(); \
if (M_UNLIKELY (out == src)) return; \
M_F(name, _write_read_lock)(out, src); \
M_ON_EXCEPTION( M_F(name, _write_read_unlock)(out, src) ) \
@@ -681,6 +682,7 @@ fattr shared_t *M_F(name, _acquire)(shared_t *out) \
\
fattr void M_F(name, _release)(shared_t *out) \
{ \
M_GLOBAL_CONTEXT(); \
if (out != NULL && M_C3(m_shar3d_, name, _dec_owner)(out)) { \
M_CALL_CLEAR(oplist, out->data); \
M_F(name, _clear_lock)(out); \
@@ -704,12 +706,12 @@ M_EMPLACE_QUEUE_DEF( (name, fattr), shared_t, M_F(name, _make), oplist, M_SHAR3D
#define M_SHAR3D_PTR_DEF_BASIC_MAKE(name_attr, shared_t, function_name, oplist, init_func, exp_emplace_type) \
M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type)) \
{ \
M_GLOBAL_CONTEXT(); \
shared_t *out = M_CALL_NEW(oplist, shared_t); \
if (M_UNLIKELY_NOMEM( out == NULL)) { \
M_MEMORY_FULL(sizeof (shared_t)); \
abort(); \
M_MEMORY_FULL(shared_t, 1); \
} \
M_ON_EXCEPTION( M_CALL_FREE(oplist, out) ) \
M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, out->data, exp_emplace_type); \
M_F(M_PAIR_1 name_attr, _init_lock)(out); \
return out; \
@@ -751,6 +753,7 @@ M_IF_METHOD(RESET, oplist)( \
fattr void M_F(name, _reset)(shared_t *out) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
/* RESET cannot throw exception */ \
M_CALL_RESET(oplist, out->data); \
@@ -863,6 +866,7 @@ M_IF_METHOD(ADD, oplist)( \
fattr void M_F(name, _add)(shared_t *out, const shared_t *src1, const shared_t *src2) \
{ \
M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_read2_lock)(out, src1, src2); \
M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \
M_CALL_ADD(oplist, out->data, src1->data, src2->data); \
@@ -874,6 +878,7 @@ M_IF_METHOD(SUB, oplist)( \
fattr void M_F(name, _sub)(shared_t *out, const shared_t *src1, const shared_t *src2) \
{ \
M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_read2_lock)(out, src1, src2); \
M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \
M_CALL_SUB(oplist, out->data, src1->data, src2->data); \
@@ -885,6 +890,7 @@ M_IF_METHOD(MUL, oplist)( \
fattr void M_F(name, _mul)(shared_t *out, const shared_t *src1, const shared_t *src2) \
{ \
M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_read2_lock)(out, src1, src2); \
M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \
M_CALL_MUL(oplist, out->data, src1->data, src2->data); \
@@ -896,6 +902,7 @@ M_IF_METHOD(DIV, oplist)( \
fattr void M_F(name, _div)(shared_t *out, const shared_t *src1, const shared_t *src2) \
{ \
M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_read2_lock)(out, src1, src2); \
M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \
M_CALL_DIV(oplist, out->data, src1->data, src2->data); \
@@ -907,6 +914,7 @@ M_IF_METHOD(SPLICE, oplist)( \
fattr void M_F(name, _splice)(shared_t *out, shared_t *src) \
{ \
M_ASSERT(out != NULL && src != NULL); \
M_GLOBAL_CONTEXT(); \
if (out < src) { \
M_F(name, _write_lock)(out); \
M_F(name, _write_lock)(src); \
@@ -936,6 +944,7 @@ M_IF_METHOD(GET_KEY, oplist)( \
{ \
M_ASSERT (out != NULL); \
M_ASSERT (value != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _read_lock)(out); \
/* No exception */ \
value_type *p = M_CALL_GET_KEY(oplist, out->data, key); \
@@ -952,6 +961,7 @@ M_IF_METHOD(SAFE_GET_KEY, oplist)( \
{ \
M_ASSERT (out != NULL); \
M_ASSERT (value != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) { \
value_type *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \
@@ -967,6 +977,7 @@ M_IF_METHOD(SET_KEY, oplist)( \
fattr void M_F(name, _set_at)(shared_t *out, key_type const key, value_type const value) \
{ \
M_ASSERT (out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \
M_CALL_SET_KEY(oplist, out->data, key, value); \
@@ -979,6 +990,7 @@ M_IF_METHOD(ERASE_KEY, oplist)( \
fattr bool M_F(name, _erase)(shared_t *out, key_type const key) \
{ \
M_ASSERT (out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
/* No exception */ \
bool r = M_CALL_ERASE_KEY(oplist, out->data, key); \
@@ -1009,6 +1021,7 @@ M_IF_METHOD(PUSH, oplist)( \
fattr void M_F(name, _push)(shared_t *out, sub_type const value) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
while (true) { \
if (M_CALL_FULL_P(oplist, out->data) == false) { \
@@ -1025,6 +1038,7 @@ M_IF_METHOD(PUSH, oplist)( \
fattr bool M_F(name, _try_push)(shared_t *out, sub_type const value) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
bool ret = false; \
M_F(name, _write_lock)(out); \
if (M_CALL_FULL_P(oplist, out->data) == false) { \
@@ -1041,6 +1055,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \
fattr void M_F(name, _push_move)(shared_t *out, sub_type *value) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
while (true) { \
if (M_CALL_FULL_P(oplist, out->data) == false) { \
@@ -1057,6 +1072,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \
fattr bool M_F(name, _try_push_move)(shared_t *out, sub_type *value) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
bool ret = false; \
M_F(name, _write_lock)(out); \
if (M_CALL_FULL_P(oplist, out->data) == false) { \
@@ -1078,6 +1094,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \
fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
while (true) { \
if (M_CALL_FULL_P(oplist, out->data) == false) { \
@@ -1100,6 +1117,7 @@ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_ty
fattr bool function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
bool ret = false; \
M_F(name, _write_lock)(out); \
if (M_CALL_FULL_P(oplist, out->data) == false) { \
@@ -1128,6 +1146,7 @@ M_IF_METHOD(POP, oplist)( \
fattr void M_F(name, _pop)(sub_type *value, shared_t *out) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
while (true) { \
if (M_CALL_EMPTY_P(oplist, out->data) == false) { \
@@ -1144,6 +1163,7 @@ M_IF_METHOD(POP, oplist)( \
fattr bool M_F(name, _try_pop)(sub_type *value, shared_t *out) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
bool ret = false; \
M_F(name, _write_lock)(out); \
if (M_CALL_EMPTY_P(oplist, out->data) == false) { \
@@ -1160,6 +1180,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \
fattr void M_F(name, _pop_move)(sub_type *value, shared_t *out) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
while (true) { \
if (M_CALL_EMPTY_P(oplist, out->data) == false) { \
@@ -1176,6 +1197,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \
fattr bool M_F(name, _try_pop_move)(sub_type *value, shared_t *out) \
{ \
M_ASSERT(out != NULL); \
M_GLOBAL_CONTEXT(); \
bool ret = false; \
M_F(name, _write_lock)(out); \
if (M_CALL_EMPTY_P(oplist, out->data) == false) { \
@@ -1286,8 +1308,8 @@ M_IF_METHOD(OUT_STR, oplist)( extern void M_F(name, _out_str)(FILE *, const shar
M_IF_METHOD(IN_STR, oplist)( extern bool M_F(name, _in_str)(shared_t *, FILE *); , ) \
M_IF_METHOD(GET_STR, oplist)( extern void M_F(name, _get_str)(m_string_t, const shared_t *, bool); , ) \
M_IF_METHOD(PARSE_STR, oplist)( extern bool M_F(name, _parse_str)(shared_t *, const char *, const char **); , ) \
M_IF_METHOD(OUT_SERIAL, oplist)( extern m_serial_return_code_t M_F(name, _out_serial)(m_serial_write_t, const shared_t *); , ) \
M_IF_METHOD(IN_SERIAL, oplist)( extern m_serial_return_code_t M_F(name, _in_serial)(shared_t *, m_serial_read_t); , ) \
M_IF_METHOD(OUT_SERIAL, oplist)( extern m_serial_return_code_t M_F(M_P_EXPAND name, _out_serial)(m_serial_write_t, const shared_t *); , ) \
M_IF_METHOD(IN_SERIAL, oplist)( extern m_serial_return_code_t M_F(M_P_EXPAND name, _in_serial)(shared_t *, m_serial_read_t); , ) \
#define M_SHAR3D_PTR_DEF_IO(name, shared_t, type, oplist, fattr) \
M_IF_METHOD(OUT_STR, oplist)( \
@@ -1304,6 +1326,7 @@ M_IF_METHOD(IN_STR, oplist)( \
fattr bool M_F(name, _in_str)(shared_t *out, FILE *file) \
{ \
M_ASSERT (out != NULL && file != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
m_volatile bool r = false; \
M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \
@@ -1318,9 +1341,10 @@ M_IF_METHOD(GET_STR, oplist)( \
fattr void M_F(name, _get_str)(m_string_t str, const shared_t *out, bool append) \
{ \
M_ASSERT (out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _read_lock)(out); \
/* No exception */ \
M_CALL_GET_STR(oplist, str, out->data, append); \
M_ON_EXCEPTION( M_F(name, _read_unlock)(out) ) \
M_CALL_GET_STR(oplist, str, out->data, append); \
M_F(name, _read_unlock)(out); \
} \
, ) \
@@ -1328,6 +1352,7 @@ M_IF_METHOD(PARSE_STR, oplist)( \
fattr bool M_F(name, _parse_str)(shared_t *out, const char str[], const char **endp) \
{ \
M_ASSERT (out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
m_volatile bool r = false; \
M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \
@@ -1339,12 +1364,13 @@ M_IF_METHOD(PARSE_STR, oplist)( \
} \
, ) \
M_IF_METHOD(OUT_SERIAL, oplist)( \
fattr m_serial_return_code_t M_F(name, _out_serial)(m_serial_write_t serial, const shared_t *out) \
fattr m_serial_return_code_t M_F(name, _out_serial)(M_P_EXPAND m_serial_write_t serial, const shared_t *out) \
{ \
M_ASSERT (out != NULL); \
M_F(name, _read_lock)(out); \
/* No exception */ \
m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, serial, out->data); \
m_volatile m_serial_return_code_t r = M_SERIAL_FAIL; \
M_ON_EXCEPTION( M_F(name, _read_unlock)(out) ) \
r = M_CALL_OUT_SERIAL(oplist, serial, out->data); \
M_F(name, _read_unlock)(out); \
return r; \
} \
@@ -1353,6 +1379,7 @@ M_IF_METHOD(IN_SERIAL, oplist)( \
fattr m_serial_return_code_t M_F(name, _in_serial)(shared_t *out, m_serial_read_t serial) \
{ \
M_ASSERT (out != NULL); \
M_GLOBAL_CONTEXT(); \
M_F(name, _write_lock)(out); \
m_volatile m_serial_return_code_t r = M_SERIAL_FAIL; \
M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \
-555
View File
@@ -1,555 +0,0 @@
/*
* M*LIB - SHARED Pointer Module
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_SHARED_PTR_H
#define MSTARLIB_SHARED_PTR_H
#include "m-core.h"
#include "m-atomic.h"
#include "m-genint.h"
M_BEGIN_PROTECTED_CODE
/* Define shared pointer and its function.
USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */
#define M_SHARED_PTR_DEF(name, ...) \
M_SHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
/* Define shared pointer and its function
as the given name name_t
USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
#define M_SHARED_PTR_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_ATOMIC_OPLIST, name_t ), \
(name, __VA_ARGS__ , M_SHAR3D_ATOMIC_OPLIST, name_t ))) \
M_END_PROTECTED_CODE
/* Define the oplist of a shared pointer.
USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */
#define M_SHARED_PTR_OPLIST(...) \
M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_BASIC_OPLIST ), \
(__VA_ARGS__ )))
/* Define relaxed shared pointer and its function (thread unsafe).
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
#define M_SHARED_PTR_RELAXED_DEF(name, ...) \
M_SHARED_PTR_RELAXED_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
/* Define relaxed shared pointer and its function (thread unsafe)
as the given name name_t
USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */
#define M_SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_INTEGER_OPLIST, name_t ), \
(name, __VA_ARGS__, M_SHAR3D_INTEGER_OPLIST, name_t ))) \
M_END_PROTECTED_CODE
/* Define shared resource and its function.
This is a bounded pool of resource shared by multiple owners.
USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */
#define M_SHARED_RESOURCE_DEF(name, ...) \
M_SHARED_RESOURCE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
/* Define shared resource and its function
as the given name named_t and the iterator it_t
This is a bounded pool of resource shared by multiple owners.
USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */
#define M_SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_SHAR3D_RESOURCE_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
/*****************************************************************************/
/********************************** INTERNAL *********************************/
/*****************************************************************************/
// deferred evaluation
#define M_SHAR3D_PTR_OPLIST_P1(arg) M_SHAR3D_PTR_OPLIST_P2 arg
/* Validation of the given, shared_t oplist */
#define M_SHAR3D_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(M_SHAR3D_PTR_OPLIST_P3, M_SHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define M_SHAR3D_PTR_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
#define M_SHAR3D_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_F(name, _init)), \
CLEAR(M_F(name, _clear)), \
INIT_SET(M_F(name, _init_set)), \
SET(M_F(name, _set)) \
INIT_MOVE(M_F(name, _init_move)), \
RESET(M_F(name, _reset)), \
MOVE(M_F(name, _move)), \
SWAP(M_F(name, _swap)) \
,NAME(name) \
,TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*) \
)
// OPLIST to handle a counter of atomic type
#define M_SHAR3D_ATOMIC_OPLIST (TYPE(atomic_int), \
INIT_SET(atomic_init), \
ADD(atomic_fetch_add), \
SUB(atomic_fetch_sub), \
IT_CREF(atomic_load))
// OPLIST to handle a counter of non-atomic type
#define M_SHAR3D_INTEGER_OPLIST (TYPE(int), \
INIT_SET(m_shar3d_integer_init_set), \
ADD(m_shar3d_integer_add), \
SUB(m_shar3d_integer_sub), \
IT_CREF(m_shar3d_integer_cref))
/* Atomic like interface for basic integers */
M_INLINE void m_shar3d_integer_init_set(int *p, int val) { *p = val; }
M_INLINE int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; }
M_INLINE int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; }
M_INLINE int m_shar3d_integer_cref(int *p) { return *p; }
/********************************** INTERNAL *********************************/
/* Contract of a shared pointer */
#define M_SHAR3D_CONTRACT(shared, cpt_oplist) do { \
M_ASSERT(shared != NULL); \
M_ASSERT(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \
} while (0)
// deferred evaluation
#define M_SHAR3D_PTR_DEF_P1(arg) M_ID( M_SHAR3D_PTR_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \
M_IF_OPLIST(oplist)(M_SHAR3D_PTR_DEF_P3, M_SHAR3D_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t)
/* Stop processing with a compilation failure */
#define M_SHAR3D_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
/* Code generation */
#define M_SHAR3D_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \
M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
M_EMPLACE_QUEUE_DEF(name, cpt_oplist, M_F(name, _init_with), oplist, M_SHAR3D_PTR_DEF_EMPLACE)
/* Define the types */
#define M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \
\
typedef struct M_F(name, _s){ \
type *data; /* Pointer to the data */ \
M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \
bool combineAlloc; /* Does the data and the ptr share the slot? */ \
} *shared_t[1]; \
typedef struct M_F(name, _s) *M_F(name, _ptr); \
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
\
/* Internal type for oplist */ \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
\
M_IF(M_OR(M_TEST_METHOD_P(INIT, oplist), M_TEST_METHOD_ALTER_P(EMPLACE_TYPE, oplist)))( \
typedef struct M_F(name, _combine_s) { \
struct M_F(name, _s) ptr; \
type data; \
} M_F(name, combine_ct)[1]; \
, /* nothing to do */ )
/* Define the core functions */
#define M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \
\
M_INLINE void \
M_F(name, _init)(shared_t shared) \
{ \
*shared = NULL; \
} \
\
M_INLINE void \
M_F(name, _init2)(shared_t shared, type *data) \
{ \
M_ASSERT (shared != NULL); \
/* The shared ptr get exclusive access to data */ \
struct M_F(name, _s) *ptr; \
if (M_UNLIKELY (data == NULL)) { \
*shared = NULL; \
return; \
} \
ptr = M_CALL_NEW(oplist, struct M_F(name, _s)); \
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _s))); \
return; \
} \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
ptr->combineAlloc = false; \
*shared = ptr; \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_INLINE void \
M_F(name, _init_new)(shared_t shared) \
{ \
/* NOTE: Alloc 1 struct with both structures. */ \
struct M_F(name, _combine_s) *p = \
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
if (M_UNLIKELY_NOMEM (p == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
return; \
} \
struct M_F(name, _s) *ptr = &p->ptr; \
ptr->combineAlloc = true; \
type *data = &p->data; \
M_CALL_INIT( oplist, *data); \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
*shared = ptr; \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
, /* No INIT */ ) \
\
M_INLINE bool \
M_F(name, _NULL_p)(const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
return *shared == NULL; \
} \
\
M_INLINE void \
M_F(name, _init_set)(shared_t dest, \
const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != shared); \
*dest = *shared; \
if (*dest != NULL) { \
int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \
(void) n; /* unused return value */ \
} \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
} \
\
M_INLINE void \
M_F(name, _clear)(shared_t dest) \
{ \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
if (*dest != NULL) { \
if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \
bool combineAlloc = (*dest)->combineAlloc; \
/* Note: if combineAlloc is true, the address of the slot \
combining both data & ptr is the same as the address of the \
first element, aka data itself. Static analyzer tools don't \
seem to detect this and report error. */ \
M_CALL_CLEAR(oplist, *(*dest)->data); \
if (combineAlloc == false) { \
M_CALL_DEL(oplist, (*dest)->data); \
} \
M_CALL_DEL(oplist, *dest); \
} \
*dest = NULL; \
} \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
} \
\
M_INLINE void \
M_F(name, _reset)(shared_t dest) \
{ \
/* NOTE: Clear will also set dest to NULL */ \
M_F(name, _clear)(dest); \
} \
\
M_INLINE void \
M_F(name, _set)(shared_t dest, \
const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_F(name, _clear)(dest); \
M_F(name, _init_set)(dest, shared); \
} \
\
M_INLINE void \
M_F(name, _init_move)(shared_t dest, \
shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != NULL && dest != shared); \
*dest = *shared; \
*shared = NULL; \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
} \
\
M_INLINE void \
M_F(name, _move)(shared_t dest, \
shared_t shared) \
{ \
M_SHAR3D_CONTRACT(dest, cpt_oplist); \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT (dest != shared); \
M_F(name, _clear)(dest); \
M_F(name, _init_move)(dest, shared); \
} \
\
M_INLINE void \
M_F(name, _swap)(shared_t p1, \
shared_t p2) \
{ \
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
/* NOTE: SWAP is not atomic */ \
M_SWAP (struct M_F(name, _s)*, *p1, *p2); \
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
} \
\
M_INLINE bool \
M_F(name, _equal_p)(const shared_t p1, \
const shared_t p2) \
{ \
M_SHAR3D_CONTRACT(p1, cpt_oplist); \
M_SHAR3D_CONTRACT(p2, cpt_oplist); \
return *p1 == *p2; \
} \
\
M_INLINE type const * \
M_F(name, _cref)(const shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT(*shared != NULL); \
type *data = (*shared)->data; \
M_ASSERT (data != NULL); \
return M_CONST_CAST (type, data); \
} \
\
M_INLINE type * \
M_F(name, _ref)(shared_t shared) \
{ \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
M_ASSERT(*shared != NULL); \
type *data = (*shared)->data; \
M_ASSERT (data != NULL); \
return data; \
} \
/* Definition of the emplace_back function for arrays */
#define M_SHAR3D_PTR_DEF_EMPLACE(name, cpt_oplist, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
function_name(M_F(name, _ct) shared \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
/* NOTE: Alloc 1 struct with both structures. */ \
struct M_F(name, _combine_s) *p = \
M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \
if (M_UNLIKELY_NOMEM (p == NULL)) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \
return; \
} \
struct M_F(name, _s) *ptr = &p->ptr; \
ptr->combineAlloc = true; \
M_F(name, _subtype_ct) *data = &p->data; \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \
ptr->data = data; \
M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \
*shared = ptr; \
M_SHAR3D_CONTRACT(shared, cpt_oplist); \
} \
/********************************** INTERNAL *********************************/
#define M_SHAR3D_RESOURCE_CONTRACT(s) do { \
M_ASSERT (s != NULL); \
M_ASSERT (s->buffer != NULL); \
} while (0)
// deferred
#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_ID( M_SHAR3D_RESOURCE_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \
M_IF_OPLIST(oplist)(M_SHAR3D_RESOURCE_DEF_P3, M_SHAR3D_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t)
/* Stop processing with a compilation failure */
#define M_SHAR3D_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist)
#define M_SHAR3D_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \
M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
/* Define the types */
#define M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \
\
/* Create an aligned type to avoid false sharing between threads */ \
typedef struct M_F(name, _atype_s) { \
atomic_uint cpt; \
type x; \
M_CACHELINE_ALIGN(align, type, atomic_uint); \
} M_F(name, _atype_ct); \
\
typedef struct M_F(name, _s) { \
m_genint_t core; \
M_F(name, _atype_ct) *buffer; \
} shared_t[1]; \
\
typedef struct M_F(name, _it_s) { \
unsigned int idx; \
struct M_F(name, _s) *ref; \
} it_t[1]; \
\
/* Internal Types for oplist */ \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \
M_INLINE void \
M_F(name, _init)(shared_t s, size_t n) \
{ \
M_ASSERT(s != NULL); \
M_ASSERT (n > 0 && n < UINT_MAX); \
s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, n); \
if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _atype_ct)) * n); \
return; \
} \
for(size_t i = 0; i < n; i++) { \
M_CALL_INIT(oplist, s->buffer[i].x); \
atomic_init (&s->buffer[i].cpt, 0U); \
} \
m_genint_init(s->core, (unsigned int) n); \
M_SHAR3D_RESOURCE_CONTRACT(s); \
} \
\
M_INLINE void \
M_F(name, _clear)(shared_t s) \
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
size_t n = m_genint_size(s->core); \
for(size_t i = 0; i < n; i++) { \
M_CALL_CLEAR(oplist, s->buffer[i].x); \
} \
M_CALL_FREE(oplist, s->buffer); \
s->buffer = NULL; \
m_genint_clear(s->core); \
} \
\
M_INLINE void \
M_F(name, _it)(it_t it, shared_t s) \
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
M_ASSERT (it != NULL); \
unsigned int idx = m_genint_pop(s->core); \
it->idx = idx; \
it->ref = s; \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \
atomic_store(&s->buffer[idx].cpt, 1U); \
} \
} \
\
M_INLINE bool \
M_F(name, _end_p)(it_t it) \
{ \
M_ASSERT (it != NULL); \
return it->idx == M_GENINT_ERROR; \
} \
\
M_INLINE type * \
M_F(name, _ref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
return &it->ref->buffer[it->idx].x; \
} \
\
M_INLINE type const * \
M_F(name, _cref)(it_t it) \
{ \
M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \
M_SHAR3D_RESOURCE_CONTRACT(it->ref); \
return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \
} \
\
M_INLINE void \
M_F(name, _end)(it_t it, shared_t s) \
{ \
M_SHAR3D_RESOURCE_CONTRACT(s); \
M_ASSERT (it != NULL); \
M_ASSERT (it->ref == s); \
unsigned int idx = it->idx; \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \
if (c == 1) { \
m_genint_push(it->ref->core, idx); \
} \
it->idx = M_GENINT_ERROR; \
} \
} \
\
M_INLINE void \
M_F(name, _it_set)(it_t itd, it_t its) \
{ \
M_ASSERT (itd != NULL && its != NULL); \
M_SHAR3D_RESOURCE_CONTRACT(its->ref); \
itd->ref = its->ref; \
unsigned int idx = its->idx; \
itd->idx = idx; \
if (M_LIKELY (idx != M_GENINT_ERROR)) { \
unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \
M_ASSERT (c >= 1); \
} \
} \
M_END_PROTECTED_CODE
/********************************** INTERNAL *********************************/
#if M_USE_SMALL_NAME
#define SHARED_PTR_OPLIST M_SHARED_PTR_OPLIST
#define SHARED_PTR_DEF M_SHARED_PTR_DEF
#define SHARED_PTR_DEF_AS M_SHARED_PTR_DEF_AS
#define SHARED_PTR_RELAXED_DEF M_SHARED_PTR_RELAXED_DEF
#define SHARED_PTR_RELAXED_DEF_AS M_SHARED_PTR_RELAXED_DEF_AS
#define SHARED_RESOURCE_DEF M_SHARED_RESOURCE_DEF
#define SHARED_RESOURCE_DEF_AS M_SHARED_RESOURCE_DEF_AS
#endif
#endif
+29 -37
View File
@@ -150,6 +150,7 @@ M_BEGIN_PROTECTED_CODE
#define M_SNAPSH0T_SPSC_CONTRACT(snap) do { \
M_ASSERT((snap) != NULL); \
unsigned char f = atomic_load (&(snap)->flags); \
(void) f; \
M_SNAPSH0T_SPSC_FLAGS_CONTRACT(f); \
} while (0)
@@ -197,10 +198,10 @@ M_BEGIN_PROTECTED_CODE
/* Define the core functions */
#define M_SNAPSH0T_SPSC_DEF_CORE(name, type, oplist, snapshot_t) \
\
M_INLINE void \
M_F(name, _init)(snapshot_t snap) \
M_P(void, name, _init, snapshot_t snap) \
{ \
M_ASSERT(snap != NULL); \
M_UNUSED_CONTEXT(); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
M_CALL_INIT(oplist, snap->data[i].x); \
} \
@@ -208,20 +209,20 @@ M_BEGIN_PROTECTED_CODE
M_SNAPSH0T_SPSC_CONTRACT(snap); \
} \
\
M_INLINE void \
M_F(name, _clear)(snapshot_t snap) \
M_P(void, name, _clear, snapshot_t snap) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
M_UNUSED_CONTEXT(); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
M_CALL_CLEAR(oplist, snap->data[i].x); \
} \
} \
\
/* const is missing for org due to use of atomic_load of org */ \
M_INLINE void \
M_F(name, _init_set)(snapshot_t snap, snapshot_t org) \
M_P(void, name, _init_set, snapshot_t snap, snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(org); \
M_UNUSED_CONTEXT(); \
M_ASSERT(snap != NULL && snap != org); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \
@@ -231,11 +232,11 @@ M_BEGIN_PROTECTED_CODE
} \
\
/* const is missing for org due to use of atomic_load of org */ \
M_INLINE void \
M_F(name, _set)(snapshot_t snap, snapshot_t org) \
M_P(void, name, _set, snapshot_t snap, snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
M_SNAPSH0T_SPSC_CONTRACT(org); \
M_UNUSED_CONTEXT(); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \
} \
@@ -259,12 +260,11 @@ M_BEGIN_PROTECTED_CODE
,) /* IF_METHOD (INIT_MOVE) */ \
\
M_IF_METHOD(MOVE, oplist)( \
M_INLINE void \
M_F(name, _move)(snapshot_t snap, \
snapshot_t org) \
M_P(void, name, _move, snapshot_t snap, snapshot_t org) \
{ \
M_SNAPSH0T_SPSC_CONTRACT(snap); \
M_SNAPSH0T_SPSC_CONTRACT(org); \
M_UNUSED_CONTEXT(); \
M_ASSERT(snap != org); \
for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \
M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \
@@ -382,8 +382,7 @@ typedef struct m_snapsh0t_mrsw_s {
} while (0)
/* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */
M_INLINE void
m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
M_P(void, m_snapsh0t, _mrsw_init, m_snapsh0t_mrsw_ct s, size_t n)
{
M_ASSERT (s != NULL);
M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER);
@@ -391,15 +390,14 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
n += M_SNAPSH0T_SPMC_EXTRA_BUFFER;
// Initialize the counters to zero (no reader use it)
atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n);
atomic_uint *ptr = M_MEMORY_REALLOC (m_context, atomic_uint, NULL, 0, n);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(sizeof (atomic_uint) * n);
return;
M_MEMORY_FULL(atomic_uint, n);
}
s->cptTab = ptr;
for(size_t i = 0; i < n; i++)
atomic_init(&s->cptTab[i], 0U);
m_genint_init (s->freeList, (unsigned int) n);
m_genint_init M_R(s->freeList, (unsigned int) n);
// Get a free buffer and set it as available for readers
unsigned int w = m_genint_pop(s->freeList);
@@ -415,12 +413,11 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n)
}
/* Clear m_snapsh0t_mrsw_ct (destructor) */
M_INLINE void
m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s)
M_P(void, m_snapsh0t, _mrsw_clear, m_snapsh0t_mrsw_ct s)
{
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
M_MEMORY_FREE (s->cptTab);
m_genint_clear(s->freeList);
M_MEMORY_FREE (m_context, atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER);
m_genint_clear M_R(s->freeList);
s->cptTab = NULL;
s->n_reader = 0;
}
@@ -639,35 +636,32 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
/* Define the core functions */
#define M_SNAPSH0T_SPMC_DEF_CORE(name, type, oplist, snapshot_t) \
\
M_INLINE void \
M_F(name, _init)(snapshot_t snap, size_t nReader) \
M_P(void, name, _init, snapshot_t snap, size_t nReader) \
{ \
M_ASSERT (snap != NULL); \
M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \
snap->data = M_CALL_REALLOC(oplist, M_F(name, _aligned_type_ct), \
NULL, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
NULL, 0, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
if (M_UNLIKELY_NOMEM (snap->data == NULL)) { \
M_MEMORY_FULL(sizeof(M_F(name, _aligned_type_ct)) * \
M_MEMORY_FULL(M_F(name, _aligned_type_ct), \
(nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \
return; \
} \
for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \
M_CALL_INIT(oplist, snap->data[i].x); \
} \
m_snapsh0t_mrsw_init(snap->core, nReader); \
m_snapsh0t_mrsw_init M_R(snap->core, nReader); \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
} \
\
M_INLINE void \
M_F(name, _clear)(snapshot_t snap) \
M_P(void, name, _clear, snapshot_t snap) \
{ \
M_SNAPSH0T_SPMC_CONTRACT(snap); \
size_t nReader = m_snapsh0t_mrsw_size(snap->core); \
for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \
M_CALL_CLEAR(oplist, snap->data[i].x); \
} \
M_CALL_FREE(oplist, snap->data); \
m_snapsh0t_mrsw_clear(snap->core); \
M_CALL_FREE(oplist, M_F(name, _aligned_type_ct), snap->data, nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \
m_snapsh0t_mrsw_clear M_R(snap->core); \
} \
\
M_INLINE type * \
@@ -746,19 +740,17 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
/* Define the core functions */
#define M_SNAPSH0T_MPMC_DEF_CORE(name, type, oplist, snapshot_t) \
\
M_INLINE void \
M_F(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \
M_P(void, name, _init, snapshot_t snap, size_t nReader, size_t nWriter) \
{ \
M_F(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \
M_F(name, _mrsw_init)M_R(snap->core, nReader + nWriter -1 ); \
unsigned int idx = snap->core->core->currentWrite; \
snap->core->core->currentWrite = M_GENINT_ERROR; \
m_snapsh0t_mrsw_write_end(snap->core->core, idx); \
} \
\
M_INLINE void \
M_F(name, _clear)(snapshot_t snap) \
M_P(void, name, _clear, snapshot_t snap) \
{ \
M_F(name, _mrsw_clear)(snap->core); \
M_F(name, _mrsw_clear)M_R(snap->core); \
} \
\
M_INLINE type * \
+167 -152
View File
@@ -281,12 +281,11 @@ m_string_init(m_string_t s)
}
/* Clear the Dynamic string (destructor) */
M_INLINE void
m_string_clear(m_string_t v)
M_P(void, m_string, _clear, m_string_t v)
{
M_STR1NG_CONTRACT(v);
if (!m_str1ng_embedded_p(v)) {
M_MEMORY_FREE(v->u.heap.ptr);
M_MEMORY_FREE(m_context, char, v->u.heap.ptr, m_string_capacity(v));
v->u.heap.ptr = NULL;
}
/* This is not needed but is safer to make
@@ -301,8 +300,7 @@ M_INLINE m_string_ptr m_str1ng_init_ref(m_string_t v) { m_string_init(v); return
and return a heap pointer to the string.
The ownership of the data is transferred back to the caller
and the returned pointer has to be released by M_MEMORY_FREE. */
M_INLINE char *
m_string_clear_get_cstr(m_string_t v)
M_P(char *, m_string, _clear_get_cstr, m_string_t v)
{
M_STR1NG_CONTRACT(v);
char *p = v->u.heap.ptr;
@@ -311,10 +309,9 @@ m_string_clear_get_cstr(m_string_t v)
p = &v->u.buffer[0];
// Need to allocate a heap string to return the copy.
size_t alloc = m_string_size(v)+1;
char *ptr = M_MEMORY_REALLOC (char, NULL, alloc);
char *ptr = M_MEMORY_REALLOC (m_context, char, NULL, 0, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(sizeof (char) * alloc);
return NULL;
M_MEMORY_FULL(char, alloc);
}
M_ASSERT(ptr != NULL && p != NULL);
memcpy(ptr, p, alloc);
@@ -368,8 +365,7 @@ m_string_empty_p(const m_string_t v)
The string 'v' no longer has a working size field.
Return a pointer to the writable string.
*/
M_INLINE char *
m_str1ng_fit2size (m_string_t v, size_t size_alloc)
M_P(char *, m_str1ng, _fit2size, m_string_t v, size_t size_alloc)
{
M_ASSERT_INDEX (0, size_alloc);
// Note: this function may be called in context where the contract
@@ -386,18 +382,13 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc)
alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc);
if (M_UNLIKELY_NOMEM (alloc <= size_alloc)) {
/* Overflow in alloc computation */
M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is currently broken.
abort();
return NULL;
M_MEMORY_FULL(char, alloc);
}
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
ptr = M_MEMORY_REALLOC (char, ptr, alloc);
//FIXME: old_alloc may not be NULL if ptr is NULL.
ptr = M_MEMORY_REALLOC (m_context, char, ptr, old_alloc, alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL)) {
M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is currently broken.
abort();
return NULL;
M_MEMORY_FULL(char, alloc);
}
// The pointer cannot be the embedded buffer of the string as it is heap allocated
M_ASSERT(ptr != &v->u.buffer[0]);
@@ -421,8 +412,7 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc)
/* Modify the string capacity to be able to handle at least 'alloc'
characters (including final nul char).
It may reduce the allocation of the string if possible */
M_INLINE void
m_string_reserve(m_string_t v, size_t alloc)
M_P(void, m_string, _reserve, m_string_t v, size_t alloc)
{
M_STR1NG_CONTRACT (v);
const size_t size = m_string_size(v);
@@ -439,7 +429,7 @@ m_string_reserve(m_string_t v, size_t alloc)
char *oldptr = v->u.heap.ptr;
memcpy(ptr, oldptr, size+1);
// Free the allocated memory on the heap
M_MEMORY_FREE(oldptr);
M_MEMORY_FREE(m_context, char, oldptr, m_string_capacity(v));
v->u.buffer[sizeof(m_string_t)-2] = 0;
v->u.buffer[sizeof(m_string_t)-1] = (char) size;
} else {
@@ -451,14 +441,12 @@ m_string_reserve(m_string_t v, size_t alloc)
unsigned char m, e;
size_t r_alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc);
if (M_UNLIKELY_NOMEM (alloc > r_alloc)) {
M_MEMORY_FULL(sizeof (char) * alloc);
return;
M_MEMORY_FULL(char, alloc);
}
char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr;
ptr = M_MEMORY_REALLOC (char, ptr, r_alloc);
ptr = M_MEMORY_REALLOC (m_context, char, ptr, m_string_capacity(v), r_alloc);
if (M_UNLIKELY_NOMEM (ptr == NULL) ) {
M_MEMORY_FULL(sizeof (char) * alloc);
return;
M_MEMORY_FULL(char, alloc);
}
if (m_str1ng_embedded_p(v)) {
// Copy the characters embedded in the structure to the allocated heap space
@@ -473,13 +461,12 @@ m_string_reserve(m_string_t v, size_t alloc)
}
/* Set the string to the C string str */
M_INLINE void
m_string_set_cstr(m_string_t v, const char str[])
M_P(void, m_string, _set_cstr, m_string_t v, const char str[])
{
M_STR1NG_CONTRACT (v);
M_ASSERT(str != NULL);
size_t size = strlen(str);
char *ptr = m_str1ng_fit2size(v, size+1);
char *ptr = m_str1ng_fit2size M_R(v, size+1);
// The memcpy will also copy the final null char of the string
memcpy(ptr, str, size+1);
m_str1ng_set_size(v, size);
@@ -487,14 +474,13 @@ m_string_set_cstr(m_string_t v, const char str[])
}
/* Set the string to the n first characters of the C string str */
M_INLINE void
m_string_set_cstrn(m_string_t v, const char str[], size_t n)
M_P(void, m_string, _set_cstrn, m_string_t v, const char str[], size_t n)
{
M_STR1NG_CONTRACT (v);
M_ASSERT(str != NULL);
size_t len = strlen(str);
size_t size = M_MIN (len, n);
char *ptr = m_str1ng_fit2size(v, size+1);
char *ptr = m_str1ng_fit2size M_R(v, size+1);
// The memcpy will not copy the final null char of the string
memcpy(ptr, str, size);
// Cannot copy the final null char using memcpy
@@ -504,14 +490,13 @@ m_string_set_cstrn(m_string_t v, const char str[], size_t n)
}
/* Set the string to the other one */
M_INLINE void
m_string_set (m_string_t v1, const m_string_t v2)
M_P(void, m_string, _set, m_string_t v1, const m_string_t v2)
{
M_STR1NG_CONTRACT (v1);
M_STR1NG_CONTRACT (v2);
if (M_LIKELY (v1 != v2)) {
const size_t size = m_string_size(v2);
char *ptr = m_str1ng_fit2size(v1, size+1);
char *ptr = m_str1ng_fit2size M_R(v1, size+1);
memcpy(ptr, m_string_get_cstr(v2), size+1);
m_str1ng_set_size(v1, size);
}
@@ -519,14 +504,13 @@ m_string_set (m_string_t v1, const m_string_t v2)
}
/* Set the string to the n first characters of other one */
M_INLINE void
m_string_set_n(m_string_t v, const m_string_t ref, size_t offset, size_t length)
M_P(void, m_string, _set_n, m_string_t v, const m_string_t ref, size_t offset, size_t length)
{
M_STR1NG_CONTRACT (v);
M_STR1NG_CONTRACT (ref);
M_ASSERT_INDEX (offset, m_string_size(ref) + 1);
size_t size = M_MIN (m_string_size(ref) - offset, length);
char *ptr = m_str1ng_fit2size(v, size+1);
char *ptr = m_str1ng_fit2size M_R(v, size+1);
// v may be equal to ref, so a memmove is needed instead of a memcpy
memmove(ptr, m_string_get_cstr(ref) + offset, size);
// Cannot copy the final null char using memcpy
@@ -537,26 +521,24 @@ m_string_set_n(m_string_t v, const m_string_t ref, size_t offset, size_t length)
/* Initialize the string and set it to the other one
(constructor) */
M_INLINE void
m_string_init_set(m_string_t v1, const m_string_t v2)
M_P(void, m_string, _init_set, m_string_t v1, const m_string_t v2)
{
// In case of exception, v1 remains initialized,
// but without any allocation done.
// Therefore it is safe, not to clear v1 on exception.
m_string_init(v1);
m_string_set(v1,v2);
m_string_set M_R(v1,v2);
}
/* Initialize the string and set it to the C string
(constructor) */
M_INLINE void
m_string_init_set_cstr(m_string_t v1, const char str[])
M_P(void, m_string, _init_set_cstr, m_string_t v1, const char str[])
{
// In case of exception, v1 remains initialized,
// but without any allocation done.
// Therefore it is safe, not to clear v1 on exception.
m_string_init(v1);
m_string_set_cstr(v1, str);
m_string_set_cstr M_R(v1, str);
}
/* Initialize the string, set it to the other one,
@@ -590,20 +572,18 @@ m_string_swap(m_string_t v1, m_string_t v2)
/* Set the string to the other one,
and destroy the other one.
(destructor) */
M_INLINE void
m_string_move(m_string_t v1, m_string_t v2)
M_P(void, m_string, _move, m_string_t v1, m_string_t v2)
{
m_string_clear(v1);
m_string_clear M_R(v1);
m_string_init_move(v1,v2);
}
/* Push the byte-character 'c' in the string 'v' */
M_INLINE void
m_string_push_back (m_string_t v, char c)
M_P(void, m_string, _push_back, m_string_t v, char c)
{
M_STR1NG_CONTRACT (v);
const size_t size = m_string_size(v);
char *ptr = m_str1ng_fit2size(v, size+2);
char *ptr = m_str1ng_fit2size M_R(v, size+2);
ptr[size+0] = c;
ptr[size+1] = 0;
m_str1ng_set_size(v, size+1);
@@ -611,29 +591,27 @@ m_string_push_back (m_string_t v, char c)
}
/* Concatenate the string with the C string */
M_INLINE void
m_string_cat_cstr(m_string_t v, const char str[])
M_P(void, m_string, _cat_cstr, m_string_t v, const char str[])
{
M_STR1NG_CONTRACT (v);
M_ASSERT (str != NULL);
const size_t old_size = m_string_size(v);
const size_t size = strlen(str);
char *ptr = m_str1ng_fit2size(v, old_size + size + 1);
char *ptr = m_str1ng_fit2size M_R(v, old_size + size + 1);
memcpy(&ptr[old_size], str, size + 1);
m_str1ng_set_size(v, old_size + size);
M_STR1NG_CONTRACT (v);
}
/* Concatenate the string with the other string */
M_INLINE void
m_string_cat(m_string_t v, const m_string_t v2)
M_P(void, m_string, _cat, m_string_t v, const m_string_t v2)
{
M_STR1NG_CONTRACT (v2);
M_STR1NG_CONTRACT (v);
const size_t size = m_string_size(v2);
if (M_LIKELY (size > 0)) {
const size_t old_size = m_string_size(v);
char *ptr = m_str1ng_fit2size(v, old_size + size + 1);
char *ptr = m_str1ng_fit2size M_R(v, old_size + size + 1);
memcpy(&ptr[old_size], m_string_get_cstr(v2), size);
ptr[old_size + size] = 0;
m_str1ng_set_size(v, old_size + size);
@@ -875,8 +853,7 @@ m_string_mid (m_string_t v, size_t index, size_t size)
into the C string str2 from start
By default, start is zero.
*/
M_INLINE size_t
m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_t start)
M_P(size_t, m_string, _replace_cstr, m_string_t v, const char str1[], const char str2[], size_t start)
{
M_STR1NG_CONTRACT (v);
M_ASSERT (str1 != NULL && str2 != NULL);
@@ -886,7 +863,7 @@ m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_
const size_t str2_l = strlen(str2);
const size_t size = m_string_size(v);
M_ASSERT(size + 1 + str2_l > str1_l);
char *ptr = m_str1ng_fit2size (v, size + str2_l - str1_l + 1);
char *ptr = m_str1ng_fit2size M_R(v, size + str2_l - str1_l + 1);
if (str1_l != str2_l) {
memmove(&ptr[i+str2_l], &ptr[i+str1_l], size - i - str1_l + 1);
m_str1ng_set_size(v, size + str2_l - str1_l);
@@ -901,19 +878,17 @@ m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_
into the C string v2 from start
By default, start is zero.
*/
M_INLINE size_t
m_string_replace (m_string_t v, const m_string_t v1, const m_string_t v2, size_t start)
M_P(size_t, m_string, _replace, m_string_t v, const m_string_t v1, const m_string_t v2, size_t start)
{
M_STR1NG_CONTRACT (v);
M_STR1NG_CONTRACT (v1);
M_STR1NG_CONTRACT (v2);
return m_string_replace_cstr(v, m_string_get_cstr(v1), m_string_get_cstr(v2), start);
return m_string_replace_cstr M_R(v, m_string_get_cstr(v1), m_string_get_cstr(v2), start);
}
/* Replace in the string the sub-string at position 'pos' for 'len' bytes
into the C string str2. */
M_INLINE void
m_string_replace_at (m_string_t v, size_t pos, size_t len, const char str2[])
M_P(void, m_string, _replace_at, m_string_t v, size_t pos, size_t len, const char str2[])
{
M_STR1NG_CONTRACT (v);
M_ASSERT(str2 != NULL);
@@ -924,7 +899,7 @@ m_string_replace_at (m_string_t v, size_t pos, size_t len, const char str2[])
if (str1_l != str2_l) {
// Move bytes from the string
M_ASSERT_INDEX (str1_l, size + str2_l + 1);
ptr = m_str1ng_fit2size (v, size + str2_l - str1_l + 1);
ptr = m_str1ng_fit2size M_R(v, size + str2_l - str1_l + 1);
M_ASSERT_INDEX (pos + str1_l, size + 1);
M_ASSUME (pos + str1_l < size + 1);
memmove(&ptr[pos+str2_l], &ptr[pos+str1_l], size - pos - str1_l + 1);
@@ -1001,8 +976,7 @@ m_str1ng_strstr_r(char org[], char src[], const char pattern[], size_t pattern_s
}
/* Replace all occurences of str1 into str2 when strlen(str1) < strlen(str2) */
M_INLINE void
m_str1ng_replace_all_cstr_1lo2 (m_string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len)
M_P(void, m_str1ng, _replace_all_cstr_1lo2, m_string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len)
{
M_STR1NG_CONTRACT (v);
M_ASSERT(str1len < str2len);
@@ -1013,7 +987,7 @@ m_str1ng_replace_all_cstr_1lo2 (m_string_t v, const char str1[], size_t str1len,
*/
size_t vlen = m_string_size(v);
size_t alloc = 1 + vlen / str1len * str2len;
char *org = m_str1ng_fit2size(v, alloc);
char *org = m_str1ng_fit2size M_R(v, alloc);
char *src = org + vlen - 1;
char *end = org + m_string_capacity(v);
char *dst = end;
@@ -1043,8 +1017,7 @@ m_str1ng_replace_all_cstr_1lo2 (m_string_t v, const char str1[], size_t str1len,
M_STR1NG_CONTRACT (v);
}
M_INLINE void
m_string_replace_all_cstr (m_string_t v, const char str1[], const char str2[])
M_P(void, m_string, _replace_all_cstr, m_string_t v, const char str1[], const char str2[])
{
size_t str1_l = strlen(str1);
size_t str2_l = strlen(str2);
@@ -1052,12 +1025,11 @@ m_string_replace_all_cstr (m_string_t v, const char str1[], const char str2[])
if (str1_l >= str2_l) {
m_str1ng_replace_all_cstr_1ge2(v, str1, str1_l, str2, str2_l );
} else {
m_str1ng_replace_all_cstr_1lo2(v, str1, str1_l, str2, str2_l );
m_str1ng_replace_all_cstr_1lo2 M_R(v, str1, str1_l, str2, str2_l);
}
}
M_INLINE void
m_string_replace_all (m_string_t v, const m_string_t str1, const m_string_t str2)
M_P(void, m_string, _replace_all, m_string_t v, const m_string_t str1, const m_string_t str2)
{
size_t str1_l = m_string_size(str1);
size_t str2_l = m_string_size(str2);
@@ -1066,7 +1038,7 @@ m_string_replace_all (m_string_t v, const m_string_t str1, const m_string_t str2
if (str1_l >= str2_l) {
m_str1ng_replace_all_cstr_1ge2(v, m_string_get_cstr(str1), str1_l, m_string_get_cstr(str2), str2_l );
} else {
m_str1ng_replace_all_cstr_1lo2(v, m_string_get_cstr(str1), str1_l, m_string_get_cstr(str2), str2_l );
m_str1ng_replace_all_cstr_1lo2 M_R(v, m_string_get_cstr(str1), str1_l, m_string_get_cstr(str2), str2_l);
}
}
@@ -1083,12 +1055,11 @@ m_string_replace_all (m_string_t v, const m_string_t str1, const m_string_t str2
# error Unexpected UINT_MAX value (workaround: Define M_USE_FAST_STRING_CONV to 0).
#endif
M_INLINE void
m_string_set_ui(m_string_t v, unsigned int n)
M_P(void, m_string, _set_ui, m_string_t v, unsigned int n)
{
M_STR1NG_CONTRACT (v);
char buffer[M_STR1NG_INT_MAX_SIZE];
m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE+1);
char *d = m_str1ng_fit2size M_R(v, M_STR1NG_INT_MAX_SIZE+1);
unsigned i = 0, j = 0;
do {
// 0123456789 are mandatory in this order as characters, as per C standard.
@@ -1096,7 +1067,6 @@ m_string_set_ui(m_string_t v, unsigned int n)
n /= 10U;
} while (n != 0);
M_ASSERT_INDEX(i, M_STR1NG_INT_MAX_SIZE);
char *d = m_str1ng_get_cstr(v);
while (i > 0) {
d[j++] = buffer[--i];
}
@@ -1105,13 +1075,12 @@ m_string_set_ui(m_string_t v, unsigned int n)
M_STR1NG_CONTRACT (v);
}
M_INLINE void
m_string_set_si(m_string_t v, int n)
M_P(void, m_string, _set_si, m_string_t v, int n)
{
M_STR1NG_CONTRACT (v);
// Compute the maximum number of characters needed for the buffer.
char buffer[M_STR1NG_INT_MAX_SIZE];
m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE+1);
char *d = m_str1ng_fit2size M_R(v, M_STR1NG_INT_MAX_SIZE+1);
unsigned i = 0, j = 0;
bool neg = n < 0;
unsigned n0 = neg ? 0U -(unsigned) n : (unsigned) n;
@@ -1121,7 +1090,6 @@ m_string_set_si(m_string_t v, int n)
n0 /= 10U;
} while (n0 != 0);
M_ASSERT_INDEX(i, M_STR1NG_INT_MAX_SIZE);
char *d = m_str1ng_get_cstr(v);
if (neg) d[j++] = '-';
while (i > 0) {
d[j++] = buffer[--i];
@@ -1135,8 +1103,7 @@ m_string_set_si(m_string_t v, int n)
#if M_USE_STDARG
/* Format in the string the given printf format */
M_INLINE int
m_string_vprintf (m_string_t v, const char format[], va_list args)
M_P(int, m_string, _vprintf, m_string_t v, const char format[], va_list args)
{
M_STR1NG_CONTRACT (v);
M_ASSERT (format != NULL);
@@ -1152,7 +1119,7 @@ m_string_vprintf (m_string_t v, const char format[], va_list args)
M_IF_EXCEPTION( m_str1ng_set_size(v, 0) );
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[0] = 0 );
// We have to realloc our string to fit the needed size
ptr = m_str1ng_fit2size (v, (size_t) size + 1);
ptr = m_str1ng_fit2size M_R(v, (size_t) size + 1);
alloc = m_string_capacity(v);
// and redo the parsing.
size = vsnprintf (ptr, alloc, format, args_org);
@@ -1161,7 +1128,7 @@ m_string_vprintf (m_string_t v, const char format[], va_list args)
if (M_LIKELY (size >= 0)) {
m_str1ng_set_size(v, (size_t) size);
} else {
// An error occured during the conversion: Assign an empty string.
// An error occurred during the conversion: Assign an empty string.
m_str1ng_set_size(v, 0);
ptr[0] = 0;
}
@@ -1171,21 +1138,20 @@ m_string_vprintf (m_string_t v, const char format[], va_list args)
}
/* Format in the string the given printf format */
M_INLINE int
m_string_printf (m_string_t v, const char format[], ...)
// FIXME: BROKEN to add a parameter **after** the '...'!
M_P(int, m_string, _printf, m_string_t v, const char format[], ...)
{
M_STR1NG_CONTRACT (v);
M_ASSERT (format != NULL);
va_list args;
va_start (args, format);
int ret = m_string_vprintf(v, format, args);
int ret = m_string_vprintf M_R(v, format, args);
va_end (args);
return ret;
}
/* Append to the string the formatted string of the given printf format */
M_INLINE int
m_string_cat_vprintf (m_string_t v, const char format[], va_list args)
M_P(int, m_string, _cat_vprintf, m_string_t v, const char format[], va_list args)
{
M_STR1NG_CONTRACT (v);
M_ASSERT (format != NULL);
@@ -1202,7 +1168,7 @@ m_string_cat_vprintf (m_string_t v, const char format[], va_list args)
M_IF_EXCEPTION( m_str1ng_set_size(v, old_size) );
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[old_size] = 0 );
// We have to realloc our string to fit the needed size
ptr = m_str1ng_fit2size (v, old_size + (size_t) size + 1);
ptr = m_str1ng_fit2size M_R(v, old_size + (size_t) size + 1);
alloc = m_string_capacity(v);
// and redo the parsing.
size = vsnprintf (&ptr[old_size], alloc - old_size, format, args_org);
@@ -1221,28 +1187,25 @@ m_string_cat_vprintf (m_string_t v, const char format[], va_list args)
}
/* Append to the string the formatted string of the given printf format */
M_INLINE int
m_string_cat_printf (m_string_t v, const char format[], ...)
M_P(int, m_string, _cat_printf, m_string_t v, const char format[], ...)
{
M_STR1NG_CONTRACT (v);
M_ASSERT (format != NULL);
va_list args;
va_start (args, format);
int ret = m_string_cat_vprintf(v, format, args);
int ret = m_string_cat_vprintf M_R(v, format, args);
va_end (args);
return ret;
}
#if M_USE_FAST_STRING_CONV == 0
M_INLINE void
m_string_set_ui(m_string_t v, unsigned int n)
M_P(void, m_string, _set_ui, m_string_t v, unsigned int n)
{
m_string_printf(v, "%u", n);
m_string_printf M_R(v, "%u", n);
}
M_INLINE void
m_string_set_si(m_string_t v, int n)
M_P(void, m_string, _set_si, m_string_t v, int n)
{
m_string_printf(v, "%d", n);
m_string_printf M_R(v, "%d", n);
}
#endif
@@ -1251,12 +1214,11 @@ m_string_set_si(m_string_t v, int n)
#if M_USE_STDIO
/* Get a line/pure-line/file from the FILE and store it in the string */
M_INLINE bool
m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
M_P(bool, m_string, _fgets, m_string_t v, FILE *f, m_string_fgets_t arg)
{
M_STR1NG_CONTRACT(v);
M_ASSERT (f != NULL);
char *ptr = m_str1ng_fit2size (v, 100);
char *ptr = m_str1ng_fit2size M_R(v, 100);
size_t size = 0;
size_t alloc = m_string_capacity(v);
ptr[0] = 0;
@@ -1285,7 +1247,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
/* The string buffer is not big enough:
increase it and continue reading */
/* v cannot be a full embedded type */
ptr = m_str1ng_fit2size (v, alloc + alloc/2);
ptr = m_str1ng_fit2size M_R(v, alloc + alloc/2);
alloc = m_string_capacity(v);
}
}
@@ -1298,8 +1260,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
Words are supposed to be separated each other by the given list of separator
separator shall be a CONSTANT C array.
*/
M_INLINE bool
m_string_fget_word (m_string_t v, const char separator[], FILE *f)
M_P(bool, m_string, _fget_word, m_string_t v, const char separator[], FILE *f)
{
char buffer[128];
char c = 0;
@@ -1344,7 +1305,7 @@ m_string_fget_word (m_string_t v, const char separator[], FILE *f)
/* Next char is not a separator: continue parsing */
m_str1ng_set_size(v, size);
M_IF_EXCEPTION( m_str1ng_get_cstr(v)[size] = 0);
ptr = m_str1ng_fit2size (v, alloc + alloc/2);
ptr = m_str1ng_fit2size M_R(v, alloc + alloc/2);
alloc = m_string_capacity(v);
M_ASSERT (alloc > size + 1);
ptr[size++] = c;
@@ -1479,8 +1440,7 @@ m_string_oor_set(m_string_t s, unsigned char n)
/* Transform the string 'v2' into a formatted string
and set it to (or append in) the string 'v'. */
M_INLINE void
m_string_get_str(m_string_t v, const m_string_t v2, bool append)
M_P(void, m_string, _get_str, m_string_t v, const m_string_t v2, bool append)
{
M_STR1NG_CONTRACT(v2);
M_STR1NG_CONTRACT(v);
@@ -1488,7 +1448,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append)
size_t size = append ? m_string_size(v) : 0;
size_t v2_size = m_string_size(v2);
size_t targetSize = size + v2_size + 3;
char *ptr = m_str1ng_fit2size(v, targetSize);
char *ptr = m_str1ng_fit2size M_R(v, targetSize);
ptr[size ++] = '"';
for(size_t i = 0 ; i < v2_size; i++) {
const char c = m_string_get_char(v2,i);
@@ -1500,7 +1460,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append)
case '\r':
// Special characters which can be displayed in a short form.
m_str1ng_set_size(v, size);
ptr = m_str1ng_fit2size(v, ++targetSize);
ptr = m_str1ng_fit2size M_R(v, ++targetSize);
ptr[size ++] = '\\';
// This string acts as a perfect hashmap which supposes an ASCII mapping
// and (c^(c>>5)) is the hash function
@@ -1511,7 +1471,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append)
targetSize += 3;
m_str1ng_set_size(v, size);
M_IF_EXCEPTION(m_str1ng_get_cstr(v)[size] = 0);
ptr = m_str1ng_fit2size(v, targetSize);
ptr = m_str1ng_fit2size M_R(v, targetSize);
int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07;
ptr[size ++] = '\\';
ptr[size ++] = (char) ('0' + d3);
@@ -1571,8 +1531,7 @@ m_string_out_str(FILE *f, const m_string_t v)
/* Read the formatted string from the FILE
and set the converted value in the string 'v'.
Return true in case of success */
M_INLINE bool
m_string_in_str(m_string_t v, FILE *f)
M_P(bool, m_string, _in_str, m_string_t v, FILE *f)
{
M_STR1NG_CONTRACT(v);
M_ASSERT (f != NULL);
@@ -1609,7 +1568,7 @@ m_string_in_str(m_string_t v, FILE *f)
break;
}
}
m_string_push_back (v, (char) c);
m_string_push_back M_R(v, (char) c);
c = fgetc(f);
}
return c == '"';
@@ -1622,8 +1581,7 @@ m_string_in_str(m_string_t v, FILE *f)
Return true in case of success
If endptr is not null, update the position of the parsing.
*/
M_INLINE bool
m_string_parse_str(m_string_t v, const char str[], const char **endptr)
M_P(bool, m_string, _parse_str, m_string_t v, const char str[], const char **endptr)
{
M_STR1NG_CONTRACT(v);
M_ASSERT (str != NULL);
@@ -1661,7 +1619,7 @@ m_string_parse_str(m_string_t v, const char str[], const char **endptr)
break;
}
}
m_string_push_back (v, (char) c);
m_string_push_back M_R(v, (char) c);
c = *str++;
}
success = (c == '"');
@@ -1674,22 +1632,20 @@ m_string_parse_str(m_string_t v, const char str[], const char **endptr)
and output it in the given serializer
See serialization for return code.
*/
M_INLINE m_serial_return_code_t
m_string_out_serial(m_serial_write_t serial, const m_string_t v)
M_P(m_serial_return_code_t, m_string, _out_serial, m_serial_write_t serial, const m_string_t v)
{
M_ASSERT (serial != NULL && serial->m_interface != NULL);
return serial->m_interface->write_string(serial, m_string_get_cstr(v), m_string_size(v) );
return serial->m_interface->write_string M_R(serial, m_string_get_cstr(v), m_string_size(v) );
}
/* Read the formatted string from the serializer
and set the converted value in the string 'v'.
See serialization for return code.
*/
M_INLINE m_serial_return_code_t
m_string_in_serial(m_string_t v, m_serial_read_t serial)
M_P(m_serial_return_code_t, m_string, _in_serial, m_string_t v, m_serial_read_t serial)
{
M_ASSERT (serial != NULL && serial->m_interface != NULL);
return serial->m_interface->read_string(serial, v);
return serial->m_interface->read_string M_R(serial, v);
}
/* UTF8 character classification:
@@ -1954,8 +1910,7 @@ m_string_cref (m_string_it_t it)
}
/* Update the value referenced by the iterator to the given value */
M_INLINE void
m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u)
M_P(void, m_string, _it_set_ref, m_string_it_t it, m_string_t s, m_string_unicode_t new_u)
{
M_STR1NG_IT_CONTRACT(it);
M_STR1NG_CONTRACT(s);
@@ -1964,7 +1919,7 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u)
M_ASSUME( it->ptr >= ptr);
size_t offset = (size_t) (it->ptr - ptr);
// Special case if the unicode codepoint is 0
if (new_u == 0) {
if (M_UNLIKELY(new_u == 0)) {
// Null the string
m_str1ng_set_size(s, offset);
ptr[offset] = 0;
@@ -1988,8 +1943,8 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u)
size_t old_u_size = (size_t) (str - it->ptr);
// We need to replace old_u by new_u. Both are variable length
size_t str_size = m_string_size(s);
if (new_u_size != old_u_size) {
ptr = m_str1ng_fit2size(s, str_size + new_u_size - old_u_size + 1);
if (M_UNLIKELY (new_u_size != old_u_size)) {
ptr = m_str1ng_fit2size M_R(s, str_size + new_u_size - old_u_size + 1);
M_ASSUME( str_size+1 > (offset + old_u_size) );
memmove(&ptr[offset+new_u_size], &ptr[offset + old_u_size],
str_size+1 - offset - old_u_size);
@@ -2003,13 +1958,12 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u)
}
/* Push unicode code point into string, encoding it in UTF8 */
M_INLINE void
m_string_push_u (m_string_t str, m_string_unicode_t u)
M_P(void, m_string, _push_u, m_string_t str, m_string_unicode_t u)
{
M_STR1NG_CONTRACT(str);
char buffer[4+1];
m_str1ng_utf8_encode(buffer, u);
m_string_cat_cstr(str, buffer);
m_string_cat_cstr M_R(str, buffer);
}
/* Pop last unicode code point into string, encoding it in UTF8 */
@@ -2030,6 +1984,7 @@ m_string_pop_u(m_string_unicode_t *u, m_string_t str)
// Support of NULL pointer
m_string_unicode_t u_tmp;
m_string_unicode_t *u_ptr = u == NULL ? &u_tmp : u;
*u_ptr = 0;
do {
m_str1ng_utf8_decode(*tmp++, &state, u_ptr);
} while (state != M_STR1NG_UTF8_STARTING && state != M_STR1NG_UTF8_ERROR);
@@ -2064,8 +2019,7 @@ m_string_utf8_p(const m_string_t str)
/* Define the split & the join functions
in case of usage with the algorithm module */
#define M_STR1NG_SPLIT(name, oplist, type_oplist) \
M_INLINE void M_F(name, _split)(M_GET_TYPE oplist cont, \
const m_string_t str, const char sep) \
M_P(void, name, _split, M_GET_TYPE oplist cont, const m_string_t str, const char sep) \
{ \
size_t begin = 0; \
m_string_t tmp; \
@@ -2075,7 +2029,7 @@ m_string_utf8_p(const m_string_t str)
for(size_t i = 0 ; i < size; i++) { \
char c = m_string_get_char(str, i); \
if (c == sep) { \
m_string_set_cstrn(tmp, &m_string_get_cstr(str)[begin], i - begin); \
m_string_set_cstrn M_R(tmp, &m_string_get_cstr(str)[begin], i - begin); \
/* If push move method is available, use it */ \
M_IF_METHOD(PUSH_MOVE,oplist)( \
M_CALL_PUSH_MOVE(oplist, cont, &tmp); \
@@ -2086,24 +2040,23 @@ m_string_utf8_p(const m_string_t str)
begin = i + 1; \
} \
} \
m_string_set_cstrn(tmp, &m_string_get_cstr(str)[begin], size - begin); \
m_string_set_cstrn M_R(tmp, &m_string_get_cstr(str)[begin], size - begin); \
M_CALL_PUSH(oplist, cont, tmp); \
/* HACK: if method reverse is defined, it is likely that we have */ \
/* inserted the items in the wrong order (aka for a list) */ \
M_IF_METHOD(REVERSE, oplist) (M_CALL_REVERSE(oplist, cont);, ) \
m_string_clear(tmp); \
m_string_clear M_R(tmp); \
} \
\
M_INLINE void M_F(name, _join)(m_string_t dst, M_GET_TYPE oplist cont, \
const m_string_t str) \
M_P(void, name, _join, m_string_t dst, M_GET_TYPE oplist cont, const m_string_t str) \
{ \
bool init_done = false; \
m_string_reset (dst); \
for M_EACH(item, cont, oplist) { \
if (init_done) { \
m_string_cat(dst, str); \
m_string_cat M_R(dst, str); \
} \
m_string_cat (dst, *item); \
m_string_cat M_R(dst, *item); \
init_done = true; \
} \
} \
@@ -2152,13 +2105,22 @@ namespace m_lib {
m_lib::m_aligned_string<sizeof (s)>(s).string
#endif
#ifdef M_USE_CONTEXT
/* Initialize and set a string to the given formatted value. */
#define m_string_init_printf(pool, v, ...) \
(m_string_printf ( pool, m_str1ng_init_ref(v), __VA_ARGS__) )
/* Initialize and set a string to the given formatted value. */
#define m_string_init_vprintf(pool, v, format, args) \
(m_string_vprintf ( pool, m_str1ng_init_ref(v), format, args) )
#else
#define m_string_init_printf(v, ...) \
(m_string_printf ( m_str1ng_init_ref(v), __VA_ARGS__) )
/* Initialize and set a string to the given formatted value. */
#define m_string_init_vprintf(v, format, args) \
(m_string_vprintf ( m_str1ng_init_ref(v), format, args) )
#endif
/* Initialize a string with the given list of arguments.
Check if it is a formatted input or not by counting the number of arguments.
@@ -2168,13 +2130,14 @@ namespace m_lib {
C string and string. */
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
#define M_STR1NG_INIT_WITH(v, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set, m_string_init_printf)(v, __VA_ARGS__)
M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set, m_string_init_printf)M_R(v, __VA_ARGS__)
#else
#define M_STR1NG_INIT_WITH(v, ...) \
M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set_cstr, m_string_init_printf)(v, __VA_ARGS__)
M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set_cstr, m_string_init_printf)M_R(v, __VA_ARGS__)
#endif
/* Define the OPLIST of a STRING */
#ifndef M_USE_CONTEXT
#define M_STRING_OPLIST \
(INIT(m_string_init),INIT_SET(m_string_init_set), SET(m_string_set), \
INIT_WITH(M_STR1NG_INIT_WITH), \
@@ -2199,6 +2162,32 @@ namespace m_lib {
,IT_CREF(m_string_cref), PUSH(m_string_push_u) \
,EMPLACE_TYPE(const char*) \
)
#else
#define M_STRING_OPLIST \
(INIT(m_string_init),INIT_SET(API_0P(m_string_init_set)), SET(API_0P(m_string_set)), \
INIT_WITH(M_STR1NG_INIT_WITH), \
INIT_MOVE(m_string_init_move), MOVE(API_0P(m_string_move)), \
SWAP(m_string_swap), RESET(m_string_reset), \
EMPTY_P(m_string_empty_p), \
CLEAR(API_0P(m_string_clear)), HASH(m_string_hash), EQUAL(m_string_equal_p), \
CMP(m_string_cmp), TYPE(m_string_t), GENTYPE(struct m_string_s*), \
PARSE_STR(API_0P(m_string_parse_str)), GET_STR(API_0P(m_string_get_str)), \
OUT_STR(m_string_out_str), IN_STR(API_0P(m_string_in_str)), \
OUT_SERIAL(API_0P(m_string_out_serial)), IN_SERIAL(API_0P(m_string_in_serial)), \
EXT_ALGO(M_STR1NG_SPLIT), \
OOR_EQUAL(m_string_oor_equal_p), OOR_SET(m_string_oor_set) \
,SUBTYPE(m_string_unicode_t) \
,IT_TYPE(m_string_it_t) \
,IT_FIRST(m_string_it) \
,IT_END(m_string_it_end) \
,IT_SET(m_string_it_set) \
,IT_END_P(m_string_end_p) \
,IT_EQUAL_P(m_string_it_equal_p) \
,IT_NEXT(m_string_next) \
,IT_CREF(m_string_cref), PUSH(API_0P(m_string_push_u)) \
,EMPLACE_TYPE(const char*) \
)
#endif
/* Register the OPLIST as a global one */
#define M_OPL_m_string_t() M_STRING_OPLIST
@@ -2273,13 +2262,40 @@ namespace m_lib {
)(a,b,c)
/* Init & Set the string a to the string (or C string) b (constructor) */
#ifdef M_USE_CONTEXT
#define m_string_init_set(p, a,b) \
_Generic((b)+0, \
char*: m_string_init_set_cstr, \
const char *: m_string_init_set_cstr, \
default : m_string_init_set \
)(p,a,b)
#else
#define m_string_init_set(a,b) M_STR1NG_SELECT2(m_string_init_set, m_string_init_set_cstr, a, b)
#endif
/* Set the string a to the string (or C string) b */
#ifdef M_USE_CONTEXT
#define m_string_set(p, a,b) \
_Generic((b)+0, \
char*: m_string_set_cstr, \
const char *: m_string_set_cstr, \
default : m_string_set \
)(p,a,b)
#else
#define m_string_set(a,b) M_STR1NG_SELECT2(m_string_set, m_string_set_cstr, a, b)
#endif
/* Concatenate the string (or C string) b to the string a */
#ifdef M_USE_CONTEXT
#define m_string_cat(p, a,b) \
_Generic((b)+0, \
char*: m_string_cat_cstr, \
const char *: m_string_cat_cstr, \
default : m_string_cat \
)(p,a,b)
#else
#define m_string_cat(a,b) M_STR1NG_SELECT2(m_string_cat, m_string_cat_cstr, a, b)
#endif
/* Compare the string a to the string (or C string) b and return the sort order */
#define m_string_cmp(a,b) M_STR1NG_SELECT2(m_string_cmp, m_string_cmp_cstr, a, b)
@@ -2349,6 +2365,7 @@ namespace m_lib {
INIT_SET(M_F(name,_init_set)), \
SET(M_F(name,_set)), \
CLEAR(M_F(name,_clear)), \
INIT_MOVE(M_COPY_A1_DEFAULT), \
NAME(name), \
INIT_WITH( API_1(M_BOUNDED_STR1NG_INIT_WITH)), \
HASH(M_F(name,_hash)), \
@@ -2683,25 +2700,23 @@ namespace m_lib {
return ret; \
} \
\
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t serial, const bounded_t v) \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t serial, const bounded_t v) \
{ \
M_BOUNDED_STR1NG_CONTRACT(v, max_size); \
M_ASSERT (serial != NULL && serial->m_interface != NULL); \
return serial->m_interface->write_string(serial, v->s, strlen(v->s) ); \
return serial->m_interface->write_string M_R(serial, v->s, strlen(v->s) ); \
} \
\
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(bounded_t v, m_serial_read_t serial) \
M_P(m_serial_return_code_t, name, _in_serial, bounded_t v, m_serial_read_t serial) \
{ \
M_BOUNDED_STR1NG_CONTRACT(v, max_size); \
M_ASSERT (serial != NULL && serial->m_interface != NULL); \
m_string_t tmp; \
/* TODO: Not optimum */ \
m_string_init(tmp); \
m_serial_return_code_t r = serial->m_interface->read_string(serial, tmp); \
m_serial_return_code_t r = serial->m_interface->read_string M_R(serial, tmp); \
m_core_strncpy(v->s, max_size+1, m_string_get_cstr(tmp), max_size); \
m_string_clear(tmp); \
m_string_clear M_R(tmp); \
M_BOUNDED_STR1NG_CONTRACT(v, max_size); \
return r; \
}
+103 -146
View File
@@ -215,9 +215,9 @@ typedef int32_t m_tr33_index_t;
M_TR33_CONTRACT(tree); \
} \
\
M_INLINE void \
M_F(name, _reset)(tree_t tree) { \
M_P(void, name, _reset, tree_t tree) { \
M_TR33_CONTRACT(tree); \
M_UNUSED_CONTEXT(); \
if (tree->size > 0) { \
/* We don't scan recursively the node tree, but sequentially */ \
m_tr33_index_t free_index = tree->free_index; \
@@ -241,18 +241,16 @@ typedef int32_t m_tr33_index_t;
M_TR33_CONTRACT(tree); \
} \
\
M_INLINE void \
M_F(name, _clear)(tree_t tree) { \
M_F(name, _reset)(tree); \
M_P(void, name, _clear, tree_t tree) { \
M_F(name, _reset)M_R(tree); \
struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\
M_CALL_FREE(oplist, ptr); \
M_CALL_FREE(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1)); \
/* This is so reusing the object implies an assertion failure */ \
tree->size = 1; \
tree->tab = NULL; \
} \
\
M_INLINE void \
M_F(name, _reserve)(tree_t tree, size_t alloc) { \
M_P(void, name, _reserve, tree_t tree, size_t alloc) { \
M_TR33_CONTRACT(tree); \
/* Nothing to do if the request is lower than the current capacity. */ \
if (alloc <= (size_t) tree->capacity) { \
@@ -260,18 +258,16 @@ typedef int32_t m_tr33_index_t;
} \
/* Realloc the array */ \
if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \
return; \
M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \
} \
/* Allocate one more term in the array so that tab[-1] exists. \
This enables performing latter tab[M_TR33_NO_NODE].x = something; \
as M_TR33_NO_NODE is -1. This enables avoiding testing for \
M_TR33_NO_NODE in some cases, performing branchless code. */ \
struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\
ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, alloc+1);\
ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1), alloc+1); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \
return; \
M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \
} \
/* Skip the first term to keep it as empty & unused */ \
ptr++; \
@@ -305,8 +301,7 @@ typedef int32_t m_tr33_index_t;
M_TR33_CONTRACT(tree); \
} \
\
M_INLINE m_tr33_index_t \
M_C3(m_tr33_, name, _alloc_node)(tree_t tree) { \
M_P(m_tr33_index_t, name, _i_alloc_node, tree_t tree) { \
m_tr33_index_t ret = tree->free_index; \
if (M_UNLIKELY(ret < 0)) { \
/* No more enough space: realloc the array */ \
@@ -314,18 +309,16 @@ typedef int32_t m_tr33_index_t;
/* Take into account if realloc is allowed */ \
alloc += tree->allow_realloc; \
if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \
return M_TR33_NO_NODE; \
M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \
} \
/* Allocate one more term in the array so that tab[-1] exists. \
This enables performing latter tab[M_TR33_NO_NODE].x = something; \
as M_TR33_NO_NODE is -1. This enables avoiding testing for \
M_TR33_NO_NODE in some cases, performing branchless code. */ \
struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1; \
ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, alloc+1); \
ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1), alloc+1); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \
return M_TR33_NO_NODE; \
M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \
} \
/* Skip the first term to keep it as empty & unused */ \
ptr++; \
@@ -360,11 +353,10 @@ typedef int32_t m_tr33_index_t;
tree->free_index = i; \
} \
\
M_INLINE it_t \
M_F(name, _set_root)(tree_t tree, type const data) { \
M_P(it_t, name, _set_root, tree_t tree, type const data) { \
M_TR33_CONTRACT(tree); \
M_F(name, _reset)(tree); \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(tree); \
M_F(name, _reset)M_R(tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(tree); \
tree->tab[i].parent = M_TR33_ROOT_NODE; \
tree->tab[i].left = M_TR33_NO_NODE; \
tree->tab[i].right = M_TR33_NO_NODE; \
@@ -446,10 +438,9 @@ typedef int32_t m_tr33_index_t;
return i < 0 ? NULL : &it.tree->tab[i].data; \
} \
\
M_INLINE it_t \
M_F(name, _insert_up_raw)(it_t it) { \
M_P(it_t, name, _insert_up_raw, it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \
m_tr33_index_t parent = it.tree->tab[it.index].parent; \
m_tr33_index_t left = it.tree->tab[it.index].left; \
m_tr33_index_t right = it.tree->tab[it.index].right; \
@@ -476,26 +467,23 @@ typedef int32_t m_tr33_index_t;
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_up)(it_t pos, type const data) { \
it_t it = M_F(name, _insert_up_raw)(pos); \
M_P(it_t, name, _insert_up, it_t pos, type const data) { \
it_t it = M_F(name, _insert_up_raw)M_R(pos); \
M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _move_up)(it_t pos, type *data) { \
it_t it = M_F(name, _insert_up_raw)(pos); \
M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_P(it_t, name, _move_up, it_t pos, type *data) { \
it_t it = M_F(name, _insert_up_raw)M_R(pos); \
M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_down_raw)(it_t it) { \
M_P(it_t, name, _insert_down_raw, it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \
m_tr33_index_t child = it.tree->tab[it.index].child; \
it.tree->tab[i].parent = it.index; \
it.tree->tab[i].left = M_TR33_NO_NODE; \
@@ -513,28 +501,25 @@ typedef int32_t m_tr33_index_t;
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_down)(it_t pos, type const data) { \
it_t it = M_F(name, _insert_down_raw)(pos); \
M_P(it_t, name, _insert_down, it_t pos, type const data) { \
it_t it = M_F(name, _insert_down_raw)M_R(pos); \
M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _move_down)(it_t pos, type *data) { \
it_t it = M_F(name, _insert_down_raw)(pos); \
M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_P(it_t, name, _move_down, it_t pos, type *data) { \
it_t it = M_F(name, _insert_down_raw)M_R(pos); \
M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_child_raw)(it_t it) { \
M_P(it_t, name, _insert_child_raw, it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
/* Insert a node as a child of another, making the current children \
of the nodes their siblings */ \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \
m_tr33_index_t child = it.tree->tab[it.index].child; \
it.tree->tab[i].parent = it.index; \
it.tree->tab[i].left = M_TR33_NO_NODE; \
@@ -550,27 +535,24 @@ typedef int32_t m_tr33_index_t;
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_child)(it_t pos, type const data) { \
it_t it = M_F(name, _insert_child_raw)(pos); \
M_P(it_t, name, _insert_child, it_t pos, type const data) { \
it_t it = M_F(name, _insert_child_raw)M_R(pos); \
M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _move_child)(it_t pos, type *data) { \
it_t it = M_F(name, _insert_child_raw)(pos); \
M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_P(it_t, name, _move_child, it_t pos, type *data) { \
it_t it = M_F(name, _insert_child_raw)M_R(pos); \
M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_left_raw)(it_t it) { \
M_P(it_t, name, _insert_left_raw, it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
M_ASSERT(it.index != it.tree->root_index); \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \
m_tr33_index_t left = it.tree->tab[it.index].left; \
m_tr33_index_t parent = it.tree->tab[it.index].parent; \
it.tree->tab[i].parent = parent; \
@@ -590,27 +572,24 @@ typedef int32_t m_tr33_index_t;
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_left)(it_t pos, type const data) { \
it_t it = M_F(name, _insert_left_raw)(pos); \
M_P(it_t, name, _insert_left, it_t pos, type const data) { \
it_t it = M_F(name, _insert_left_raw)M_R(pos); \
M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _move_left)(it_t pos, type *data) { \
it_t it = M_F(name, _insert_left_raw)(pos); \
M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_P(it_t, name, _move_left, it_t pos, type *data) { \
it_t it = M_F(name, _insert_left_raw)M_R(pos); \
M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_right_raw)(it_t it) { \
M_P(it_t, name, _insert_right_raw, it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
M_ASSERT(it.index != it.tree->root_index); \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \
m_tr33_index_t right = it.tree->tab[it.index].right; \
it.tree->tab[i].parent = it.tree->tab[it.index].parent; \
it.tree->tab[i].left = it.index; \
@@ -624,18 +603,16 @@ typedef int32_t m_tr33_index_t;
return it; \
} \
\
M_INLINE it_t \
M_F(name, _insert_right)(it_t pos, type const data) { \
it_t it = M_F(name, _insert_right_raw)(pos); \
M_P(it_t, name, _insert_right, it_t pos, type const data) { \
it_t it = M_F(name, _insert_right_raw)M_R(pos); \
M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
\
M_INLINE it_t \
M_F(name, _move_right)(it_t pos, type *data) { \
it_t it = M_F(name, _insert_right_raw)(pos); \
M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_P(it_t, name, _move_right, it_t pos, type *data) { \
it_t it = M_F(name, _insert_right_raw)M_R(pos); \
M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \
M_TR33_IT_CONTRACT(it, true); \
return it; \
} \
@@ -884,9 +861,9 @@ typedef int32_t m_tr33_index_t;
return &it.tree->tab[it.index].data; \
} \
\
M_INLINE bool \
M_F(name, _remove)(it_t it) { \
M_P(bool, name, _remove, it_t it) { \
M_TR33_IT_CONTRACT(it, false); \
M_UNUSED_CONTEXT(); \
if (M_UNLIKELY(it.index < 0)) { return false; } \
type *ptr = M_F(name, _unlink)(it); \
M_CALL_CLEAR(oplist, *ptr); \
@@ -1018,15 +995,14 @@ typedef int32_t m_tr33_index_t;
assert(b); \
} \
\
M_INLINE void \
M_F(name, _prune)(it_t it) { \
M_P(void, name, _prune, it_t it) { \
M_TR33_IT_CONTRACT(it, true); \
/* remove the node, including its childs */ \
it_t child = M_F(name, _it_subpost)(it); \
while (!M_F(name, _end_p)(child)) { \
it_t next = child; \
M_F(name, _next_subpost)(&next, it); \
bool b = M_F(name, _remove)(child); \
bool b = M_F(name, _remove)M_R(child); \
(void) b; /* parameter not used */ \
M_ASSERT(b); \
child = next; \
@@ -1122,8 +1098,7 @@ typedef int32_t m_tr33_index_t;
/* Define the classic extended missing methods of a tree */
#define M_TR33_DEF_P4_EXT(name, type, oplist, tree_t, it_t) \
M_INLINE void \
M_F(name, _init_set)(tree_t tree, const tree_t ref) { \
M_P(void, name, _init_set, tree_t tree, const tree_t ref) { \
tree->size = ref->size; \
tree->capacity = ref->capacity; \
tree->root_index = ref->root_index; \
@@ -1134,10 +1109,9 @@ typedef int32_t m_tr33_index_t;
tree->tab = NULL; \
} else { \
struct M_F(name, _node_s) *ptr = \
M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, alloc+1); \
M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, 0, alloc+1); \
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
M_MEMORY_FULL(sizeof(struct M_F(name, _node_s)) * alloc); \
return; \
M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \
} \
tree->tab = ++ptr; \
/* We don't scan recursively the node tree, but sequentially */ \
@@ -1155,11 +1129,10 @@ typedef int32_t m_tr33_index_t;
M_TR33_CONTRACT(tree); \
} \
\
M_INLINE void \
M_F(name, _set)(tree_t tree, const tree_t ref) { \
M_P(void, name, _set, tree_t tree, const tree_t ref) { \
/* No optimum, but good enough currently */ \
M_F(name, _clear)(tree); \
M_F(name, _init_set)(tree, ref); \
M_F(name, _clear)M_R(tree); \
M_F(name, _init_set)M_R(tree, ref); \
} \
\
M_INLINE void \
@@ -1175,9 +1148,8 @@ typedef int32_t m_tr33_index_t;
ref->tab = NULL; \
} \
\
M_INLINE void \
M_F(name, _move)(tree_t tree, tree_t ref) { \
M_F(name, _clear)(tree); \
M_P(void, name, _move, tree_t tree, tree_t ref) { \
M_F(name, _clear)M_R(tree); \
M_F(name, _init_move)(tree, ref); \
} \
\
@@ -1299,30 +1271,29 @@ typedef int32_t m_tr33_index_t;
/* Define the IO methods of a tree */
#define M_TR33_DEF_P4_IO(name, type, oplist, tree_t, it_t) \
M_IF_METHOD(GET_STR, oplist)( \
M_INLINE void \
M_F(name, _get_str)(m_string_t str, /*const*/ tree_t tree, bool append) { \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
M_P(void, name, _get_str, m_string_t str, /*const*/ tree_t tree, bool append) { \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
it_t it = M_F(name, _it)(tree); \
while (!M_F(name, _end_p)(it)) { \
m_string_push_back (str, '{'); \
m_string_push_back M_R(str, '{'); \
type const *item = M_F(name, _cref)(it); \
M_CALL_GET_STR(oplist, str, *item, true); \
/* Go down the tree */ \
if (M_F(name, _it_down)(&it)) { \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back (str, '['); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, '['); \
continue; \
} \
m_string_push_back (str, '}'); \
m_string_push_back M_R(str, '}'); \
if (M_F(name, _it_right)(&it)) { \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
continue; \
} \
while (M_F(name, _it_up)(&it)) { \
m_string_push_back (str, ']'); \
m_string_push_back (str, '}'); \
m_string_push_back M_R(str, ']'); \
m_string_push_back M_R(str, '}'); \
if (M_F(name, _it_right)(&it)) { \
m_string_push_back (str, M_GET_SEPARATOR oplist); \
m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \
goto continue_tree; \
} \
} \
@@ -1330,17 +1301,16 @@ M_F(name, _get_str)(m_string_t str, /*const*/ tree_t tree, bool append) { \
continue_tree: \
(void) 0; \
} \
m_string_push_back (str, ']'); \
m_string_push_back M_R(str, ']'); \
} \
, /* No GET_STR */ ) \
\
M_IF_METHOD(PARSE_STR, oplist)( \
M_INLINE bool \
M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) { \
M_P(bool, name, _parse_str, tree_t tree, const char str[], const char **endp) { \
M_TR33_CONTRACT(tree); \
int cmd = 0; \
it_t it; \
M_F(name, _reset)(tree); \
M_F(name, _reset)M_R(tree); \
bool success = false; \
int c = *str; \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -1357,9 +1327,9 @@ M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) { \
if (b == false || c == 0) break; \
/* Insert the item as the root or as a right sibling or as a child */ \
switch (cmd) { \
case 0: it = M_F(name, _set_root)(tree, item); break; \
case 1: it = M_F(name, _insert_right)(it, item); break; \
case 2: it = M_F(name, _insert_child)(it, item); break; \
case 0: it = M_F(name, _set_root)M_R(tree, item); break; \
case 1: it = M_F(name, _insert_right)M_R(it, item); break; \
case 2: it = M_F(name, _insert_child)M_R(it, item); break; \
default: M_ASSERT(0); \
} \
if (c == ',') { \
@@ -1432,12 +1402,11 @@ M_F(name, _out_str)(FILE *f, /*const*/ tree_t tree) { \
, /* No OUT_STR */ ) \
\
M_IF_METHOD(IN_STR, oplist)( \
M_INLINE bool \
M_F(name, _in_str)(tree_t tree, FILE *f) { \
M_P(bool, name, _in_str, tree_t tree, FILE *f) { \
M_TR33_CONTRACT(tree); \
int cmd = 0; \
it_t it; \
M_F(name, _reset)(tree); \
M_F(name, _reset)M_R(tree); \
bool success = false; \
int c = fgetc(f); \
if (M_UNLIKELY (c != '[')) goto exit; \
@@ -1455,9 +1424,9 @@ M_F(name, _in_str)(tree_t tree, FILE *f) { \
if (b == false || c == 0) break; \
/* Insert the item as the root or as a right sibling or as a child */ \
switch (cmd) { \
case 0: it = M_F(name, _set_root)(tree, item); break; \
case 1: it = M_F(name, _insert_right)(it, item); break; \
case 2: it = M_F(name, _insert_child)(it, item); break; \
case 0: it = M_F(name, _set_root)M_R(tree, item); break; \
case 1: it = M_F(name, _insert_right)M_R(it, item); break; \
case 2: it = M_F(name, _insert_child)M_R(it, item); break; \
default: M_ASSERT(0); \
} \
if (c == ',') { \
@@ -1494,22 +1463,20 @@ exit: \
/* Define the emplace methods of a tree */
#define M_TR33_DEF_P4_EMPLACE(name, type, oplist, tree_t, it_t) \
M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace_root), oplist, M_TR33_EMPLACE_ROOT_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_up), oplist, M_TR33_EMPLACE_UP_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_down), oplist, M_TR33_EMPLACE_DOWN_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_child), oplist, M_TR33_EMPLACE_CHILD_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_left), oplist, M_TR33_EMPLACE_LEFT_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_right), oplist, M_TR33_EMPLACE_RIGHT_DEF)
M_EMPLACE_QUEUE_DEF(name, tree_t, _emplace_root, oplist, M_TR33_EMPLACE_ROOT_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_up, oplist, M_TR33_EMPLACE_UP_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_down, oplist, M_TR33_EMPLACE_DOWN_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_child, oplist, M_TR33_EMPLACE_CHILD_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_left, oplist, M_TR33_EMPLACE_LEFT_DEF) \
M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_right, oplist, M_TR33_EMPLACE_RIGHT_DEF)
/* Definition of the emplace_back functions */
#define M_TR33_EMPLACE_ROOT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE M_F(name, _it_ct) \
function_name(name_t tree \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(M_F(name, _it_ct), name, function_name, name_t tree M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_TR33_CONTRACT(tree); \
M_F(name, _reset)(tree); \
m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(tree); \
M_F(name, _reset)M_R(tree); \
m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(tree); \
tree->tab[i].parent = M_TR33_ROOT_NODE; \
tree->tab[i].left = M_TR33_NO_NODE; \
tree->tab[i].right = M_TR33_NO_NODE; \
@@ -1525,55 +1492,45 @@ exit: \
}
#define M_TR33_EMPLACE_UP_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE name_t \
function_name(name_t pos \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
name_t it = M_F(name, _insert_up_raw)(pos); \
name_t it = M_F(name, _insert_up_raw)M_R(pos); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \
exp_emplace_type); \
return it; \
}
#define M_TR33_EMPLACE_DOWN_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE name_t \
function_name(name_t pos \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
name_t it = M_F(name, _insert_down_raw)(pos); \
name_t it = M_F(name, _insert_down_raw)M_R(pos); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \
exp_emplace_type); \
return it; \
}
#define M_TR33_EMPLACE_CHILD_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE name_t \
function_name(name_t pos \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
name_t it = M_F(name, _insert_child_raw)(pos); \
name_t it = M_F(name, _insert_child_raw)M_R(pos); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \
exp_emplace_type); \
return it; \
}
#define M_TR33_EMPLACE_LEFT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE name_t \
function_name(name_t pos \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
name_t it = M_F(name, _insert_left_raw)(pos); \
name_t it = M_F(name, _insert_left_raw)M_R(pos); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \
exp_emplace_type); \
return it; \
}
#define M_TR33_EMPLACE_RIGHT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE name_t \
function_name(name_t pos \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
name_t it = M_F(name, _insert_right_raw)(pos); \
name_t it = M_F(name, _insert_right_raw)M_R(pos); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \
exp_emplace_type); \
return it; \
+1 -1
View File
@@ -620,7 +620,7 @@ _Pragma("GCC diagnostic pop")
// In case of MEMORY FULL errors, throw an error instead of aborting.
#undef M_MEMORY_FULL
#define M_MEMORY_FULL(size) M_THROW(M_ERROR_MEMORY, (intptr_t)(size))
#define M_MEMORY_FULL(type, size) M_THROW(M_ERROR_MEMORY, (intptr_t)sizeof(type), (intptr_t)(size))
// Add attribute volatile if exceptions are enabled
#undef m_volatile
+67 -38
View File
@@ -243,7 +243,8 @@ namespace m_lib {
/* Define the INIT method calling the INIT method for all params */
#define M_TUPL3_DEFINE_INIT(name, ...) \
M_INLINE void M_F(name, _init)(M_F(name,_ct) my) { \
M_P(void, name, _init, M_F(name,_ct) my) { \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_INIT_FUNC , __VA_ARGS__) {} \
}
@@ -252,8 +253,9 @@ namespace m_lib {
/* Define the INIT_SET method calling the INIT_SET method for all params */
#define M_TUPL3_DEFINE_INIT_SET(name, ...) \
M_INLINE void M_F(name, _init_set)(M_F(name,_ct) my , M_F(name,_ct) const org) { \
M_P(void, name, _init_set, M_F(name,_ct) my , M_F(name,_ct) const org) { \
M_TUPL3_CONTRACT(org); \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_INIT_SET_FUNC , __VA_ARGS__) {} \
}
#define M_TUPL3_DEFINE_INIT_SET_FUNC(a) \
@@ -262,15 +264,11 @@ namespace m_lib {
/* Define the INIT_WITH method calling the INIT_SET method for all params. */
#define M_TUPL3_DEFINE_INIT_SET2(name, ...) \
M_INLINE void M_F(name, _init_emplace)(M_F(name,_ct) my \
M_MAP(M_TUPL3_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \
) { \
M_P(void, name, _init_emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) {} \
}
#define M_TUPL3_DEFINE_INIT_SET2_PROTO(a) \
, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a
#define M_TUPL3_DEFINE_INIT_SET2_FUNC(a) \
M_CHAIN_OBJ(M_TUPL3_GET_FIELD a, M_TUPL3_GET_OPLIST a, \
my -> M_TUPL3_GET_FIELD a , M_TUPL3_GET_FIELD a )
@@ -278,10 +276,10 @@ namespace m_lib {
/* Define the SET method calling the SET method for all params. */
#define M_TUPL3_DEFINE_SET(name, ...) \
M_INLINE void M_F(name, _set)(M_F(name,_ct) my , \
M_F(name,_ct) const org) { \
M_P(void, name, _set, M_F(name,_ct) my, M_F(name,_ct) const org) { \
M_TUPL3_CONTRACT(my); \
M_TUPL3_CONTRACT(org); \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_SET_FUNC , __VA_ARGS__) \
}
@@ -291,10 +289,9 @@ namespace m_lib {
/* Define the SET_WITH method calling the SET method for all params. */
#define M_TUPL3_DEFINE_SET2(name, ...) \
M_INLINE void M_F(name, _emplace)(M_F(name,_ct) my \
M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) \
) { \
M_P(void, name, _emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \
M_TUPL3_CONTRACT(my); \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_SET2_FUNC , __VA_ARGS__) \
}
#define M_TUPL3_DEFINE_SET2_PROTO(a) \
@@ -306,8 +303,9 @@ namespace m_lib {
/* Define the CLEAR method calling the CLEAR method for all params. */
#define M_TUPL3_DEFINE_CLEAR(name, ...) \
M_INLINE void M_F(name, _clear)(M_F(name,_ct) my) { \
M_P(void, name, _clear, M_F(name,_ct) my) { \
M_TUPL3_CONTRACT(my); \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_CLEAR_FUNC , __VA_ARGS__) \
}
@@ -343,8 +341,9 @@ namespace m_lib {
#define M_TUPL3_DEFINE_SETTER_FIELD_PROTO(name, a) \
M_INLINE void M_C3(name, _set_, M_TUPL3_GET_FIELD a) \
(M_F(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \
(M_P_EXPAND M_F(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \
M_TUPL3_CONTRACT(my); \
M_UNUSED_CONTEXT(); \
M_TUPL3_CALL_SET(a, my ->M_TUPL3_GET_FIELD a, M_TUPL3_GET_FIELD a); \
}
@@ -360,9 +359,10 @@ namespace m_lib {
#define M_TUPL3_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
function_name(name_t v \
function_name(M_P_EXPAND name_t v \
M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \
{ \
M_UNUSED_CONTEXT(); \
M_CALL_CLEAR(oplist, v->name); \
M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->name, exp_emplace_type); \
}
@@ -468,27 +468,26 @@ namespace m_lib {
/* Define a GET_STR method by calling the GET_STR methods for all params */
#define M_TUPL3_DEFINE_GET_STR(name, ...) \
M_INLINE void M_F(name, _get_str)(m_string_t str, \
M_F(name,_ct) const el, \
bool append) { \
M_P(void, name, _get_str, m_string_t str, M_F(name,_ct) const el, bool append) \
{ \
bool comma = false; \
M_TUPL3_CONTRACT(el); \
M_ASSERT (str != NULL); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "("); \
(append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "("); \
M_MAP(M_TUPL3_DEFINE_GET_STR_FUNC , __VA_ARGS__) \
m_string_push_back (str, ')'); \
m_string_push_back M_R(str, ')'); \
}
#define M_TUPL3_DEFINE_GET_STR_FUNC(a) \
if (comma) m_string_push_back (str, ','); \
if (comma) m_string_push_back M_R(str, ','); \
comma = true; \
M_TUPL3_CALL_GET_STR(a, str, el -> M_TUPL3_GET_FIELD a, true); \
/* Define a OUT_STR method by calling the OUT_STR methods for all params */
#define M_TUPL3_DEFINE_OUT_STR(name, ...) \
M_INLINE void M_F(name, _out_str)(FILE *f, \
M_F(name,_ct) const el) { \
M_INLINE void M_F(name, _out_str)(FILE *f, M_F(name,_ct) const el) \
{ \
bool comma = false; \
M_TUPL3_CONTRACT(el); \
M_ASSERT (f != NULL); \
@@ -505,9 +504,11 @@ namespace m_lib {
/* Define a IN_STR method by calling the IN_STR methods for all params */
#define M_TUPL3_DEFINE_IN_STR(name, ...) \
M_INLINE bool M_F(name, _in_str)(M_F(name,_ct) el, FILE *f) { \
M_P(bool, name, _in_str, M_F(name,_ct) el, FILE *f) \
{ \
bool comma = false; \
M_TUPL3_CONTRACT(el); \
M_UNUSED_CONTEXT(); \
M_ASSERT (f != NULL); \
int c = fgetc(f); \
if (c != '(') return false; \
@@ -528,11 +529,11 @@ namespace m_lib {
/* Define a PARSE_STR method by calling the PARSE_STR methods for all params */
#define M_TUPL3_DEFINE_PARSE_STR(name, ...) \
M_INLINE bool M_F(name, _parse_str)(M_F(name,_ct) el, \
const char str[], \
const char **endptr) { \
M_P(bool, name, _parse_str, M_F(name,_ct) el, const char str[], const char **endptr) \
{ \
M_TUPL3_CONTRACT(el); \
M_ASSERT (str != NULL); \
M_UNUSED_CONTEXT(); \
bool success = false; \
bool comma = false; \
int c = *str++; \
@@ -562,9 +563,8 @@ namespace m_lib {
/* Define a OUT_SERIAL method by calling the OUT_SERIAL methods for all params */
#define M_TUPL3_DEFINE_OUT_SERIAL(name, ...) \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, \
M_F(name,_ct) const el) { \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, M_F(name,_ct) const el) \
{ \
M_TUPL3_CONTRACT(el); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
const int field_max = M_NARGS(__VA_ARGS__); \
@@ -574,24 +574,25 @@ namespace m_lib {
int index = 0; \
m_serial_local_t local; \
m_serial_return_code_t ret; \
ret = f->m_interface->write_tuple_start(local, f); \
ret = f->m_interface->write_tuple_start M_R(local, f); \
M_MAP(M_TUPL3_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \
M_ASSERT( index == field_max); \
ret |= f->m_interface->write_tuple_end(local, f); \
ret |= f->m_interface->write_tuple_end M_R(local, f); \
return ret & M_SERIAL_FAIL; \
}
#define M_TUPL3_DEFINE_OUT_SERIAL_FUNC(a) \
f->m_interface->write_tuple_id(local, f, field_name, field_max, index); \
f->m_interface->write_tuple_id M_R(local, f, field_name, field_max, index); \
M_TUPL3_CALL_OUT_SERIAL(a, f, el -> M_TUPL3_GET_FIELD a); \
index++; \
/* Define a IN_SERIAL method by calling the IN_SERIAL methods for all params */
#define M_TUPL3_DEFINE_IN_SERIAL(name, ...) \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(M_F(name,_ct) el, m_serial_read_t f) { \
M_P(m_serial_return_code_t, name, _in_serial, M_F(name,_ct) el, m_serial_read_t f) \
{ \
M_TUPL3_CONTRACT(el); \
M_UNUSED_CONTEXT(); \
M_ASSERT (f != NULL && f->m_interface != NULL); \
int index = -1; \
const int field_max = M_NARGS(__VA_ARGS__); \
@@ -634,8 +635,9 @@ namespace m_lib {
/* Define a MOVE method by calling the MOVE methods for all params */
#define M_TUPL3_DEFINE_MOVE(name, ...) \
M_INLINE void M_F(name, _move)(M_F(name,_ct) el, M_F(name,_ct) org) { \
M_P(void, name, _move, M_F(name,_ct) el, M_F(name,_ct) org) { \
M_TUPL3_CONTRACT(el); \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_MOVE_FUNC , __VA_ARGS__) \
}
@@ -657,8 +659,9 @@ namespace m_lib {
/* Define a RESET method by calling the RESET methods for all params */
#define M_TUPL3_DEFINE_RESET(name, ...) \
M_INLINE void M_F(name, _reset)(M_F(name,_ct) el1) { \
M_P(void, name, _reset, M_F(name,_ct) el1) { \
M_TUPL3_CONTRACT(el1); \
M_UNUSED_CONTEXT(); \
M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \
} \
@@ -743,6 +746,7 @@ namespace m_lib {
((M_LIB_ERROR(ONE_ARGUMENT_OF_M_TUPL3_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
/* Define the TUPLE oplist */
#ifndef M_USE_CONTEXT
#define M_TUPL3_OPLIST_P3(name, ...) \
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_F(name,_init)),), \
INIT_SET(M_F(name, _init_set)), \
@@ -767,6 +771,31 @@ namespace m_lib {
M_IF_METHOD_ALL(RESET, __VA_ARGS__)(RESET(M_F(name, _reset)),), \
EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \
)
#else
#define M_TUPL3_OPLIST_P3(name, ...) \
(M_IF_METHOD_ALL(INIT, __VA_ARGS__)(API_0P(INIT(M_F(name,_init))),), \
INIT_SET(API_0P(M_F(name, _init_set))), \
INIT_WITH(API_1(M_TUPL3_INIT_WITH)), \
SET(API_0P(M_F(name,_set))), \
CLEAR(API_0P(M_F(name, _clear))), \
NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
OPLIST( (__VA_ARGS__) ), \
M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_F(name, _cmp)),), \
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_F(name, _hash)),), \
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(API_0P(M_F(name, _get_str))),), \
M_IF_METHOD_ALL(PARSE_STR, __VA_ARGS__)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \
M_IF_METHOD_ALL(IN_STR, __VA_ARGS__)(IN_STR(API_0P(M_F(name, _in_str))),), \
M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_F(name, _out_str)),), \
M_IF_METHOD_ALL(IN_SERIAL, __VA_ARGS__)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \
M_IF_METHOD_ALL(OUT_SERIAL, __VA_ARGS__)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_F(name, _init_move)),), \
M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(API_0P(M_F(name, _move))),), \
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \
M_IF_METHOD_ALL(RESET, __VA_ARGS__)(RESET(API_0P(M_F(name, _reset))),), \
EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \
)
#endif
/* Support for EMPLACE_TYPE in OPLIST. It refers the created internal type alias */
#define M_TUPL3_OPLIST_SUBTYPE(name, num) \
+84 -55
View File
@@ -224,15 +224,17 @@
/* Define the INIT_SET function. */
#define M_VAR1ANT_DEFINE_INIT_SET(name, ...) \
M_INLINE void M_F(name, _init_set)(M_F(name,_ct) my , \
M_F(name,_ct) const org) { \
M_P(void, name, _init_set, M_F(name,_ct) my, M_F(name,_ct) const org) \
{ \
M_VAR1ANT_CONTRACT(name, org); \
M_UNUSED_CONTEXT(); \
my->type = org->type; \
switch (org->type) { \
M_MAP2(M_VAR1ANT_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \
case M_F(name, _EMPTY): /* fallthrough */ \
default: M_ASSUME(org->type == M_F(name, _EMPTY)); break; \
} \
M_VAR1ANT_CONTRACT(name, my); \
}
#define M_VAR1ANT_DEFINE_INIT_SET_FUNC(name, a) \
@@ -244,14 +246,14 @@
/* Define the SET function. */
#define M_VAR1ANT_DEFINE_SET(name, ...) \
M_INLINE void M_F(name, _set)(M_F(name,_ct) my , \
M_F(name,_ct) const org) { \
M_P(void, name, _set, M_F(name,_ct) my, M_F(name,_ct) const org) \
{ \
M_VAR1ANT_CONTRACT(name, my); \
M_VAR1ANT_CONTRACT(name, org); \
if (my->type != org->type) { \
/* Different types: clear previous one and create new */ \
M_F(name, _clear)(my); \
M_F(name, _init_set)(my, org); \
M_F(name, _clear)M_R(my); \
M_F(name, _init_set)M_R(my, org); \
} else { \
/* Same type: optimize the set */ \
switch (org->type) { \
@@ -260,6 +262,8 @@
default: M_ASSUME(org->type == M_F(name, _EMPTY)); break; \
} \
} \
M_ASSERT( my->type == org->type ); \
M_VAR1ANT_CONTRACT(name, my); \
}
#define M_VAR1ANT_DEFINE_SET_FUNC(name, a) \
@@ -271,8 +275,10 @@
/* Define the CLEAR function. */
#define M_VAR1ANT_DEFINE_CLEAR(name, ...) \
M_INLINE void M_F(name, _clear)(M_F(name,_ct) my) { \
M_P(void, name, _clear, M_F(name,_ct) my) \
{ \
M_VAR1ANT_CONTRACT(name, my); \
M_UNUSED_CONTEXT(); \
switch (my->type) { \
M_MAP2(M_VAR1ANT_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \
case M_F(name, _EMPTY): /* fallthrough */ \
@@ -314,7 +320,9 @@
#define M_VAR1ANT_DEFINE_INIT_FIELD_FUNC(name, a) \
M_INLINE void \
M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my) { \
M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my) \
{ \
M_UNUSED_CONTEXT(); \
/* Reinit variable with the given value */ \
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
M_VAR1ANT_CALL_INIT(a, my -> value. M_VAR1ANT_GET_FIELD a); \
@@ -327,15 +335,17 @@
#define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC(name, num, a) \
M_INLINE void \
M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \
{ \
M_UNUSED_CONTEXT(); \
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
M_VAR1ANT_GET_FIELD a); \
} \
M_INLINE void \
M_C4(m_var1ant_, name, _init_set_, num)(M_F(name,_ct) my, \
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
M_C4(m_var1ant_, name, _init_set_, num)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \
{ \
M_UNUSED_CONTEXT(); \
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
M_VAR1ANT_GET_FIELD a); \
@@ -348,14 +358,14 @@
#define M_VAR1ANT_DEFINE_SETTER_FIELD_FUNC(name, a) \
M_INLINE void \
M_C3(name, _set_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \
M_C3(name, _set_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, \
M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \
M_VAR1ANT_CONTRACT(name, my); \
if (my->type == M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) ) { \
M_VAR1ANT_CALL_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
M_VAR1ANT_GET_FIELD a); \
} else { \
M_F(name, _clear)(my); \
M_F(name, _clear)M_R(my); \
/* Reinit variable with the given value */ \
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \
@@ -403,8 +413,7 @@
#define M_VAR1ANT_DEFINE_INIT_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
function_name(name_t my \
M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
function_name(M_P_EXPAND name_t my M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
{ \
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \
@@ -412,13 +421,13 @@ M_INLINE void \
#define M_VAR1ANT_DEFINE_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \
M_INLINE void \
function_name(name_t my \
M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
function_name(M_P_EXPAND name_t my M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \
{ \
/* No optimization done */ \
M_C(M_PAIR_1 name, _clear)(my); \
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
M_C(M_PAIR_1 name, _clear)M_R(my); \
my->type = M_F(M_PAIR_1 name, _EMPTY); \
M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \
my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \
} \
/* Define the EQUAL_P function. */
@@ -491,11 +500,9 @@ M_INLINE void \
It can be optimized if both types are the same.
*/
#define M_VAR1ANT_DEFINE_MOVE(name, ...) \
M_INLINE void \
M_F(name, _move)(M_F(name,_ct) el, M_F(name,_ct) org) { \
M_VAR1ANT_CONTRACT(name, el); \
M_VAR1ANT_CONTRACT(name, org); \
M_F(name, _clear)(el); \
M_P(void, name, _move, M_F(name,_ct) el, M_F(name,_ct) org) \
{ \
M_F(name, _clear)M_R(el); \
M_F(name, _init_move)(el , org); \
}
@@ -506,10 +513,10 @@ M_INLINE void \
#define M_VAR1ANT_DEFINE_MOVER_FUNC(name, a) \
M_INLINE void \
M_C3(name, _move_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \
M_C3(name, _move_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, \
M_VAR1ANT_GET_TYPE a M_VAR1ANT_GET_FIELD a ) { \
M_VAR1ANT_CONTRACT(name, my); \
M_F(name, _clear)(my); \
M_F(name, _clear)M_R(my); \
/* Reinit variable with the given value */ \
my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \
M_VAR1ANT_CALL_INIT_MOVE(a, my -> value. M_VAR1ANT_GET_FIELD a, \
@@ -555,40 +562,38 @@ M_INLINE void \
/* Define the GET_STR function */
#define M_VAR1ANT_DEFINE_GET_STR(name, ...) \
M_INLINE void M_F(name, _get_str)(m_string_t str, \
M_F(name,_ct) const el, \
bool append) { \
M_P(void, name, _get_str, m_string_t str, M_F(name,_ct) const el, bool append) \
{ \
M_VAR1ANT_CONTRACT(name, el); \
M_ASSERT (str != NULL); \
void (*func)(m_string_t, const char *); \
void (*func)(M_P_EXPAND m_string_t, const char *); \
func = append ? m_string_cat_cstr : m_string_set_cstr; \
switch (el->type) { \
case M_F(name, _EMPTY): func(str, "@EMPTY@"); break; \
case M_F(name, _EMPTY): func M_R(str, "@EMPTY@"); break; \
M_MAP2(M_VAR1ANT_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \
default: M_ASSUME(false); break; \
} \
m_string_push_back (str, '@'); \
m_string_push_back M_R(str, '@'); \
}
#define M_VAR1ANT_DEFINE_GET_STR_FUNC(name, a) \
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
func(str, "@" M_AS_STR(M_VAR1ANT_GET_FIELD a) "@"); \
func M_R(str, "@" M_AS_STR(M_VAR1ANT_GET_FIELD a) "@"); \
M_VAR1ANT_CALL_GET_STR(a, str, el -> value . M_VAR1ANT_GET_FIELD a, true); \
break;
/* Define the PARSE_STR function */
#define M_VAR1ANT_DEFINE_PARSE_STR(name, ...) \
M_INLINE bool M_F(name, _parse_str)(M_F(name,_ct) el, \
const char str[], \
const char **endp) { \
M_P(bool, name, _parse_str, M_F(name,_ct) el, const char str[], const char **endp) \
{ \
M_VAR1ANT_CONTRACT(name, el); \
M_ASSERT (str != NULL); \
bool success = false; \
char variantTypeBuf[M_USE_IDENTIFIER_ALLOC+1]; \
int c = *str++; \
unsigned int i = 0; \
M_F(name, _reset)(el); \
M_F(name, _reset)M_R(el); \
if (c != '@') goto exit; \
/* First read the name of the type */ \
c = *str++; \
@@ -622,8 +627,8 @@ M_INLINE void \
/* Define the OUT_STR function */
#define M_VAR1ANT_DEFINE_OUT_STR(name, ...) \
M_INLINE void M_F(name, _out_str)(FILE *f, \
M_F(name,_ct) const el) { \
M_INLINE void M_F(name, _out_str)(FILE *f, M_F(name,_ct) const el) \
{ \
M_VAR1ANT_CONTRACT(name, el); \
M_ASSERT (f != NULL); \
switch (el->type) { \
@@ -643,12 +648,12 @@ M_INLINE void \
/* Define the IN_STR function */
#define M_VAR1ANT_DEFINE_IN_STR(name, ...) \
M_INLINE bool M_F(name, _in_str)(M_F(name,_ct) el, \
FILE *f) { \
M_P(bool, name, _in_str, M_F(name,_ct) el, FILE *f) \
{ \
M_VAR1ANT_CONTRACT(name, el); \
M_ASSERT (f != NULL); \
char variantTypeBuf[M_USE_IDENTIFIER_ALLOC+1]; \
M_F(name, _reset)(el); \
M_F(name, _reset)M_R(el); \
if (fgetc(f) != '@') return false; \
/* First read the name of the type */ \
bool b = true; \
@@ -685,9 +690,8 @@ M_INLINE void \
/* Define the OUT_SERIAL function */
#define M_VAR1ANT_DEFINE_OUT_SERIAL(name, ...) \
M_INLINE m_serial_return_code_t \
M_F(name, _out_serial)(m_serial_write_t f, \
M_F(name,_ct) const el) { \
M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, M_F(name,_ct) const el) \
{ \
M_VAR1ANT_CONTRACT(name, el); \
const int field_max = M_NARGS(__VA_ARGS__); \
static const char *const field_name[] = \
@@ -697,18 +701,18 @@ M_INLINE void \
m_serial_return_code_t ret; \
switch (el->type) { \
case M_F(name, _EMPTY): \
return f->m_interface->write_variant_start(local, f, field_name, field_max, -1); \
return f->m_interface->write_variant_start M_R(local, f, field_name, field_max, -1); \
break; \
M_MAP2(M_VAR1ANT_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \
default: M_ASSUME(false); break; \
} \
ret |= f->m_interface->write_variant_end(local, f); \
ret |= f->m_interface->write_variant_end M_R(local, f); \
return ret & M_SERIAL_FAIL; \
}
#define M_VAR1ANT_DEFINE_OUT_SERIAL_FUNC(name, a) \
case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \
ret = f->m_interface->write_variant_start(local, f, field_name, field_max, \
ret = f->m_interface->write_variant_start M_R(local, f, field_name, field_max, \
M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) -1); \
M_VAR1ANT_CALL_OUT_SERIAL(a, f, el -> value . M_VAR1ANT_GET_FIELD a); \
break;
@@ -716,9 +720,8 @@ M_INLINE void \
/* Define the IN_SERIAL function */
#define M_VAR1ANT_DEFINE_IN_SERIAL(name, ...) \
M_INLINE m_serial_return_code_t \
M_F(name, _in_serial)(M_F(name,_ct) el, \
m_serial_read_t f) { \
M_P(m_serial_return_code_t, name, _in_serial, M_F(name,_ct) el, m_serial_read_t f) \
{ \
M_VAR1ANT_CONTRACT(name, el); \
const int field_max = M_NARGS(__VA_ARGS__); \
static const char *const field_name[] = \
@@ -727,7 +730,7 @@ M_INLINE void \
m_serial_local_t local; \
m_serial_return_code_t ret; \
int id = -1; \
M_F(name, _reset)(el); \
M_F(name, _reset)M_R(el); \
ret = f->m_interface->read_variant_start(local, f, field_name, field_max, &id); \
if (ret != M_SERIAL_OK_CONTINUE) return ret; \
M_ASSERT (id >= 0 && id < field_max); \
@@ -750,10 +753,10 @@ M_INLINE void \
/* Define the RESET function */
#define M_VAR1ANT_DEFINE_RESET_FUNC(name, ...) \
M_INLINE void M_F(name, _reset)(M_F(name,_ct) my) \
M_P(void, name, _reset, M_F(name,_ct) my) \
{ \
M_VAR1ANT_CONTRACT(name, my); \
M_F(name, _clear)(my); \
M_F(name, _clear)M_R(my); \
M_F(name, _init)(my); \
} \
@@ -772,6 +775,7 @@ M_INLINE void \
((M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__)))
/* Define the oplist */
#ifndef M_USE_CONTEXT
#define M_VAR1ANT_OPLIST_P3(name, ...) \
(INIT(M_F(name,_init)), \
INIT_SET(M_F(name, _init_set)), \
@@ -796,6 +800,31 @@ M_INLINE void \
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \
M_IF_METHOD_ALL(FIELD, __VA_ARGS__)(M_VAR1ANT_OPLIST_EMPLACE_TYPE,M_EAT)(name, __VA_ARGS__), \
)
#else
#define M_VAR1ANT_OPLIST_P3(name, ...) \
(INIT(M_F(name,_init)), \
INIT_SET(API_0P(M_F(name, _init_set))), \
SET(API_0P(M_F(name,_set))), \
CLEAR(API_0P(M_F(name, _clear))), \
RESET(API_0P(M_F(name, _reset))), \
NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \
EMPTY_P(M_F(name,_empty_p)), \
SIZE( M_NARGS(__VA_ARGS__) ), \
INIT_WITH( API_1(M_VAR1ANT_INIT_WITH) ), \
M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_F(name, _hash)),), \
M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_F(name, _equal_p)),), \
M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(API_0P(M_F(name, _get_str))),), \
M_IF_METHOD2_ALL(PARSE_STR, INIT, __VA_ARGS__)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \
M_IF_METHOD2_ALL(IN_STR, INIT, __VA_ARGS__)(IN_STR(API_0P(M_F(name, _in_str))),), \
M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_F(name, _out_str)),), \
M_IF_METHOD2_ALL(IN_SERIAL, INIT, __VA_ARGS__)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \
M_IF_METHOD_ALL(OUT_SERIAL, __VA_ARGS__)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_F(name, _init_move)),), \
M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(MOVE(API_0P(M_F(name, _move))),), \
M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \
M_IF_METHOD_ALL(FIELD, __VA_ARGS__)(M_VAR1ANT_OPLIST_EMPLACE_TYPE,M_EAT)(name, __VA_ARGS__), \
)
#endif
/* Expand to an EMPLACE_TYPE compatible with OPLIST definition
(Use M_REDUCE2 which is already used by M_IF_METHOD_ALL)
+25 -18
View File
@@ -142,8 +142,7 @@ typedef struct m_work3r_thread_s {
} m_work3r_thread_ct;
/* Definition of the queue that will record the work orders */
M_BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0,
M_BUFFER_QUEUE|M_BUFFER_UNBLOCKING_PUSH|M_BUFFER_BLOCKING_POP|M_BUFFER_THREAD_SAFE|M_BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
M_BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0, M_BUFFER_QUEUE|M_BUFFER_DEFERRED_POP, M_WORK3R_OPLIST)
/* Definition the global pool of workers */
typedef struct m_worker_s {
@@ -235,9 +234,10 @@ typedef struct m_worker_sync_s {
M_INLINE void \
M_C3(m_work3r_, name, _clear)(struct M_C3(m_worker_, name, _s) *p) \
{ \
M_GLOBAL_CONTEXT(); \
M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_CALLBACK_CLEAR, data, __VA_ARGS__) \
/* TODO: Overload */ \
M_MEMORY_DEL(p); \
M_MEMORY_DEL(m_context, p); \
} \
\
M_INLINE void \
@@ -263,15 +263,16 @@ typedef struct m_worker_sync_s {
M_MAP3_C(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD, data, __VA_ARGS__) \
) \
{ \
M_GLOBAL_CONTEXT(); \
if (!m_work3r_queue_full_p(block->worker->queue_g)) { \
struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \
struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC (m_context, struct M_C3(m_worker_, name, _s)); \
if (M_UNLIKELY_NOMEM(p == NULL)) { \
M_MEMORY_FULL(sizeof (struct M_C3(m_worker_, name, _s))); \
M_MEMORY_FULL(struct M_C3(m_worker_, name, _s), 1); \
} \
p->callback = callback; \
M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_COPY, data, __VA_ARGS__) \
M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_INIT_SET, data, __VA_ARGS__) \
const m_work3r_order_ct w = { block, p, M_C3(m_work3r_, name, _callback) M_WORK3R_EXTRA_ORDER }; \
if (m_work3r_queue_push (block->worker->queue_g, w) == true) { \
if (m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { \
atomic_fetch_add (&block->num_spawn, 1); \
return; \
} \
@@ -288,7 +289,7 @@ typedef struct m_worker_sync_s {
#define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD(data, num, oplist) \
M_GET_TYPE oplist M_C(param, num)
#define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_COPY(data, num, oplist) \
#define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_INIT_SET(data, num, oplist) \
M_CALL_INIT_SET(oplist, p-> M_C(field, num), M_C(param, num) );
#define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_ALONE(data, num, oplist) \
@@ -361,6 +362,7 @@ m_work3r_thread(void *arg)
{
// Get back the given argument
struct m_worker_s *g = M_ASSIGN_CAST(struct m_worker_s *, arg);
M_GLOBAL_CONTEXT();
while (true) {
m_work3r_order_ct w;
// If needed, reset the global state of the worker
@@ -369,7 +371,7 @@ m_work3r_thread(void *arg)
}
// Waiting for data
M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", m_work3r_queue_size(g->queue_g), m_work3r_queue_capacity(g->queue_g));
m_work3r_queue_pop(&w, g->queue_g);
m_work3r_queue_pop (&w, g->queue_g);
// We received a work order
// Note: that the work order is still present in the queue
// preventing further work order to be pushed in the queue until it finishes doing the work
@@ -409,12 +411,12 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset
// numWorker can still be 0 if it is a single core cpu (no worker available)
M_ASSERT(numWorker >= 0);
size_t numWorker_st = (size_t) numWorker;
g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, numWorker_st);
M_GLOBAL_CONTEXT();
g->worker = M_MEMORY_REALLOC(m_context, m_work3r_thread_ct, NULL, 0, numWorker_st);
if (M_UNLIKELY_NOMEM (g->worker == NULL)) {
M_MEMORY_FULL(sizeof (m_work3r_thread_ct) * numWorker_st);
return;
M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st);
}
m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue);
m_work3r_queue_init (g->queue_g, numWorker_st + extraQueue);
g->numWorker_g = (unsigned int) numWorker_st;
g->resetFunc_g = resetFunc;
g->clearFunc_g = clearFunc;
@@ -441,6 +443,7 @@ M_INLINE void
m_worker_clear(m_worker_t g)
{
M_ASSERT (m_work3r_queue_empty_p (g->queue_g));
M_GLOBAL_CONTEXT();
// Push the terminate order on the queue
for(unsigned int i = 0; i < g->numWorker_g; i++) {
m_work3r_order_ct w = M_WORK3R_EMPTY_ORDER;
@@ -454,10 +457,10 @@ m_worker_clear(m_worker_t g)
m_thread_join(g->worker[i].id);
}
// Clear memory
M_MEMORY_FREE(g->worker);
M_MEMORY_FREE(m_context, m_work3r_thread_ct, g->worker, g->numWorker_g);
m_mutex_clear(g->lock);
m_cond_clear(g->a_thread_ends);
m_work3r_queue_clear(g->queue_g);
m_work3r_queue_clear (g->queue_g);
}
/* Start a new collaboration between workers of pool 'g'
@@ -479,8 +482,9 @@ M_INLINE void
m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data)
{
const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER };
M_GLOBAL_CONTEXT();
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
&& m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) {
M_WORK3R_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -497,8 +501,9 @@ M_INLINE void
m_work3r_spawn_block(m_worker_sync_t block, void (^func)(void *data), void *data)
{
const m_work3r_order_ct w = { block, data, NULL, func };
M_GLOBAL_CONTEXT();
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
&& m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) {
M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -516,8 +521,9 @@ M_INLINE void
m_work3r_spawn_function(m_worker_sync_t block, std::function<void(void *data)> func, void *data)
{
const m_work3r_order_ct w = { block, data, NULL, func };
M_GLOBAL_CONTEXT();
if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g))
&& m_work3r_queue_push (block->worker->queue_g, w) == true) {
&& m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) {
M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
@@ -558,6 +564,7 @@ M_INLINE void
m_worker_flush(m_worker_t g)
{
m_work3r_order_ct w;
M_GLOBAL_CONTEXT();
while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) {
m_work3r_exec(&w);
m_work3r_queue_pop_release(g->queue_g);
+1
View File
@@ -198,6 +198,7 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \
M-GENINT ../m-genint.h test-mgenint.synt \
M-I-LIST test-milist.c.c test-milist.synt \
M-I-SHARED test-mishared.c.c test-mishared.synt \
M-QUEUE test-mqueue.c.c test-mqueue.synt \
M-LIST test-mlist.c.c test-mlist.synt \
M-MEMPOOL test-mmempool.c.c test-mmempool.synt \
M-PRIOQUEUE test-mprioqueue.c.c test-mprioqueue.synt \
+3
View File
@@ -125,6 +125,9 @@
#define M_TR33_CONTRACT(...) (void)0
#undef M_TR33_IT_CONTRACT
#define M_TR33_IT_CONTRACT(...) (void)0
#undef M_QUEU3_CONTRACT
#define M_QUEU3_CONTRACT(...) (void)0
/* Overwrite M_UNLIKELY_NOMEM so that it can never fails, to avoid spurious coverage */
#undef M_UNLIKELY_NOMEM
#define M_UNLIKELY_NOMEM(...) 0
+1 -2
View File
@@ -20,6 +20,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-obj.h"
#include "m-list.h"
#include "m-i-list.h"
#include "m-array.h"
@@ -29,8 +30,6 @@
#include "m-tuple.h"
#include "m-algo.h"
#include "test-obj.h"
typedef struct over_s {
unsigned long data;
ILIST_INTERFACE(ilist_over, over_s);
+3 -3
View File
@@ -33,9 +33,9 @@ END_COVERAGE
#define ARRAY_UINT_OPLIST ARRAY_OPLIST(array_uint)
// Array with the minimum number of methods.
ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear)))
ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear)))
ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) ))
ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) ) )
ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT)))
ARRAY_DEF(array_ulong, uint64_t)
ARRAY_DEF(array_string, string_t)
+1 -2
View File
@@ -20,10 +20,9 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "coverage.h"
#include "m-bitset.h"
static void test1(void)
+1 -3
View File
@@ -20,11 +20,9 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-bptree.h"
#include "test-obj.h"
#include "coverage.h"
START_COVERAGE
+1 -2
View File
@@ -20,9 +20,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "m-core.h"
#include "test-obj.h"
#include "coverage.h"
#include "m-bstring.h"
static void test0(void)
+35 -116
View File
@@ -20,25 +20,22 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "m-buffer.h"
#include "test-obj.h"
#include "m-buffer.h"
#include "coverage.h"
START_COVERAGE
// Define a fixed queue of unsigned int
BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE|BUFFER_BLOCKING)
BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE)
QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE)
QUEUE_SPSC_DEF(squeue_uint, unsigned int, BUFFER_QUEUE)
END_COVERAGE
// Define a variable stack of float
BUFFER_DEF(buffer_floats, float, 0, BUFFER_STACK|BUFFER_BLOCKING)
BUFFER_DEF(buffer_floats, float, 0, BUFFER_STACK)
// Define a fixed stack of char
BUFFER_DEF(buffer_char, char, 10, BUFFER_STACK|BUFFER_UNBLOCKING)
// Define a fixed queue of long long
BUFFER_DEF(buffer_llong, long long, 16, BUFFER_QUEUE|BUFFER_THREAD_UNSAFE|BUFFER_UNBLOCKING)
BUFFER_DEF(buffer_char, char, 10, BUFFER_STACK)
// Define a buffer of complex structure.
BUFFER_DEF(buffer_mpz, testobj_t, 32, BUFFER_QUEUE, TESTOBJ_OPLIST)
@@ -170,8 +167,7 @@ static void test_global(void)
assert (buffer_uint_size(g_buffB) == 5);
for(unsigned int i = 0; i < 5;i++) {
unsigned int j;
bool b= buffer_uint_pop(&j, g_buffB);
assert(b);
buffer_uint_pop(&j, g_buffB);
assert(j == i);
}
assert (buffer_uint_empty_p(g_buffB));
@@ -182,8 +178,7 @@ static void test_global(void)
assert (buffer_uint_size(g_buffB) == 5);
for(unsigned int i = 0; i < 5;i++) {
unsigned int j;
bool b= buffer_uint_pop(&j, g_buffB);
assert(b);
buffer_uint_pop(&j, g_buffB);
assert(j == i);
}
assert (buffer_uint_empty_p(g_buffB));
@@ -231,56 +226,25 @@ static void test_stack2(void)
buffer_char_init(buff, 10);
for(int i = 0; i < 10; i++) {
c = (char) i;
b = buffer_char_push(buff, c);
b = buffer_char_push_blocking(buff, c, false);
assert (b == true);
assert (buffer_char_empty_p(buff) == false);
}
b = buffer_char_push(buff, c);
b = buffer_char_push_blocking(buff, c, false);
assert (b == false);
assert (buffer_char_full_p(buff) == true);
for(int i = 0; i < 10; i++) {
buffer_char_pop(&c, buff);
b = buffer_char_pop_blocking(&c, buff, false);
assert(b);
assert(c == 9-i);
assert (buffer_char_full_p(buff) == false);
}
b = buffer_char_pop(&c, buff);
b = buffer_char_pop_blocking(&c, buff, false);
assert (b == false);
assert (buffer_char_empty_p(buff) == true);
buffer_char_clear(buff);
}
static void test_no_thread(void)
{
buffer_llong_t buff;
bool b;
long long c;
buffer_llong_init(buff, 16);
for(int i = 0; i < 16; i++) {
c = i;
b = buffer_llong_push(buff, c);
assert (b == true);
assert (buffer_llong_empty_p(buff) == false);
}
b = buffer_llong_push(buff, c);
assert (b == false);
assert (buffer_llong_full_p(buff) == true);
for(int i = 0; i < 16; i++) {
buffer_llong_pop(&c, buff);
assert(c == i);
assert (buffer_llong_full_p(buff) == false);
}
b = buffer_llong_pop(&c, buff);
assert (b == false);
assert (buffer_llong_empty_p(buff) == true);
b = buffer_llong_push(buff, c);
assert (b == true);
buffer_llong_reset(buff);
assert (buffer_llong_empty_p(buff) == true);
buffer_llong_clear(buff);
}
static void test_emplace(void)
{
buffer_mpz_t b;
@@ -295,77 +259,44 @@ static void test_emplace(void)
}
/********************************************************************************************/
/* Test intrusive shared pointer + buffer */
#include "m-i-shared.h"
/* Test integration shared pointer + buffer */
#include "m-shared-ptr.h"
// Tiny test structure
typedef struct test_s {
ISHARED_PTR_INTERFACE(ishared_itest, struct test_s);
char buffer[52];
char bigbuffer[1000000];
} test_t;
static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); }
static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); }
ISHARED_PTR_DEF(ishared_itest, test_t,
(INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(free)))
SHARED_PTR_DEF(shared_test, test_t, (INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR)))
typedef struct test2_s {
ISHARED_PTR_INTERFACE(ishared_itest2, struct test_s);
char buffer[52];
} test2_t;
static inline void ishared_itest2_init_data(test2_t *d)
{
memset(d->buffer, 0, sizeof (d->buffer));
}
ISHARED_PTR_DEF(ishared_itest2, test2_t, (INIT(API_2(ishared_itest2_init_data)), CLEAR(M_NOTHING_DEFAULT)))
typedef struct test3_s {
ISHARED_PTR_INTERFACE(ishared_itest3, struct test_s);
char buffer[52];
} test3_t;
ISHARED_PTR_DEF(ishared_itest3, test3_t, (CLEAR(M_NOTHING_DEFAULT)))
typedef struct test4_s {
ISHARED_PTR_INTERFACE(ishared_itest4, struct test_s);
char buffer[52];
} test4_t;
ISHARED_PTR_DEF(ishared_itest4, test4_t, (INIT(0), DEL(0), INIT(M_MEMSET_DEFAULT), CLEAR(M_NOTHING_DEFAULT)))
static test_t *test_new(void)
{
test_t *p = M_ASSIGN_CAST(test_t*, malloc (sizeof (test_t)));
assert (p != NULL);
test_init (p);
return ishared_itest_init(p);
}
BUFFER_DEF(buffer_itest, test_t *, 16, BUFFER_PUSH_INIT_POP_MOVE,
ISHARED_PTR_OPLIST(ishared_itest))
BUFFER_DEF(buffer_itest, shared_test_t *, 16, BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(shared_test, (INIT(1), CLEAR(1))))
static buffer_itest_t comm1;
static buffer_itest_t comm2;
static void test_conso1(void *arg)
{
test_t *p;
shared_test_t *p;
assert (arg == NULL);
for(int i = 0; i < 10;i++) {
buffer_itest_pop(&p, comm1);
for(int j = 0; j < 52; j++)
assert (p->buffer[j] == (char) ((j * j * 17) + j * 42 + 1));
ishared_itest_clear(p);
assert (shared_test_ref(p)->buffer[j] == (char) ((j * j * 17) + j * 42 + 1));
shared_test_release(p);
}
}
static void test_conso2(void *arg)
{
test_t *p;
shared_test_t *p;
assert (arg == NULL);
for(int i = 0; i < 10;i++) {
buffer_itest_pop(&p, comm2);
for(int j = 0; j < 52; j++)
assert (p->buffer[j] == (char) ((j * j * 17) + j * 42 + 1));
ishared_itest_clear(p);
assert (shared_test_ref(p)->buffer[j] == (char) ((j * j * 17) + j * 42 + 1));
shared_test_release(p);
}
}
@@ -373,13 +304,13 @@ static void test_prod(void *arg)
{
assert (arg == NULL);
for(unsigned int i = 0; i < 10;i++) {
test_t *p = test_new();
shared_test_t *p = shared_test_new();
for(int j = 0; j < 52; j++) {
p->buffer[j] = (char) ((j * j * 17) + j * 42 + 1);
shared_test_ref(p)->buffer[j] = (char) ((j * j * 17) + j * 42 + 1);
}
buffer_itest_push(comm1, p);
buffer_itest_push(comm2, p);
ishared_itest_clear(p);
shared_test_clear(p);
}
}
@@ -582,33 +513,25 @@ static void test_spsc(void)
static void test_double1(void)
{
bool b;
M_LET(buffer, BufferDouble1) {
b = BufferDouble1_push(buffer, 0.0);
assert(b);
b= BufferDouble1_push(buffer, 1.0);
assert(b);
BufferDouble1_push(buffer, 0.0);
BufferDouble1_push(buffer, 1.0);
double d;
b = BufferDouble1_pop(&d, buffer);
assert(b);
BufferDouble1_pop(&d, buffer);
assert(d == 0.0);
b = BufferDouble1_pop(&d, buffer);
assert(b);
BufferDouble1_pop(&d, buffer);
assert(d == 1.0);
}
}
static void test_double2(void)
{
bool b;
BufferDouble2 buffer;
BufferDouble2_init(buffer, 2);
b = BufferDouble2_push(buffer, 0.0);
assert(b);
b= BufferDouble2_push(buffer, 1.0);
assert(b);
BufferDouble2_push(buffer, 0.0);
BufferDouble2_push(buffer, 1.0);
double d;
b = BufferDouble2_pop(&d, buffer);
bool b = BufferDouble2_pop(&d, buffer);
assert(b);
assert(d == 0.0);
b = BufferDouble2_pop(&d, buffer);
@@ -619,15 +542,12 @@ static void test_double2(void)
static void test_double3(void)
{
bool b;
BufferDouble3 buffer;
BufferDouble3_init(buffer, 2);
b = BufferDouble3_push(buffer, 0.0);
assert(b);
b= BufferDouble3_push(buffer, 1.0);
assert(b);
BufferDouble3_push(buffer, 0.0);
BufferDouble3_push(buffer, 1.0);
double d;
b = BufferDouble3_pop(&d, buffer);
bool b = BufferDouble3_pop(&d, buffer);
assert(b);
assert(d == 0.0);
b = BufferDouble3_pop(&d, buffer);
@@ -668,7 +588,6 @@ int main(void)
test_global();
test_stack();
test_stack2();
test_no_thread();
test_emplace();
test_global_ishared();
test_queue(1000000, 2, 2148371710223136ULL);
-208
View File
@@ -1,208 +0,0 @@
/*
* M*LIB - Test for Concurrent memory pool allocator
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "m-c-mempool.h"
#include "m-thread.h"
C_MEMPOOL_DEF(lf_mempool, int)
m_gc_t gc;
/**********************************************************************/
#define MAX_VALUE 100
#define MAX_THREAD 4
lf_mempool_t g;
typedef struct {
int step;
int *ptr[MAX_VALUE];
int value[MAX_VALUE];
} p_t;
p_t g_tab[MAX_THREAD];
static void do_stuff(m_gc_tid_t id)
{
// Mix of local and more global allocation
int *d[MAX_VALUE];
for(int i = 0; i < MAX_VALUE; i++) {
d[i] = lf_mempool_new(g, id);
*d[i] = i*i;
}
switch (g_tab[id].step)
{
case 0:
for(int i = 0; i < 50; i++) {
g_tab[id].value[i] += i;
g_tab[id].ptr[i] = lf_mempool_new(g, id);
*g_tab[id].ptr[i] = g_tab[id].value[i];
}
g_tab[id].step = 1;
break;
case 1:
for(int i = 50; i < MAX_VALUE; i++) {
g_tab[id].value[i] += i;
g_tab[id].ptr[i] = lf_mempool_new(g, id);
*g_tab[id].ptr[i] = g_tab[id].value[i];
}
g_tab[id].step = 2;
break;
case 2:
for(int i = 0; i < 50; i++) {
assert(g_tab[id].ptr[i] != NULL);
assert(*g_tab[id].ptr[i] == g_tab[id].value[i] );
lf_mempool_del(g, g_tab[id].ptr[i], id);
g_tab[id].ptr[i] = NULL;
}
g_tab[id].step = 3;
break;
case 3:
for(int i = 50; i < MAX_VALUE; i++) {
assert(g_tab[id].ptr[i] != NULL);
assert(*g_tab[id].ptr[i] == g_tab[id].value[i] );
lf_mempool_del(g, g_tab[id].ptr[i], id);
g_tab[id].ptr[i] = NULL;
}
g_tab[id].step = 0;
break;
default:
break;
}
for(int i = 0; i < MAX_VALUE; i++) {
assert (*d[i] == i*i);
lf_mempool_del(g, d[i], id);
}
}
static void thread1(void *arg)
{
(void)arg;
/* Attach this thread to the GC */
m_gc_tid_t id = m_gc_attach_thread(gc);
for(int n = 0; n < 100000; n ++) {
/* Awake the thread: now we can alloc nodes */
m_gc_awake(gc, id);
/* Do some stuff */
do_stuff(id);
/* Sleep the thread. A Garbage Collect may occur if possible */
m_gc_sleep(gc, id);
}
/* Detach the thread from the GC */
m_gc_detach_thread(gc, id);
}
static void thread2(void *arg)
{
(void)arg;
m_gc_tid_t id = m_gc_attach_thread(gc);
for(int n = 0; n < 10000; n ++) {
m_gc_awake(gc, id);
do_stuff(id);
m_thread_sleep(1);
m_gc_sleep(gc, id);
}
m_gc_detach_thread(gc, id);
}
static void test(void)
{
/* First create the Garbage Collector */
m_gc_init (gc, MAX_THREAD);
/* Create a mempool and attach it to the Garbage Collector */
lf_mempool_init(g, gc, 256, MAX_THREAD);
m_thread_t id[MAX_THREAD];
for(int i = 0; i < MAX_THREAD; i+=2) {
m_thread_create(id[i], thread1, NULL);
m_thread_create(id[i+1], thread2, NULL);
}
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_join(id[i]);
}
/* Destroy the mempool */
lf_mempool_clear(g);
/* Destroy the Garbage Collector */
m_gc_clear (gc);
}
static void test2(void)
{
/* First create the Garbage Collector */
m_gc_init (gc, MAX_THREAD);
/* Create a mempool and attach it to the Garbage Collector */
lf_mempool_init(g, gc, 256, MAX_THREAD);
/* Create another mempool and attach it to the Garbage Collector */
lf_mempool_t g2;
lf_mempool_init(g2, gc, 256, MAX_THREAD);
/* Register VLA */
m_vlapool_t vla;
m_vlapool_init(vla, gc);
/* Attach the thread */
m_gc_tid_t id = m_gc_attach_thread(gc);
/* Awake the thread: now we can alloc nodes */
m_gc_awake(gc, id);
/* Test some allocation */
void *ptr = m_vlapool_new(vla, id, sizeof (int));
*(int*)ptr = 42;
m_vlapool_del(vla, ptr, id);
int *pi = lf_mempool_new(g, id);
*pi = 44;
lf_mempool_del(g, pi, id);
int *pi2 = lf_mempool_new(g2, id);
*pi2 = 46;
lf_mempool_del(g2, pi2, id);
/* Test that the data remain accessible
as it has only be logically deleted */
assert (*(int*)ptr == 42);
assert (*pi == 44);
assert (*pi2 == 46);
/* Sleep the thread */
m_gc_sleep(gc, id);
/* Detach the thread */
m_gc_detach_thread(gc, id);
/* Clear everything */
m_vlapool_clear(vla);
lf_mempool_clear(g);
lf_mempool_clear(g2);
m_gc_clear(gc);
}
int main(void)
{
test();
test2();
exit(0);
}
-250
View File
@@ -1,250 +0,0 @@
/*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "coverage.h"
#include "m-array.h"
#include "m-bptree.h"
#include "m-deque.h"
#include "m-dict.h"
#include "m-list.h"
#include "m-prioqueue.h"
#include "m-rbtree.h"
#include "m-tuple.h"
#include "m-variant.h"
#include "m-concurrent.h"
TUPLE_DEF2(point, (x, int), (y, int))
#define M_OPL_point_t() TUPLE_OPLIST(point, M_BASIC_OPLIST, M_BASIC_OPLIST)
START_COVERAGE
CONCURRENT_DEF(ppoint, point_t)
END_COVERAGE
VARIANT_DEF2(dimension, (x, int), (y, float))
#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_BASIC_OPLIST, M_BASIC_OPLIST)
CONCURRENT_DEF(pdimension, dimension_t)
ARRAY_DEF(array1, int)
CONCURRENT_DEF(parray1, array1_t, ARRAY_OPLIST(array1))
DICT_DEF2(dict1, int, int)
CONCURRENT_DEF(pdict1, dict1_t, DICT_OPLIST(dict1))
DICT_SET_DEF(dict2, int)
CONCURRENT_DEF(pdict2, dict2_t, DICT_SET_OPLIST(dict2))
LIST_DEF(list1, int)
CONCURRENT_DEF(plist1, list1_t, LIST_OPLIST(list1))
LIST_DUAL_PUSH_DEF(list2, int)
CONCURRENT_DEF(plist2, list2_t, LIST_OPLIST(list2))
DEQUE_DEF(deque1, int)
CONCURRENT_DEF(pdeque1, deque1_t, DEQUE_OPLIST(deque1))
PRIOQUEUE_DEF(prio1, int)
CONCURRENT_DEF(pprio1, prio1_t, PRIOQUEUE_OPLIST(prio1))
BPTREE_DEF2(bptree1, 10, int, int)
CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_BASIC_OPLIST, M_BASIC_OPLIST))
BPTREE_DEF(bptree2, 10, int)
CONCURRENT_DEF(pbtree2, bptree2_t, BPTREE_OPLIST(bptree2))
RBTREE_DEF(rbtree1, int)
CONCURRENT_DEF(prbtree1, rbtree1_t, RBTREE_OPLIST(rbtree1))
DICT_DEF2(string_pool, string_t, string_t)
#define STRING_POOL_OPLIST \
DICT_OPLIST(string_pool, STRING_OPLIST, STRING_OPLIST)
#define M_OPL_string_pool_t() STRING_POOL_OPLIST
CONCURRENT_DEF(string_pool_ts, string_pool_t, STRING_POOL_OPLIST)
#define STRING_POOL_TS_OPLIST \
CONCURRENT_OPLIST(string_pool_ts, STRING_POOL_OPLIST)
#define M_OPL_string_pool_ts_t() STRING_POOL_TS_OPLIST
TUPLE_DEF2(my_tuple, (pool, string_pool_ts_t))
#define MY_TUPLE_OPLIST TUPLE_OPLIST(my_tuple, STRING_POOL_TS_OPLIST)
#define M_OPL_my_tuple_t() MY_TUPLE_OPLIST
ARRAY_DEF(key_list, string_t)
#define M_OPL_key_list_t() ARRAY_OPLIST(key_list, STRING_OPLIST)
CONCURRENT_DEF(key_list_ts, key_list_t)
CONCURRENT_RP_DEF(rparray1, array1_t, ARRAY_OPLIST(array1))
CONCURRENT_RP_DEF(rpdict1, dict1_t, DICT_OPLIST(dict1))
CONCURRENT_DEF_AS(ConcurrentDouble, ConcurrentDouble, double)
CONCURRENT_RP_DEF_AS(ConcurrentRpDouble, ConcurrentRpDouble, double)
/* OA dict needs more operators than the default ones to work */
static inline bool int_oor_equal_p(int s, unsigned char n)
{
return s == -n;
}
static inline void int_oor_set(int *s, unsigned char n)
{
*s = -n;
}
#define INT_OA_OPLIST \
M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set)))
DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_BASIC_OPLIST)
CONCURRENT_DEF(pdict3, dict3_t, DICT_OPLIST(dict3))
/********************************/
parray1_t arr;
static void conso(void *p)
{
assert (p == NULL);
for(int i = 0; i < 1000; i++) {
int j;
bool b = parray1_pop_blocking(&j, arr, true);
assert (b);
assert (j == i);
}
}
static void test_thread(void)
{
m_thread_t idx;
parray1_init(arr);
m_thread_create (idx, conso, NULL);
m_thread_sleep(1000);
for(int i = 0; i < 1000; i++) {
parray1_push (arr, i);
while (!parray1_empty_p(arr));
}
m_thread_join(idx);
parray1_clear(arr);
}
static void test_basic(void)
{
pdict1_t dict;
pdict1_init(dict);
int z;
pdict1_set_at(dict, 2, 3);
pdict1_get_copy(&z, dict, 2);
assert (z == 3);
z = 1;
bool b = pdict1_get_blocking(&z, dict, 2, false);
assert (b);
assert (z == 3);
assert (pdict1_size(dict) == 1);
pdict1_clear(dict);
M_LET(str, string_t)
M_LET(pool, string_pool_ts_t) {
string_pool_ts_set_at (pool, STRING_CTE("A"), STRING_CTE("B"));
b = string_pool_ts_get_copy (&str, pool, STRING_CTE("A"));
assert (b);
assert (string_equal_str_p (str, "B"));
}
M_LET(tuple, my_tuple_t) {
assert (string_pool_ts_empty_p(tuple->pool));
}
}
rparray1_t rarr;
static void conso_rp(void *p)
{
assert (p == NULL);
for(int i = 0; i < 1000; i++) {
int j;
bool b = rparray1_pop_blocking(&j, rarr, true);
assert (b);
assert (j == i);
}
}
static void test_rp_thread(void)
{
m_thread_t idx;
rparray1_init(rarr);
m_thread_create (idx, conso_rp, NULL);
m_thread_sleep(1000);
for(int i = 0; i < 1000; i++) {
rparray1_push (rarr, i);
while (!rparray1_empty_p(rarr));
}
m_thread_join(idx);
rparray1_clear(rarr);
}
static void test_rp_basic(void)
{
rpdict1_t dict;
rpdict1_init(dict);
int z = 0;
rpdict1_set_at(dict, 2, 3);
rpdict1_get_copy(&z, dict, 2);
assert (z == 3);
z = 1;
bool b = rpdict1_get_blocking(&z, dict, 2, false);
assert (b);
assert (z == 3);
assert (rpdict1_size(dict) == 1);
rpdict1_clear(dict);
}
static void test_double(void)
{
ConcurrentDouble d;
ConcurrentDouble_init(d);
ConcurrentDouble_reset(d);
ConcurrentDouble_clear(d);
ConcurrentRpDouble r;
ConcurrentRpDouble_init(r);
ConcurrentRpDouble_reset(r);
ConcurrentRpDouble_clear(r);
}
static void test_emplace(void)
{
key_list_ts_t ts;
key_list_ts_init(ts);
key_list_ts_emplace(ts, "HELLO");
M_LET(s, string_t) {
key_list_ts_pop(&s, ts);
assert(string_equal_str_p(s, "HELLO"));
}
key_list_ts_clear(ts);
}
int main(void)
{
test_basic();
test_rp_basic();
test_thread();
test_rp_thread();
test_double();
test_emplace();
exit(0);
}
+11 -25
View File
@@ -29,9 +29,8 @@
#define M_F(a,b) M_OVERRIDE_F(a,b)
#define M_OVERRIDE__method() , _get_method ,
#define M_OVERRIDE__method2() , _get_method2
#include "m-core.h"
#include "test-obj.h"
#include "m-core.h"
static bool tmp_init(void) { return true; }
static bool tmp_get_method(void) { return true; }
@@ -747,65 +746,54 @@ typedef struct { int b,c; } ts;
static void f_ti(ti x)
{
ti y;
M_MOVE_A1_DEFAULT(y,x);
M_COPY_A1_DEFAULT(y,x);
assert(y[0] == 9);
assert(x[0] == 0);
}
static void f_ts(ts x)
{
ts y;
M_MOVE_DEFAULT(y,x);
M_SET_DEFAULT(y,x);
assert(y.b == 2);
assert(y.c == 3);
assert(x.b == 0);
assert(x.c == 0);
}
static void f_ts2(ts *x)
{
ts y;
M_MOVE_DEFAULT(y,*x);
M_SET_DEFAULT(y,*x);
assert(y.b == 2);
assert(y.c == 3);
assert(x->b == 0);
assert(x->c == 0);
}
static void test_move_default(void)
{
int o, p;
o = 9;
M_MOVE_DEFAULT(p, o);
M_SET_DEFAULT(p, o);
assert(p == 9);
assert(o == 0);
double u, k;
k = -1.0;
u = 9.5;
M_MOVE_DEFAULT(k, u);
M_SET_DEFAULT(k, u);
assert(k == 9.5);
assert(u == 0.0); // NOTE: memset(0) sets an IEEE-754 number to 0.0
int *ptr = &o, *m;
M_MOVE_DEFAULT(m, ptr);
assert( ptr == NULL);
assert( m == &o);
M_SET_DEFAULT(m, ptr);
(void)m;
ti x, y;
x[0] = 9;
M_MOVE_A1_DEFAULT(y, x);
M_COPY_A1_DEFAULT(y, x);
assert(y[0] == 9);
assert(x[0] == 0);
x[0] = 9;
f_ti(x);
assert(x[0] == 0);
ts y2, x2 = { 2, 3};
M_MOVE_DEFAULT(y2, x2);
M_SET_DEFAULT(y2, x2);
assert(y2.b == 2 && y2.c == 3);
assert(x2.b == 0 && x2.c == 0);
x2.b = 2; x2.c = 3;
f_ts(x2);
@@ -813,8 +801,6 @@ static void test_move_default(void)
assert(x2.c == 3);
f_ts2(&x2);
assert(x2.b == 0);
assert(x2.c == 0);
}
static void test_builtin(void)
+1 -1
View File
@@ -35,7 +35,7 @@ END_COVERAGE
DEQUE_DEF(deque_mpz, testobj_t, TESTOBJ_OPLIST)
// Deque with the minimum number of methods.
DEQUE_DEF(deque_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
DEQUE_DEF(deque_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) ))
// Dequeue of an enumerate
typedef enum {
+3 -4
View File
@@ -21,17 +21,16 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <assert.h>
#include "test-obj.h"
#include "m-dict.h"
#include "m-array.h"
#include "m-string.h"
#include "test-obj.h"
#include "coverage.h"
static inline bool oor_equal_p(int k, unsigned char n) { return k == (int)-n-1; }
static inline void oor_set(int *k, unsigned char n) { *k = (int)-n-1; }
static inline void update_value (int *p, const int p1, const int p2) { *p = p1 + p2; }
#include "coverage.h"
START_COVERAGE
DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST)
DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_OPEXTEND(M_BASIC_OPLIST, ADD(update_value M_IPTR)))
-1
View File
@@ -20,7 +20,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-funcobj.h"
+3 -7
View File
@@ -21,19 +21,15 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#include <assert.h>
#include "coverage.h"
#include "test-obj.h"
#include "m-string.h"
#include "m-array.h"
#include "m-list.h"
#include "m-generic.h"
#include "coverage.h"
// Generic is not supported if not C11
// TCC has some issues in the preprocessing.
// See https://lists.nongnu.org/archive/html/tinycc-devel/2025-12/msg00004.html
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__TINYC__)
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
ARRAY_DEF(array_int, int)
#define M_OPL_array_int_t() ARRAY_OPLIST(array_int, M_BASIC_OPLIST)
+1 -2
View File
@@ -20,12 +20,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-thread.h"
#include "m-atomic.h"
#include "m-core.h"
#include "coverage.h"
#include "m-genint.h"
#define MAX_N 256
+3 -4
View File
@@ -22,9 +22,9 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-i-list.h"
#include "coverage.h"
typedef struct test_s {
int n;
@@ -37,12 +37,11 @@ static inline bool test_equal_p(const test_t *i1, const test_t *i2)
return i1->n == i2->n;
}
#include "coverage.h"
START_COVERAGE
ILIST_DEF(ilist_tname, test_t, M_OPEXTEND(M_POD_OPLIST, EQUAL(API_6(test_equal_p))))
END_COVERAGE
ILIST_DEF(ilist_free, test_t, (DEL(free)))
ILIST_DEF(ilist_free, test_t, (DEL(API(free, NONE, ARG2))))
typedef struct testd_s {
double n;
-153
View File
@@ -1,153 +0,0 @@
/*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include "test-obj.h"
#include "m-i-shared.h"
#include "m-thread.h"
#include "coverage.h"
typedef struct ishared_s {
ISHARED_PTR_INTERFACE(ishared1, struct ishared_s);
ISHARED_PTR_INTERFACE(ishared2, struct ishared_s);
int data[100];
} ishared_t[1];
static bool ishared_init_sleep = false;
static void ishared_init_data(struct ishared_s *x)
{
for(int i = 0 ; i < 100; i++)
x->data[i] = i * i;
if (ishared_init_sleep) {
// Slow down init
m_thread_sleep(100);
}
}
static void ishared_test(struct ishared_s *x)
{
for(int i = 0 ; i < 100; i++) {
assert (x->data[i] == i*i);
}
}
START_COVERAGE
ISHARED_PTR_DEF(ishared1, struct ishared_s, (INIT(API_2(ishared_init_data))))
ISHARED_PTR_DEF(ishared2, struct ishared_s, (INIT(API_2(ishared_init_data)), NEW(0), DEL(0)) )
END_COVERAGE
/*ISHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double) */
static void test_single(void)
{
ishared1_t p1, p2;
p1 = ishared1_init_new();
ishared_test(p1);
p2 = ishared1_init_set(p1);
ishared_test(p2);
ishared1_clear(p1);
ishared_test(p2);
p1 = ishared1_init(NULL);
ishared1_set(&p1, p2);
ishared1_reset(&p2);
assert(p2 == NULL);
ishared_test(p1);
ishared1_clear(p1);
p1 = ishared1_init_set(p2);
assert(p1 == NULL);
ishared1_clear(p1);
ishared1_clear(p2);
struct ishared_s *x = (struct ishared_s *) malloc(sizeof (struct ishared_s));
assert(x != NULL);
ishared_init_data(x);
p1 = ishared1_init(x);
ishared_test(p1);
ishared1_clear(p1);
}
static struct ishared_s g_var = {
ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s),
ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s),
{ 0 }
};
static void test_static(void)
{
ishared2_t p1, p2;
p1 = ishared2_init_once(NULL);
assert(p1 == NULL);
p1 = ishared2_init_once(&g_var);
ishared_test(p1);
p2 = ishared2_init_once(&g_var);
ishared_test(p2);
ishared2_clear(p1);
ishared_test(p2);
ishared2_clear(p2);
}
#define MAX_THREAD 128
#define MAX_VAR 5
#define VAL(x) { ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), { 0 } }
static struct ishared_s g_tab[MAX_VAR] = {
M_MAP_C(VAL, M_SEQ(1, MAX_VAR))
};
static void func(void *arg)
{
int id = (int)(intptr_t) arg;
int v = id % MAX_VAR;
ishared2_t p = ishared2_init_once(&g_tab[v]);
for(int i = 0; i < 100; i++) {
ishared_test(p);
}
ishared2_clear(p);
}
static void test_shared(void)
{
m_thread_t id[MAX_THREAD];
ishared_init_sleep = true;
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_create(id[i], func, (void*) (intptr_t) i);
}
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_join(id[i]);
}
ishared_init_sleep = false;
}
int main(void)
{
test_single();
test_static();
test_shared();
exit(0);
}
+3 -4
View File
@@ -20,12 +20,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-list.h"
#include "coverage.h"
START_COVERAGE
LIST_DEF(list_uint, unsigned int)
LIST_DEF(list_mpz, testobj_t, TESTOBJ_OPLIST)
@@ -36,8 +35,8 @@ LIST_DUAL_PUSH_DEF(list2_mpz, testobj_t, TESTOBJ_OPLIST)
#define LIST2_DOUBLE_OPLIST LIST_OPLIST(list2_double)
// Array with the minimum number of methods.
LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear)))
LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) ))
LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT)))
LIST_DEF(list_string, string_t)
#define M_OPL_list_string_t() LIST_OPLIST(list_string, STRING_OPLIST)
-109
View File
@@ -1,109 +0,0 @@
/*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include "m-mempool.h"
#include "coverage.h"
START_COVERAGE
MEMPOOL_DEF(mempool_uint, unsigned int)
END_COVERAGE
MEMPOOL_DEF_AS(MempoolDouble, MempoolDouble, unsigned int)
static void test(void)
{
mempool_uint_t m;
mempool_uint_init(m);
unsigned int *tab[100000];
for(unsigned int i = 0; i < 100000; i++) {
tab[i] = mempool_uint_alloc(m);
*tab[i] = i;
}
for(unsigned int i = 0; i < 100000; i++) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i+=2) {
mempool_uint_free(m, tab[i]);
tab[i] = NULL;
}
for(unsigned int i = 1; i < 100000; i+=2) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i+=2) {
tab[i] = mempool_uint_alloc(m);
*tab[i] = i;
}
for(unsigned int i = 0; i < 100000; i++) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i++) {
mempool_uint_free(m, tab[i]);
tab[i] = NULL;
}
mempool_uint_clear(m);
}
static void test_double(void)
{
MempoolDouble m;
MempoolDouble_init(m);
unsigned int *tab[100000];
for(unsigned int i = 0; i < 100000; i++) {
tab[i] = MempoolDouble_alloc(m);
*tab[i] = i;
}
for(unsigned int i = 0; i < 100000; i++) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i+=2) {
MempoolDouble_free(m, tab[i]);
tab[i] = NULL;
}
for(unsigned int i = 1; i < 100000; i+=2) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i+=2) {
tab[i] = MempoolDouble_alloc(m);
*tab[i] = i;
}
for(unsigned int i = 0; i < 100000; i++) {
assert (*tab[i] == i);
}
for(unsigned int i = 0; i < 100000; i++) {
MempoolDouble_free(m, tab[i]);
tab[i] = NULL;
}
MempoolDouble_clear(m);
}
int main(void)
{
test();
test_double();
exit(0);
}
+1 -3
View File
@@ -20,13 +20,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <assert.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-prioqueue.h"
#include "coverage.h"
START_COVERAGE
PRIOQUEUE_DEF(int_pqueue, int)
END_COVERAGE
+171
View File
@@ -0,0 +1,171 @@
/*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-obj.h"
#include "m-queue.h"
#include "coverage.h"
START_COVERAGE
STACK_DEF(stack_obj, testobj_t, 0, TESTOBJ_OPLIST)
END_COVERAGE
M_QUEUE_DEF(queue_obj, testobj_t, 10, TESTOBJ_OPLIST)
M_STACK_DEF(stack_int, int, 15)
QUEUE_DEF(buffer_llong, long long, 0)
static void test_obj(void)
{
stack_obj_t b1, b2;
testobj_t o;
bool b;
testobj_init(o);
stack_obj_init(b1, 24);
assert( stack_obj_empty_p(b1) == true);
assert( stack_obj_full_p(b1) == false);
assert( stack_obj_size(b1) == 0);
assert( stack_obj_capacity(b1) == 24);
stack_obj_reset(b1);
assert( stack_obj_empty_p(b1) == true);
assert( stack_obj_full_p(b1) == false);
assert( stack_obj_size(b1) == 0);
for(unsigned i = 0; i < 24; i++) {
testobj_set_ui(o, i);
assert( stack_obj_full_p(b1) == false);
b = stack_obj_push(b1, o);
assert(b);
assert( stack_obj_empty_p(b1) == false);
assert( stack_obj_size(b1) == i+1);
}
assert( stack_obj_full_p(b1) == true);
assert( stack_obj_size(b1) == 24);
b = stack_obj_push(b1, o);
assert(!b);
assert( stack_obj_size(b1) == 24);
for(unsigned i = 23; i < 24; i--) {
testobj_set_ui(o, i);
assert( stack_obj_empty_p(b1) == false);
b = stack_obj_pop(&o, b1);
assert(b);
assert( stack_obj_full_p(b1) == false);
assert( stack_obj_size(b1) == i);
assert( testobj_cmp_ui(o, i) == 0);
}
assert( stack_obj_empty_p(b1) == true);
assert( stack_obj_size(b1) == 0);
b = stack_obj_pop(&o, b1);
assert(!b);
assert( stack_obj_size(b1) == 0);
for(unsigned i = 0; i < 24; i++) {
testobj_set_ui(o, i);
assert( stack_obj_full_p(b1) == false);
b = stack_obj_push(b1, o);
assert(b);
assert( stack_obj_empty_p(b1) == false);
assert( stack_obj_size(b1) == i+1);
}
stack_obj_init_set(b2, b1);
stack_obj_reset(b1);
assert( stack_obj_empty_p(b1) == true);
assert( stack_obj_size(b1) == 0);
b = stack_obj_pop(&o, b1);
assert(!b);
assert( stack_obj_size(b1) == 0);
assert( stack_obj_full_p(b2) == true);
assert( stack_obj_size(b2) == 24);
b = stack_obj_push(b2, o);
assert(!b);
assert( stack_obj_size(b2) == 24);
stack_obj_set(b1, b2);
assert( stack_obj_size(b1) == 24);
stack_obj_clear(b1);
stack_obj_clear(b2);
testobj_clear(o);
}
static void test_queue_llong(void)
{
buffer_llong_t buff;
bool b;
long long c;
buffer_llong_init(buff, 16);
assert (buffer_llong_empty_p(buff) == true);
for(int i = 0; i < 16; i++) {
assert (buffer_llong_full_p(buff) == false);
c = i;
b = buffer_llong_push(buff, c);
assert (b == true);
assert (buffer_llong_empty_p(buff) == false);
}
assert (buffer_llong_full_p(buff) == true);
b = buffer_llong_push(buff, c);
assert (b == false);
for(int i = 0; i < 16; i++) {
assert (buffer_llong_empty_p(buff) == false);
buffer_llong_pop(&c, buff);
assert(c == i);
assert (buffer_llong_full_p(buff) == false);
}
assert (buffer_llong_empty_p(buff) == true);
b = buffer_llong_pop(&c, buff);
assert (b == false);
b = buffer_llong_push(buff, c);
assert (b == true);
assert (buffer_llong_empty_p(buff) == false);
buffer_llong_reset(buff);
assert (buffer_llong_empty_p(buff) == true);
buffer_llong_clear(buff);
}
static void test_emplace(void)
{
stack_obj_t b;
stack_obj_init(b, 32);
stack_obj_emplace_str(b, "56");
testobj_t o;
testobj_init(o);
stack_obj_pop(&o, b);
assert( testobj_cmp_ui(o, 56) == 0 );
testobj_clear(o);
stack_obj_clear(b);
}
int main(void)
{
test_obj();
test_queue_llong();
test_emplace();
testobj_final_check();
exit(0);
}
+1 -2
View File
@@ -20,10 +20,10 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-rbtree.h"
#include "coverage.h"
static bool uint_in_str(unsigned int *u, FILE *f)
{
@@ -49,7 +49,6 @@ static void uint_get_str(string_t str, unsigned int u, bool append)
(append ? string_cat_printf : string_printf) (str, "%u", u);
}
#include "coverage.h"
START_COVERAGE
RBTREE_DEF(rbtree_uint, unsigned int, M_OPEXTEND(M_BASIC_OPLIST, IN_STR(uint_in_str M_IPTR), OUT_STR(uint_out_str), GET_STR(uint_get_str), PARSE_STR(uint_parse_str M_IPTR)) )
END_COVERAGE
+1
View File
@@ -20,6 +20,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-obj.h"
#include "m-tuple.h"
#include "m-array.h"
#include "m-variant.h"
+1
View File
@@ -20,6 +20,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-obj.h"
#include "m-tuple.h"
#include "m-array.h"
#include "m-variant.h"
+1 -4
View File
@@ -20,10 +20,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-shared-ptr.h"
#include "m-string.h"
#include "m-array.h"
#include "m-bptree.h"
@@ -34,7 +32,6 @@
#include "m-rbtree.h"
#include "m-tuple.h"
#include "m-variant.h"
#include "coverage.h"
// TEST WITH INT
-249
View File
@@ -1,249 +0,0 @@
/*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include "test-obj.h"
#include "m-shared.h"
#include "coverage.h"
START_COVERAGE
SHARED_PTR_DEF(shared_int, int)
SHARED_RESOURCE_DEF(shared_ressource, testobj_t, TESTOBJ_OPLIST)
END_COVERAGE
SHARED_PTR_DEF(shared_mpz, testobj_t, TESTOBJ_OPLIST)
SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int)
SHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double)
SHARED_PTR_RELAXED_DEF_AS(SharedDouble2, SharedDouble2, double, M_BASIC_OPLIST)
SHARED_RESOURCE_DEF_AS(SharedRessource, SharedRessource, SharedRessourceIt, double)
// Test with incomplete structure
struct incomplete_s;
extern void incomplete_clear(struct incomplete_s *ptr);
SHARED_PTR_DEF( shared_incomplete, struct incomplete_s, (INIT(0), CLEAR(API_2(incomplete_clear))) )
static int f(const shared_int_t p)
{
return *shared_int_cref(p);
}
static void test1(void)
{
shared_int_t p1, p2;
int *p = M_ASSIGN_CAST(int*, malloc(sizeof(int)));
assert (p != NULL);
shared_int_init2(p1, p);
assert(!shared_int_NULL_p(p1));
assert(shared_int_ref(p1) != NULL);
*shared_int_ref(p1) = 12;
shared_int_init_set(p2, p1);
assert(f(p2) == 12);
shared_int_reset(p1);
assert(shared_int_NULL_p(p1));
assert(!shared_int_NULL_p(p2));
assert(f(p2) == 12);
shared_int_set(p1, p2);
shared_int_reset(p2);
assert(!shared_int_NULL_p(p1));
assert(shared_int_NULL_p(p2));
assert(f(p1) == 12);
shared_int_set(p2, p1);
assert(!shared_int_NULL_p(p1));
assert(!shared_int_NULL_p(p2));
assert(f(p2) == 12);
shared_int_reset(p2);
shared_int_reset(p1);
assert(shared_int_NULL_p(p1));
assert(shared_int_NULL_p(p2));
shared_int_clear(p2);
shared_int_clear(p1);
shared_int_init2(p1, NULL);
assert(shared_int_NULL_p(p1));
shared_int_clear(p1);
shared_int_init(p1);
assert(shared_int_NULL_p(p1));
shared_int_clear(p1);
shared_int_init_new(p1);
assert(!shared_int_NULL_p(p1));
*shared_int_ref(p1) = 1;
shared_int_init_new(p2);
assert(!shared_int_NULL_p(p2));
*shared_int_ref(p2) = 2;
assert(!shared_int_equal_p(p1, p2));
assert (*shared_int_cref(p1) == 1);
assert (*shared_int_cref(p2) == 2);
shared_int_swap(p1, p2);
assert (*shared_int_cref(p1) == 2);
assert (*shared_int_cref(p2) == 1);
shared_int_set(p1, p2);
assert(shared_int_equal_p(p1, p2));
assert (*shared_int_cref(p1) == 1);
assert (*shared_int_cref(p2) == 1);
shared_int_clear(p1);
shared_int_init_move(p1, p2);
assert (*shared_int_cref(p1) == 1);
shared_int_init_new(p2);
assert (*shared_int_cref(p2) == 0);
shared_int_set(p2, p1);
shared_int_move(p2, p1);
assert (*shared_int_cref(p2) == 1);
shared_int_clear(p2);
}
static void test2(void)
{
shared_int_t p1, p2;
shared_int_init_new (p1);
*shared_int_ref(p1) = 1;
shared_int_init_new (p2);
*shared_int_ref(p2) = 2;
shared_int_set(p1, p2);
assert (*shared_int_ref(p1) == 2);
assert (*shared_int_ref(p2) == 2);
shared_int_clear(p2);
assert (*shared_int_ref(p1) == 2);
shared_int_clear(p1);
}
static void test_emplace(void)
{
shared_mpz_t z;
shared_mpz_init_with_ui(z, 23);
assert ( (*shared_mpz_ref(z))->ptr[0] == 23);
shared_mpz_clear(z);
}
#define MAX_RESSOURCE 10
static void test_ressource(int n)
{
shared_ressource_t ressource;
shared_ressource_it_t it[MAX_RESSOURCE];
shared_ressource_it_t copy[MAX_RESSOURCE];
shared_ressource_it_t onemore;
shared_ressource_init (ressource, (size_t) n);
for(int i = 0; i < n ; i++) {
shared_ressource_it (it[i], ressource);
assert (!shared_ressource_end_p(it[i]));
testobj_t *z = shared_ressource_ref(it[i]);
assert (z != NULL);
testobj_set_ui(*z, (unsigned int) i);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
for(int i = 0; i < n ; i++) {
shared_ressource_it_set (copy[i], it[i]);
assert (!shared_ressource_end_p(copy[i]));
const testobj_t *z = shared_ressource_cref(copy[i]);
assert (z != NULL);
assert (testobj_cmp_ui(*z, (unsigned int) i) == 0);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
for(int i = 0; i < n ; i++) {
shared_ressource_end (it[i], ressource);
}
shared_ressource_it (onemore, ressource);
assert (shared_ressource_end_p(onemore));
for(int i = n-1; i >= 0 ; i--) {
const testobj_t *z = shared_ressource_cref(copy[i]);
assert (z != NULL);
shared_ressource_end (copy[i], ressource);
assert (shared_ressource_end_p(copy[i]));
shared_ressource_it (onemore, ressource);
assert (!shared_ressource_end_p(onemore));
shared_ressource_end (onemore, ressource);
shared_ressource_end (copy[i], ressource);
}
shared_ressource_clear(ressource);
}
static void test_double(void){
SharedDouble p;
SharedDouble_init_new(p);
assert(*SharedDouble_ref(p) == 0.0);
*SharedDouble_ref(p) = 5678.0;
SharedDouble q;
SharedDouble_init_set(q, p);
assert(*SharedDouble_ref(q) == 5678.0);
SharedDouble_clear(p);
SharedDouble_clear(q);
}
static void test_double2(void){
SharedDouble2 p;
SharedDouble2_init_new(p);
assert(*SharedDouble2_ref(p) == 0.0);
*SharedDouble2_ref(p) = 5678.0;
SharedDouble2 q;
SharedDouble2_init_set(q, p);
assert(*SharedDouble2_ref(q) == 5678.0);
SharedDouble2_clear(p);
SharedDouble2_clear(q);
}
static void test_double_res(void){
SharedRessource r;
SharedRessource_init(r, 4);
SharedRessourceIt i;
SharedRessource_it(i, r);
assert(*SharedRessource_ref(i) == 0);
*SharedRessource_ref(i) = 3456.0;
SharedRessource_end(i, r);
SharedRessource_it(i, r);
assert(*SharedRessource_ref(i) == 3456.0);
SharedRessource_clear(r);
}
int main(void)
{
test1();
test2();
test_emplace();
for(int i = 1; i < MAX_RESSOURCE; i++) {
test_ressource(i);
}
test_double();
test_double2();
test_double_res();
testobj_final_check();
exit(0);
}
-2
View File
@@ -21,10 +21,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-obj.h"
#include "m-snapshot.h"
#include "m-thread.h"
#include "coverage.h"
// Long Structure with a simple CRC to check for proper passing
+5 -4
View File
@@ -22,9 +22,8 @@
*/
#define M_USE_ADDITIONAL_CHECKS 1
#include "m-core.h"
#include "test-obj.h"
#include "coverage.h"
#include "m-string.h"
BOUNDED_STRING_DEF(string16, 16)
@@ -609,16 +608,18 @@ static void test0(void)
assert (string_equal_str_p(s1, "QWERTYQWERTY"));
string_clear (s2);
size_t cap = string_capacity(s1);
char *s = string_clear_get_str (s1);
assert(strcmp(s, "QWERTYQWERTY") == 0);
free(s);
overloaded_free(1, s, cap <= sizeof (m_str1ng_heap_ct) - 1 ? strlen(s)+1 : cap );
string_t s3;
string_init(s3);
string_cat_str(s3, "ABC");
cap = string_capacity(s3);
s = string_clear_get_str(s3);
assert(strcmp(s, "ABC") == 0);
free(s);
overloaded_free(1, s, cap <= sizeof (m_str1ng_heap_ct) - 1 ? strlen(s)+1 : cap );
string_init_set_str(s1, "RESTART");
assert (string_equal_str_p(s1, "RESTART"));
+1 -9
View File
@@ -20,11 +20,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "m-tree.h"
#include "test-obj.h"
#include "m-tree.h"
#include "m-string.h"
#include "coverage.h"
@@ -298,31 +295,26 @@ static void test_basic(void)
tree_move_up(it2, &data);
tree_get_str(s, t, false);
assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{2,[{1,[{5}]}]}]}]}]"));
assert(data == 0);
data = 11;
tree_move_left(it2, &data);
tree_get_str(s, t, false);
assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{1,[{5}]}]}]}]}]"));
assert(data == 0);
data = 12;
tree_move_right(it2, &data);
tree_get_str(s, t, false);
assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{1,[{5}]}]},{12}]}]}]"));
assert(data == 0);
data = 13;
tree_move_child(it2, &data);
tree_get_str(s, t, false);
assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{13},{1,[{5}]}]},{12}]}]}]"));
assert(data == 0);
data = 14;
tree_move_down(it2, &data);
tree_get_str(s, t, false);
assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{14,[{13},{1,[{5}]}]}]},{12}]}]}]"));
assert(data == 0);
tree_it_set(&it, root);
assert(tree_it_equal_p(it, root));
-1
View File
@@ -51,7 +51,6 @@ static bool test_final_in_progress;
#include "test-obj.h"
#include "coverage.h"
#include "m-try.h"
M_TRY_DEF_ONCE()
+1 -3
View File
@@ -20,13 +20,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-tuple.h"
#include "coverage.h"
START_COVERAGE
TUPLE_DEF2(pair,
(key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))),
+1 -3
View File
@@ -20,13 +20,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include "test-obj.h"
#include "m-string.h"
#include "m-variant.h"
#include "coverage.h"
START_COVERAGE
VARIANT_DEF2(pair,
(key, int, M_BASIC_OPLIST),
+1 -2
View File
@@ -20,9 +20,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "m-core.h"
#include "test-obj.h"
#include "coverage.h"
#include "m-worker.h"
/* Compute Fibonacci number using thread systems. */
+9 -8
View File
@@ -37,16 +37,16 @@ static inline void test_obj_except_trigger(void);
extern int test_obj_except__malloc_counter;
#ifdef __cplusplus
# include <cstdlib>
# define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
# define M_MEMORY_REALLOC(type, ptr, n) \
# define M_MEMORY_ALLOC(ctx, type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type)))
# define M_MEMORY_DEL(ctx, ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) \
((type*) (test_obj_except_trigger(), test_obj_except__malloc_counter+= (ptr == NULL), std::realloc ((ptr), (n)*sizeof (type))))
# define M_MEMORY_FREE(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
# define M_MEMORY_FREE(ctx, type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr))
#else
# define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type)))
# define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
# define M_MEMORY_REALLOC(type, ptr, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
# define M_MEMORY_ALLOC(ctx, type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type)))
# define M_MEMORY_DEL(ctx, ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type)))
# define M_MEMORY_FREE(ctx, type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr))
#endif
// Include M*LIB headers
@@ -236,6 +236,7 @@ static inline size_t test_obj_except__hash(const test_obj_except__t z)
INIT_SET(test_obj_except__init_set), \
SET(test_obj_except__set), \
CLEAR(test_obj_except__clear), \
INIT_MOVE(M_COPY_A1_DEFAULT), \
TYPE(test_obj_except__t), \
ADD(test_obj_except__add), \
OUT_STR(test_obj_except__out_str), \
+53 -2
View File
@@ -25,6 +25,53 @@
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// First overwrite memory handling function so that we can check if everything is ok
#ifdef M_MEMORY_REALLOC
# error ERROR: Do not include M*LIB headers before this header.
#endif
static size_t amount_allocated = 0;
static inline void *overloaded_realloc(size_t st, void *ptr, size_t o, size_t n)
{
size_t *p = (size_t *) ptr;
if (p != NULL) {
p -= 2;
assert(p[0] == st);
assert(p[1] == o);
amount_allocated -= st * o;
}
ptr = realloc((void*)p, 2*sizeof(size_t) + st * n);
assert(ptr != NULL);
p = (size_t*) ptr;
p[0] = st;
p[1] = n;
amount_allocated += st * n;
return (void*) (&p[2]);
}
static inline void overloaded_free(size_t st, void *ptr, size_t n)
{
size_t *p = (size_t *) ptr;
if (p == NULL) {
return;
}
p -= 2;
assert(p[0] == st);
assert(p[1] == n);
amount_allocated -= st * n;
free(p);
}
#define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (type *) overloaded_realloc(sizeof(type), ptr, o, n)
#define M_MEMORY_FREE(ctx, type, ptr, o) overloaded_free(sizeof(type), ptr, o)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "m-string.h"
@@ -45,6 +92,8 @@ static inline void testobj_final_check(void)
{
// All created testobj shall have been cleared at the end.
assert(testobj_init_counter == 0);
// All memory allocations shall be cleared
assert(amount_allocated == 0);
}
static inline void testobj_init(testobj_t z)
@@ -179,11 +228,12 @@ static inline void testobj_str(string_t str, const testobj_t z, bool append)
// This enables testing good macro expansion in OPLIST usage
#define testobj_clear_indirect(op, x) testobj_clear(x)
#define TESTOBJ_OPLIST \
#define TESTOBJ_OPLIST \
(INIT(testobj_init), \
INIT_SET(testobj_init_set), \
SET(testobj_set), \
CLEAR(API_1(testobj_clear_indirect)), \
INIT_MOVE(M_COPY_A1_DEFAULT), \
TYPE(testobj_t), \
OUT_STR(testobj_out_str), \
IN_STR(testobj_in_str), \
@@ -194,11 +244,12 @@ static inline void testobj_str(string_t str, const testobj_t z, bool append)
EMPLACE_TYPE( LIST( (_ui, testobj_init_set_ui, unsigned int), (_str, testobj_init_set_str, const char *), ( /*empty*/, testobj_init_set, testobj_t) ) ) \
)
#define TESTOBJ_CMP_OPLIST \
#define TESTOBJ_CMP_OPLIST \
(INIT(testobj_init), \
INIT_SET(testobj_init_set), \
SET(testobj_set), \
CLEAR(testobj_clear), \
INIT_MOVE(M_COPY_A1_DEFAULT), \
TYPE(testobj_t), \
OUT_STR(testobj_out_str), \
IN_STR(testobj_in_str), \