Merge pull request #134 from P-p-H-d/feature/new-memory-model
New memory model
This commit is contained in:
77 files changed
+3839
-6840
No files matched your search
@@ -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
|
||||
|
||||
+23
-1
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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); \
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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 */)
|
||||
|
||||
|
||||
@@ -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 **********************************/
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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 */) \
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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; \
|
||||
}
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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))),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
@@ -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), \
|
||||
|
||||
Reference in new issue
Block a user