diff --git a/m-atomic.h b/m-atomic.h index f4d9339a..70e3392e 100644 --- a/m-atomic.h +++ b/m-atomic.h @@ -30,6 +30,7 @@ See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60932 clang++ has no issue with this header but if someone includes atomic from C++, there is incompatibility between atomic & stdatomic. + Moreover some compilers lack a working stdatomic header. GCC 4.9 doesn't have a working implementation of 'atomic'. APPLE Clang defines __GNUC__ to be only 4 despite having full support for atomic. @@ -149,7 +150,7 @@ using std::memory_order_seq_cst; 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. - We also assume that the call to the atomic_* interface is "clean". + We also assume that the call to the atomic_* interface is "macro clean". */ #else diff --git a/m-bptree.h b/m-bptree.h index 77099bd4..f3b95fe5 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -294,7 +294,11 @@ typedef key_t subtype_t; \ ) \ \ - /* Node of a B+TREE */ \ + /* Define a Node of a B+TREE \ + * For a reason of simplicity, it allocates one more element than \ + * needed so that the code can push one more element in the node and \ + * then split the nodes (simplify the code) \ + */ \ typedef struct M_C(name, _node_s) { \ int num; /* Abs=Number of keys. Sign <0 is leaf */ \ key_t key[N+1]; /* We can temporary push one more key */ \ @@ -319,13 +323,13 @@ typedef value_t M_C(name, _value_ct); \ typedef tree_t M_C(name, _ct); \ \ - /* Parent Iterator */ \ + /* Define the Parent Tree Iterator */ \ typedef struct M_C(name, _parent_it_s) { \ int num; \ node_t parent[BPTREEI_MAX_STACK]; \ } pit_t[1]; \ \ - /* Iterator */ \ + /* Define the Iterator */ \ typedef struct M_C(name, _it_s) { \ M_IF(isMap)(struct M_C(name, _pair_s) pair;,) \ node_t node; \ diff --git a/m-buffer.h b/m-buffer.h index 3b001d01..38534245 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -148,7 +148,9 @@ typedef enum { \ typedef struct M_C(name, _s) *M_C(name, _ptr); \ typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ - typedef union { M_C(name, _srcptr) cptr; M_C(name, _ptr) ptr; } M_C(name, _uptr); \ + /* Internal type used to unconst the buffer */ \ + typedef union { M_C(name, _srcptr) cptr; M_C(name, _ptr) ptr; } M_C(name, _uptr_ct); \ + /* Internal types used by the oplist */ \ typedef type M_C(name, _subtype_ct); \ typedef buffer_t M_C(name, _ct); \ \ @@ -263,7 +265,7 @@ M_C(name, _init)(buffer_t v, size_t size) \ M_C(name, _init_set)(buffer_t dest, const buffer_t src) \ { \ /* unconst 'src', so that we can lock it (semantically it is const) */ \ - M_C(name, _uptr) vu; \ + M_C(name, _uptr_ct) vu; \ vu.cptr = src; \ M_C(name, _ptr) v = vu.ptr; \ assert (dest != v); \ @@ -307,7 +309,7 @@ M_C(name, _init)(buffer_t v, size_t size) \ M_C(name, _set)(buffer_t dest, const buffer_t src) \ { \ /* unconst 'src', so that we can lock it (semantically it is const) */ \ - M_C(name, _uptr) vu; \ + M_C(name, _uptr_ct) vu; \ vu.cptr = src; \ M_C(name, _ptr) v = vu.ptr; \ BUFFERI_CONTRACT(dest,m_size); \ diff --git a/m-concurrent.h b/m-concurrent.h index e546c85f..1cd98f6a 100644 --- a/m-concurrent.h +++ b/m-concurrent.h @@ -143,6 +143,7 @@ */ #define CONCURRENTI_DEF_P3(name, type, oplist, concurrent_t) \ \ + /* Define a concurrent container using a lock */ \ typedef struct M_C(name, _s) { \ struct M_C(name, _s) *self; \ m_mutex_t lock; \ @@ -150,6 +151,7 @@ type data; \ } concurrent_t[1]; \ \ + /* Define alias for pointer types */ \ typedef struct M_C(name, _s) *M_C(name, _ptr); \ typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ \ @@ -157,6 +159,7 @@ typedef concurrent_t M_C(name, _ct); \ typedef type M_C(name, _subtype_ct); \ \ + /* Don't define iterator as it cannot be reliable in a concurrent type */ \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ \ /* Define the lock strategy (global & shared lock) */ \ diff --git a/m-deque.h b/m-deque.h index f6d05fa1..ccb0f064 100644 --- a/m-deque.h +++ b/m-deque.h @@ -114,7 +114,7 @@ typedef struct M_C(name, _it2_s) { \ node_t *node; \ size_t index; \ - } M_C(name, _it2_t)[1]; \ + } M_C(name, _it2_ct)[1]; \ \ /* Define the deque type: \ - 'list' if the list of buckets containing the objects. \ @@ -124,15 +124,17 @@ */ \ typedef struct M_C(name, _s) { \ M_C(name, _node_list_t) list; \ - M_C(name, _it2_t) front; \ - M_C(name, _it2_t) back; \ + M_C(name, _it2_ct) front; \ + M_C(name, _it2_ct) back; \ size_t default_size; \ size_t count; \ } deque_t[1]; \ \ + /* Define pointer alias */ \ typedef struct M_C(name, _s) *M_C(name, _ptr); \ typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ \ + /* Define the iterator object */ \ typedef struct M_C(name, _it_s) { \ node_t *node; \ size_t index; \ diff --git a/m-i-shared.h b/m-i-shared.h index d0f71d69..29db7070 100644 --- a/m-i-shared.h +++ b/m-i-shared.h @@ -100,7 +100,7 @@ M_BEGIN_PROTECTED_CODE /* The shared pointer is only a pointer to the type */ \ typedef type *shared_t; \ \ - /* Define internal types for oplits */ \ + /* Define internal types for oplist */ \ typedef shared_t M_C(name, _ct); \ typedef type M_C(name, _subtype_ct); \ \ diff --git a/m-mempool.h b/m-mempool.h index c74a283e..ef6a591f 100644 --- a/m-mempool.h +++ b/m-mempool.h @@ -59,17 +59,24 @@ #define MEMPOOL_DEF_P2(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_C(name,_union_s) { \ type t; \ union M_C(name,_union_s) *next; \ } M_C(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_C(name,_segment_s) { \ unsigned int count; \ struct M_C(name,_segment_s) *next; \ M_C(name,_union_ct) tab[MEMPOOL_MAX_PER_SEGMENT(type)]; \ } M_C(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_C(name, _s) { \ M_C(name,_union_ct) *free_list; \ M_C(name,_segment_ct) *current_segment; \ @@ -108,14 +115,18 @@ M_C(name,_alloc)(name_t mem) \ { \ MEMPOOLI_CONTRACT(mem, type); \ + /* Test if one object is in the free list */ \ M_C(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_C(name,_segment_ct) *segment = mem->current_segment; \ assert(segment != NULL); \ unsigned int count = segment->count; \ + /* If segment is full, allocate a new one from the system */ \ if (M_UNLIKELY (count >= MEMPOOL_MAX_PER_SEGMENT(type))) { \ M_C(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_C(name,_segment_ct)); \ if (M_UNLIKELY (new_segment == NULL)) { \ @@ -128,6 +139,7 @@ segment = new_segment; \ count = 0; \ } \ + /* Return the object as the last element of the current segment */ \ ret = &segment->tab[count]; \ segment->count = count + 1; \ MEMPOOLI_CONTRACT(mem, type); \ @@ -141,12 +153,15 @@ /* NOTE: Unsafe cast: suppose that the given pointer \ was allocated by the previous alloc function. */ \ M_C(name,_union_ct) *ret = (M_C(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 */ \ MEMPOOLI_CONTRACT(mem, type); \ } \ - +/* MEMPOOL contract */ #define MEMPOOLI_CONTRACT(mempool, type) do { \ assert((mempool) != NULL); \ assert((mempool)->current_segment != NULL); \ diff --git a/m-prioqueue.h b/m-prioqueue.h index 80207c66..f83e71d1 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -26,7 +26,7 @@ #define MSTARLIB_PRIOQUEUE_H #include "m-core.h" -#include "m-array.h" +#include "m-array.h" /* Priority queue are built upon array */ /* Priority queue based on binary heap implementation */ @@ -108,10 +108,11 @@ /* Definition of the internal array used to construct the priority queue */ \ ARRAY_DEF(M_C(name, _array), type, oplist) \ \ - \ + /* Define the priority queue over the defined array */ \ typedef struct M_C(name, _s) { \ M_C(name, _array_t) array; \ } prioqueue_t[1]; \ + /* Define the pointer references to the priority queue */ \ typedef struct M_C(name, _s) *M_C(name, _ptr); \ typedef const struct M_C(name, _s) *M_C(name, _srcptr); \ \ @@ -216,8 +217,11 @@ static inline void \ M_C(name, _push)(prioqueue_t p, type const x) \ { \ + /* Push back the new element at the end of the array */ \ M_C(name, _array_push_back)(p->array, x); \ \ + /* Reorder the array by swapping with its parent \ + * until it reaches the right position */ \ size_t i = M_C(name, _array_size)(p->array)-1; \ while (i > 0) { \ size_t j = M_C(name, _i_parent)(i); \ @@ -237,25 +241,31 @@ static inline void \ M_C(name, _pop)(type *x, prioqueue_t p) \ { \ + /* Swap the front element with the last element */ \ size_t size = M_C(name, _array_size)(p->array)-1; \ M_C(name, _array_swap_at) (p->array, 0, size); \ + /* Swap the new last element */ \ M_C(name, _array_pop_back)(x, p->array); \ \ + /* Reorder the heap */ \ size_t i = 0; \ while (true) { \ size_t child = M_C(name, _i_lchild)(i); \ - if (child >= size) break; \ + if (child >= size) \ + break; \ size_t otherChild = M_C(name, _i_rchild)(i); \ if (otherChild < size \ && M_C(name, _i_cmp)(p, otherChild, child) < 0 ) { \ child = otherChild; \ } \ - if (M_C(name, _i_cmp)(p, i, child) <= 0) break; \ + if (M_C(name, _i_cmp)(p, i, child) <= 0) \ + break; \ M_C(name, _array_swap_at) (p->array, i, child); \ i = child; \ } \ } \ \ + /* Define iterators over the array iterator */ \ static inline void \ M_C(name, _it)(it_t it, prioqueue_t const v) \ { \ diff --git a/m-rbtree.h b/m-rbtree.h index 7cdc5df1..634189ec 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -176,7 +176,7 @@ typedef enum { rbtreei_color_e color; \ } node_t; \ \ - /* Red/Black tree */ \ + /* Define the Red/Black tree */ \ typedef struct M_C(name, _s) { \ size_t size; /* Number of elements in the tree */ \ node_t *node; /* Root node of the tree */ \