* Remove some obsolete macros
* Fix spelling * A little bit of refactoring
This commit is contained in:
1 parent
52b58c5a51
commit
26cec1591a
26 files changed
+225
-249
No files matched your search
@@ -6248,17 +6248,6 @@ Apply 'func' to each triplet composed of data, one argument of arglist1 and one
|
||||
==>
|
||||
f(5, 1, 2) f(5, 1, 4) f(5, 3, 2) f(5, 3, 4)
|
||||
|
||||
##### M\_MAP\_PAIR(func, args...)
|
||||
|
||||
Map a macro to all given pair of arguments (Using recursion).
|
||||
Can not be chained.
|
||||
|
||||
M_MAP_PAIR(f, a, b, c, d)
|
||||
==>
|
||||
f(a, b) f(c, d)
|
||||
|
||||
OBSOLETE macro
|
||||
|
||||
##### M\_REDUCE(funcMap, funcReduce, args...)
|
||||
|
||||
Map the macro funcMap to all given arguments 'args'
|
||||
|
||||
@@ -796,7 +796,7 @@
|
||||
{ \
|
||||
M_ASSERT (it != NULL && a == it->array); \
|
||||
M_F(name, _pop_at)(NULL, a, it->index); \
|
||||
/* NOTE: it->index will naturaly point to the next element */ \
|
||||
/* NOTE: it->index will naturally point to the next element */ \
|
||||
} \
|
||||
, /* End of SET | INIT_SET */ ) \
|
||||
\
|
||||
@@ -918,7 +918,7 @@
|
||||
bool b = M_CALL_EQUAL(oplist, *item1, *item2); \
|
||||
if (!b) return false; \
|
||||
} \
|
||||
return i == array1->size; \
|
||||
return true; \
|
||||
} \
|
||||
, /* no EQUAL */ ) \
|
||||
\
|
||||
@@ -946,7 +946,7 @@
|
||||
/* To overflow newSize, we need to a1 and a2 a little bit above \
|
||||
SIZE_MAX/2, which is not possible in the classic memory model as we \
|
||||
should have exhausted all memory before reaching such sizes. */ \
|
||||
M_ASSERT(newSize > a1->size); \
|
||||
M_ASSERT_INDEX(a1->size, newSize); \
|
||||
if (newSize > a1->alloc) { \
|
||||
type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \
|
||||
if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
#ifndef MSTARLIB_ATOMIC_H
|
||||
#define MSTARLIB_ATOMIC_H
|
||||
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officialy,
|
||||
/* NOTE: Due to the C++ not having recognized stdatomic.h officially,
|
||||
it is hard to use this header directly with a C++ compiler.
|
||||
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932
|
||||
clang++ has no issue with this header but if someone includes
|
||||
|
||||
+3
-3
@@ -286,7 +286,7 @@ m_bitset_resize (m_bitset_t v, size_t size)
|
||||
M_B1TSET_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Reserve allocation in the bitset to accomodate at least 'size' bits without reallocation */
|
||||
/* 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)
|
||||
{
|
||||
@@ -750,7 +750,7 @@ m_bitset_not(m_bitset_t dest)
|
||||
M_B1TSET_CONTRACT(dest);
|
||||
}
|
||||
|
||||
/* Copute a hash of the bitset */
|
||||
/* Compute a hash of the bitset */
|
||||
M_INLINE size_t
|
||||
m_bitset_hash(const m_bitset_t set)
|
||||
{
|
||||
@@ -961,7 +961,7 @@ M_END_PROTECTED_CODE
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Output to a m_string_t 'str' the formatted text representation of the bitset 'set'
|
||||
or append it to the strinf (append=true) */
|
||||
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)
|
||||
{
|
||||
|
||||
+4
-4
@@ -147,7 +147,7 @@
|
||||
so that all arguments are evaluated before further expansion */
|
||||
#define M_BPTR33_KEY_OPLIST_P1(arg) M_BPTR33_KEY_OPLIST_P2 arg
|
||||
|
||||
/* Validation of the given oplists */
|
||||
/* Validation of the given oplist */
|
||||
#define M_BPTR33_KEY_OPLIST_P2(name, oplist) \
|
||||
M_IF_OPLIST(oplist)(M_BPTR33_KEY_OPLIST_P3, M_BPTR33_KEY_OPLIST_FAILURE)(name, oplist)
|
||||
|
||||
@@ -950,7 +950,7 @@
|
||||
node_t parent = pit->parent[--pit->num]; \
|
||||
M_ASSERT (parent != NULL); \
|
||||
k = M_F(name, _search_for_node)(parent, leaf); \
|
||||
/* Look for the neighboor of the removed key. */ \
|
||||
/* 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); \
|
||||
@@ -1042,6 +1042,7 @@
|
||||
b->size = ref->size; \
|
||||
b->root = ref->root; \
|
||||
ref->root = NULL; \
|
||||
ref->size = 1; \
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
|
||||
} \
|
||||
\
|
||||
@@ -1209,7 +1210,7 @@
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
/* NOTE: We can't compare two trees directly as they can be \
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
structurally different but functionally equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
@@ -1263,7 +1264,6 @@
|
||||
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
|
||||
M_ASSERT(str != NULL); \
|
||||
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \
|
||||
/* NOTE: The print is really naive, and not really efficient */ \
|
||||
bool commaToPrint = false; \
|
||||
it_t it; \
|
||||
for (M_F(name, _it)(it, t1) ; \
|
||||
|
||||
+27
-27
@@ -78,7 +78,7 @@ typedef enum {
|
||||
(__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define a nearly lock-free queue for Many Producer Many Consummer.
|
||||
/* Define a nearly lock-free queue for Many Producers Many Consumers.
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
@@ -88,7 +88,7 @@ typedef enum {
|
||||
M_QUEUE_MPMC_DEF_AS(name, M_F(name,_t), type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a nearly lock-free queue for Many Producer Many Consummer
|
||||
/* Define a nearly lock-free queue for Many Producers Many Consumers
|
||||
as the provided type name_t.
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
@@ -103,7 +103,7 @@ typedef enum {
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a wait-free queue for Single Producer Single Consummer
|
||||
/* Define a wait-free queue for Single Producer Single Consumer
|
||||
Much faster than queue of BUFFER_DEF or QUEUE_MPMC in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
Size of created queue shall be a power of 2 and is defined at run-time.
|
||||
@@ -113,7 +113,7 @@ typedef enum {
|
||||
M_QUEUE_SPSC_DEF_AS(name, M_F(name, _t), type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a wait-free queue for Single Producer Single Consummer
|
||||
/* Define a wait-free queue for Single Producer Single Consumer
|
||||
as the provided type name_t.
|
||||
Much faster than queue of BUFFER_DEF in heavy communication scenario
|
||||
but without any blocking features (this is let to the user).
|
||||
@@ -278,7 +278,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
m_cond_t there_is_data; /* condition raised when there is data */ \
|
||||
/* Read only Data */ \
|
||||
M_BUFF3R_IF_CTE_SIZE(m_size)( ,size_t capacity;) /* Capacity of the buffer */ \
|
||||
/* Data for a consummer */ \
|
||||
/* Data for a consumer */ \
|
||||
m_cond_t there_is_room_for_data; /* Cond. raised when there is room */ \
|
||||
m_mutex_t mutexPop; /* MUTEX used for popping elements */ \
|
||||
size_t idx_cons; /* Index of the consumption threads */ \
|
||||
@@ -291,13 +291,13 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy)
|
||||
\
|
||||
typedef struct M_F(name, _s) *M_F(name, _ptr); \
|
||||
typedef const struct M_F(name, _s) *M_F(name, _srcptr); \
|
||||
/* Internal type used to unconst the buffer */ \
|
||||
/* Internal type used to un-const the buffer */ \
|
||||
typedef union { M_F(name, _srcptr) cptr; M_F(name, _ptr) ptr; } M_F(name, _uptr_ct); \
|
||||
/* Internal types used by the oplist */ \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef buffer_t M_F(name, _ct); \
|
||||
|
||||
/* Define the core functionnalities of a buffer */
|
||||
/* Define the core functionalities of a buffer */
|
||||
#define M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \
|
||||
\
|
||||
M_INLINE void \
|
||||
@@ -415,7 +415,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_INLINE void \
|
||||
M_F(name, _init_set)(buffer_t dest, const buffer_t src) \
|
||||
{ \
|
||||
/* unconst 'src', so that we can lock it (semantically it is const) */ \
|
||||
/* 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; \
|
||||
@@ -459,7 +459,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(buffer_t dest, const buffer_t src) \
|
||||
{ \
|
||||
/* unconst 'src', so that we can lock it (semantically it is const) */ \
|
||||
/* 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; \
|
||||
@@ -607,7 +607,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
v->idx_prod = idx; \
|
||||
\
|
||||
/* number[] is the only variable which can be modified by both \
|
||||
the consummer thread which has the pop lock and the producer \
|
||||
the consumer thread which has the pop lock and the producer \
|
||||
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 */ \
|
||||
@@ -615,14 +615,14 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \
|
||||
previousSize = m_buff3r_number_inc (v->number[1], policy); \
|
||||
} \
|
||||
/* From this point, consummer may read the data in the table */ \
|
||||
/* 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 consummer \
|
||||
may be waiting. Signal to them the availibility of the data \
|
||||
/* 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); \
|
||||
@@ -641,7 +641,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_BUFF3R_CONTRACT(v,m_size); \
|
||||
M_ASSERT (data != NULL); \
|
||||
\
|
||||
/* Consummer lock (mutex lock performs an acquire memory barrier) */ \
|
||||
/* 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)) { \
|
||||
@@ -675,7 +675,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
\
|
||||
/* number[] is the only variable which can be modified by both \
|
||||
the consummer thread which has the pop lock and the producer \
|
||||
the consumer thread which has the pop lock and the producer \
|
||||
thread which has the push lock. As such, it is an atomic variable \
|
||||
that performs a release memory barrier. */ \
|
||||
/* Decrement number of elements in the buffer */ \
|
||||
@@ -687,11 +687,11 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
} \
|
||||
/* Space may be reused by a producer thread from this point */ \
|
||||
\
|
||||
/* Consummer unlock (mutex unlock perfoms a release memory barrier) */ \
|
||||
/* 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 availibility of the free room \
|
||||
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)) { \
|
||||
@@ -750,7 +750,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Definition of a a QUEUE for Many Produccer / Many Consummer
|
||||
/* Definition of a a QUEUE for Many Producers / Many consumers
|
||||
for high bandwidth scenario:
|
||||
* nearly lock-free,
|
||||
* quite fast
|
||||
@@ -805,7 +805,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
\
|
||||
/* The sequence number of an element will be equal to either \
|
||||
- 2* the index of the production which creates it, \
|
||||
- 1 + 2* the index of the consumption which consummes it \
|
||||
- 1 + 2* the index of the consumption which consumes it \
|
||||
In case of wrapping, as there is no order comparison but only \
|
||||
equal comparison, there is no special issue. \
|
||||
Each element is put in a separate cache line to avoid false \
|
||||
@@ -817,7 +817,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
M_CACHELINE_ALIGN(align, atomic_uint, type); \
|
||||
} M_F(name, _el_ct); \
|
||||
\
|
||||
/* If there is only one producer and one consummer, then they won't \
|
||||
/* If there is only one producer and one consumer, then they won't \
|
||||
typically use the same cache line, increasing performance. */ \
|
||||
typedef struct M_F(name, _s) { \
|
||||
atomic_uint ProdIdx; /* Can only increase until wrapping */ \
|
||||
@@ -831,7 +831,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef buffer_t M_F(name, _ct); \
|
||||
|
||||
/* Define the core functionnalities of a MPMC queue */
|
||||
/* 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) \
|
||||
@@ -952,7 +952,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
const unsigned int iC = atomic_load_explicit(&table->ConsoIdx, memory_order_relaxed); \
|
||||
const unsigned int iP = atomic_load_explicit(&table->ProdIdx, memory_order_acquire); \
|
||||
/* We return an approximation as we can't read both iC & iP atomically \
|
||||
As we read producer index after consummer index, \
|
||||
As we read producer index after consumer index, \
|
||||
and they are atomic variables without reordering \
|
||||
producer index is always greater or equal than consumer index \
|
||||
(or on overflow occurs, in which case as we compute with modulo \
|
||||
@@ -986,7 +986,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
|
||||
/********************************** INTERNAL *********************************/
|
||||
|
||||
/* Definition of a a QUEUE for Single Producer / Single Consummer
|
||||
/* Definition of a a QUEUE for Single Producer / Single consumer
|
||||
for high bandwidth scenario:
|
||||
* wait-free,
|
||||
* quite fast
|
||||
@@ -1038,7 +1038,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
/* Define the type of a SPSC queue */
|
||||
#define M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
/* Single producer / Single consummer \
|
||||
/* Single producer / Single consumer \
|
||||
So, only one thread will write in this table. The other thread \
|
||||
will only read. As such, there is no concurrent write, and no \
|
||||
need to align the structure for best performance. */ \
|
||||
@@ -1057,7 +1057,7 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
typedef buffer_t M_F(name, _ct); \
|
||||
|
||||
/* Define the core functionnalities of a SPSC queue */
|
||||
/* Define the core functionalities of a SPSC queue */
|
||||
#define M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \
|
||||
\
|
||||
M_INLINE bool \
|
||||
@@ -1208,14 +1208,14 @@ M_F(name, _init)(buffer_t v, size_t size) \
|
||||
unsigned int w = atomic_load_explicit(&table->prodIdx, \
|
||||
memory_order_acquire); \
|
||||
/* We return an approximation as we can't read both r & w atomically \
|
||||
As we read producer index after consummer index, \
|
||||
As we read producer index after consumer index, \
|
||||
and they are atomic variables without reordering \
|
||||
producer index is always greater or equal than consumer index \
|
||||
(or on overflow occurs, in which case as we compute with modulo \
|
||||
arithmetic, the right result is computed). \
|
||||
We may return a result which is greater than the size of the queue \
|
||||
if the function is interrupted a long time between reading the \
|
||||
indexs. The function is not protected against it. \
|
||||
index. The function is not protected against it. \
|
||||
*/ \
|
||||
return w-r; \
|
||||
} \
|
||||
|
||||
+10
-10
@@ -114,14 +114,14 @@ M_BEGIN_PROTECTED_CODE
|
||||
- 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 sucessfull push of NB in Q1. NA.next is set to NB.
|
||||
- Thread 2 performs a sucessfull pop of NA in Q1
|
||||
- Thread 2 performs a sucessfull push of NA in Q2. NA.next is set to NIL.
|
||||
- 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 alignement to reduce memory consumption. NIL object can use []
|
||||
/* 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) \
|
||||
\
|
||||
@@ -232,7 +232,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
} \
|
||||
/* 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 itsef, \
|
||||
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. */ \
|
||||
@@ -263,7 +263,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
memory_order_release, \
|
||||
memory_order_relaxed); \
|
||||
} else { \
|
||||
/* Test if the node is old enought to be popped */ \
|
||||
/* 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 */ \
|
||||
@@ -338,15 +338,15 @@ M_BEGIN_PROTECTED_CODE
|
||||
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 dimensionned to avoid calling the system allocator during
|
||||
sufficiently dimensioned to avoid calling the system allocator during
|
||||
the normal processing.
|
||||
Then each thread pushs its deleted node into another pool of nodes,
|
||||
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 thare are sufficiently
|
||||
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.
|
||||
|
||||
@@ -822,7 +822,7 @@ m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id)
|
||||
// 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 logicaly free memory into the list of the nodes to be reclaimed.
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -329,7 +329,7 @@
|
||||
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 mutexs are locked: T1 has locked A \
|
||||
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 \
|
||||
@@ -641,7 +641,7 @@
|
||||
M_C0NCURRENT_CONTRACT(out1); \
|
||||
M_C0NCURRENT_CONTRACT(out2); \
|
||||
if (M_UNLIKELY (out1 == out2)) return true; \
|
||||
/* See comment above on mutal mutexs */ \
|
||||
/* See comment above on mutual mutexes */ \
|
||||
if (out1 < out2) { \
|
||||
M_F(name, _read_lock)(out1); \
|
||||
M_F(name, _read_lock)(out2); \
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
# define M_ASSUME(x) M_ASSERT(x)
|
||||
#endif
|
||||
|
||||
/* M_LIKELY / M_UNLIKELY gives hints on the compiler of the likehood
|
||||
/* M_LIKELY / M_UNLIKELY gives hints on the compiler of the likelihood
|
||||
of the given condition */
|
||||
#ifdef __GNUC__
|
||||
# define M_LIKELY(cond) __builtin_expect(!!(cond), 1)
|
||||
@@ -153,7 +153,7 @@
|
||||
* and CLANG failed to realize it.
|
||||
* See https://bugs.llvm.org//show_bug.cgi?id=22712
|
||||
*
|
||||
* * A manualy created buffer is given to fscanf. It is needed
|
||||
* * A manually created buffer is given to fscanf. It is needed
|
||||
* to give the size of the array of char to fscanf (this is the safe way).
|
||||
*/
|
||||
#if defined(__clang__) && defined(__cplusplus)
|
||||
@@ -396,7 +396,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define the default assertion macro used by M*LIB.
|
||||
* By default, it is an encapsulation of CLIB assert.
|
||||
* NOTE: Can be overiden by user if it needs to keep finer access
|
||||
* NOTE: Can be overriden by user if it needs to keep finer access
|
||||
* on the assertions.
|
||||
*/
|
||||
#ifndef M_ASSERT
|
||||
@@ -404,9 +404,9 @@ M_BEGIN_PROTECTED_CODE
|
||||
#endif
|
||||
|
||||
|
||||
/* If within the M*LIB tests, perform additional (potentialy slow) checks
|
||||
/* If within the M*LIB tests, perform additional (potentially slow) checks
|
||||
* By default, it is an encapsulation of CLIB assert for M*LIB own tests.
|
||||
* NOTE: Can be overiden by user if it needs to keep finer access
|
||||
* NOTE: Can be overriden by user if it needs to keep finer access
|
||||
* on the assertions.
|
||||
*/
|
||||
#ifndef M_ASSERT_SLOW
|
||||
@@ -419,7 +419,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Always perform a runtime check of the given condition
|
||||
* NOTE: Can be overiden by user if it needs to keep finer access
|
||||
* NOTE: Can be overriden by user if it needs to keep finer access
|
||||
* on the assertions or display message on another device.
|
||||
*/
|
||||
#ifndef M_ASSERT_INIT
|
||||
@@ -434,7 +434,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Define an assertion check on an index, compared to its maximum.
|
||||
* The index is supposed to be unsigned.
|
||||
* It is only used to valid user input, not an intermediary calculus.
|
||||
* NOTE: Can be overiden by user if it needs to keep access under control
|
||||
* NOTE: Can be overriden by user if it needs to keep access under control
|
||||
* even on release mode
|
||||
* NOTE: (index)-(index) is used to represent 0, but to avoid spurious
|
||||
* warning by the compiler on "comparaison is always true" for unsigned
|
||||
@@ -449,12 +449,12 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Terminate the compilation of the current unit with an error message.
|
||||
The error parameter is a C token which classifies the error
|
||||
with an optional message detailling the error.
|
||||
with an optional message detailing the error.
|
||||
It is not an expression and shall not be used in an expression.
|
||||
It shall be used outside of a function, therefore it is not an expression.
|
||||
In C99, it uses a bitfield to be compatible with most compilers
|
||||
(so that it properly displays 'error' on the command line
|
||||
Quite usefull to terminate with a proper error message rather than
|
||||
Quite useful to terminate with a proper error message rather than
|
||||
a garbage of error due to incorrect code generation in the methods
|
||||
expansion.
|
||||
*/
|
||||
@@ -467,7 +467,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Test at compile time if the given condition is true.
|
||||
The error parameter is a C token which classifies the error
|
||||
with an optional message detailling the error.
|
||||
with an optional message detailing the error.
|
||||
In C99, it uses a bitfield to be compatible with most compilers
|
||||
(so that it properly displays 'error' on the command line
|
||||
C11 static Assert is not usable in expression,
|
||||
@@ -476,7 +476,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
compute its size and cast it to void.
|
||||
NOTE: Some implementation claims to be C11 (default mode) but fails
|
||||
to deliver a working assert.h with static_assert so we test for the
|
||||
explicity precense of the macro static_assert.
|
||||
explicitly presence of the macro static_assert.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
# define M_STATIC_ASSERT(cond, error, msg) \
|
||||
@@ -518,13 +518,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Generation of function name by concatenation
|
||||
Can be ovverrided by user
|
||||
Can be overriden by user
|
||||
*/
|
||||
#ifndef M_F
|
||||
#define M_F(a, b) M_C2I(a, b)
|
||||
#endif
|
||||
|
||||
/* Concatenation of function name that enable developer to use customizaton
|
||||
/* Concatenation of function name that enable developer to use customization
|
||||
developer shall provide its own name customization by forcing M_F to it
|
||||
then provide its own suffix in the namespace M_OVERRIDE_ ## suffix ():
|
||||
Each generated suffix shall start with a comma.
|
||||
@@ -760,7 +760,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_ADDI_52(n) M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(n))))))))))))))))))))))))))))))))))))))))))))))))))))
|
||||
|
||||
|
||||
/* Substract two integers with both integers from [0 to M_MAX_NB_ARGUMENT[
|
||||
/* Subtract two integers with both integers from [0 to M_MAX_NB_ARGUMENT[
|
||||
Generated by:
|
||||
for i in $(seq 0 52) ; do printf "#define M_SUBI_%d(n) " $i ; for j in $(seq 1 $i) ; do printf "M_DEC(";done ; printf "n" ; for j in $(seq 1 $i) ; do printf ")" ;done ; printf "\n" ; done */
|
||||
#define M_SUB(x,y) M_C(M_SUBI_, y)(x)
|
||||
@@ -903,7 +903,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
/* Return the nth argument of a VA_ARGS.
|
||||
- M_RET_ARG<n> lets the VA_ARGS been evaluated, and returns the <n> argument.
|
||||
- M_RETI_ARG<n> returns the <n> argument.
|
||||
- M_RET_ARG takes n as argument, evaluate the arguments, and returns the 'n' argument.
|
||||
- M_RET_ARG takes 'n' as argument, evaluate the arguments, and returns the 'n' argument.
|
||||
NOTE: A comma is added at the end in M_RET_ARG<n> in order to avoid error if the number of
|
||||
argument is exactly <n> (in which case, otherwise the __VA_ARGS__ will be non existent).
|
||||
Generated by:
|
||||
@@ -1398,7 +1398,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_IF_EMPTY(...) M_IF(M_EMPTY_P(__VA_ARGS__))
|
||||
|
||||
|
||||
/* Concatene the two preprocessing token.
|
||||
/* Concatenate the two preprocessing token.
|
||||
* Handle the case where the second argument is empty, in which case
|
||||
* it returns the first token without concatenation.
|
||||
*/
|
||||
@@ -1497,7 +1497,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_EAT_KEYWORD____(...) __VA_ARGS__
|
||||
|
||||
|
||||
/* Necessary macros to handle recursivity,
|
||||
/* Necessary macros to handle recursion,
|
||||
delaying the evaluation by one (or more) level of macro expansion.
|
||||
The argument is a macro-function which has to be deferred */
|
||||
#define M_DELAY0()
|
||||
@@ -1515,7 +1515,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
forcing the pre-processor to expand the given macro a lot of times.
|
||||
NOTE: There can be only one EVAL macro per complete macro-evaluation pass.
|
||||
As such the given macro cannot contain M_EVAL itself,
|
||||
NOTE: Using recursivity impacts compilation time performance.
|
||||
NOTE: Using recursion impacts compilation time performance.
|
||||
*/
|
||||
#define M_EVAL(...) M_EVAL1(M_EVAL1(M_EVAL1(__VA_ARGS__)))
|
||||
#define M_EVAL1(...) M_EVAL2(M_EVAL2(M_EVAL2(__VA_ARGS__)))
|
||||
@@ -1534,7 +1534,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
|
||||
/* MAP: apply the given macro to all arguments.
|
||||
NOTE: Perform a first step evalution so that the given VA_ARGS is fullu evaluated
|
||||
NOTE: Perform a first step evaluation so that the given VA_ARGS is fully evaluated
|
||||
and expanded before further preprocessing. This helps if the argument given to M_MAP
|
||||
perform a construction of the VA_ARGS as its argument.
|
||||
NOTE: It is a non recursive version that is much faster than the recursive one.
|
||||
@@ -1741,6 +1741,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_MAP2B_74(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) f(d, _53) f(d, _54) f(d, _55) f(d, _56) f(d, _57) f(d, _58) f(d, _59) f(d, _60) f(d, _61) f(d, _62) f(d, _63) f(d, _64) f(d, _65) f(d, _66) f(d, _67) f(d, _68) f(d, _69) f(d, _70) f(d, _71) f(d, _72) f(d, _73) f(d, _74)
|
||||
#define M_MAP2B_75(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) f(d, _53) f(d, _54) f(d, _55) f(d, _56) f(d, _57) f(d, _58) f(d, _59) f(d, _60) f(d, _61) f(d, _62) f(d, _63) f(d, _64) f(d, _65) f(d, _66) f(d, _67) f(d, _68) f(d, _69) f(d, _70) f(d, _71) f(d, _72) f(d, _73) f(d, _74) f(d, _75)
|
||||
|
||||
|
||||
/* Map a macro to all given arguments with two additional fixed data (non recursive version):
|
||||
one of the parameter is given and one numerical which is the argument number.
|
||||
Example:
|
||||
@@ -1804,15 +1805,6 @@ M_BEGIN_PROTECTED_CODE
|
||||
#define M_MAP3I_52(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52) f(d, 1, _1) f(d, 2, _2) f(d, 3, _3) f(d, 4, _4) f(d, 5, _5) f(d, 6, _6) f(d, 7, _7) f(d, 8, _8) f(d, 9, _9) f(d, 10, _10) f(d, 11, _11) f(d, 12, _12) f(d, 13, _13) f(d, 14, _14) f(d, 15, _15) f(d, 16, _16) f(d, 17, _17) f(d, 18, _18) f(d, 19, _19) f(d, 20, _20) f(d, 21, _21) f(d, 22, _22) f(d, 23, _23) f(d, 24, _24) f(d, 25, _25) f(d, 26, _26) f(d, 27, _27) f(d, 28, _28) f(d, 29, _29) f(d, 30, _30) f(d, 31, _31) f(d, 32, _32) f(d, 33, _33) f(d, 34, _34) f(d, 35, _35) f(d, 36, _36) f(d, 37, _37) f(d, 38, _38) f(d, 39, _39) f(d, 40, _40) f(d, 41, _41) f(d, 42, _42) f(d, 43, _43) f(d, 44, _44) f(d, 45, _45) f(d, 46, _46) f(d, 47, _47) f(d, 48, _48) f(d, 49, _49) f(d, 50, _50) f(d, 51, _51) f(d, 52, _52)
|
||||
|
||||
|
||||
|
||||
/* Map a macro to all given pair of arguments (Using recursivity) (OBSOLETE) */
|
||||
/* Example: M_MAP_PAIR(f, a, b, c, d) ==> f(a,b) f(c,d) */
|
||||
#define M_MAP_PAIR_L0_INDIRECT() M_MAP_PAIR_L0
|
||||
#define M_MAP_PAIR_L0(f, ...) M_IF_NARGS_EQ2(__VA_ARGS__)( f(__VA_ARGS__) , M_MAP_PAIR_L1(f, __VA_ARGS__))
|
||||
#define M_MAP_PAIR_L1(f, a, b, ...) f(a,b) M_DELAY3(M_MAP_PAIR_L0_INDIRECT) () (f, __VA_ARGS__)
|
||||
#define M_MAP_PAIR(f, ...) M_IF_EMPTY(__VA_ARGS__)( /* end */, M_EVAL(M_MAP_PAIR_L0(f, __VA_ARGS__)))
|
||||
|
||||
|
||||
/* Map a macro to all given arguments and reduce all theses computation
|
||||
with another reduce macro.
|
||||
Example:
|
||||
@@ -2314,13 +2306,14 @@ done
|
||||
#define M_CROSSI_MAP2_51b(f, d, blist, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a1), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a2), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a3), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a4), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a5), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a6), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a7), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a8), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a9), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a10), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a11), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a12), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a13), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a14), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a15), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a16), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a17), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a18), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a19), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a20), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a21), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a22), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a23), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a24), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a25), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a26), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a27), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a28), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a29), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a30), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a31), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a32), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a33), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a34), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a35), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a36), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a37), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a38), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a39), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a40), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a41), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a42), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a43), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a44), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a45), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a46), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a47), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a48), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a49), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a50), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a51), M_ID blist)
|
||||
#define M_CROSSI_MAP2_52(...) M_CROSSI_MAP2_52b(__VA_ARGS__)
|
||||
#define M_CROSSI_MAP2_52b(f, d, blist, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a1), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a2), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a3), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a4), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a5), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a6), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a7), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a8), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a9), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a10), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a11), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a12), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a13), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a14), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a15), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a16), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a17), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a18), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a19), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a20), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a21), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a22), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a23), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a24), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a25), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a26), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a27), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a28), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a29), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a30), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a31), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a32), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a33), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a34), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a35), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a36), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a37), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a38), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a39), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a40), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a41), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a42), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a43), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a44), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a45), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a46), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a47), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a48), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a49), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a50), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a51), M_ID blist) M_MAP2(M_CROSSI_MAP2_F_A, (f, d, a52), M_ID blist)
|
||||
|
||||
/* Wrapper function that unpacks the argument to call the real macro with the right arguments */
|
||||
#define M_CROSSI_MAP2_F_A(d, b) M_CROSSI_MAP2_F_B(M_ID d, b)
|
||||
#define M_CROSSI_MAP2_F_B(...) M_CROSSI_MAP2_F_C(__VA_ARGS__)
|
||||
#define M_CROSSI_MAP2_F_C(f, d, a1, b1) f(d, a1, b1)
|
||||
|
||||
|
||||
/* Sequence of numerical
|
||||
/* Sequence of numbers
|
||||
Example:
|
||||
M_SEQ(init,end)==>init, init+1, ...end
|
||||
M_MAP(f, M_SEQ(init, end)) ==> f(init) f(init+1) .... f(end)
|
||||
@@ -2368,10 +2361,11 @@ done
|
||||
/* Return the tail sublist of the sublist of the VA_ARGS (removing the 3 first elements) */
|
||||
#define M_TAIL_3(x, y, z, ...) __VA_ARGS__
|
||||
|
||||
/* Concatene two arglists 'a' and 'b',
|
||||
|
||||
/* Concatenate two arglists 'a' and 'b',
|
||||
handling the case of empty arglist
|
||||
handling the cases where the arguments are not arglist.
|
||||
and returning an arglist within parenthesis if it concats.
|
||||
Always return an arglist within parenthesis if it concatenates
|
||||
(internal macro)
|
||||
*/
|
||||
#define M_CAT_ARGLIST(a, b) \
|
||||
@@ -2456,7 +2450,7 @@ done
|
||||
#define M_ID(...) __VA_ARGS__
|
||||
|
||||
|
||||
/* Globber the input */
|
||||
/* Remove the input from preprocessing evaluation */
|
||||
#define M_EAT(...)
|
||||
|
||||
|
||||
@@ -2477,9 +2471,9 @@ done
|
||||
#define M_IF_NARGS_EQ2(...) M_IF(M_EQUAL(M_NARGS(__VA_ARGS__), 2))
|
||||
|
||||
|
||||
/* If NDEBUG macro is defined
|
||||
M_IF_DEBUG(code if NDEBUG is not defined)
|
||||
Note: not 100% robust */
|
||||
/* If NDEBUG macro is not defined, expand code
|
||||
USAGE: M_IF_DEBUG(code if NDEBUG is not defined)
|
||||
Note: not 100% robust but sufficient for its usage */
|
||||
#define M_TEST_NDEBUG_P() M_C3(M_, NDEBUG, _TEST)
|
||||
#define M_NDEBUG_TEST 0
|
||||
#define M_IF_DEBUG(a) M_IF(M_TEST_NDEBUG_P())(,a)
|
||||
@@ -2488,7 +2482,7 @@ done
|
||||
/* If the Function Object is included, expands the code,
|
||||
otherwise do nothing.
|
||||
M_FUNC0BJ_IS_NOT_DEFINED is defined to 0.
|
||||
NOTE: M_IF is the variable is not defined assummes yes.
|
||||
NOTE: M_IF is the variable is not defined assumes yes.
|
||||
*/
|
||||
#define M_IF_FUNCOBJ(a) M_IF(M_FUNC0BJ_IS_NOT_DEFINED)( ,a)
|
||||
|
||||
@@ -2680,7 +2674,7 @@ m_core_fscan_bool (bool *ptr, FILE *f)
|
||||
{
|
||||
int c = fgetc(f);
|
||||
*ptr = (c == '1');
|
||||
return (c == '0' || c == '1');
|
||||
return (c == '0') || (c == '1');
|
||||
}
|
||||
|
||||
M_INLINE bool
|
||||
@@ -2828,20 +2822,6 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
*/
|
||||
#define M_AS_TYPE(type, x) _Generic(((void)0,(x)), type: (x), default: (type) {0})
|
||||
|
||||
/* Perform a C conditional operator with the following restriction:
|
||||
* - cond shall be a compile time constant.
|
||||
* However, true_expr and false_expr can be objects of different types.
|
||||
* The type of the returned expression will be the same as the
|
||||
* returned object without any promotion.
|
||||
* NOTE: The classic conditional operator can return different types
|
||||
* if and only both objects are pointers. If the selected pointer is
|
||||
* a null pointer constant, the returned type depends if the **other**
|
||||
* expression is itself a null pointer constant or not.
|
||||
* NOTE: Not compatible with C++.
|
||||
*/
|
||||
#define M_CONDITIONAL(cond, true_expr, false_expr) \
|
||||
_Generic(1 ? (float *) 0 : (void *)(intptr_t) (cond), float *: false_expr, void *: true_expr)
|
||||
|
||||
/* Return the minimum between x and y (computed in compile time) */
|
||||
#define M_MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
@@ -2884,7 +2864,7 @@ M_PARSE_DEFAULT_TYPE_DEF(m_core_parse_ldouble, long double, strtold, )
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
# define M_CONST_CAST(type, n) \
|
||||
(((union { type *ptr; type const *cptr; }){n}).cptr)
|
||||
(((union { type *ptr; type const *cptr; }){ .ptr = n}).cptr)
|
||||
#else
|
||||
# define M_CONST_CAST(type, n) const_cast<type*>(n)
|
||||
#endif
|
||||
@@ -3515,7 +3495,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[])
|
||||
#define M_GET_LIMITS(...) M_GET_METHOD(LIMITS, M_LIMITS_DEFAULT, __VA_ARGS__)
|
||||
#define M_GET_PROPERTIES(...) M_GET_METHOD(PROPERTIES, (), __VA_ARGS__)
|
||||
#define M_GET_EMPLACE_TYPE(...) M_GET_METHOD(EMPLACE_TYPE, M_NO_DEFAULT, __VA_ARGS__)
|
||||
// As sttribute customization
|
||||
// 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__)
|
||||
@@ -4252,6 +4232,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
#define M_OPL_bool() M_BOOL_OPLIST
|
||||
#define M_OPL__Bool() M_BOOL_OPLIST
|
||||
|
||||
|
||||
/************************************************************/
|
||||
/******************** Syntax Enhancing **********************/
|
||||
/************************************************************/
|
||||
@@ -4362,7 +4343,7 @@ m_core_parse2_enum (const char str[], const char **endptr)
|
||||
#define M_LET_TRY_INJECT_POST(cont, oplist, name)
|
||||
|
||||
/*
|
||||
Internal M_LET for use for withing container.
|
||||
Internal M_LET for use within container.
|
||||
*/
|
||||
#define M_QLET(x, type, oplist) \
|
||||
M_LET(x, M_OPEXTEND(oplist, TYPE(type)))
|
||||
|
||||
@@ -449,7 +449,7 @@
|
||||
/* No next obj. \
|
||||
It is only possible if there was only 1 element */ \
|
||||
M_ASSERT(d->count == 1); \
|
||||
/* Reset the deque to the midle of the current node */ \
|
||||
/* Reset the deque to the middle of the current node */ \
|
||||
d->back->node = d->front->node; \
|
||||
index = d->front->node->size/2; \
|
||||
d->back->index = d->front->node->size/2; \
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a dictionary asssociating the key key_type to the value value_type and its associated functions.
|
||||
/* Define a dictionary associating the key key_type to the value value_type and its associated functions.
|
||||
It stores the computed hash value, avoiding the need of recomputing it but increasing memory
|
||||
consumption.
|
||||
USAGE:
|
||||
@@ -67,7 +67,7 @@
|
||||
M_DICT_STOREHASH_DEF2_AS(name, M_F(name,_t), M_F(name,_it_t), M_F(name,_itref_t), key_type, __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a dictionary asssociating the key key_type to the value value_type and its associated functions.
|
||||
/* Define a dictionary associating the key key_type to the value value_type and its associated functions.
|
||||
as the given name name_t with its associated functions.
|
||||
It stores the computed hash value, avoiding the need of recomputing it but increasing memory
|
||||
consumption.
|
||||
@@ -157,7 +157,7 @@
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a dictionnary (DICT_DEF2, DICT_STOREHASH_DEF2 or DICT_OA_DEF2).
|
||||
/* Define the oplist of a dictionary (DICT_DEF2, DICT_STOREHASH_DEF2 or DICT_OA_DEF2).
|
||||
USAGE:
|
||||
DICT_OPLIST(name, oplist of the key type, oplist of the value type)
|
||||
OR
|
||||
@@ -169,7 +169,7 @@
|
||||
M_D1CT_OPLIST_P1((__VA_ARGS__ )))
|
||||
|
||||
|
||||
/* Define the oplist of a dictionnary (DICT_SET_DEF).
|
||||
/* Define the oplist of a dictionary (DICT_SET_DEF).
|
||||
USAGE: DICT_SET_OPLIST(name[, oplist of the key type]) */
|
||||
#define M_DICT_SET_OPLIST(...) \
|
||||
M_IF_NARGS_EQ1(__VA_ARGS__) \
|
||||
@@ -218,7 +218,7 @@
|
||||
It is defined as an array of singly linked list (each list
|
||||
representing a bucket).
|
||||
*/
|
||||
/* Defered evaluation for arg */
|
||||
/* Deferred evaluation for arg */
|
||||
#define M_D1CT_SHASH_DEF2_P1(arg) M_ID( M_D1CT_SHASH_DEF2_P2 arg )
|
||||
|
||||
/* Validate the key oplist before going further */
|
||||
@@ -271,7 +271,7 @@
|
||||
|
||||
|
||||
|
||||
/* Define the structure of a chained dictionnary for all kind of dictionaries
|
||||
/* Define the structure of a chained dictionary for all kind of dictionaries
|
||||
* name: prefix of the container,
|
||||
* key_type: type of the key
|
||||
* key_oplist: oplist of the key
|
||||
@@ -282,7 +282,7 @@
|
||||
* isSet: is the container a SET (=1) or a MAP (=0)
|
||||
* isStoreHash: is the computed hash stored in the bucker (=1) or not (=0)
|
||||
* dict_t: name of the type to construct
|
||||
* dict_it_t: name of the iterator within the dictionnary.
|
||||
* dict_it_t: name of the iterator within the dictionary.
|
||||
* it_deref_t: name of the type returned by an iterator
|
||||
*/
|
||||
#define M_D1CT_FUNC_DEF2_P5(name, key_type, key_oplist, value_type, value_oplist, pair_type, pair_oplist, isSet, isStoreHash, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -458,7 +458,7 @@
|
||||
M_MEMORY_FULL((size_t)-1); \
|
||||
} \
|
||||
M_ASSERT (old_size > 1 && new_size > 1); \
|
||||
/* Resize the table of the dictionnary */ \
|
||||
/* Resize the table of the dictionary */ \
|
||||
M_F(name, _array_list_pair_resize)(map->table, new_size); \
|
||||
/* Move the items to the new upper part */ \
|
||||
for(size_t i = 0; i < old_size; i++) { \
|
||||
@@ -706,8 +706,8 @@
|
||||
M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t)
|
||||
|
||||
|
||||
/* Define additional functions for dictionnary (Common for all kinds of dictionnary).
|
||||
Do not used any specific fields of the dictionnary but the public API
|
||||
/* Define additional functions for dictionary (Common for all kinds of dictionary).
|
||||
Do not used any specific fields of the dictionary but the public API
|
||||
|
||||
It is not possible to define a method for IT_REMOVE: we could easily define it
|
||||
by performing an _erase of the key get by the _cref method. However,
|
||||
@@ -716,19 +716,19 @@
|
||||
dict may perform a resize down operation, reducing the size of the array,
|
||||
base of the dict, by two. This operation renders the computation of the
|
||||
'next' element impossible as the order of the elements in the dict
|
||||
has fundamentaly changed in this case. We could detect this and restart
|
||||
has fundamentally changed in this case. We could detect this and restart
|
||||
the iteration from the first element, but it wouldn't fit the contract
|
||||
of the IT_REMOVE operator.
|
||||
|
||||
HASH method for dictionnary itself seems hard to implement:
|
||||
we have to handle the case where two dictionaries are structuraly
|
||||
different, but functionnaly identical (seems they have the same
|
||||
HASH method for dictionary itself seems hard to implement:
|
||||
we have to handle the case where two dictionaries are structurally
|
||||
different, but functionally identical (seems they have the same
|
||||
members, but put in a different order).
|
||||
We cannot iterator over the dictionary to compute a hash, as the
|
||||
order of the items in the dictionnary is not specified: they more
|
||||
order of the items in the dictionary is not specified: they more
|
||||
or less follow the hash of the keys, but if the low bits of the
|
||||
hash of the key is equal, they order may be different.
|
||||
Or if the table of the dictionnary has different values (this may
|
||||
Or if the table of the dictionary has different values (this may
|
||||
be avoided).
|
||||
*/
|
||||
#define M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) \
|
||||
@@ -1057,7 +1057,7 @@
|
||||
#define M_D1CT_OPLIST_FAILURE(name, key_oplist, value_oplist) \
|
||||
((M_LIB_ERROR(ARGUMENT_OF_DICT_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist)))
|
||||
|
||||
/* Define the oplist of a dictionnary
|
||||
/* Define the oplist of a dictionary
|
||||
NOTE: IT_REF is not exported so that the contained appears as not modifiable
|
||||
by algorithm.*/
|
||||
#define M_D1CT_OPLIST_P4(name, key_oplist, value_oplist) \
|
||||
@@ -1194,11 +1194,11 @@ enum m_d1ct_oa_element_e {
|
||||
# define M_D1CT_OA_PROBING(s) ((s)++)
|
||||
#endif
|
||||
|
||||
/* Lower Bound of the hash table (TODO: Common macro for both dictionnary) */
|
||||
/* Lower Bound of the hash table (TODO: Common macro for both dictionary) */
|
||||
#ifndef M_D1CT_OA_LOWER_BOUND
|
||||
#define M_D1CT_OA_LOWER_BOUND 0.2
|
||||
#endif
|
||||
/* Upper Bound of the hash table (TODO: Common macro for both dictionnary) */
|
||||
/* Upper Bound of the hash table (TODO: Common macro for both dictionary) */
|
||||
#ifndef M_D1CT_OA_UPPER_BOUND
|
||||
#define M_D1CT_OA_UPPER_BOUND 0.7
|
||||
#endif
|
||||
@@ -1416,7 +1416,7 @@ enum m_d1ct_oa_element_e {
|
||||
/* Then let's rehash all the entries in their **exact** position. \
|
||||
If we can't, let's put them in the 'tmp' array. \
|
||||
It has been measured that the size of this 'tmp' array is \
|
||||
around 6% of the size of updated dictionnary. \
|
||||
around 6% of the size of updated dictionary. \
|
||||
NOTE: This should be much cache friendly than typical hash code */ \
|
||||
M_F(name, _array_pair_ct) tmp; \
|
||||
M_F(name, _array_pair_init)(tmp); \
|
||||
@@ -1950,7 +1950,7 @@ enum m_d1ct_oa_element_e {
|
||||
M_D1CT_OA_CONTRACT(dict); \
|
||||
size_t size; \
|
||||
/* Get the size which will allow to fit this capacity \
|
||||
NOTE: Stricly speaking we need to perform a round up to ensure \
|
||||
NOTE: Strictly speaking we need to perform a round up to ensure \
|
||||
that no reallocation of the hash map occurs up to capacity */ \
|
||||
size = (size_t) m_core_roundpow2 ((uint64_t) ((double) capacity * (1.0 / coeff_up))); \
|
||||
/* Test for overflow of the computation */ \
|
||||
|
||||
+2
-2
@@ -96,7 +96,7 @@
|
||||
/*****************************************************************************/
|
||||
|
||||
/* To be used by M_IF_FUNCOBJ macro defined in m-core.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliabely.
|
||||
NOTE: It is reversed (0 instead of 1) so that it can be used in M_IF reliably.
|
||||
*/
|
||||
#define M_FUNC0BJ_IS_NOT_DEFINED 0
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
*
|
||||
* Structure definitions are specialized in function of the presence or not
|
||||
* of parameters and/or attributes
|
||||
* FIXME: How to factorize reasonnably well between the definitions?
|
||||
* FIXME: How to factorize reasonably well between the definitions?
|
||||
*/
|
||||
|
||||
/* Specialization of the OPLIST in function if there is at least one member or not */
|
||||
|
||||
+1
-1
@@ -329,7 +329,7 @@ typedef const char **m_g3n_cstring_end;
|
||||
( M_FPRINT_ARG_OUT_STR(f, M_PAIR_2 x, M_PAIR_1 x), \
|
||||
M_FPRINT_ARG_G3N(f, x) )
|
||||
|
||||
/* Ovverride M_PRINT */
|
||||
/* Override M_PRINT */
|
||||
#undef M_PRINT
|
||||
#define M_PRINT(...) do { M_REDUCE2(M_G3N_FPRINT_ARG, M_SEPARATE_PER_SEMICOLON, stdout, __VA_ARGS__); } while (0)
|
||||
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ typedef struct m_genint_s {
|
||||
|((M_GEN1NT_ABA_CPT_T)((master) + 1)))
|
||||
|
||||
/* Initialize an integer generator (CONSTRUCTOR).
|
||||
* Initialy, the container is full of all the integers up to 'n-1'
|
||||
* Initially, the container is full of all the integers up to 'n-1'
|
||||
* The typical sequence is to initialize the container, and pop
|
||||
* the integer from it. Each pop integer is **unique** for all threads,
|
||||
* meaning it can be used to index global unique resources shared
|
||||
|
||||
+2
-2
@@ -63,7 +63,7 @@
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define the oplist of a doubly-linked instrusive list of type.
|
||||
/* Define the oplist of a doubly-linked intrusive list of type.
|
||||
USAGE:
|
||||
ILIST_OPLIST(name [, oplist_of_the_type]) */
|
||||
#define M_ILIST_OPLIST(...) \
|
||||
@@ -234,7 +234,7 @@ typedef struct m_il1st_head_s {
|
||||
{ \
|
||||
/* Nothing to do more than clean the list itself */ \
|
||||
M_F(name, _reset)(list); \
|
||||
/* For safety purpose (create invalid represenation of object) */ \
|
||||
/* For safety purpose (create invalid representation of object) */ \
|
||||
list->name.next = NULL; \
|
||||
list->name.prev = NULL; \
|
||||
} \
|
||||
|
||||
+3
-3
@@ -46,11 +46,11 @@ M_BEGIN_PROTECTED_CODE
|
||||
atomic_int M_F(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization (Uses C99 designated element). */
|
||||
/* 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 intialization (Uses C89 designated element). */
|
||||
/* 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)
|
||||
|
||||
@@ -103,7 +103,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/******************************** INTERNAL ***********************************/
|
||||
|
||||
// Deferred evaluatioin
|
||||
// Deferred evaluation
|
||||
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
|
||||
@@ -188,6 +188,23 @@
|
||||
- node_t: alias for M_F(name, _node_t) [ node ]
|
||||
*/
|
||||
#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_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of a list
|
||||
(there is nothing worthy to be checked) */
|
||||
#define M_L1ST_CONTRACT(v) do { \
|
||||
M_ASSERT (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Define the type of a list */
|
||||
#define M_L1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
\
|
||||
/* Define the node of a list, and the list as a pointer to a node */ \
|
||||
typedef struct M_F(name, _s) { \
|
||||
@@ -207,22 +224,9 @@
|
||||
typedef list_t M_F(name, _ct); \
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
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_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
|
||||
/* Define the internal contract of a list
|
||||
(there is nothing worthy to be checked) */
|
||||
#define M_L1ST_CONTRACT(v) do { \
|
||||
M_ASSERT (v != NULL); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Internal list function definition
|
||||
/* Internal list function definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the list
|
||||
- oplist: oplist of the type of the elements of the container
|
||||
@@ -539,7 +543,7 @@
|
||||
*update_list = next; \
|
||||
if (M_UNLIKELY_NOMEM (next == NULL)) { \
|
||||
M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \
|
||||
/* FIXME: Partialy initialized list. What to do? */ \
|
||||
/* FIXME: Partially initialized list. What to do? */ \
|
||||
return; \
|
||||
} \
|
||||
update_list = &next->next; \
|
||||
@@ -666,8 +670,6 @@
|
||||
} \
|
||||
*list = previous; \
|
||||
} \
|
||||
\
|
||||
M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF)
|
||||
|
||||
|
||||
/* Internal list function definition using only iterator functions
|
||||
@@ -927,6 +929,15 @@
|
||||
#define M_L1ST_DUAL_PUSH_DEF_FAILURE(name, type, oplist, list_t, it_t) \
|
||||
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DUAL_PUSH_DEF): the given argument is not a valid oplist: " #oplist)
|
||||
|
||||
|
||||
/* Define the internal contract of an dual-push list */
|
||||
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
|
||||
M_ASSERT (l != NULL); \
|
||||
M_ASSERT ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Internal dual-push list definition
|
||||
- name: prefix to be used
|
||||
- type: type of the elements of the array
|
||||
@@ -935,7 +946,17 @@
|
||||
- it_t: alias for M_F(name, _it_t) [ iterator of the container ]
|
||||
*/
|
||||
#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_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the type of a dual-push list */
|
||||
#define M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \
|
||||
/* Node of a list (it is liked the singly linked list) */ \
|
||||
struct M_F(name, _s) { \
|
||||
struct M_F(name, _s) *next; \
|
||||
@@ -965,19 +986,6 @@
|
||||
typedef it_t M_F(name, _it_ct); \
|
||||
typedef type M_F(name, _subtype_ct); \
|
||||
\
|
||||
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_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t)
|
||||
|
||||
|
||||
/* Define the internal contract of an dual-push list */
|
||||
#define M_L1ST_DUAL_PUSH_CONTRACT(l) do { \
|
||||
M_ASSERT (l != NULL); \
|
||||
M_ASSERT ( (l->back == NULL && l->front == NULL) \
|
||||
|| (l->back != NULL && l->front != NULL)); \
|
||||
} while (0)
|
||||
|
||||
/* Internal dual-push list definition
|
||||
- name: prefix to be used
|
||||
@@ -1510,9 +1518,7 @@
|
||||
list->back = previous; \
|
||||
M_L1ST_DUAL_PUSH_CONTRACT(list); \
|
||||
} \
|
||||
\
|
||||
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)
|
||||
|
||||
|
||||
#if M_USE_SMALL_NAME
|
||||
#define LIST_DEF M_LIST_DEF
|
||||
|
||||
+2
-2
@@ -55,8 +55,8 @@
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* User shall be able to cutomize the size of the region segment and/or
|
||||
the minimun number of elements.
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
+2
-2
@@ -30,13 +30,13 @@
|
||||
|
||||
/* Priority queue based on binary heap implementation */
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
/* Define a priority queue (prioqueue) of a given type and its associated functions.
|
||||
USAGE: PRIOQUEUE_DEF(name, type [, oplist_of_the_type]) */
|
||||
#define M_PRIOQUEUE_DEF(name, ...) \
|
||||
M_PRIOQUEUE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a prioqueue of a given type and its associated functions.
|
||||
/* Define a priority queue (prioqueue) of a given type and its associated functions.
|
||||
as the name name_t with an iterator named it_t
|
||||
USAGE: PRIOQUEUE_DEF_AS(name, name_t, it_t, type [, oplist_of_the_type]) */
|
||||
#define M_PRIOQUEUE_DEF_AS(name, name_t, it_t, ...) \
|
||||
|
||||
+2
-2
@@ -905,7 +905,7 @@ typedef enum {
|
||||
M_ASSERT (M_C3(m_rbtr33_,name,_black_p)(s)); \
|
||||
} \
|
||||
M_ASSERT (p != NULL && u == p->child[nbChild]); \
|
||||
/* if both childreen of s are black */ \
|
||||
/* if both children of s are black */ \
|
||||
/* perform recoloring and recur on parent if black */ \
|
||||
if (s != NULL \
|
||||
&& M_C3(m_rbtr33_,name,_black_p)(s->child[0]) \
|
||||
@@ -983,7 +983,7 @@ typedef enum {
|
||||
it_t it1; \
|
||||
it_t it2; \
|
||||
/* NOTE: We can't compare two tree directly as they can be \
|
||||
structuraly different but functionnaly equal (you get this by \
|
||||
structurally different but functionally equal (you get this by \
|
||||
constructing the tree in a different way). We have to \
|
||||
compare the ordered value within the tree. */ \
|
||||
M_F(name, _it)(it1, t1); \
|
||||
|
||||
+12
-12
@@ -31,13 +31,13 @@
|
||||
|
||||
M_BEGIN_PROTECTED_CODE
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
/* Define a Single Producer Single Consumer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPSC_DEF(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPSC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPSC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Single Consummer snapshot and its functions
|
||||
/* Define a Single Producer Single Consumer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPSC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPSC_DEF_AS(name, name_t, ...) \
|
||||
@@ -48,13 +48,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Single Producer Multiple Consumer snapshot and its functions
|
||||
USAGE: SNAPSHOT_SPMC_DEF(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_SPMC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Single Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Single Producer Multiple Consumer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_SPMC_DEF_AS(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_SPMC_DEF_AS(name, name_t, ...) \
|
||||
@@ -65,13 +65,13 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Multiple Producer Multiple Consumer snapshot and its functions
|
||||
USAGE: SNAPSHOT_MPMC_DEF(name, type[, oplist]) */
|
||||
#define M_SNAPSHOT_MPMC_DEF(name, ...) \
|
||||
M_SNAPSHOT_MPMC_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
|
||||
|
||||
|
||||
/* Define a Multiple Producer Multiple Consummer snapshot and its functions
|
||||
/* Define a Multiple Producer Multiple Consumer snapshot and its functions
|
||||
as the given name name_t
|
||||
USAGE: SNAPSHOT_MPMC_DEF_AS(name, name_t, type[, oplist]) */
|
||||
#define M_SNAPSHOT_MPMC_DEF_AS(name, name_t, ...) \
|
||||
@@ -154,10 +154,10 @@ M_BEGIN_PROTECTED_CODE
|
||||
} while (0)
|
||||
|
||||
// A snapshot is basically an atomic triple buffer (Lock Free)
|
||||
// between a single producer thread and a single consummer thread.
|
||||
// between a single producer thread and a single Consumer thread.
|
||||
#define M_SNAPSH0T_SPSC_MAX_BUFFER 3
|
||||
|
||||
// Defered evaluation of the arguments.
|
||||
// Deferred evaluation of the arguments.
|
||||
#define M_SNAPSH0T_SPSC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPSC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
@@ -514,7 +514,7 @@ m_snapsh0t_mrsw_write_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
{
|
||||
M_SNAPSH0T_SPMC_INT_CONTRACT(s);
|
||||
|
||||
// Provide this write bufer to the readers
|
||||
// Provide this write buffer to the readers
|
||||
unsigned int newNext, previous = atomic_load(&s->lastNext);
|
||||
do {
|
||||
newNext = M_SNAPSH0T_SPMC_INT_FLAG(idx, true);
|
||||
@@ -558,7 +558,7 @@ m_snapsh0t_mrsw_read_start(m_snapsh0t_mrsw_ct s)
|
||||
if (idx == M_SNAPSH0T_SPMC_INT_FLAG_W(previous)) {
|
||||
// This is still ok if the index has not changed
|
||||
// We can get previous to true again if the writer has recycled the index,
|
||||
// while we reserved it, and the reader get prempted until its CAS.
|
||||
// while we reserved it, and the reader get preempted until its CAS.
|
||||
if (M_UNLIKELY (M_SNAPSH0T_SPMC_INT_FLAG_N(previous) == true)) goto reforce;
|
||||
break;
|
||||
}
|
||||
@@ -601,7 +601,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
} while (0)
|
||||
|
||||
|
||||
// Defered evaluation
|
||||
// Deferred evaluation
|
||||
#define M_SNAPSH0T_SPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_SPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
@@ -714,7 +714,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx)
|
||||
|
||||
// MPMC is built upon SPMC
|
||||
|
||||
// Defered evaluation
|
||||
// Deferred evaluation
|
||||
#define M_SNAPSH0T_MPMC_DEF_P1(arg) M_ID( M_SNAPSH0T_MPMC_DEF_P2 arg )
|
||||
|
||||
/* Validate the oplist before going further */
|
||||
|
||||
+25
-25
@@ -238,13 +238,13 @@ m_string_clear(m_string_t v)
|
||||
v->u.stack.buffer[sizeof (m_str1ng_heap_ct) - 1] = CHAR_MAX;
|
||||
}
|
||||
|
||||
/* NOTE: Internaly used by M_STRING_DECL_INIT */
|
||||
/* NOTE: Internally used by M_STRING_DECL_INIT */
|
||||
M_INLINE void m_str1ng_clear2(m_string_t *v) { m_string_clear(*v); }
|
||||
M_INLINE m_string_ptr m_str1ng_init_ref(m_string_t v) { m_string_init(v); return v; }
|
||||
|
||||
/* Clear the Dynamic string (destructor)
|
||||
and return a heap pointer to the string.
|
||||
The ownership of the data is transfered back to the caller
|
||||
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)
|
||||
@@ -319,7 +319,7 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc)
|
||||
// Note: this function may be called in context where the contract
|
||||
// is not fulfilled.
|
||||
const size_t old_alloc = m_string_capacity(v);
|
||||
// This line enables the compiler to completly remove this function
|
||||
// This line enables the compiler to completely remove this function
|
||||
// for very short constant strings.
|
||||
M_ASSUME(old_alloc >= sizeof (m_str1ng_heap_ct) - 1);
|
||||
if (M_UNLIKELY (size_alloc > old_alloc)) {
|
||||
@@ -536,7 +536,7 @@ m_string_push_back (m_string_t v, char c)
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Concatene the string with the C string */
|
||||
/* Concatenate the string with the C string */
|
||||
M_INLINE void
|
||||
m_string_cat_cstr(m_string_t v, const char str[])
|
||||
{
|
||||
@@ -550,7 +550,7 @@ m_string_cat_cstr(m_string_t v, const char str[])
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Concatene the string with the other string */
|
||||
/* Concatenate the string with the other string */
|
||||
M_INLINE void
|
||||
m_string_cat(m_string_t v, const m_string_t v2)
|
||||
{
|
||||
@@ -613,7 +613,7 @@ m_string_equal_p(const m_string_t v1, const m_string_t v2)
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the C string
|
||||
(case insentive according to the current locale)
|
||||
(case insensitive according to the current locale)
|
||||
Note: doesn't work with UTF-8 strings.
|
||||
*/
|
||||
M_INLINE int
|
||||
@@ -635,7 +635,7 @@ m_string_cmpi_cstr(const m_string_t v1, const char p2[])
|
||||
}
|
||||
|
||||
/* Test if the string is equal to the other string
|
||||
(case insentive according to the current locale)
|
||||
(case insensitive according to the current locale)
|
||||
Note: doesn't work with UTF-8 strings.
|
||||
*/
|
||||
M_INLINE int
|
||||
@@ -796,7 +796,7 @@ m_string_mid (m_string_t v, size_t index, size_t size)
|
||||
m_string_left(v, size);
|
||||
}
|
||||
|
||||
/* Replace in the string the firt occurence of the C string str1
|
||||
/* Replace in the string the first occurrence of the C string str1
|
||||
into the C string str2 from start
|
||||
By default, start is zero.
|
||||
*/
|
||||
@@ -822,7 +822,7 @@ m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Replace in the string the firt occurence of the C string v1
|
||||
/* Replace in the string the first occurrence of the C string v1
|
||||
into the C string v2 from start
|
||||
By default, start is zero.
|
||||
*/
|
||||
@@ -861,7 +861,7 @@ m_string_replace_at (m_string_t v, size_t pos, size_t len, const char str2[])
|
||||
M_STR1NG_CONTRACT (v);
|
||||
}
|
||||
|
||||
/* Replace all occurences of str1 into str2 when strlen(str1) >= strlen(str2) */
|
||||
/* Replace all occurrences of str1 into str2 when strlen(str1) >= strlen(str2) */
|
||||
M_INLINE void
|
||||
m_str1ng_replace_all_cstr_1ge2 (m_string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len)
|
||||
{
|
||||
@@ -1167,7 +1167,7 @@ m_string_set_si(m_string_t v, int n)
|
||||
|
||||
#if M_USE_STDIO
|
||||
|
||||
/* Get a line/pureline/file from the FILE and store it in the string */
|
||||
/* 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)
|
||||
{
|
||||
@@ -1192,7 +1192,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
}
|
||||
m_str1ng_set_size(v, size);
|
||||
M_STR1NG_CONTRACT(v);
|
||||
return retcode; /* Normal terminaison */
|
||||
return retcode; /* Normal termination */
|
||||
} else if (ptr[size-1] != '\n' && !feof(f)) {
|
||||
/* The string buffer is not big enough:
|
||||
increase it and continue reading */
|
||||
@@ -1203,7 +1203,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg)
|
||||
}
|
||||
m_str1ng_set_size(v, size);
|
||||
M_STR1NG_CONTRACT (v);
|
||||
return retcode; /* Abnormal terminaison */
|
||||
return retcode; /* Abnormal termination */
|
||||
}
|
||||
|
||||
/* Get a word from the FILE and store it in the string.
|
||||
@@ -1333,30 +1333,30 @@ m_string_hash(const m_string_t v)
|
||||
return m_core_hash(m_string_get_cstr(v), m_string_size(v));
|
||||
}
|
||||
|
||||
// Return true if c is a character from charac
|
||||
// Return true if c is a character from the C-String tab
|
||||
M_INLINE bool
|
||||
m_str1ng_strim_char(char c, const char charac[])
|
||||
m_str1ng_strim_char(char c, const char tab[])
|
||||
{
|
||||
for(const char *s = charac; *s; s++) {
|
||||
for(const char *s = tab; *s; s++) {
|
||||
if (c == *s)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Remove any characters from charac that are present
|
||||
in the begining of the string and the end of the string. */
|
||||
/* Remove any characters from tab that are present
|
||||
in the beginning of the string and the end of the string. */
|
||||
M_INLINE void
|
||||
m_string_strim(m_string_t v, const char charac[])
|
||||
m_string_strim(m_string_t v, const char tab[])
|
||||
{
|
||||
M_STR1NG_CONTRACT (v);
|
||||
char *ptr = m_str1ng_get_cstr(v);
|
||||
char *b = ptr;
|
||||
size_t size = m_string_size(v);
|
||||
while (size > 0 && m_str1ng_strim_char(b[size-1], charac))
|
||||
while (size > 0 && m_str1ng_strim_char(b[size-1], tab))
|
||||
size --;
|
||||
if (size > 0) {
|
||||
while (m_str1ng_strim_char(*b, charac))
|
||||
while (m_str1ng_strim_char(*b, tab))
|
||||
b++;
|
||||
M_ASSERT (b >= ptr && size >= (size_t) (b - ptr) );
|
||||
size -= (size_t) (b - ptr);
|
||||
@@ -1374,7 +1374,7 @@ m_string_oor_equal_p(const m_string_t s, unsigned char n)
|
||||
return (s->ptr == NULL) & (s->u.heap.alloc == ~(size_t)n);
|
||||
}
|
||||
|
||||
/* Set the unitialized string to the OOR value */
|
||||
/* Set the uninitialized string to the OOR value */
|
||||
M_INLINE void
|
||||
m_string_oor_set(m_string_t s, unsigned char n)
|
||||
{
|
||||
@@ -1633,7 +1633,7 @@ m_string_in_serial(m_string_t v, m_serial_read_t serial)
|
||||
It shall be (nearly) branchless on any CPU.
|
||||
It takes a byte, and the previous state and the previous value of the unicode code point.
|
||||
It updates the state and the decoded unicode code point.
|
||||
A decoded unicoded code point is valid only when the state is STARTING.
|
||||
A decoded unicode code point is valid only when the state is STARTING.
|
||||
*/
|
||||
M_INLINE void
|
||||
m_str1ng_utf8_decode(char c, m_str1ng_utf8_state_e *state,
|
||||
@@ -1753,7 +1753,7 @@ m_string_it_set(m_string_it_t it, const m_string_it_t itsrc)
|
||||
}
|
||||
|
||||
/* Set the iterator to the given position in the string.
|
||||
The given position shall reference a valide code point in the string.
|
||||
The given position shall reference a valid code point in the string.
|
||||
*/
|
||||
M_INLINE void
|
||||
m_string_it_pos(m_string_it_t it, const m_string_t str, const size_t n)
|
||||
@@ -2524,7 +2524,7 @@ namespace m_lib {
|
||||
M_F(name, _hash)(const bounded_t s) \
|
||||
{ \
|
||||
M_BOUNDED_STR1NG_CONTRACT(s, max_size); \
|
||||
/* Cannot use m_core_hash: alignment not sufficent */ \
|
||||
/* Cannot use m_core_hash: alignment guarantee is not sufficient */ \
|
||||
return m_core_cstr_hash(s->s); \
|
||||
} \
|
||||
\
|
||||
|
||||
+5
-5
@@ -136,7 +136,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
(void) rc;
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -187,7 +187,7 @@ M_END_PROTECTED_CODE
|
||||
* We cannot add theses warnings in M_BEGIN_PROTECTED_CODE
|
||||
* as they need to be disabled **BEFORE** including any system header
|
||||
* and m-core includes some system headers.
|
||||
* So we need to disable them explictly here.
|
||||
* So we need to disable them explicitly here.
|
||||
*/
|
||||
#if defined(__clang__) && __clang_major__ >= 4
|
||||
_Pragma("clang diagnostic push")
|
||||
@@ -294,7 +294,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
CloseHandle(*t);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -453,7 +453,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
M_ASSERT (_rc == 0);
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
@@ -659,7 +659,7 @@ M_INLINE void m_thread_join(m_thread_t t)
|
||||
t->SemHandle = 0;
|
||||
}
|
||||
|
||||
/* The thread has nothing meaningfull to do.
|
||||
/* The thread has nothing meaningful to do.
|
||||
Inform the OS to let other threads be scheduled */
|
||||
M_INLINE void m_thread_yield(void)
|
||||
{
|
||||
|
||||
@@ -532,7 +532,7 @@ typedef int32_t m_tr33_index_t;
|
||||
M_INLINE it_t \
|
||||
M_F(name, _insert_child_raw)(it_t it) { \
|
||||
M_TR33_IT_CONTRACT(it, true); \
|
||||
/* Insert a node as a child of another, making the current childreen \
|
||||
/* 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 child = it.tree->tab[it.index].child; \
|
||||
@@ -1157,7 +1157,7 @@ typedef int32_t m_tr33_index_t;
|
||||
\
|
||||
M_INLINE void \
|
||||
M_F(name, _set)(tree_t tree, const tree_t ref) { \
|
||||
/* No optimum, but good enought for present time */ \
|
||||
/* No optimum, but good enough currently */ \
|
||||
M_F(name, _clear)(tree); \
|
||||
M_F(name, _init_set)(tree, ref); \
|
||||
} \
|
||||
@@ -1213,7 +1213,7 @@ typedef int32_t m_tr33_index_t;
|
||||
return (size_t) tree->capacity; \
|
||||
} \
|
||||
\
|
||||
/* Service not really usefull as the affectation operator works with it */\
|
||||
/* Service not really useful as the affectation operator works with it */ \
|
||||
M_INLINE void \
|
||||
M_F(name, _it_set)(it_t *dst, it_t src ){ \
|
||||
*dst = src; \
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
|
||||
/*
|
||||
* Start a protected section of code 'name' where all exceptions are catched
|
||||
* Start a protected section of code 'name' where all exceptions are caught
|
||||
* by the associated CATCH section.
|
||||
*/
|
||||
#define M_TRY(name) \
|
||||
@@ -249,7 +249,7 @@ namespace m_lib {
|
||||
// Use of builtin setjmp / longjmp for GCC
|
||||
// There are at least twice faster at worst, and reduce stack consumption
|
||||
// See https://gcc.gnu.org/onlinedocs/gcc/Nonlocal-Gotos.html
|
||||
// CLANG doesn't support these builtins officialy (https://groups.google.com/g/llvm-dev/c/9QgfdW23K8M)
|
||||
// CLANG doesn't support these builtins officially (https://groups.google.com/g/llvm-dev/c/9QgfdW23K8M)
|
||||
#define m_try_setjmp(x) __builtin_setjmp(x)
|
||||
#define m_try_longjmp(x,v) __builtin_longjmp(x, v)
|
||||
typedef intptr_t m_try_jmp_buf[5];
|
||||
@@ -281,7 +281,7 @@ typedef intptr_t m_try_jmp_buf[5];
|
||||
// this point in the stack frame. Each nodes are linked together, so that we can
|
||||
// analyze the stack frame on exception.
|
||||
typedef struct m_try_s {
|
||||
enum { M_STATE_TRY, M_STATE_EXCEPTION_IN_PROGRESS, M_STATE_EXCEPTION_CATCHED,
|
||||
enum { M_STATE_TRY, M_STATE_EXCEPTION_IN_PROGRESS, M_STATE_EXCEPTION_CAUGHT,
|
||||
M_STATE_CLEAR_JMPBUF, M_STATE_CLEAR_CB } kind;
|
||||
struct m_try_s *next;
|
||||
union {
|
||||
@@ -354,7 +354,7 @@ extern M_ATTR_NO_RETURN M_ATTR_COLD_FUNCTION void m_throw(const struct m_excepti
|
||||
} \
|
||||
/* No exception found. \
|
||||
Display the information and halt program . */ \
|
||||
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not catched. Program aborted.\n", \
|
||||
M_RAISE_FATAL("Exception '%u' raised by (%s:%d) is not caught. Program aborted.\n", \
|
||||
exception->error_code, exception->filename, exception->line); \
|
||||
}
|
||||
|
||||
@@ -376,8 +376,8 @@ m_catch(m_try_t state, unsigned error_code, const struct m_exception_s **excepti
|
||||
*exception = &m_global_exception;
|
||||
if (error_code != 0 && m_global_exception.error_code != error_code)
|
||||
return false;
|
||||
// The exception has been catched.
|
||||
state->kind = M_STATE_EXCEPTION_CATCHED;
|
||||
// The exception has been caught.
|
||||
state->kind = M_STATE_EXCEPTION_CAUGHT;
|
||||
// Unstack the try block, so that next throw command in the CATCH block
|
||||
// will reach the upper TRY block.
|
||||
m_global_error_list = state->next;
|
||||
@@ -413,7 +413,7 @@ m_try_clear(m_try_t state)
|
||||
|
||||
// Implement the M_LET injection macros, so that the CLEAR operator is called on exception
|
||||
// Helper functions
|
||||
// Each mechanisme provide 3 helper functions:
|
||||
// Each mechanism provide 3 helper functions:
|
||||
// * pre: which is called before the constructor
|
||||
// * post: which is called after the constructor
|
||||
// * final: which is called before the destructor.
|
||||
|
||||
+10
-10
@@ -185,7 +185,7 @@ typedef struct m_worker_sync_s {
|
||||
M_END_PROTECTED_CODE
|
||||
|
||||
/* Output a valid oplist with the given type.
|
||||
input is (fieldname, type) or (fieldname, type, oplist)
|
||||
input is (field-name, type) or (field-name, type, oplist)
|
||||
Output shall be : M_OPEXTEND(M_GLOBAL_OPLIST_OR_DEF(type_or_oplist)(), TYPE(type)) / M_OPEXTEND(oplist, TYPE(type))
|
||||
*/
|
||||
#define M_WORK3R_SPAWN_EXTEND_P0(...) M_BY_NARGS(M_WORK3R_SPAWN_EXTEND_P0, M_ID __VA_ARGS__) __VA_ARGS__
|
||||
@@ -377,7 +377,7 @@ m_work3r_thread(void *arg)
|
||||
if (w.block == NULL) break;
|
||||
// Execute the work order
|
||||
m_work3r_exec(&w);
|
||||
// Consumme fully the work order in the queue
|
||||
// Consume fully the work order in the queue
|
||||
m_work3r_queue_pop_release(g->queue_g);
|
||||
// Signal that a worker has finished.
|
||||
m_mutex_lock(g->lock);
|
||||
@@ -395,7 +395,7 @@ m_work3r_thread(void *arg)
|
||||
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@resetFunc: function to reset the state of a worker between work orders (or NULL if none)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (or NULL if none)
|
||||
@clearFunc: function to clear the state of a worker before terminating (or NULL if none)
|
||||
*/
|
||||
M_INLINE void
|
||||
m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*resetFunc)(void), void (*clearFunc)(void))
|
||||
@@ -432,7 +432,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset
|
||||
@numWorker: number of worker to create (0=autodetect, -1=2*autodetect)
|
||||
@extraQueue: number of extra work order we can get if all workers are full
|
||||
@resetFunc: function to reset the state of a worker between work orders (optional)
|
||||
@clearFunc: function to clear the state of a worker before terminaning (optional)
|
||||
@clearFunc: function to clear the state of a worker before terminating (optional)
|
||||
*/
|
||||
#define m_worker_init(...) m_worker_init(M_DEFAULT_ARGS(5, (0, 0, NULL, NULL), __VA_ARGS__))
|
||||
|
||||
@@ -444,12 +444,12 @@ m_worker_clear(m_worker_t g)
|
||||
// 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;
|
||||
// Normaly all worker threads shall be waiting at this
|
||||
// Normally all worker threads shall be waiting at this
|
||||
// stage, so all push won't block as the queue is empty.
|
||||
// But for robustness, let's wait.
|
||||
m_work3r_queue_push_blocking (g->queue_g, w, true);
|
||||
}
|
||||
// Wait for thread terminanison
|
||||
// Wait for thread termination
|
||||
for(unsigned int i = 0; i < g->numWorker_g; i++) {
|
||||
m_thread_join(g->worker[i].id);
|
||||
}
|
||||
@@ -532,9 +532,9 @@ m_work3r_spawn_function(m_worker_sync_t block, std::function<void(void *data)> f
|
||||
M_INLINE bool
|
||||
m_worker_sync_p(m_worker_sync_t block)
|
||||
{
|
||||
/* If the number of spawns is greated than the number
|
||||
/* If the number of spawns is greater than the number
|
||||
of terminated spawns, some spawns are still working.
|
||||
So wait for terminaison */
|
||||
So wait for termination */
|
||||
return (atomic_load(&block->num_spawn) == atomic_load (&block->num_terminated_spawn));
|
||||
}
|
||||
|
||||
@@ -542,7 +542,7 @@ m_worker_sync_p(m_worker_sync_t block)
|
||||
M_INLINE void
|
||||
m_worker_sync(m_worker_sync_t block)
|
||||
{
|
||||
M_WORK3R_DEBUG ("Waiting for thread terminasion.\n");
|
||||
M_WORK3R_DEBUG ("Waiting for thread termination.\n");
|
||||
// Fast case: all workers have finished
|
||||
if (m_worker_sync_p(block)) return;
|
||||
// Slow case: perform a locked wait to put this thread to waiting state
|
||||
@@ -574,7 +574,7 @@ m_worker_count(m_worker_t g)
|
||||
|
||||
/* Spawn the 'core' block computation into another thread if
|
||||
a worker thread is available. Compute it in the current thread otherwise.
|
||||
'block' shall be the initialised synchronised block for all threads.
|
||||
'block' shall be the initialised synchronized block for all threads.
|
||||
'input' is the list of input variables of the 'core' block within "( )"
|
||||
'output' is the list of output variables of the 'core' block within "( )"
|
||||
Output variables are only available after a synchronisation block.
|
||||
|
||||
Reference in new issue
Block a user