From 5b4c9cd6182b77c3ed8df6349162d3860ce07d4a Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 21 Dec 2024 12:35:46 +0100 Subject: [PATCH 01/91] Update spec of memory functions --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c317690a..f2d5875b 100644 --- a/README.md +++ b/README.md @@ -641,10 +641,10 @@ Other documented operators are: * `KEY_OPLIST()` --> `oplist`: Return the oplist of the key type for associative containers. * `VALUE_OPLIST()` --> `oplist`: Return the oplist of the value type for associative containers. * `NEW(type)` --> `type pointer`: allocate a new object (with suitable alignment and size) and return a pointer to it. The returned object is **not initialized** (a constructor operator shall be called afterward). The default method is `M_MEMORY_ALLOC` (that allocates from the heap). It returns NULL in case of failure. -* `DEL(&obj)`: free the allocated uninitialized object `obj`. The destructor of the pointed object shall be called before freeing the memory by calling this method. The object shall have been allocated by the associated NEW method. The default method is `M_MEMORY_DEL` (that frees to the heap). `obj` shall not be NULL and shall be of the proper type. -* `REALLOC(type, type pointer, number)` --> `type pointer`: reallocate the given array referenced by type pointer (either a NULL pointer or a pointer returned by the associated `REALLOC` method itself) to an array of the number of objects of this type and return a pointer to this new array. Previously objects pointed by the pointer are kept up to the minimum of the new size and old one but may have moved from their original positions (if the array is reallocated otherwhere). New objects are not initialized (a constructor operator shall be called afterward). Freed objects are not cleared (A destructor operator shall be called before). The default is `M_MEMORY_REALLOC` (that allocates from the heap). It returns NULL in case of failure in which case the original array is not modified. -* `FREE(&obj)`: free the allocated uninitialized array object `obj`. The destructor of the pointed objects shall be called before freeing the memory by calling this method. The objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap). -* `INC_ALLOC(size_t s)` --> `size_t`: Define the growing policy of an array (or equivalent structure). It returns a new allocation size based on the old allocation size (`s`). Default policy is to get the maximum between `2*s` and 16. +* `DEL(&obj)`: free the allocated uninitialized object `obj`. The destructor of the pointed object shall be called before freeing the memory by calling this method. The object shall have been allocated by the associated NEW method. `sizeof obj` is the size of the allocated object. The default method is `M_MEMORY_DEL` (that frees to the heap). `obj` shall not be NULL and shall be of the proper type. +* `REALLOC(type, pointer, previous_number, new_number)` --> `pointer`: reallocate the given array of `previous_number` elements of type `type` referenced by `pointer` (either a NULL pointer or a pointer returned by a previous call to `REALLOC`) to an array of `new_number` objects of type `type` and return a pointer to this new array. Previously objects pointed by the pointer are kept up to the minimum of the new size and old one but may have moved from their original positions (if the array is reallocated otherwhere). New objects are not initialized (a constructor operator shall be called afterward). Freed objects are not cleared (A destructor operator shall be called before). The default is `M_MEMORY_REALLOC` (that allocates from the heap). It returns NULL in case of failure in which case the original array is not modified. If `pointer` is NULL, then `previous_number` should be 0. +* `FREE(type, pointer, number)`: free the allocated uninitialized array of `number` elements of type `type` referenced by `pointer`. The destructor of the pointed objects shall be called before freeing the memory. The memory of the objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap). +* `INC_ALLOC(size_t s)` --> `size_t`: Define the growing policy of an array (or equivalent structure). It returns a new allocation size based on the old allocation size (`s`). Default policy is to get the maximum between `2*s` and 16. In case of overflow, it shall return a number less or equal than the original size. > [!NOTE] > It doesn't check for overflow: if the returned value is lower @@ -1035,8 +1035,8 @@ Memory Allocation functions can be globally set by overriding the following macr * `M_MEMORY_ALLOC (type)` --> `ptr`: return a pointer to a new object of type `type`. * `M_MEMORY_DEL (ptr)`: free the single object pointed by `ptr`. -* `M_MEMORY_REALLOC (type, ptr, number)` --> `ptr`: return a pointer to an array of 'number' objects of type `type`, reusing the old array pointed by `ptr`. `ptr` can be NULL, in which case the array will be created. -* `M_MEMORY_FREE (ptr)`: free the array of objects pointed by `ptr`. +* `M_MEMORY_REALLOC (type, ptr, old_number, new_number)` --> `ptr`: return a pointer to an array of `new_number` objects of type `type`, reusing the old array pointed by `ptr` of `old_number` objects. `ptr` can be NULL, in which case the array will be created. +* `M_MEMORY_FREE (type, ptr, number)`: free the array of `number` objects of type `type` pointed by `ptr`. `ALLOC` and `DEL` operators are supposed to allocate fixed size single element object (no array). These objects are not expected to grow. @@ -7854,12 +7854,12 @@ that was previously allocated by the macro `M_MEMORY_ALLOC`. The default used function is the `free` function of the LIBC. -##### `type *M_MEMORY_REALLOC (type, ptr, number)` +##### `type *M_MEMORY_REALLOC (type, ptr, old_number, new_number)` -Return a pointer to an array of `number` objects of type `type` +Return a pointer to an array of `new_number` objects of type `type` `ptr` is either NULL (in which the array is allocated), or a pointer returned from a previous call of `M_MEMORY_REALLOC` -(in which case the array is reallocated). +(in which case the array is reallocated) with `old_number` objects. The objects are not initialized, nor the state of previous objects changed (in case of reallocation). The address of the previous objects may have moved and the `MOVE` operator @@ -7868,9 +7868,9 @@ In case of allocation error, it returns NULL. The default used function is the `realloc` function of the LIBC. -##### `void M_MEMORY_FREE (type *ptr)` +##### `void M_MEMORY_FREE (type, ptr, number)` -Delete the cleared object pointed by the pointer `ptr`. +Delete the cleared array of `number` objects of type `type pointed by the pointer `ptr`. The pointer was previously allocated by the macro `M_MEMORY_REALLOC`. `ptr` can not be NULL. From 1f2584ccea42a45e2f7d092917fa5d6c7e4d1911 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 21 Dec 2024 12:36:01 +0100 Subject: [PATCH 02/91] Port to new memory model --- m-array.h | 24 ++++++++++++------------ m-bitset.h | 12 ++++++------ m-bstring.h | 8 ++++---- m-buffer.h | 12 ++++++------ m-c-mempool.h | 14 +++++++------- m-core.h | 20 ++++++++++---------- m-deque.h | 12 +++++++++--- m-dict.h | 24 +++++++++++++----------- m-genint.h | 4 ++-- m-shared-ptr.h | 8 ++++---- m-shared.h | 4 ++-- m-snapshot.h | 8 ++++---- m-string.h | 11 ++++++----- m-tree.h | 8 ++++---- m-worker.h | 4 ++-- tests/test-obj-except.h | 8 ++++---- 16 files changed, 95 insertions(+), 86 deletions(-) diff --git a/m-array.h b/m-array.h index dac946ea..dcb7309b 100644 --- a/m-array.h +++ b/m-array.h @@ -227,7 +227,7 @@ { \ M_ARRA4_CONTRACT(v); \ M_F(name, _reset)(v); \ - M_CALL_FREE(oplist, v->ptr); \ + M_CALL_FREE(oplist, type, v->ptr, v->alloc); \ /* This is so reusing the object implies an assertion failure */ \ v->alloc = 1; \ v->ptr = NULL; \ @@ -242,7 +242,7 @@ if (M_UNLIKELY (d == s)) return; \ if (s->size > d->alloc) { \ const size_t alloc = s->size; \ - type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, d->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return ; \ @@ -329,7 +329,7 @@ return NULL; \ } \ M_ASSERT (alloc > v->size); \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return NULL; \ @@ -398,7 +398,7 @@ return ; \ } \ M_ASSERT (alloc > v->size); \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return; \ @@ -430,7 +430,7 @@ /* Increase size of array */ \ if (size > v->alloc) { \ size_t alloc = size ; \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return; \ @@ -457,11 +457,11 @@ alloc = v->size; \ } \ if (M_UNLIKELY (alloc == 0)) { \ - M_CALL_FREE(oplist, v->ptr); \ + M_CALL_FREE(oplist, type, v->ptr, v->alloc); \ v->size = v->alloc = 0; \ v->ptr = NULL; \ } else { \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return; \ @@ -488,7 +488,7 @@ M_MEMORY_FULL(sizeof (type) * alloc); \ return NULL; \ } \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return NULL; \ @@ -618,7 +618,7 @@ M_MEMORY_FULL(sizeof (type) * alloc); \ return ; \ } \ - type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, alloc); \ + type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * alloc); \ return; \ @@ -908,13 +908,13 @@ if (M_UNLIKELY (l->size < 2)) \ return; \ /* NOTE: if size is <= 4, no need to perform an allocation */ \ - type *temp = M_CALL_REALLOC(oplist, type, NULL, l->size); \ + type *temp = M_CALL_REALLOC(oplist, type, NULL, 0, l->size); \ if (M_UNLIKELY_NOMEM (temp == NULL)) { \ M_MEMORY_FULL(sizeof (type) * l->size); \ return ; \ } \ M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \ - M_CALL_FREE(oplist, temp); \ + M_CALL_FREE(oplist, type, temp, l->size); \ } \ ,) /* IF SWAP & SET methods */ \ \ @@ -966,7 +966,7 @@ should have exhausted all memory before reaching such sizes. */ \ M_ASSERT_INDEX(a1->size, newSize); \ if (newSize > a1->alloc) { \ - type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, newSize); \ + type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, a1->alloc, newSize); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (type) * newSize); \ } \ diff --git a/m-bitset.h b/m-bitset.h index bd7a7c97..1e32710e 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -105,7 +105,7 @@ M_INLINE void m_bitset_clear(m_bitset_t t) { m_bitset_reset(t); - M_MEMORY_FREE(t->ptr); + M_MEMORY_FREE(m_b1tset_limb_ct, t->ptr, t->alloc); // This is not really needed, but is safer // This representation is invalid and will be detected by the contract. // A C compiler should be able to optimize out theses initializations. @@ -124,7 +124,7 @@ m_bitset_set(m_bitset_t d, const m_bitset_t s) if (M_LIKELY (s->size > 0)) { // Test if enough space in target if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) { - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, needAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(needAlloc); return ; @@ -216,7 +216,7 @@ m_bitset_push_back (m_bitset_t v, bool x) return; } // Alloc memory - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, needAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc); // Check if success if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct)); @@ -255,7 +255,7 @@ m_bitset_resize (m_bitset_t v, size_t size) size_t newAlloc = M_B1TSET_TO_ALLOC (size); if (newAlloc > v->alloc) { // Allocate more limbs to store the bitset. - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct)); return; @@ -302,12 +302,12 @@ m_bitset_reserve (m_bitset_t v, size_t alloc) } if (M_UNLIKELY (newAlloc == 0)) { // Free all memory used by the bitsets - M_MEMORY_FREE (v->ptr); + M_MEMORY_FREE (m_b1tset_limb_ct, v->ptr, v->alloc); v->size = v->alloc = 0; v->ptr = NULL; } else { // Allocate more memory or reduce memory usage - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, newAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct)); return; diff --git a/m-bstring.h b/m-bstring.h index 25182cf0..85d16b83 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -78,7 +78,7 @@ M_INLINE void m_bstring_clear(m_bstring_t s) { M_BSTRING_CONTRACT(s); - M_MEMORY_FREE(s->ptr); + M_MEMORY_FREE(uint8_t, s->ptr, s->alloc); s->offset = (size_t) -1; } @@ -166,7 +166,7 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc) if (M_UNLIKELY_NOMEM (alloc < size_alloc)) { goto allocation_error; } - uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, alloc); + uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { goto allocation_error; } @@ -401,13 +401,13 @@ m_bstring_reserve (m_bstring_t v, size_t n) n = v->offset + size; } if (n == 0) { - M_MEMORY_FREE(v->ptr); + M_MEMORY_FREE(uint8_t, v->ptr, v->alloc); v->offset = 0; v->size = 0; v->alloc = 0; v->ptr = NULL; } else { - uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, n); + uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(n); } diff --git a/m-buffer.h b/m-buffer.h index c4f8c573..20a3b01a 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -319,7 +319,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ } \ \ M_BUFF3R_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \ - v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, M_BUFF3R_SIZE(m_size)); \ + v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, M_BUFF3R_SIZE(m_size)); \ if (M_UNLIKELY_NOMEM (v->data == NULL)) { \ M_MEMORY_FULL (M_BUFF3R_SIZE(m_size)*sizeof(M_F(name, _el_ct))); \ return; \ @@ -371,7 +371,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_BUFF3R_CONTRACT(v,m_size); \ M_C3(m_buff3r_,name,_clear_obj)(v); \ M_BUFF3R_IF_CTE_SIZE(m_size)( , \ - M_CALL_FREE(oplist, v->data); \ + M_CALL_FREE(oplist, M_F(name, _el_ct), v->data, M_BUFF3R_SIZE(m_size)); \ v->data = NULL; \ ) \ v->overwrite = 0; \ @@ -906,7 +906,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ atomic_init(&buffer->ProdIdx, (unsigned int) size); \ atomic_init(&buffer->ConsoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ - buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, size); \ + buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \ if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \ M_MEMORY_FULL (size*sizeof(M_F(name, _el_ct) )); \ return; \ @@ -940,7 +940,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ j = 0; \ } \ } \ - M_CALL_FREE(oplist, buffer->Tab); \ + M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, M_BUFF3R_SIZE(m_size)); \ buffer->Tab = NULL; /* safer */ \ buffer->size = 3; \ } \ @@ -1248,7 +1248,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ atomic_init(&buffer->prodIdx, (unsigned int) size); \ atomic_init(&buffer->consoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ - buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, size); \ + buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \ if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \ M_MEMORY_FULL (size*sizeof(M_F(name, _el_ct) )); \ return; \ @@ -1281,7 +1281,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ j = 0; \ } \ } \ - M_CALL_FREE(oplist, buffer->Tab); \ + M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, M_BUFF3R_SIZE(m_size)); \ buffer->Tab = NULL; /* safer */ \ buffer->size = 3; \ } \ diff --git a/m-c-mempool.h b/m-c-mempool.h index bfae37a1..be1f3501 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -464,7 +464,7 @@ M_BEGIN_PROTECTED_CODE { \ const size_t max_thread = gc_mem->max_thread; \ /* Initialize the thread data of the mempool */ \ - mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, max_thread); \ + mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \ if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \ M_MEMORY_FULL(max_thread * sizeof(M_F(name, _lfmp_thread_ct))); \ return; \ @@ -497,7 +497,7 @@ M_BEGIN_PROTECTED_CODE for(unsigned i = 0; i < max_thread;i++) { \ M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \ } \ - M_MEMORY_FREE(mem->thread_data); \ + M_MEMORY_FREE(M_F(name, _lfmp_thread_ct), mem->thread_data, mem->gc_mem->max_thread); \ mem->thread_data = NULL; \ M_F(name, _lflist_clear)(mem->empty); \ M_F(name, _lflist_clear)(mem->free); \ @@ -587,7 +587,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread) atomic_init(&gc_mem->ticket, 0UL); m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread); - gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, max_thread); + gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) { M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct)); return; @@ -608,7 +608,7 @@ m_gc_clear(m_gc_t gc_mem) for(m_gc_tid_t i = 0; i < gc_mem->max_thread;i++) { m_core_backoff_clear(gc_mem->thread_data[i].bkoff); } - M_MEMORY_FREE(gc_mem->thread_data); + M_MEMORY_FREE(m_gc_lfmp_thread_ct, gc_mem->thread_data, gc_mem->max_thread); gc_mem->thread_data = NULL; m_genint_clear(gc_mem->thread_alloc); } @@ -757,7 +757,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem) const size_t max_thread = gc_mem->max_thread; /* Initialize the thread data of the vlapool */ - mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, max_thread); + mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { M_MEMORY_FULL(max_thread * sizeof(m_vlapool_lfmp_thread_ct)); return; @@ -784,7 +784,7 @@ m_vlapool_clear(m_vlapool_t mem) for(unsigned i = 0; i < max_thread;i++) { m_vlapool_lfmp_thread_clear(&mem->thread_data[i]); } - M_MEMORY_FREE(mem->thread_data); + M_MEMORY_FREE(m_vlapool_lfmp_thread_ct, mem->thread_data, mem->gc_mem->max_thread); mem->thread_data = NULL; m_vlapool_lflist_clear(mem->empty); M_ASSERT(m_vlapool_lflist_empty_p(mem->to_be_reclaimed)); @@ -807,7 +807,7 @@ m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size) size += offsetof(struct m_vlapool_slist_node_s, data); // Simply wrap around a system call to get the memory - char *ptr = M_MEMORY_REALLOC(char, NULL, size); + char *ptr = M_MEMORY_REALLOC(char, NULL, 0, size); return (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data)); } diff --git a/m-core.h b/m-core.h index 64537ff5..65f5e0e8 100644 --- a/m-core.h +++ b/m-core.h @@ -379,21 +379,21 @@ M_BEGIN_PROTECTED_CODE #endif /* Define allocators for array - * void *M_MEMORY_REALLOC(type, ptr, n): Return a pointer to a new array of 'n' object of type 'type' - * If ptr is NULL, it creates a new array. - * If ptr is not null, it reallocates the given array to the new size. + * void *M_MEMORY_REALLOC(type, ptr, o, n): Return a pointer to a new array of 'n' object of type 'type' + * If ptr is NULL, it creates a new array of type 'type' and size 'n' + * If ptr is not null, it reallocates the given array of type 'type' and size 'o' to the new size. * It returns NULL in case of memory allocation failure. - * void M_MEMORY_FREE(ptr): Free the object associated to the array. + * void M_MEMORY_FREE(type, ptr, o): Free the object associated to the array of type 'type' at base 'ptr' of size 'o'. */ #ifndef M_MEMORY_REALLOC #ifdef __cplusplus # include -# define M_MEMORY_REALLOC(type, ptr, n) \ +# define M_MEMORY_REALLOC(type, ptr, o, n) \ ((type*) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : std::realloc ((ptr), (n)*sizeof (type)))) -# define M_MEMORY_FREE(ptr) std::free(ptr) +# define M_MEMORY_FREE(type, ptr, o) std::free(ptr) #else -# define M_MEMORY_REALLOC(type, ptr, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type))) -# define M_MEMORY_FREE(ptr) free(ptr) +# define M_MEMORY_REALLOC(type, ptr, o, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type))) +# define M_MEMORY_FREE(type, ptr, o) free(ptr) #endif #endif @@ -3942,8 +3942,8 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_FALSE_DEFAULT(...) false #define M_NEW_DEFAULT(a) M_MEMORY_ALLOC(a) #define M_DEL_DEFAULT(a) M_MEMORY_DEL(a) -#define M_REALLOC_DEFAULT(t,p,s) M_MEMORY_REALLOC(t,p,s) -#define M_FREE_DEFAULT(a) M_MEMORY_FREE(a) +#define M_REALLOC_DEFAULT(t,p,o,s) M_MEMORY_REALLOC(t,p,o,s) +#define M_FREE_DEFAULT(t,a,o) M_MEMORY_FREE(t,a,o) #define M_EQUAL_DEFAULT(a,b) ((a) == (b)) #define M_CMP_DEFAULT(a,b) ((a) < (b) ? -1 : (a) > (b)) #define M_ADD_DEFAULT(a,b,c) ((a) = (b) + (c)) diff --git a/m-deque.h b/m-deque.h index d21bcb19..54a7c898 100644 --- a/m-deque.h +++ b/m-deque.h @@ -127,7 +127,12 @@ The interfaces are compatible. \ */ \ /* FIXME: How can I separate public types and private implementation? */ \ - M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_GET_FREE oplist)) ) \ + static inline void M_F(name, _del_node)(node_t *ptr) \ + { \ + /* FIXME: ptr->size can be incorrect as old size ! */ \ + M_CALL_FREE(oplist, char, ptr, sizeof(node_t) + ptr->size * sizeof(type)); \ + } \ + M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_F(name, _del_node))) ) \ \ /* Define an internal iterator */ \ typedef struct M_F(name, _it2_s) { \ @@ -182,7 +187,7 @@ } \ /* Alloc a new node with dynamic size */ \ node_t*n = (node_t*) (void*) \ - M_CALL_REALLOC(oplist, char, NULL, \ + M_CALL_REALLOC(oplist, char, NULL, 0, \ sizeof(node_t) + def * sizeof(type) ); \ if (M_UNLIKELY_NOMEM (n==NULL)) { \ M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ @@ -711,7 +716,8 @@ /* Node deletion */ \ M_ASSERT(d->count > 1); \ M_F(name, _node_list_unlink)(n); \ - M_CALL_FREE(oplist, n); \ + /* FIXME: oldsize broken as size is corrupted! */ \ + M_CALL_FREE(oplist, char, n, sizeof(node_t) + n->size * sizeof(type) ); \ } else { \ memmove(&n->data[it->index], &n->data[it->index+1], \ sizeof(type) * (it->node->size - it->index - 1)); \ diff --git a/m-dict.h b/m-dict.h index 05e4f06c..f988a258 100644 --- a/m-dict.h +++ b/m-dict.h @@ -337,14 +337,14 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) map->count_delete = 0; \ M_C3(m_d1ct_,name,_update_limit)(map, M_D1CT_INITIAL_SIZE); \ /* The first 2 buckets are reserved for (empty) and (deleted) access. Allocation could be avoided */ \ - map->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), NULL, (size_t) 1+2+map->upper_limit); \ + map->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), NULL, 0, (size_t) 1+2+map->upper_limit); \ if (M_UNLIKELY_NOMEM (map->data == NULL)) { \ M_MEMORY_FULL( (2+M_D1CT_INITIAL_SIZE) * sizeof (M_F(name, _freelist_ct))); \ return ; \ } \ map->freelist_first_data = 0; \ map->freelist_count = 2; \ - map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, (size_t)(0+M_D1CT_INITIAL_SIZE)); \ + map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, 0, (size_t)(0+M_D1CT_INITIAL_SIZE)); \ if (M_UNLIKELY_NOMEM (map->index == NULL)) { \ M_MEMORY_FULL( (2+M_D1CT_INITIAL_SIZE) * sizeof (m_indexhash_t)); \ return ; \ @@ -371,8 +371,9 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_CALL_CLEAR(value_oplist, map->data[d].pair.value); \ } \ } \ - M_CALL_FREE(key_oplist, map->index); \ - M_CALL_FREE(key_oplist, map->data); \ + M_CALL_FREE(key_oplist, m_indexhash_t, map->index, map->mask+1); \ + /* FIXME: How much? */ \ + M_CALL_FREE(key_oplist, M_F(name, _freelist_ct), map->data, -1); \ /* Mark the dictionary as cleared */ \ map->data = NULL; \ map->index = NULL; \ @@ -471,13 +472,14 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* We need to allocate '2' for the dummy first two entries in the table (not used), \ then we can have at maximum only up to 'upper_limit+1' data */ \ if (1+2+h->upper_limit > h->freelist_count) { \ - h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, (size_t) 1+2+h->upper_limit); \ + /*FIXME; oldsize incorrect */ \ + h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, -1, (size_t) 1+2+h->upper_limit); \ if (M_UNLIKELY_NOMEM (h->data == NULL) ) { \ M_MEMORY_FULL((2+newSize)*sizeof (M_F(name, _freelist_ct))); \ return ; \ } \ } \ - m_indexhash_t *index = M_MEMORY_REALLOC(m_indexhash_t, h->index,(size_t) 0+newSize); \ + m_indexhash_t *index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \ if (M_UNLIKELY_NOMEM (index == NULL) ) { \ M_MEMORY_FULL(newSize*sizeof(m_indexhash_t)); \ return ; \ @@ -599,7 +601,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) if (newSize != oldSize) { \ h->mask = newSize-1; \ M_C3(m_d1ct_,name,_update_limit)(h, newSize); \ - h->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, (size_t)0+newSize); \ + h->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \ M_ASSERT (h->index != NULL); \ /* FIXME: What to do for h->data ? */ \ } \ @@ -1485,7 +1487,7 @@ enum m_d1ct_oa_element_e { dict->count = 0; \ dict->count_delete = 0; \ M_C3(m_d1ct_,name,_update_limit)(dict, M_D1CT_INITIAL_SIZE); \ - dict->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), NULL, M_D1CT_INITIAL_SIZE); \ + dict->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), NULL, 0, M_D1CT_INITIAL_SIZE); \ if (M_UNLIKELY_NOMEM (dict->data == NULL)) { \ M_MEMORY_FULL(sizeof (M_F(name, _pair_ct)) * M_D1CT_INITIAL_SIZE); \ return ; \ @@ -1509,7 +1511,7 @@ enum m_d1ct_oa_element_e { M_CALL_CLEAR(value_oplist, dict->data[i].value); \ } \ } \ - M_CALL_FREE(key_oplist, dict->data); \ + M_CALL_FREE(key_oplist, M_F(name, _pair_ct), dict->data, dict->mask+1); \ /* Not really needed, but safer */ \ dict->mask = 0; \ dict->data = NULL; \ @@ -1566,7 +1568,7 @@ enum m_d1ct_oa_element_e { M_F(name, _pair_ct) *data = h->data; \ /* resize can be called just to delete the items */ \ if (newSize > oldSize) { \ - data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, newSize); \ + data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, oldSize, newSize); \ if (M_UNLIKELY_NOMEM (data == NULL) ) { \ M_MEMORY_FULL(sizeof (M_F(name, _pair_ct)) * newSize); \ return ; \ @@ -1833,7 +1835,7 @@ enum m_d1ct_oa_element_e { if (newSize != oldSize) { \ h->mask = newSize-1; \ M_C3(m_d1ct_,name,_update_limit)(h, newSize); \ - h->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, newSize); \ + h->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, oldSize, newSize); \ M_ASSERT (h->data != NULL); \ } \ M_IF_DEBUG (M_ASSERT (M_C3(m_d1ct_,name,_control_after_resize)(h));) \ diff --git a/m-genint.h b/m-genint.h index 24f1138d..1bacf991 100644 --- a/m-genint.h +++ b/m-genint.h @@ -109,7 +109,7 @@ m_genint_init(m_genint_t s, unsigned int n) M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC); const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE; const unsigned int index = n % M_GEN1NT_LIMBSIZE; - atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, alloc); + atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(alloc); return; @@ -130,7 +130,7 @@ M_INLINE void m_genint_clear(m_genint_t s) { M_GEN1NT_CONTRACT(s); - M_MEMORY_FREE(s->data); + M_MEMORY_FREE(atomic_ullong, s->data, s->alloc); s->data = NULL; } diff --git a/m-shared-ptr.h b/m-shared-ptr.h index 401d823f..fe928523 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -618,7 +618,7 @@ M_IF_METHOD(INIT, oplist)( \ M_MEMORY_FULL(sizeof (shared_t)); \ abort(); \ } \ - M_ON_EXCEPTION( M_CALL_FREE(oplist, out) ) \ + M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ M_CALL_INIT(oplist, out->data); \ M_F(name, _init_lock)(out); \ return out; \ @@ -635,7 +635,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ abort(); \ } \ M_F(name, _read_lock)(src); \ - M_ON_EXCEPTION( M_F(name, _read_unlock)(src), M_CALL_FREE(oplist, out) ) \ + M_ON_EXCEPTION( M_F(name, _read_unlock)(src), M_CALL_DEL(oplist, out) ) \ M_CALL_INIT_SET(oplist, out->data, src->data); \ M_F(name, _read_unlock)(src); \ M_F(name, _init_lock)(out); \ @@ -651,7 +651,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ M_MEMORY_FULL(sizeof (shared_t)); \ abort(); \ } \ - M_ON_EXCEPTION( M_CALL_FREE(oplist, out) ) \ + M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ M_CALL_INIT_SET(oplist, out->data, src); \ M_F(name, _init_lock)(out); \ return out; \ @@ -709,7 +709,7 @@ M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_ M_MEMORY_FULL(sizeof (shared_t)); \ abort(); \ } \ - M_ON_EXCEPTION( M_CALL_FREE(oplist, out) ) \ + M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, out->data, exp_emplace_type); \ M_F(M_PAIR_1 name_attr, _init_lock)(out); \ return out; \ diff --git a/m-shared.h b/m-shared.h index 1bd4c9b5..6becc2e0 100644 --- a/m-shared.h +++ b/m-shared.h @@ -445,7 +445,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } { \ M_ASSERT(s != NULL); \ M_ASSERT (n > 0 && n < UINT_MAX); \ - s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, n); \ + s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, 0, n); \ if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \ M_MEMORY_FULL(sizeof(M_F(name, _atype_ct)) * n); \ return; \ @@ -466,7 +466,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } for(size_t i = 0; i < n; i++) { \ M_CALL_CLEAR(oplist, s->buffer[i].x); \ } \ - M_CALL_FREE(oplist, s->buffer); \ + M_CALL_FREE(oplist, M_F(name, _atype_ct), s->buffer, n); \ s->buffer = NULL; \ m_genint_clear(s->core); \ } \ diff --git a/m-snapshot.h b/m-snapshot.h index afb69262..fd03fc52 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -391,7 +391,7 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n) n += M_SNAPSH0T_SPMC_EXTRA_BUFFER; // Initialize the counters to zero (no reader use it) - atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, n); + atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, 0, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(sizeof (atomic_uint) * n); return; @@ -419,7 +419,7 @@ M_INLINE void m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s) { M_SNAPSH0T_SPMC_INT_CONTRACT(s); - M_MEMORY_FREE (s->cptTab); + M_MEMORY_FREE (atomic_uint, s->cptTab, s->n_reader-M_SNAPSH0T_SPMC_EXTRA_BUFFER); m_genint_clear(s->freeList); s->cptTab = NULL; s->n_reader = 0; @@ -645,7 +645,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) M_ASSERT (snap != NULL); \ M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \ snap->data = M_CALL_REALLOC(oplist, M_F(name, _aligned_type_ct), \ - NULL, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \ + NULL, 0, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \ if (M_UNLIKELY_NOMEM (snap->data == NULL)) { \ M_MEMORY_FULL(sizeof(M_F(name, _aligned_type_ct)) * \ (nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \ @@ -666,7 +666,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \ M_CALL_CLEAR(oplist, snap->data[i].x); \ } \ - M_CALL_FREE(oplist, snap->data); \ + M_CALL_FREE(oplist, M_F(name, _aligned_type_ct), snap->data, nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \ m_snapsh0t_mrsw_clear(snap->core); \ } \ \ diff --git a/m-string.h b/m-string.h index 836c203b..e4c29078 100644 --- a/m-string.h +++ b/m-string.h @@ -286,7 +286,7 @@ m_string_clear(m_string_t v) { M_STR1NG_CONTRACT(v); if (!m_str1ng_embedded_p(v)) { - M_MEMORY_FREE(v->u.heap.ptr); + M_MEMORY_FREE(char, v->u.heap.ptr, m_string_capacity(v)); v->u.heap.ptr = NULL; } /* This is not needed but is safer to make @@ -311,7 +311,7 @@ m_string_clear_get_cstr(m_string_t v) p = &v->u.buffer[0]; // Need to allocate a heap string to return the copy. size_t alloc = m_string_size(v)+1; - char *ptr = M_MEMORY_REALLOC (char, NULL, alloc); + char *ptr = M_MEMORY_REALLOC (char, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(sizeof (char) * alloc); return NULL; @@ -392,7 +392,8 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc) return NULL; } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; - ptr = M_MEMORY_REALLOC (char, ptr, alloc); + //FIXME: old_alloc may not be NULL if ptr is NULL. + ptr = M_MEMORY_REALLOC (char, ptr, old_alloc, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(sizeof (char) * alloc); // NOTE: Return is currently broken. @@ -439,7 +440,7 @@ m_string_reserve(m_string_t v, size_t alloc) char *oldptr = v->u.heap.ptr; memcpy(ptr, oldptr, size+1); // Free the allocated memory on the heap - M_MEMORY_FREE(oldptr); + M_MEMORY_FREE(char, oldptr, m_string_capacity(v)); v->u.buffer[sizeof(m_string_t)-2] = 0; v->u.buffer[sizeof(m_string_t)-1] = (char) size; } else { @@ -455,7 +456,7 @@ m_string_reserve(m_string_t v, size_t alloc) return; } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; - ptr = M_MEMORY_REALLOC (char, ptr, r_alloc); + ptr = M_MEMORY_REALLOC (char, ptr, m_string_capacity(v), r_alloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(sizeof (char) * alloc); return; diff --git a/m-tree.h b/m-tree.h index d9ff20ec..929a47c6 100644 --- a/m-tree.h +++ b/m-tree.h @@ -245,7 +245,7 @@ typedef int32_t m_tr33_index_t; M_F(name, _clear)(tree_t tree) { \ M_F(name, _reset)(tree); \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\ - M_CALL_FREE(oplist, ptr); \ + M_CALL_FREE(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1); \ /* This is so reusing the object implies an assertion failure */ \ tree->size = 1; \ tree->tab = NULL; \ @@ -268,7 +268,7 @@ typedef int32_t m_tr33_index_t; as M_TR33_NO_NODE is -1. This enables avoiding testing for \ M_TR33_NO_NODE in some cases, performing branchless code. */ \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\ - ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, alloc+1);\ + ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \ return; \ @@ -322,7 +322,7 @@ typedef int32_t m_tr33_index_t; as M_TR33_NO_NODE is -1. This enables avoiding testing for \ M_TR33_NO_NODE in some cases, performing branchless code. */ \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1; \ - ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, alloc+1); \ + ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \ return M_TR33_NO_NODE; \ @@ -1134,7 +1134,7 @@ typedef int32_t m_tr33_index_t; tree->tab = NULL; \ } else { \ struct M_F(name, _node_s) *ptr = \ - M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, alloc+1); \ + M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, 0, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(sizeof(struct M_F(name, _node_s)) * alloc); \ return; \ diff --git a/m-worker.h b/m-worker.h index 26ff02de..e78d213e 100644 --- a/m-worker.h +++ b/m-worker.h @@ -409,7 +409,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset // numWorker can still be 0 if it is a single core cpu (no worker available) M_ASSERT(numWorker >= 0); size_t numWorker_st = (size_t) numWorker; - g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, numWorker_st); + g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st); if (M_UNLIKELY_NOMEM (g->worker == NULL)) { M_MEMORY_FULL(sizeof (m_work3r_thread_ct) * numWorker_st); return; @@ -454,7 +454,7 @@ m_worker_clear(m_worker_t g) m_thread_join(g->worker[i].id); } // Clear memory - M_MEMORY_FREE(g->worker); + M_MEMORY_FREE(m_work3r_thread_ct, g->worker, g->numWorker_g); m_mutex_clear(g->lock); m_cond_clear(g->a_thread_ends); m_work3r_queue_clear(g->queue_g); diff --git a/tests/test-obj-except.h b/tests/test-obj-except.h index 512108d7..b09457d5 100644 --- a/tests/test-obj-except.h +++ b/tests/test-obj-except.h @@ -39,14 +39,14 @@ extern int test_obj_except__malloc_counter; # include # define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type))) # define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) -# define M_MEMORY_REALLOC(type, ptr, n) \ +# define M_MEMORY_REALLOC(type, ptr, o, n) \ ((type*) (test_obj_except_trigger(), test_obj_except__malloc_counter+= (ptr == NULL), std::realloc ((ptr), (n)*sizeof (type)))) -# define M_MEMORY_FREE(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) +# define M_MEMORY_FREE(type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) #else # define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type))) # define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) -# define M_MEMORY_REALLOC(type, ptr, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type))) -# define M_MEMORY_FREE(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) +# define M_MEMORY_REALLOC(type, ptr, o, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type))) +# define M_MEMORY_FREE(type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) #endif // Include M*LIB headers From 93112a5a7cda2fe76c9370604af58b30ef31afc5 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 21 Dec 2024 13:01:15 +0100 Subject: [PATCH 03/91] Update example --- example/ex-alloc1.c | 4 ++-- example/ex-alloc2.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/ex-alloc1.c b/example/ex-alloc1.c index 0ce8728c..49390dae 100644 --- a/example/ex-alloc1.c +++ b/example/ex-alloc1.c @@ -47,8 +47,8 @@ static void my_array_free(void *ptr) # define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr) // Allocate for array of objects -# define M_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n) -# define M_MEMORY_FREE(ptr) my_array_free(ptr) +# define M_MEMORY_REALLOC(type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) +# define M_MEMORY_FREE(type, ptr, n) my_array_free(ptr) #include "m-list.h" #include "m-array.h" diff --git a/example/ex-alloc2.c b/example/ex-alloc2.c index e233cb49..48a441dd 100644 --- a/example/ex-alloc2.c +++ b/example/ex-alloc2.c @@ -76,8 +76,8 @@ static void my_array_free(void *ptr) } // Allocate for array of objects -# define MY_MEMORY_REALLOC(type, ptr, n) my_array_alloc (sizeof (type), ptr, n) -# define MY_MEMORY_FREE(ptr) my_array_free(ptr) +# define MY_MEMORY_REALLOC(type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) +# define MY_MEMORY_FREE(type, ptr, n) my_array_free(ptr) //////////////////////////////////////////////////////////// From 450d2c90009db0e86ec904a1e8be7747c7707775 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 21 Dec 2024 13:01:52 +0100 Subject: [PATCH 04/91] Update spec of M_MEMORY_FULL --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f2d5875b..16d0bb26 100644 --- a/README.md +++ b/README.md @@ -7876,9 +7876,9 @@ The pointer was previously allocated by the macro `M_MEMORY_REALLOC`. The default used function is the `free` function of the LIBC. -##### `void M_MEMORY_FULL (size_t size)` +##### `void M_MEMORY_FULL (type, number)` -This macro is called by M\*LIB when a memory error has been detected. +This macro is called by M\*LIB when a memory error has been detected when trying to allocate an array of `number` type `type`. The parameter `size` is what was tried to be allocated (as a hint). The macro can: From 1e196fe22a7be866310bf6c33cfae848bf38c3be Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 21 Dec 2024 13:02:17 +0100 Subject: [PATCH 05/91] Port to new spec M_MEMORY_FULL --- m-array.h | 28 ++++++++++++++-------------- m-bitset.h | 12 ++++++------ m-bptree.h | 2 +- m-bstring.h | 4 ++-- m-buffer.h | 6 +++--- m-c-mempool.h | 10 +++++----- m-core.h | 9 +++++---- m-deque.h | 4 ++-- m-dict.h | 26 +++++++++++++------------- m-genint.h | 2 +- m-i-shared.h | 2 +- m-list.h | 14 +++++++------- m-mempool.h | 4 ++-- m-rbtree.h | 6 +++--- m-shared-ptr.h | 8 ++++---- m-shared.h | 8 ++++---- m-snapshot.h | 4 ++-- m-string.h | 10 +++++----- m-tree.h | 10 +++++----- m-try.h | 2 +- m-worker.h | 4 ++-- 21 files changed, 88 insertions(+), 87 deletions(-) diff --git a/m-array.h b/m-array.h index dcb7309b..d6d2a5e3 100644 --- a/m-array.h +++ b/m-array.h @@ -244,7 +244,7 @@ const size_t alloc = s->size; \ type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, d->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return ; \ } \ d->ptr = ptr; \ @@ -325,13 +325,13 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return NULL; \ } \ M_ASSERT (alloc > v->size); \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return NULL; \ } \ v->ptr = ptr; \ @@ -394,13 +394,13 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return ; \ } \ M_ASSERT (alloc > v->size); \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return; \ } \ v->ptr = ptr; \ @@ -432,7 +432,7 @@ size_t alloc = size ; \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return; \ } \ v->ptr = ptr; \ @@ -463,7 +463,7 @@ } else { \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return; \ } \ v->ptr = ptr; \ @@ -485,12 +485,12 @@ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ /* In case of overflow of size_t */ \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return NULL; \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return NULL; \ } \ v->ptr = ptr; \ @@ -608,19 +608,19 @@ if (M_UNLIKELY_NOMEM (size <= v->size)) { \ /* Unlikely case of nothing to do */ \ if (num == 0) return; \ - M_MEMORY_FULL(sizeof (type) * v->size); \ + M_MEMORY_FULL(type, v->size); \ return ; \ } \ /* Test if alloc array is sufficient */ \ if (size > v->alloc) { \ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return ; \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * alloc); \ + M_MEMORY_FULL(type, alloc); \ return; \ } \ v->ptr = ptr; \ @@ -910,7 +910,7 @@ /* NOTE: if size is <= 4, no need to perform an allocation */ \ type *temp = M_CALL_REALLOC(oplist, type, NULL, 0, l->size); \ if (M_UNLIKELY_NOMEM (temp == NULL)) { \ - M_MEMORY_FULL(sizeof (type) * l->size); \ + M_MEMORY_FULL(type, l->size); \ return ; \ } \ M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \ @@ -968,7 +968,7 @@ if (newSize > a1->alloc) { \ type *ptr = M_CALL_REALLOC(oplist, type, a1->ptr, a1->alloc, newSize); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (type) * newSize); \ + M_MEMORY_FULL(type, newSize); \ } \ a1->ptr = ptr; \ a1->alloc = newSize; \ diff --git a/m-bitset.h b/m-bitset.h index 1e32710e..0ff8a975 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -126,7 +126,7 @@ m_bitset_set(m_bitset_t d, const m_bitset_t s) if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) { m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { - M_MEMORY_FULL(needAlloc); + M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); return ; } d->ptr = ptr; @@ -212,14 +212,14 @@ m_bitset_push_back (m_bitset_t v, bool x) const size_t needAlloc = M_B1TSET_INC_ALLOC_SIZE(v->alloc); // Check for integer overflow if (M_UNLIKELY_NOMEM (needAlloc <= v->alloc)) { - M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct)); + M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); return; } // Alloc memory m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc); // Check if success if (M_UNLIKELY_NOMEM (ptr == NULL) ) { - M_MEMORY_FULL(needAlloc * sizeof(m_b1tset_limb_ct)); + M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); return; } v->ptr = ptr; @@ -248,7 +248,7 @@ m_bitset_resize (m_bitset_t v, size_t size) M_B1TSET_CONTRACT (v); // Check for overflow if (M_UNLIKELY_NOMEM (size >= ((size_t)-1) - M_B1TSET_LIMB_BIT)) { - M_MEMORY_FULL((size_t) -1); + M_MEMORY_FULL(char, (size_t) -1); return; } // Compute the needed allocation. @@ -257,7 +257,7 @@ m_bitset_resize (m_bitset_t v, size_t size) // Allocate more limbs to store the bitset. m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { - M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct)); + M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc); return; } v->ptr = ptr; @@ -309,7 +309,7 @@ m_bitset_reserve (m_bitset_t v, size_t alloc) // Allocate more memory or reduce memory usage m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { - M_MEMORY_FULL(newAlloc * sizeof(m_b1tset_limb_ct)); + M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc); return; } v->ptr = ptr; diff --git a/m-bptree.h b/m-bptree.h index 83bbd50c..a99e03c9 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -412,7 +412,7 @@ "Number of items per node shall be >= 2."); \ node_t n = M_CALL_NEW(key_oplist, struct M_F(name, _node_s)); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ - M_MEMORY_FULL(sizeof (node_t)); \ + M_MEMORY_FULL(node_t, 1); \ M_ASSERT (0); \ } \ n->next = NULL; \ diff --git a/m-bstring.h b/m-bstring.h index 85d16b83..9fce5b5d 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -180,7 +180,7 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc) } return &v->ptr[v->offset]; allocation_error: - M_MEMORY_FULL(size_alloc); + M_MEMORY_FULL(uint8_t, size_alloc); // NOTE: Return is currently broken. abort(); return NULL; @@ -409,7 +409,7 @@ m_bstring_reserve (m_bstring_t v, size_t n) } else { uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { - M_MEMORY_FULL(n); + M_MEMORY_FULL(uint8_t, n); } // The string cannot be fully embedded anymore. v->ptr = ptr; diff --git a/m-buffer.h b/m-buffer.h index 20a3b01a..16936596 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -321,7 +321,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_BUFF3R_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \ v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, M_BUFF3R_SIZE(m_size)); \ if (M_UNLIKELY_NOMEM (v->data == NULL)) { \ - M_MEMORY_FULL (M_BUFF3R_SIZE(m_size)*sizeof(M_F(name, _el_ct))); \ + M_MEMORY_FULL (M_F(name, _el_ct), M_BUFF3R_SIZE(m_size)); \ return; \ } \ ) \ @@ -908,7 +908,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ buffer->size = (unsigned int) size; \ buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \ if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \ - M_MEMORY_FULL (size*sizeof(M_F(name, _el_ct) )); \ + M_MEMORY_FULL (M_F(name, _el_ct), size); \ return; \ } \ for(unsigned int j = 0; j < (unsigned int) size; j++) { \ @@ -1250,7 +1250,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ buffer->size = (unsigned int) size; \ buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \ if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \ - M_MEMORY_FULL (size*sizeof(M_F(name, _el_ct) )); \ + M_MEMORY_FULL (M_F(name, _el_ct), size); \ return; \ } \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ diff --git a/m-c-mempool.h b/m-c-mempool.h index be1f3501..d065115c 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -312,7 +312,7 @@ M_BEGIN_PROTECTED_CODE M_F(name, _lf_node_t) * node; \ node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \ if (M_UNLIKELY_NOMEM (node == NULL)) { \ - M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \ + M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ return NULL; \ } \ atomic_init(&node->next, (M_F(name, _lf_node_t) *) 0); \ @@ -322,7 +322,7 @@ M_BEGIN_PROTECTED_CODE M_F(name, _slist_node_ct) *n; \ n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ - M_MEMORY_FULL(sizeof(M_F(name, _lf_node_t))); \ + M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ return NULL; \ } \ M_F(name, _slist_push)(node->list, n); \ @@ -466,7 +466,7 @@ M_BEGIN_PROTECTED_CODE /* Initialize the thread data of the mempool */ \ mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \ if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \ - M_MEMORY_FULL(max_thread * sizeof(M_F(name, _lfmp_thread_ct))); \ + M_MEMORY_FULL(M_F(name, _lfmp_thread_ct), max_thread); \ return; \ } \ for(unsigned i = 0; i < max_thread;i++) { \ @@ -589,7 +589,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread) m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread); gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) { - M_MEMORY_FULL(max_thread * sizeof(m_gc_lfmp_thread_ct)); + M_MEMORY_FULL(m_gc_lfmp_thread_ct, max_thread); return; } for(unsigned i = 0; i < max_thread;i++) { @@ -759,7 +759,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem) /* Initialize the thread data of the vlapool */ mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { - M_MEMORY_FULL(max_thread * sizeof(m_vlapool_lfmp_thread_ct)); + M_MEMORY_FULL(m_vlapool_lfmp_thread_ct, max_thread); return; } for(unsigned i = 0; i < max_thread;i++) { diff --git a/m-core.h b/m-core.h index 65f5e0e8..1ef264d5 100644 --- a/m-core.h +++ b/m-core.h @@ -398,13 +398,14 @@ M_BEGIN_PROTECTED_CODE #endif /* This macro is called on memory allocation failure. - * By default, it raises a fatal error. + * By default, it raises a fatal error and abort execution. * NOTE: Can be overloaded by user code. */ #ifndef M_MEMORY_FULL -#define M_MEMORY_FULL(size) \ - M_RAISE_FATAL("Cannot allocate %zu bytes of memory at (%s:%s:%d).\n", \ - (size_t) (size), __FILE__, __func__, __LINE__) +#define M_MEMORY_FULL(type, number) \ + M_RAISE_FATAL("Cannot allocate %zu objects of type '%s' (size '%zu') at (%s:%s:%d).\n", \ + (size_t) (number), M_AS_STR(type), sizeof (type), \ + __FILE__, __func__, __LINE__) #endif diff --git a/m-deque.h b/m-deque.h index 54a7c898..268436ea 100644 --- a/m-deque.h +++ b/m-deque.h @@ -181,7 +181,7 @@ size_t def = d->default_size; \ /* Test for overflow of the size computation */ \ if (M_UNLIKELY_NOMEM (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \ - M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ + M_MEMORY_FULL(char, sizeof(node_t)+def * sizeof(type)); \ abort(); \ return NULL; \ } \ @@ -190,7 +190,7 @@ M_CALL_REALLOC(oplist, char, NULL, 0, \ sizeof(node_t) + def * sizeof(type) ); \ if (M_UNLIKELY_NOMEM (n==NULL)) { \ - M_MEMORY_FULL(sizeof(node_t)+def * sizeof(type)); \ + M_MEMORY_FULL(char, sizeof(node_t)+def * sizeof(type)); \ abort(); \ return NULL; \ } \ diff --git a/m-dict.h b/m-dict.h index f988a258..e7ff592d 100644 --- a/m-dict.h +++ b/m-dict.h @@ -339,14 +339,14 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* The first 2 buckets are reserved for (empty) and (deleted) access. Allocation could be avoided */ \ map->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), NULL, 0, (size_t) 1+2+map->upper_limit); \ if (M_UNLIKELY_NOMEM (map->data == NULL)) { \ - M_MEMORY_FULL( (2+M_D1CT_INITIAL_SIZE) * sizeof (M_F(name, _freelist_ct))); \ + M_MEMORY_FULL(M_F(name, _freelist_ct), 2+M_D1CT_INITIAL_SIZE); \ return ; \ } \ map->freelist_first_data = 0; \ map->freelist_count = 2; \ map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, 0, (size_t)(0+M_D1CT_INITIAL_SIZE)); \ if (M_UNLIKELY_NOMEM (map->index == NULL)) { \ - M_MEMORY_FULL( (2+M_D1CT_INITIAL_SIZE) * sizeof (m_indexhash_t)); \ + M_MEMORY_FULL(m_indexhash_t, 2+M_D1CT_INITIAL_SIZE); \ return ; \ } \ /* Populate the initial table with the 'empty' representation which is 0 */ \ @@ -475,13 +475,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /*FIXME; oldsize incorrect */ \ h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, -1, (size_t) 1+2+h->upper_limit); \ if (M_UNLIKELY_NOMEM (h->data == NULL) ) { \ - M_MEMORY_FULL((2+newSize)*sizeof (M_F(name, _freelist_ct))); \ + M_MEMORY_FULL(M_F(name, _freelist_ct), 2+newSize); \ return ; \ } \ } \ m_indexhash_t *index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \ if (M_UNLIKELY_NOMEM (index == NULL) ) { \ - M_MEMORY_FULL(newSize*sizeof(m_indexhash_t)); \ + M_MEMORY_FULL(m_indexhash_t, newSize); \ return ; \ } \ h->index = index; \ @@ -655,7 +655,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) if (map->count > newSize/2) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= map->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ M_C3(m_d1ct_,name,_resize_up)(map, newSize, true); \ @@ -714,7 +714,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) if (map->count > newSize/2) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= map->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ M_C3(m_d1ct_,name,_resize_up)(map, newSize, true); \ @@ -972,7 +972,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_ASSERT (M_POWEROF2_P(size)); \ /* Test for overflow of the computation */ \ if (M_UNLIKELY_NOMEM (size < capacity)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ if (size > dict->mask+1) { \ dict->upper_limit = (M_F(name, _index_ct)) ((double) size * M_D1CT_OA_UPPER_BOUND) - 1; \ @@ -1489,7 +1489,7 @@ enum m_d1ct_oa_element_e { M_C3(m_d1ct_,name,_update_limit)(dict, M_D1CT_INITIAL_SIZE); \ dict->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), NULL, 0, M_D1CT_INITIAL_SIZE); \ if (M_UNLIKELY_NOMEM (dict->data == NULL)) { \ - M_MEMORY_FULL(sizeof (M_F(name, _pair_ct)) * M_D1CT_INITIAL_SIZE); \ + M_MEMORY_FULL(M_F(name, _pair_ct), M_D1CT_INITIAL_SIZE); \ return ; \ } \ /* Populate the initial table with the 'empty' representation */ \ @@ -1570,7 +1570,7 @@ enum m_d1ct_oa_element_e { if (newSize > oldSize) { \ data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, oldSize, newSize); \ if (M_UNLIKELY_NOMEM (data == NULL) ) { \ - M_MEMORY_FULL(sizeof (M_F(name, _pair_ct)) * newSize); \ + M_MEMORY_FULL(M_F(name, _pair_ct), newSize); \ return ; \ } \ \ @@ -1695,7 +1695,7 @@ enum m_d1ct_oa_element_e { if (dict->count > (dict->mask / 2)) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ @@ -1749,7 +1749,7 @@ enum m_d1ct_oa_element_e { if (dict->count > (dict->mask / 2)) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ @@ -2114,7 +2114,7 @@ M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], ke if (dict->count > (dict->mask / 2)) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ @@ -2177,7 +2177,7 @@ M_F(name, _bulk_update)(dict_t dict, unsigned n, value_type val[M_VLA(n)], key_t if (dict->count > (dict->mask / 2)) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL((size_t)-1); \ + M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ diff --git a/m-genint.h b/m-genint.h index 1bacf991..2c4e1f19 100644 --- a/m-genint.h +++ b/m-genint.h @@ -111,7 +111,7 @@ m_genint_init(m_genint_t s, unsigned int n) const unsigned int index = n % M_GEN1NT_LIMBSIZE; atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { - M_MEMORY_FULL(alloc); + M_MEMORY_FULL(atomic_ullong, alloc); return; } s->n = n; diff --git a/m-i-shared.h b/m-i-shared.h index 0caa361b..d1bcc1cd 100644 --- a/m-i-shared.h +++ b/m-i-shared.h @@ -192,7 +192,7 @@ M_BEGIN_PROTECTED_CODE { \ type *ptr = M_CALL_NEW(oplist, type); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ - M_MEMORY_FULL(sizeof(type)); \ + M_MEMORY_FULL(type, 1); \ return NULL; \ } \ M_CALL_INIT(oplist, *ptr); \ diff --git a/m-list.h b/m-list.h index 7c1918a0..bdda2f60 100644 --- a/m-list.h +++ b/m-list.h @@ -278,7 +278,7 @@ struct M_F(name, _s) *next; \ next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return NULL; \ } \ type *ret = &next->data; \ @@ -499,7 +499,7 @@ M_ASSERT(M_F(name, _sublist_p)(list, insertion_point)); \ struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ } \ M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \ @@ -552,7 +552,7 @@ while (it_org != NULL) { \ next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ *update_list = NULL; \ return; \ } \ @@ -1062,7 +1062,7 @@ M_L1ST_DUAL_PUSH_CONTRACT(v); \ struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return NULL; \ } \ type *ret = &next->data; \ @@ -1180,7 +1180,7 @@ M_L1ST_DUAL_PUSH_CONTRACT(v); \ struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return NULL; \ } \ type *ret = &next->data; \ @@ -1344,7 +1344,7 @@ M_ASSERT (insertion_point != NULL); \ struct M_F(name, _s) *m_volatile next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ } \ M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \ @@ -1406,7 +1406,7 @@ while (it_org != NULL) { \ next = M_C3(m_l1st_,name,_new)(); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ } \ M_CALL_INIT_SET(oplist, next->data, it_org->data); \ diff --git a/m-mempool.h b/m-mempool.h index f08f7da7..adb4ad71 100644 --- a/m-mempool.h +++ b/m-mempool.h @@ -115,7 +115,7 @@ mem->free_list = NULL; \ mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \ if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \ - M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \ + M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ return; \ } \ mem->current_segment->next = NULL; \ @@ -157,7 +157,7 @@ if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \ M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \ if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \ - M_MEMORY_FULL(sizeof (M_F(name,_segment_ct))); \ + M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ return NULL; \ } \ new_segment->next = segment; \ diff --git a/m-rbtree.h b/m-rbtree.h index c4fd1ac7..d07e6173 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -318,7 +318,7 @@ typedef enum { if (n == NULL) { \ n = M_C3(m_rbtr33_,name,_new)(); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ - M_MEMORY_FULL(sizeof (node_t)); \ + M_MEMORY_FULL(node_t, 1); \ return; \ } \ /* Copy the data in the root node */ \ @@ -359,7 +359,7 @@ typedef enum { /* Create new node to store the data */ \ n = M_C3(m_rbtr33_,name,_new)(); \ if (M_UNLIKELY_NOMEM (n == NULL) ) { \ - M_MEMORY_FULL (sizeof (node_t)); \ + M_MEMORY_FULL (node_t, 1); \ return; \ } \ /* Copy the data and mark the node as red */ \ @@ -690,7 +690,7 @@ typedef enum { if (o == NULL) return NULL; \ node_t *n = M_C3(m_rbtr33_,name,_new)(); \ if (M_UNLIKELY_NOMEM (n == NULL) ) { \ - M_MEMORY_FULL (sizeof (node_t)); \ + M_MEMORY_FULL (node_t, 1); \ return NULL; \ } \ M_CALL_INIT_SET(oplist, n->data, o->data); \ diff --git a/m-shared-ptr.h b/m-shared-ptr.h index fe928523..059811a9 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -615,7 +615,7 @@ M_IF_METHOD(INIT, oplist)( \ { \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ - M_MEMORY_FULL(sizeof (shared_t)); \ + M_MEMORY_FULL(shared_t, 1); \ abort(); \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ @@ -631,7 +631,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ M_ASSERT(src != NULL); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ - M_MEMORY_FULL(sizeof (shared_t)); \ + M_MEMORY_FULL(shared_t, 1); \ abort(); \ } \ M_F(name, _read_lock)(src); \ @@ -648,7 +648,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ { \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ - M_MEMORY_FULL(sizeof (shared_t)); \ + M_MEMORY_FULL(shared_t, 1); \ abort(); \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ @@ -706,7 +706,7 @@ M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_ { \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ - M_MEMORY_FULL(sizeof (shared_t)); \ + M_MEMORY_FULL(shared_t, 1); \ abort(); \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ diff --git a/m-shared.h b/m-shared.h index 6becc2e0..59622be6 100644 --- a/m-shared.h +++ b/m-shared.h @@ -211,7 +211,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } } \ ptr = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ - M_MEMORY_FULL(sizeof(struct M_F(name, _s))); \ + M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ } \ ptr->data = data; \ @@ -229,7 +229,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } struct M_F(name, _combine_s) *p = \ M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \ if (M_UNLIKELY_NOMEM (p == NULL)) { \ - M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \ + M_MEMORY_FULL(struct M_F(name, _combine_s), 1); \ return; \ } \ struct M_F(name, _s) *ptr = &p->ptr; \ @@ -376,7 +376,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } struct M_F(name, _combine_s) *p = \ M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \ if (M_UNLIKELY_NOMEM (p == NULL)) { \ - M_MEMORY_FULL(sizeof(struct M_F(name, _combine_s))); \ + M_MEMORY_FULL(struct M_F(name, _combine_s), 1); \ return; \ } \ struct M_F(name, _s) *ptr = &p->ptr; \ @@ -447,7 +447,7 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } M_ASSERT (n > 0 && n < UINT_MAX); \ s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, 0, n); \ if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \ - M_MEMORY_FULL(sizeof(M_F(name, _atype_ct)) * n); \ + M_MEMORY_FULL(M_F(name, _atype_ct), n); \ return; \ } \ for(size_t i = 0; i < n; i++) { \ diff --git a/m-snapshot.h b/m-snapshot.h index fd03fc52..eb7dfd43 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -393,7 +393,7 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n) // Initialize the counters to zero (no reader use it) atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, 0, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { - M_MEMORY_FULL(sizeof (atomic_uint) * n); + M_MEMORY_FULL(atomic_uint, n); return; } s->cptTab = ptr; @@ -647,7 +647,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) snap->data = M_CALL_REALLOC(oplist, M_F(name, _aligned_type_ct), \ NULL, 0, nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); \ if (M_UNLIKELY_NOMEM (snap->data == NULL)) { \ - M_MEMORY_FULL(sizeof(M_F(name, _aligned_type_ct)) * \ + M_MEMORY_FULL(M_F(name, _aligned_type_ct), \ (nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \ return; \ } \ diff --git a/m-string.h b/m-string.h index e4c29078..b5db698a 100644 --- a/m-string.h +++ b/m-string.h @@ -313,7 +313,7 @@ m_string_clear_get_cstr(m_string_t v) size_t alloc = m_string_size(v)+1; char *ptr = M_MEMORY_REALLOC (char, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { - M_MEMORY_FULL(sizeof (char) * alloc); + M_MEMORY_FULL(char, alloc); return NULL; } M_ASSERT(ptr != NULL && p != NULL); @@ -386,7 +386,7 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc) alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc); if (M_UNLIKELY_NOMEM (alloc <= size_alloc)) { /* Overflow in alloc computation */ - M_MEMORY_FULL(sizeof (char) * alloc); + M_MEMORY_FULL(char, alloc); // NOTE: Return is currently broken. abort(); return NULL; @@ -395,7 +395,7 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc) //FIXME: old_alloc may not be NULL if ptr is NULL. ptr = M_MEMORY_REALLOC (char, ptr, old_alloc, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { - M_MEMORY_FULL(sizeof (char) * alloc); + M_MEMORY_FULL(char, alloc); // NOTE: Return is currently broken. abort(); return NULL; @@ -452,13 +452,13 @@ m_string_reserve(m_string_t v, size_t alloc) unsigned char m, e; size_t r_alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc); if (M_UNLIKELY_NOMEM (alloc > r_alloc)) { - M_MEMORY_FULL(sizeof (char) * alloc); + M_MEMORY_FULL(char, alloc); return; } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; ptr = M_MEMORY_REALLOC (char, ptr, m_string_capacity(v), r_alloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { - M_MEMORY_FULL(sizeof (char) * alloc); + M_MEMORY_FULL(char, alloc); return; } if (m_str1ng_embedded_p(v)) { diff --git a/m-tree.h b/m-tree.h index 929a47c6..7e4f0ca9 100644 --- a/m-tree.h +++ b/m-tree.h @@ -260,7 +260,7 @@ typedef int32_t m_tr33_index_t; } \ /* Realloc the array */ \ if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \ + M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return; \ } \ /* Allocate one more term in the array so that tab[-1] exists. \ @@ -270,7 +270,7 @@ typedef int32_t m_tr33_index_t; struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\ ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \ + M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return; \ } \ /* Skip the first term to keep it as empty & unused */ \ @@ -314,7 +314,7 @@ typedef int32_t m_tr33_index_t; /* Take into account if realloc is allowed */ \ alloc += tree->allow_realloc; \ if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \ + M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return M_TR33_NO_NODE; \ } \ /* Allocate one more term in the array so that tab[-1] exists. \ @@ -324,7 +324,7 @@ typedef int32_t m_tr33_index_t; struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1; \ ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof (struct M_F(name, _node_s)) * alloc); \ + M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return M_TR33_NO_NODE; \ } \ /* Skip the first term to keep it as empty & unused */ \ @@ -1136,7 +1136,7 @@ typedef int32_t m_tr33_index_t; struct M_F(name, _node_s) *ptr = \ M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, 0, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ - M_MEMORY_FULL(sizeof(struct M_F(name, _node_s)) * alloc); \ + M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return; \ } \ tree->tab = ++ptr; \ diff --git a/m-try.h b/m-try.h index fc367130..15c77cd3 100644 --- a/m-try.h +++ b/m-try.h @@ -620,7 +620,7 @@ _Pragma("GCC diagnostic pop") // In case of MEMORY FULL errors, throw an error instead of aborting. #undef M_MEMORY_FULL -#define M_MEMORY_FULL(size) M_THROW(M_ERROR_MEMORY, (intptr_t)(size)) +#define M_MEMORY_FULL(type, size) M_THROW(M_ERROR_MEMORY, (intptr_t)sizeof(type), (intptr_t)(size)) // Add attribute volatile if exceptions are enabled #undef m_volatile diff --git a/m-worker.h b/m-worker.h index e78d213e..7022483e 100644 --- a/m-worker.h +++ b/m-worker.h @@ -266,7 +266,7 @@ typedef struct m_worker_sync_s { if (!m_work3r_queue_full_p(block->worker->queue_g)) { \ struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \ if (M_UNLIKELY_NOMEM(p == NULL)) { \ - M_MEMORY_FULL(sizeof (struct M_C3(m_worker_, name, _s))); \ + M_MEMORY_FULL(struct M_C3(m_worker_, name, _s), 1); \ } \ p->callback = callback; \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_COPY, data, __VA_ARGS__) \ @@ -411,7 +411,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset size_t numWorker_st = (size_t) numWorker; g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st); if (M_UNLIKELY_NOMEM (g->worker == NULL)) { - M_MEMORY_FULL(sizeof (m_work3r_thread_ct) * numWorker_st); + M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st); return; } m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue); From 9f4f9d1d5dd60f6ba976ea3ad83b5282f2d0971a Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 21 Dec 2024 13:06:52 +0100 Subject: [PATCH 06/91] Update --- doc/API.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/API.txt b/doc/API.txt index e61f6725..7017a405 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -85,4 +85,13 @@ V0.7.2: * Rename m-mutex.h header in m-thread.h V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated. Use DICT_DEF2 / DICT_DEF2_AS - \ No newline at end of file + +V0.7.4 : * REALLOC / FREE operators are incompatible: + Add the old number of elements of the array as argument of REALLOC + Add the number of elements of the array and its base type as arguments of FREE. + You need to ignore the new arguments. + Also impact M_MEMORY_REALLOC & M_MEMORY_FREE + This allows more and efficient integration into custom allocators. + * M_MEMORY_FULL: replace the failed size allocation size argument + into the base type and the number of elements that failed to be allocated. + From b4c29d5423d3b2f7f97f2a6fcd6ff8312b1315e3 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 23 Dec 2024 22:29:16 +0100 Subject: [PATCH 07/91] Update spec --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 16d0bb26..e4196281 100644 --- a/README.md +++ b/README.md @@ -643,7 +643,7 @@ Other documented operators are: * `NEW(type)` --> `type pointer`: allocate a new object (with suitable alignment and size) and return a pointer to it. The returned object is **not initialized** (a constructor operator shall be called afterward). The default method is `M_MEMORY_ALLOC` (that allocates from the heap). It returns NULL in case of failure. * `DEL(&obj)`: free the allocated uninitialized object `obj`. The destructor of the pointed object shall be called before freeing the memory by calling this method. The object shall have been allocated by the associated NEW method. `sizeof obj` is the size of the allocated object. The default method is `M_MEMORY_DEL` (that frees to the heap). `obj` shall not be NULL and shall be of the proper type. * `REALLOC(type, pointer, previous_number, new_number)` --> `pointer`: reallocate the given array of `previous_number` elements of type `type` referenced by `pointer` (either a NULL pointer or a pointer returned by a previous call to `REALLOC`) to an array of `new_number` objects of type `type` and return a pointer to this new array. Previously objects pointed by the pointer are kept up to the minimum of the new size and old one but may have moved from their original positions (if the array is reallocated otherwhere). New objects are not initialized (a constructor operator shall be called afterward). Freed objects are not cleared (A destructor operator shall be called before). The default is `M_MEMORY_REALLOC` (that allocates from the heap). It returns NULL in case of failure in which case the original array is not modified. If `pointer` is NULL, then `previous_number` should be 0. -* `FREE(type, pointer, number)`: free the allocated uninitialized array of `number` elements of type `type` referenced by `pointer`. The destructor of the pointed objects shall be called before freeing the memory. The memory of the objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap). +* `FREE(type, pointer, number)`: free the allocated uninitialized array of `number` elements of type `type` referenced by `pointer`. The destructor of the pointed objects shall be called before freeing the memory. The memory of the objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap). If pointer is NULL, then the function shall do nothing. * `INC_ALLOC(size_t s)` --> `size_t`: Define the growing policy of an array (or equivalent structure). It returns a new allocation size based on the old allocation size (`s`). Default policy is to get the maximum between `2*s` and 16. In case of overflow, it shall return a number less or equal than the original size. > [!NOTE] @@ -7872,7 +7872,7 @@ The default used function is the `realloc` function of the LIBC. Delete the cleared array of `number` objects of type `type pointed by the pointer `ptr`. The pointer was previously allocated by the macro `M_MEMORY_REALLOC`. -`ptr` can not be NULL. +If `ptr` is NULL, the function shall do nothing. The default used function is the `free` function of the LIBC. From d40a6e5bc3b0946c798e8bb508ad6e0fa0316454 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 23 Dec 2024 22:29:30 +0100 Subject: [PATCH 08/91] Document limitation --- m-c-mempool.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/m-c-mempool.h b/m-c-mempool.h index d065115c..a1b0633f 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -497,7 +497,7 @@ M_BEGIN_PROTECTED_CODE for(unsigned i = 0; i < max_thread;i++) { \ M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \ } \ - M_MEMORY_FREE(M_F(name, _lfmp_thread_ct), mem->thread_data, mem->gc_mem->max_thread); \ + M_MEMORY_FREE(M_F(name, _lfmp_thread_ct), mem->thread_data, max_thread); \ mem->thread_data = NULL; \ M_F(name, _lflist_clear)(mem->empty); \ M_F(name, _lflist_clear)(mem->free); \ @@ -784,7 +784,7 @@ m_vlapool_clear(m_vlapool_t mem) for(unsigned i = 0; i < max_thread;i++) { m_vlapool_lfmp_thread_clear(&mem->thread_data[i]); } - M_MEMORY_FREE(m_vlapool_lfmp_thread_ct, mem->thread_data, mem->gc_mem->max_thread); + M_MEMORY_FREE(m_vlapool_lfmp_thread_ct, mem->thread_data, max_thread); mem->thread_data = NULL; m_vlapool_lflist_clear(mem->empty); M_ASSERT(m_vlapool_lflist_empty_p(mem->to_be_reclaimed)); @@ -808,7 +808,12 @@ m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size) // Simply wrap around a system call to get the memory char *ptr = M_MEMORY_REALLOC(char, NULL, 0, size); - return (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data)); + // TODO: save the allocated size somewhere (create a new field in vla) + // FIXME: Bug, we call DEL operator to free the node, but we have allocated it with the REALLOC one! + // And they are not necessarily compatible as per the spec (even if they are if they both use 'free') + // And the generic used slist expects to use the DEL one, since the vlapool abuse the memory system. + // Honnestly, it is fundamentally broken and it needs a huge rewrite. + return M_UNLIKELY (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data)); } M_INLINE void From 50e8d1f4696df0579aa4e2b997dface617b7e743 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 23 Dec 2024 22:30:08 +0100 Subject: [PATCH 09/91] Fix old size parameter for memory allocation --- m-buffer.h | 4 ++-- m-deque.h | 9 ++++----- m-dict.h | 13 ++++++------- m-genint.h | 2 +- m-snapshot.h | 2 +- m-tree.h | 6 +++--- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/m-buffer.h b/m-buffer.h index 16936596..16c23780 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -940,7 +940,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ j = 0; \ } \ } \ - M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, M_BUFF3R_SIZE(m_size)); \ + M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, buffer->size); \ buffer->Tab = NULL; /* safer */ \ buffer->size = 3; \ } \ @@ -1281,7 +1281,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ j = 0; \ } \ } \ - M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, M_BUFF3R_SIZE(m_size)); \ + M_CALL_FREE(oplist, M_F(name, _el_ct), buffer->Tab, buffer->size); \ buffer->Tab = NULL; /* safer */ \ buffer->size = 3; \ } \ diff --git a/m-deque.h b/m-deque.h index 268436ea..2bb79e1a 100644 --- a/m-deque.h +++ b/m-deque.h @@ -116,7 +116,7 @@ \ typedef struct M_F(name, _node_s) { \ M_ILIST_INTERFACE(M_F(name, _node_list), struct M_F(name, _node_s)); \ - size_t size; \ + size_t size, capacity; \ type data[M_MIN_FLEX_ARRAY_SIZE]; \ } node_t; \ \ @@ -129,8 +129,7 @@ /* FIXME: How can I separate public types and private implementation? */ \ static inline void M_F(name, _del_node)(node_t *ptr) \ { \ - /* FIXME: ptr->size can be incorrect as old size ! */ \ - M_CALL_FREE(oplist, char, ptr, sizeof(node_t) + ptr->size * sizeof(type)); \ + M_CALL_FREE(oplist, char, ptr, sizeof(node_t) + ptr->capacity * sizeof(type)); \ } \ M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_F(name, _del_node))) ) \ \ @@ -196,6 +195,7 @@ } \ /* Initialize the node */ \ n->size = def; \ + n->capacity = def; \ M_F(name, _node_list_init_field)(n); \ /* Increase the next bucket allocation */ \ /* Do not increase it too much if there are few items */ \ @@ -716,8 +716,7 @@ /* Node deletion */ \ M_ASSERT(d->count > 1); \ M_F(name, _node_list_unlink)(n); \ - /* FIXME: oldsize broken as size is corrupted! */ \ - M_CALL_FREE(oplist, char, n, sizeof(node_t) + n->size * sizeof(type) ); \ + M_CALL_FREE(oplist, char, n, sizeof(node_t) + n->capacity * sizeof(type) ); \ } else { \ memmove(&n->data[it->index], &n->data[it->index+1], \ sizeof(type) * (it->node->size - it->index - 1)); \ diff --git a/m-dict.h b/m-dict.h index e7ff592d..cfec705f 100644 --- a/m-dict.h +++ b/m-dict.h @@ -296,7 +296,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) m_index_t count, count_delete; \ m_index_t upper_limit, lower_limit; \ m_index_t mask; \ - m_index_t freelist_first_data, freelist_count; \ + m_index_t freelist_first_data, freelist_count, freelist_cap; \ m_indexhash_t *index; \ M_F(name, _freelist_ct) *data; \ } dict_t[1]; \ @@ -344,6 +344,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) } \ map->freelist_first_data = 0; \ map->freelist_count = 2; \ + map->freelist_cap = 1+2+map->upper_limit; \ map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, 0, (size_t)(0+M_D1CT_INITIAL_SIZE)); \ if (M_UNLIKELY_NOMEM (map->index == NULL)) { \ M_MEMORY_FULL(m_indexhash_t, 2+M_D1CT_INITIAL_SIZE); \ @@ -372,8 +373,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) } \ } \ M_CALL_FREE(key_oplist, m_indexhash_t, map->index, map->mask+1); \ - /* FIXME: How much? */ \ - M_CALL_FREE(key_oplist, M_F(name, _freelist_ct), map->data, -1); \ + M_CALL_FREE(key_oplist, M_F(name, _freelist_ct), map->data, map->freelist_cap); \ /* Mark the dictionary as cleared */ \ map->data = NULL; \ map->index = NULL; \ @@ -467,17 +467,16 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) if (newSize > oldSize) { \ /* h->data is not always the same size than h->index: it may be bigger \ if there is some erase of items: h->index will shrink, but not h->data \ - To have an estimate of the size, we look at the maximum index of it: \ if it is bigger than our new size, then we don't need to reallocate */ \ /* We need to allocate '2' for the dummy first two entries in the table (not used), \ then we can have at maximum only up to 'upper_limit+1' data */ \ - if (1+2+h->upper_limit > h->freelist_count) { \ - /*FIXME; oldsize incorrect */ \ - h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, -1, (size_t) 1+2+h->upper_limit); \ + if (1+2+h->upper_limit > h->freelist_cap) { \ + h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, h->freelist_cap, (size_t) 1+2+h->upper_limit); \ if (M_UNLIKELY_NOMEM (h->data == NULL) ) { \ M_MEMORY_FULL(M_F(name, _freelist_ct), 2+newSize); \ return ; \ } \ + h->freelist_cap = 1+2+h->upper_limit; \ } \ m_indexhash_t *index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \ if (M_UNLIKELY_NOMEM (index == NULL) ) { \ diff --git a/m-genint.h b/m-genint.h index 2c4e1f19..b19596c2 100644 --- a/m-genint.h +++ b/m-genint.h @@ -130,7 +130,7 @@ M_INLINE void m_genint_clear(m_genint_t s) { M_GEN1NT_CONTRACT(s); - M_MEMORY_FREE(atomic_ullong, s->data, s->alloc); + M_MEMORY_FREE(atomic_ullong, s->data, s->max+1); s->data = NULL; } diff --git a/m-snapshot.h b/m-snapshot.h index eb7dfd43..3ebfc379 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -419,7 +419,7 @@ M_INLINE void m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s) { M_SNAPSH0T_SPMC_INT_CONTRACT(s); - M_MEMORY_FREE (atomic_uint, s->cptTab, s->n_reader-M_SNAPSH0T_SPMC_EXTRA_BUFFER); + M_MEMORY_FREE (atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); m_genint_clear(s->freeList); s->cptTab = NULL; s->n_reader = 0; diff --git a/m-tree.h b/m-tree.h index 7e4f0ca9..c767f118 100644 --- a/m-tree.h +++ b/m-tree.h @@ -245,7 +245,7 @@ typedef int32_t m_tr33_index_t; M_F(name, _clear)(tree_t tree) { \ M_F(name, _reset)(tree); \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\ - M_CALL_FREE(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1); \ + M_CALL_FREE(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1)); \ /* This is so reusing the object implies an assertion failure */ \ tree->size = 1; \ tree->tab = NULL; \ @@ -268,7 +268,7 @@ typedef int32_t m_tr33_index_t; as M_TR33_NO_NODE is -1. This enables avoiding testing for \ M_TR33_NO_NODE in some cases, performing branchless code. */ \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\ - ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1, alloc+1); \ + ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1), alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return; \ @@ -322,7 +322,7 @@ typedef int32_t m_tr33_index_t; as M_TR33_NO_NODE is -1. This enables avoiding testing for \ M_TR33_NO_NODE in some cases, performing branchless code. */ \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1; \ - ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, tree->capacity+1, alloc+1); \ + ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1), alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ return M_TR33_NO_NODE; \ From 37b2f4d2ac8a43446c286b19c29bea46b85bd4f9 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 23 Dec 2024 22:30:24 +0100 Subject: [PATCH 10/91] Update test suite to properly allocation & deallocation --- tests/test-malgo.c | 3 +-- tests/test-mbitset.c | 3 +-- tests/test-mbptree.c | 4 +--- tests/test-mbstring.c | 3 +-- tests/test-mbuffer.c | 4 ++-- tests/test-mconcurrent.c | 2 +- tests/test-mcore.c | 3 +-- tests/test-mdict.c | 7 +++--- tests/test-mfuncobj.c | 1 - tests/test-mgeneric.c | 6 ++--- tests/test-mgenint.c | 3 +-- tests/test-milist.c | 5 ++-- tests/test-mishared.c | 3 --- tests/test-mlist.c | 3 +-- tests/test-mmempool.c | 6 ++--- tests/test-mprioqueue.c | 4 +--- tests/test-mrbtree.c | 3 +-- tests/test-mserial-bin.c | 1 + tests/test-mserial-json.c | 1 + tests/test-mshared-ptr.c | 5 +--- tests/test-mshared.c | 4 +--- tests/test-msnapshot.c | 2 -- tests/test-mstring.c | 9 ++++---- tests/test-mtree.c | 5 +--- tests/test-mtry.c | 1 - tests/test-mtuple.c | 4 +--- tests/test-mvariant.c | 4 +--- tests/test-mworker.c | 3 +-- tests/test-obj.h | 48 +++++++++++++++++++++++++++++++++++++++ 29 files changed, 82 insertions(+), 68 deletions(-) diff --git a/tests/test-malgo.c b/tests/test-malgo.c index 3138b52b..32e65241 100644 --- a/tests/test-malgo.c +++ b/tests/test-malgo.c @@ -20,6 +20,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "test-obj.h" #include "m-list.h" #include "m-i-list.h" #include "m-array.h" @@ -29,8 +30,6 @@ #include "m-tuple.h" #include "m-algo.h" -#include "test-obj.h" - typedef struct over_s { unsigned long data; ILIST_INTERFACE(ilist_over, over_s); diff --git a/tests/test-mbitset.c b/tests/test-mbitset.c index dcb712f0..ae688f41 100644 --- a/tests/test-mbitset.c +++ b/tests/test-mbitset.c @@ -20,10 +20,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include "test-obj.h" #include "m-string.h" #include "coverage.h" - #include "m-bitset.h" static void test1(void) diff --git a/tests/test-mbptree.c b/tests/test-mbptree.c index 6ee08a84..60c5ba46 100644 --- a/tests/test-mbptree.c +++ b/tests/test-mbptree.c @@ -20,11 +20,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#include "test-obj.h" #include "m-string.h" #include "m-bptree.h" -#include "test-obj.h" #include "coverage.h" START_COVERAGE diff --git a/tests/test-mbstring.c b/tests/test-mbstring.c index 2d00103e..5602d3df 100644 --- a/tests/test-mbstring.c +++ b/tests/test-mbstring.c @@ -20,9 +20,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "m-core.h" +#include "test-obj.h" #include "coverage.h" - #include "m-bstring.h" static void test0(void) diff --git a/tests/test-mbuffer.c b/tests/test-mbuffer.c index 3474d670..6fc2032d 100644 --- a/tests/test-mbuffer.c +++ b/tests/test-mbuffer.c @@ -20,10 +20,10 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "m-buffer.h" - #include "test-obj.h" +#include "m-buffer.h" #include "coverage.h" + START_COVERAGE // Define a fixed queue of unsigned int BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE|BUFFER_BLOCKING) diff --git a/tests/test-mconcurrent.c b/tests/test-mconcurrent.c index 234c89c9..4c84c509 100644 --- a/tests/test-mconcurrent.c +++ b/tests/test-mconcurrent.c @@ -22,7 +22,6 @@ */ #include #include "test-obj.h" -#include "coverage.h" #include "m-array.h" #include "m-bptree.h" @@ -35,6 +34,7 @@ #include "m-variant.h" #include "m-concurrent.h" +#include "coverage.h" TUPLE_DEF2(point, (x, int), (y, int)) #define M_OPL_point_t() TUPLE_OPLIST(point, M_BASIC_OPLIST, M_BASIC_OPLIST) diff --git a/tests/test-mcore.c b/tests/test-mcore.c index 6f80a16c..54419440 100644 --- a/tests/test-mcore.c +++ b/tests/test-mcore.c @@ -29,9 +29,8 @@ #define M_F(a,b) M_OVERRIDE_F(a,b) #define M_OVERRIDE__method() , _get_method , #define M_OVERRIDE__method2() , _get_method2 -#include "m-core.h" - #include "test-obj.h" +#include "m-core.h" static bool tmp_init(void) { return true; } static bool tmp_get_method(void) { return true; } diff --git a/tests/test-mdict.c b/tests/test-mdict.c index fbc779cc..6d847007 100644 --- a/tests/test-mdict.c +++ b/tests/test-mdict.c @@ -21,17 +21,16 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include +#include "test-obj.h" #include "m-dict.h" #include "m-array.h" #include "m-string.h" -#include "test-obj.h" +#include "coverage.h" static inline bool oor_equal_p(int k, unsigned char n) { return k == (int)-n-1; } static inline void oor_set(int *k, unsigned char n) { *k = (int)-n-1; } static inline void update_value (int *p, const int p1, const int p2) { *p = p1 + p2; } -#include "coverage.h" + START_COVERAGE DICT_DEF2(dict_str, string_t, STRING_OPLIST, string_t, STRING_OPLIST) DICT_OA_DEF2(dict_oa_int, int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(oor_set M_IPTR)), int, M_OPEXTEND(M_BASIC_OPLIST, ADD(update_value M_IPTR))) diff --git a/tests/test-mfuncobj.c b/tests/test-mfuncobj.c index af2b63be..14fc2d3f 100644 --- a/tests/test-mfuncobj.c +++ b/tests/test-mfuncobj.c @@ -20,7 +20,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" #include "m-string.h" #include "m-funcobj.h" diff --git a/tests/test-mgeneric.c b/tests/test-mgeneric.c index 9e814baa..79abb7bd 100644 --- a/tests/test-mgeneric.c +++ b/tests/test-mgeneric.c @@ -21,14 +21,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include "coverage.h" - +#include "test-obj.h" #include "m-string.h" #include "m-array.h" #include "m-list.h" #include "m-generic.h" +#include "coverage.h" // Generic is not supported if not C11 // TCC has some issues in the preprocessing. diff --git a/tests/test-mgenint.c b/tests/test-mgenint.c index b55e56c5..69839a18 100644 --- a/tests/test-mgenint.c +++ b/tests/test-mgenint.c @@ -20,12 +20,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include "test-obj.h" #include "m-thread.h" #include "m-atomic.h" #include "m-core.h" #include "coverage.h" - #include "m-genint.h" #define MAX_N 256 diff --git a/tests/test-milist.c b/tests/test-milist.c index 72b28153..df3a3849 100644 --- a/tests/test-milist.c +++ b/tests/test-milist.c @@ -22,9 +22,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include - +#include "test-obj.h" #include "m-i-list.h" +#include "coverage.h" typedef struct test_s { int n; @@ -37,7 +37,6 @@ static inline bool test_equal_p(const test_t *i1, const test_t *i2) return i1->n == i2->n; } -#include "coverage.h" START_COVERAGE ILIST_DEF(ilist_tname, test_t, M_OPEXTEND(M_POD_OPLIST, EQUAL(API_6(test_equal_p)))) END_COVERAGE diff --git a/tests/test-mishared.c b/tests/test-mishared.c index 7d75a538..b65fc754 100644 --- a/tests/test-mishared.c +++ b/tests/test-mishared.c @@ -20,11 +20,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" - #include "m-i-shared.h" - #include "m-thread.h" #include "coverage.h" diff --git a/tests/test-mlist.c b/tests/test-mlist.c index 49f264d2..599c1dd1 100644 --- a/tests/test-mlist.c +++ b/tests/test-mlist.c @@ -20,12 +20,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" #include "m-string.h" #include "m-list.h" - #include "coverage.h" + START_COVERAGE LIST_DEF(list_uint, unsigned int) LIST_DEF(list_mpz, testobj_t, TESTOBJ_OPLIST) diff --git a/tests/test-mmempool.c b/tests/test-mmempool.c index 4d95ba37..b9513861 100644 --- a/tests/test-mmempool.c +++ b/tests/test-mmempool.c @@ -21,12 +21,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include - +#include "test-obj.h" #include "m-mempool.h" - #include "coverage.h" + START_COVERAGE MEMPOOL_DEF(mempool_uint, unsigned int) END_COVERAGE diff --git a/tests/test-mprioqueue.c b/tests/test-mprioqueue.c index b25b9228..40335953 100644 --- a/tests/test-mprioqueue.c +++ b/tests/test-mprioqueue.c @@ -20,13 +20,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include #include "test-obj.h" #include "m-string.h" #include "m-prioqueue.h" - #include "coverage.h" + START_COVERAGE PRIOQUEUE_DEF(int_pqueue, int) END_COVERAGE diff --git a/tests/test-mrbtree.c b/tests/test-mrbtree.c index 7a781f77..c2f01878 100644 --- a/tests/test-mrbtree.c +++ b/tests/test-mrbtree.c @@ -20,10 +20,10 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" #include "m-string.h" #include "m-rbtree.h" +#include "coverage.h" static bool uint_in_str(unsigned int *u, FILE *f) { @@ -49,7 +49,6 @@ static void uint_get_str(string_t str, unsigned int u, bool append) (append ? string_cat_printf : string_printf) (str, "%u", u); } -#include "coverage.h" START_COVERAGE RBTREE_DEF(rbtree_uint, unsigned int, M_OPEXTEND(M_BASIC_OPLIST, IN_STR(uint_in_str M_IPTR), OUT_STR(uint_out_str), GET_STR(uint_get_str), PARSE_STR(uint_parse_str M_IPTR)) ) END_COVERAGE diff --git a/tests/test-mserial-bin.c b/tests/test-mserial-bin.c index bbc368ae..56719c31 100644 --- a/tests/test-mserial-bin.c +++ b/tests/test-mserial-bin.c @@ -20,6 +20,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "test-obj.h" #include "m-tuple.h" #include "m-array.h" #include "m-variant.h" diff --git a/tests/test-mserial-json.c b/tests/test-mserial-json.c index b47ed40a..fcb542f9 100644 --- a/tests/test-mserial-json.c +++ b/tests/test-mserial-json.c @@ -20,6 +20,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "test-obj.h" #include "m-tuple.h" #include "m-array.h" #include "m-variant.h" diff --git a/tests/test-mshared-ptr.c b/tests/test-mshared-ptr.c index 71d9aa5f..f13f47ab 100644 --- a/tests/test-mshared-ptr.c +++ b/tests/test-mshared-ptr.c @@ -20,10 +20,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include - +#include "test-obj.h" #include "m-shared-ptr.h" - #include "m-string.h" #include "m-array.h" #include "m-bptree.h" @@ -34,7 +32,6 @@ #include "m-rbtree.h" #include "m-tuple.h" #include "m-variant.h" - #include "coverage.h" // TEST WITH INT diff --git a/tests/test-mshared.c b/tests/test-mshared.c index f7d8dd37..98bd78c3 100644 --- a/tests/test-mshared.c +++ b/tests/test-mshared.c @@ -20,12 +20,10 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" - #include "m-shared.h" - #include "coverage.h" + START_COVERAGE SHARED_PTR_DEF(shared_int, int) SHARED_RESOURCE_DEF(shared_ressource, testobj_t, TESTOBJ_OPLIST) diff --git a/tests/test-msnapshot.c b/tests/test-msnapshot.c index 51d82930..7794a447 100644 --- a/tests/test-msnapshot.c +++ b/tests/test-msnapshot.c @@ -21,10 +21,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test-obj.h" - #include "m-snapshot.h" #include "m-thread.h" - #include "coverage.h" // Long Structure with a simple CRC to check for proper passing diff --git a/tests/test-mstring.c b/tests/test-mstring.c index 5e84d8a8..78bd195b 100644 --- a/tests/test-mstring.c +++ b/tests/test-mstring.c @@ -22,9 +22,8 @@ */ #define M_USE_ADDITIONAL_CHECKS 1 -#include "m-core.h" +#include "test-obj.h" #include "coverage.h" - #include "m-string.h" BOUNDED_STRING_DEF(string16, 16) @@ -609,16 +608,18 @@ static void test0(void) assert (string_equal_str_p(s1, "QWERTYQWERTY")); string_clear (s2); + size_t cap = string_capacity(s1); char *s = string_clear_get_str (s1); assert(strcmp(s, "QWERTYQWERTY") == 0); - free(s); + overloaded_free(1, s, cap <= sizeof (m_str1ng_heap_ct) - 1 ? strlen(s)+1 : cap ); string_t s3; string_init(s3); string_cat_str(s3, "ABC"); + cap = string_capacity(s3); s = string_clear_get_str(s3); assert(strcmp(s, "ABC") == 0); - free(s); + overloaded_free(1, s, cap <= sizeof (m_str1ng_heap_ct) - 1 ? strlen(s)+1 : cap ); string_init_set_str(s1, "RESTART"); assert (string_equal_str_p(s1, "RESTART")); diff --git a/tests/test-mtree.c b/tests/test-mtree.c index 9e02b997..6017b112 100644 --- a/tests/test-mtree.c +++ b/tests/test-mtree.c @@ -20,11 +20,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include - -#include "m-tree.h" - #include "test-obj.h" +#include "m-tree.h" #include "m-string.h" #include "coverage.h" diff --git a/tests/test-mtry.c b/tests/test-mtry.c index 49179c1f..bcb44027 100644 --- a/tests/test-mtry.c +++ b/tests/test-mtry.c @@ -51,7 +51,6 @@ static bool test_final_in_progress; #include "test-obj.h" #include "coverage.h" - #include "m-try.h" M_TRY_DEF_ONCE() diff --git a/tests/test-mtuple.c b/tests/test-mtuple.c index 1d72ef13..68029cd9 100644 --- a/tests/test-mtuple.c +++ b/tests/test-mtuple.c @@ -20,13 +20,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" #include "m-string.h" - #include "m-tuple.h" - #include "coverage.h" + START_COVERAGE TUPLE_DEF2(pair, (key, string_t, (INIT(string_init), INIT_SET(string_init_set), SET(string_set), CLEAR(string_clear))), diff --git a/tests/test-mvariant.c b/tests/test-mvariant.c index b9120515..96f2ac8d 100644 --- a/tests/test-mvariant.c +++ b/tests/test-mvariant.c @@ -20,13 +20,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "test-obj.h" #include "m-string.h" - #include "m-variant.h" - #include "coverage.h" + START_COVERAGE VARIANT_DEF2(pair, (key, int, M_BASIC_OPLIST), diff --git a/tests/test-mworker.c b/tests/test-mworker.c index 74aa12db..f0743d45 100644 --- a/tests/test-mworker.c +++ b/tests/test-mworker.c @@ -20,9 +20,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "m-core.h" +#include "test-obj.h" #include "coverage.h" - #include "m-worker.h" /* Compute Fibonacci number using thread systems. */ diff --git a/tests/test-obj.h b/tests/test-obj.h index eac9e982..933499c0 100644 --- a/tests/test-obj.h +++ b/tests/test-obj.h @@ -25,6 +25,52 @@ #include #include +#include +#include + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// First overwrite memory handling function so that we can check if everything is ok +#ifdef M_MEMORY_REALLOC +# error ERROR: Do not include M*LIB headers before this header. +#endif + +static size_t amount_allocated = 0; + +static inline void *overloaded_realloc(size_t st, void *ptr, size_t o, size_t n) +{ + size_t *p = (size_t *) ptr; + if (p != NULL) { + p -= 2; + assert(p[0] == st); + assert(p[1] == o); + amount_allocated -= st * o; + } + p = (size_t *) realloc(p, 2*sizeof(size_t) + st * n); + assert(p != NULL); + p[0] = st; + p[1] = n; + amount_allocated += st * n; + return (void*) (&p[2]); +} + +static inline void overloaded_free(size_t st, void *ptr, size_t n) +{ + size_t *p = (size_t *) ptr; + if (p == NULL) { + return; + } + p -= 2; + assert(p[0] == st); + assert(p[1] == n); + amount_allocated -= st * n; + free(p); +} + +#define M_MEMORY_REALLOC(type, ptr, o, n) (type *) overloaded_realloc(sizeof(type), ptr, o, n) +#define M_MEMORY_FREE(type, ptr, o) overloaded_free(sizeof(type), ptr, o) + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "m-string.h" @@ -45,6 +91,8 @@ static inline void testobj_final_check(void) { // All created testobj shall have been cleared at the end. assert(testobj_init_counter == 0); + // All memory allocations shall be cleared + assert(amount_allocated == 0); } static inline void testobj_init(testobj_t z) From 3f8c30e592300981723809aa022fdb0860deeeac Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 26 Feb 2025 21:24:31 +0100 Subject: [PATCH 11/91] Port ARRAY & STRING to new memory model with memory context support --- m-array.h | 155 +++++++++++++++------------------- m-core.h | 77 ++++++++++++++++- m-string.h | 240 ++++++++++++++++++++++++++++------------------------- 3 files changed, 270 insertions(+), 202 deletions(-) diff --git a/m-array.h b/m-array.h index d6d2a5e3..c8c5b28c 100644 --- a/m-array.h +++ b/m-array.h @@ -137,6 +137,7 @@ /********************************** INTERNAL *********************************/ /* Define the internal contract of an array */ +//TODO: Can be simplified in release build to speed up compilation speed. #define M_ARRA4_CONTRACT(a) do { \ M_ASSERT (a != NULL); \ M_ASSERT (a->size <= a->alloc); \ @@ -171,9 +172,10 @@ #define M_ARRA4_DEF_P3(name, type, oplist, array_t, it_t) \ M_ARRA4_DEF_TYPE(name, type, oplist, array_t, it_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + /* TODO: Check if type has not disabled INIT_MOVE */ \ M_ARRA4_DEF_CORE(name, type, oplist, array_t, it_t) \ M_ARRA4_DEF_IO(name, type, oplist, array_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, array_t, M_F(name, _emplace_back), oplist, M_ARRA4_EMPLACE_DEF) + M_EMPLACE_QUEUE_DEF(name, array_t, _emplace_back, oplist, M_ARRA4_EMPLACE_DEF) /* Define the types */ #define M_ARRA4_DEF_TYPE(name, type, oplist, array_t, it_t) \ @@ -212,21 +214,20 @@ M_ARRA4_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(array_t v) \ + M_P(void, name, _reset, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ + M_ASSERT_POOL(); \ for(size_t i = 0; i < v->size; i++) \ M_CALL_CLEAR(oplist, v->ptr[i]); \ v->size = 0; \ M_ARRA4_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(array_t v) \ + M_P(void, name, _clear, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ - M_F(name, _reset)(v); \ + M_F(name, _reset) M_R(v); \ M_CALL_FREE(oplist, type, v->ptr, v->alloc); \ /* This is so reusing the object implies an assertion failure */ \ v->alloc = 1; \ @@ -234,8 +235,7 @@ } \ \ M_IF_METHOD2(INIT_SET, SET, oplist)( \ - M_INLINE void \ - M_F(name, _set)(array_t d, const array_t s) \ + M_P(void, name, _set, array_t d, const array_t s) \ { \ M_ARRA4_CONTRACT(d); \ M_ARRA4_CONTRACT(s); \ @@ -264,13 +264,12 @@ M_ARRA4_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _init_set)(array_t d, const array_t s) \ + M_P(void, name, _init_set, array_t d, const array_t s) \ { \ M_ASSERT (d != s); \ - M_ON_EXCEPTION(M_F(name, _clear)(d) ) { \ + M_ON_EXCEPTION(M_F(name, _clear) M_R(d) ) { \ M_F(name, _init)(d); \ - M_F(name, _set)(d, s); \ + M_F(name, _set) M_R(d, s); \ } \ } \ , /* No SET & INIT_SET */) \ @@ -289,19 +288,18 @@ M_ARRA4_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _move)(array_t d, array_t s) \ + M_P(void, name, _move, array_t d, array_t s) \ { \ M_ASSERT (d != s); \ - M_F(name, _clear)(d); \ + M_F(name, _clear) M_R(d); \ M_F(name, _init_move)(d, s); \ } \ \ M_IF_METHOD(SET, oplist)( \ - M_INLINE void \ - M_F(name, _set_at)(array_t v, size_t i, type const x) \ + M_P(void, name, _set_at, array_t v, size_t i, type const x) \ { \ M_ARRA4_CONTRACT(v); \ + M_ASSERT_POOL(); \ M_ASSERT(v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ M_CALL_SET(oplist, v->ptr[i], x); \ @@ -317,15 +315,14 @@ return &v->ptr[v->size-1]; \ } \ \ - M_INLINE type * \ - M_F(name, _push_raw)(array_t v) \ + M_P(type *, name, _push_raw, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ if (M_UNLIKELY (v->size >= v->alloc)) { \ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, alloc); \ + M_MEMORY_FULL(type, -1U); \ return NULL; \ } \ M_ASSERT (alloc > v->size); \ @@ -346,10 +343,9 @@ } \ \ M_IF_METHOD(INIT_SET, oplist)( \ - M_INLINE void \ - M_F(name, _push_back)(array_t v, type const x) \ + M_P(void, name, _push_back, array_t v, type const x) \ { \ - type *data = M_F(name, _push_raw)(v); \ + type *data = M_F(name, _push_raw) M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ M_IF_EXCEPTION( v->size --); \ @@ -359,10 +355,9 @@ , /* No INIT_SET */ ) \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _push_new)(array_t v) \ + M_P(type *, name, _push_new, array_t v) \ { \ - type *data = M_F(name, _push_raw)(v); \ + type *data = M_F(name, _push_raw) M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return NULL; \ M_IF_EXCEPTION( v->size --); \ @@ -373,11 +368,10 @@ , /* No INIT */ ) \ \ M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _push_move)(array_t v, type *x) \ + M_P(void, name, _push_move, array_t v, type *x) \ { \ M_ASSERT (x != NULL); \ - type *data = M_F(name, _push_raw)(v); \ + type *data = M_F(name, _push_raw) M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ M_DO_INIT_MOVE (oplist, *data, *x); \ @@ -385,8 +379,7 @@ , /* INIT_SET | INIT_MOVE */ ) \ \ M_IF_METHOD(INIT_SET, oplist)( \ - M_INLINE void \ - M_F(name, _push_at)(array_t v, size_t key, type const x) \ + M_P(void, name, _push_at, array_t v, size_t key, type const x) \ { \ M_ARRA4_CONTRACT(v); \ M_ASSERT_INDEX(key, v->size+1); \ @@ -394,7 +387,7 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, alloc); \ + M_MEMORY_FULL(type, -1U); \ return ; \ } \ M_ASSERT (alloc > v->size); \ @@ -417,8 +410,7 @@ , /* No INIT_SET */ ) \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _resize)(array_t v, size_t size) \ + M_P(void, name, _resize, array_t v, size_t size) \ { \ M_ARRA4_CONTRACT(v); \ if (v->size > size) { \ @@ -448,8 +440,7 @@ } \ , /* No INIT */ ) \ \ - M_INLINE void \ - M_F(name, _reserve)(array_t v, size_t alloc) \ + M_P(void, name, _reserve, array_t v, size_t alloc) \ { \ M_ARRA4_CONTRACT(v); \ /* NOTE: Reserve below needed size to perform a shrink to fit */ \ @@ -473,8 +464,7 @@ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _safe_get)(array_t v, size_t idx) \ + M_P(type *, name, _safe_get, array_t v, size_t idx) \ { \ M_ARRA4_CONTRACT(v); \ const size_t size = idx + 1; \ @@ -485,7 +475,7 @@ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ /* In case of overflow of size_t */ \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, alloc); \ + M_MEMORY_FULL(type, -1U); \ return NULL; \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ @@ -509,10 +499,10 @@ , /* No INIT */) \ \ M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _pop_back)(type *dest, array_t v) \ + M_P(void, name, _pop_back, type *dest, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ + M_ASSERT_POOL(); \ M_ASSERT (v->ptr != NULL); \ M_ASSERT_INDEX(0, v->size); \ v->size--; \ @@ -526,6 +516,8 @@ , /* SET | INIT_MOVE */ ) \ \ M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ + /* FIXME: type has to be trivially movable (imposed by array) ! */ \ + /* FIXME: Really allocation or allocation free? */ \ M_INLINE void \ M_F(name, _pop_move)(type *dest, array_t v) \ { \ @@ -534,19 +526,20 @@ M_ASSERT_INDEX(0, v->size); \ M_ASSERT (dest != NULL); \ v->size--; \ + /* FIXME: M_DO_INIT_MOVE may use INIT_SET so allocator !*/ \ M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \ M_ARRA4_CONTRACT(v); \ } \ , /* INIT_SET | INIT_MOVE */ ) \ \ + /* TODO: Factorize all INIT dependent methods within the same IF*/ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _pop_until)(array_t v, it_t pos) \ + M_P(void, name, _pop_until, array_t v, it_t pos) \ { \ M_ARRA4_CONTRACT(v); \ M_ASSERT (v == pos->array); \ M_ASSERT_INDEX(pos->index, v->size+1); \ - M_F(name, _resize)(v, pos->index); \ + M_F(name, _resize) M_R(v, pos->index); \ } \ , /* No INIT */ ) \ \ @@ -572,12 +565,13 @@ } \ \ M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _pop_at)(type *dest, array_t v, size_t i) \ + M_P(void, name, _pop_at, type *dest, array_t v, size_t i) \ { \ M_ARRA4_CONTRACT(v); \ + M_ASSERT_POOL(); \ M_ASSERT (v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ + /* FIXME: type is trivially movable */ \ if (dest) \ M_DO_MOVE (oplist, *dest, v->ptr[i]); \ else \ @@ -587,19 +581,17 @@ M_ARRA4_CONTRACT(v); \ } \ \ - M_INLINE bool \ - M_F(name, _erase)(array_t a, size_t i) \ + M_P(bool, name, _erase, array_t a, size_t i) \ { \ M_ARRA4_CONTRACT(a); \ if (i >= a->size) return false; \ - M_F(name, _pop_at)(NULL, a, i); \ + M_F(name, _pop_at) M_R(NULL, a, i); \ return true; \ } \ , /* SET | INIT_MOVE */ ) \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _insert_v)(array_t v, size_t i, size_t num) \ + M_P(void, name, _insert_v, array_t v, size_t i, size_t num) \ { \ M_ARRA4_CONTRACT(v); \ M_ASSERT_INDEX(i, v->size+1); \ @@ -615,7 +607,7 @@ if (size > v->alloc) { \ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, alloc); \ + M_MEMORY_FULL(type, -1U); \ return ; \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ @@ -637,10 +629,10 @@ } \ , /* No INIT */) \ \ - M_INLINE void \ - M_F(name, _remove_v)(array_t v, size_t i, size_t j) \ + M_P(void, name, _remove_v, array_t v, size_t i, size_t j) \ { \ M_ARRA4_CONTRACT(v); \ + M_ASSERT_POOL(); \ M_ASSERT(i < j && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ M_ASSERT_INDEX(j, v->size+1); \ @@ -797,22 +789,20 @@ } \ \ M_IF_METHOD(INIT_SET, oplist)( \ - M_INLINE void \ - M_F(name, _insert)(array_t a, it_t it, type const x) \ + M_P(void, name, _insert, array_t a, it_t it, type const x) \ { \ M_ASSERT (it != NULL && a == it->array); \ size_t index = M_F(name, _end_p)(it) ? 0 : it->index+1; \ - M_F(name, _push_at)(a, index, x); \ + M_F(name, _push_at)M_R(a, index, x); \ it->index = index; \ } \ , /* End of INIT_SET */ ) \ \ M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _remove)(array_t a, it_t it) \ + M_P(void, name, _remove, array_t a, it_t it) \ { \ M_ASSERT (it != NULL && a == it->array); \ - M_F(name, _pop_at)(NULL, a, it->index); \ + M_F(name, _pop_at) M_R(NULL, a, it->index); \ /* NOTE: it->index will naturally point to the next element */ \ } \ , /* End of SET | INIT_SET */ ) \ @@ -902,8 +892,7 @@ M_ASSERT (org_tab == tab); \ } \ \ - M_INLINE void \ - M_F(name, _special_stable_sort)(array_t l) \ + M_P(void, name, _special_stable_sort, array_t l) \ { \ if (M_UNLIKELY (l->size < 2)) \ return; \ @@ -953,8 +942,7 @@ } \ , /* no HASH */ ) \ \ - M_INLINE void \ - M_F(name, _splice)(array_t a1, array_t a2) \ + M_P(void, name, _splice, array_t a1, array_t a2) \ { \ M_ARRA4_CONTRACT(a1); \ M_ARRA4_CONTRACT(a2); \ @@ -987,12 +975,10 @@ #define M_ARRA4_DEF_IO(name, type, oplist, array_t, it_t) \ \ M_IF_METHOD(GET_STR, oplist)( \ - M_INLINE void \ - M_F(name, _get_str)(m_string_t str, array_t const array, \ - bool append) \ + M_P(void, name, _get_str, m_string_t str, array_t const array, bool append) \ { \ M_ARRA4_CONTRACT(array); \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \ it_t it; \ for (M_F(name, _it)(it, array) ; \ !M_F(name, _end_p)(it); \ @@ -1000,9 +986,9 @@ type const *item = M_F(name, _cref)(it); \ M_CALL_GET_STR(oplist, str, *item, true); \ if (!M_F(name, _last_p)(it)) \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ } \ - m_string_push_back (str, ']'); \ + m_string_push_back M_R(str, ']'); \ } \ , /* no GET_STR */ ) \ \ @@ -1024,12 +1010,11 @@ , /* no OUT_STR */ ) \ \ M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(array_t array, const char str[], const char**endp) \ + M_P(bool, name, _parse_str, array_t array, const char str[], const char**endp) \ { \ M_ARRA4_CONTRACT(array); \ M_ASSERT (str != NULL); \ - M_F(name,_reset)(array); \ + M_F(name,_reset)M_R(array); \ int c = *str++; \ if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \ c = m_core_str_nospace(&str); \ @@ -1041,7 +1026,7 @@ bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ c = m_core_str_nospace(&str); \ if (b == false || c == 0) { c = 0; break; } \ - M_F(name, _push_back)(array, item); \ + M_F(name, _push_back) M_R(array, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ exit: \ @@ -1052,12 +1037,11 @@ , /* no PARSE_STR & INIT */ ) \ \ M_IF_METHOD2(IN_STR, INIT, oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(array_t array, FILE *file) \ + M_P(bool, name, _in_str, array_t array, FILE *file) \ { \ M_ARRA4_CONTRACT(array); \ M_ASSERT (file != NULL); \ - M_F(name,_reset)(array); \ + M_F(name,_reset)M_R(array); \ int c = fgetc(file); \ if (M_UNLIKELY (c != '[')) return false; \ c = fgetc(file); \ @@ -1069,7 +1053,7 @@ bool b = M_CALL_IN_STR(oplist, item, file); \ c = m_core_fgetc_nospace(file); \ if (b == false || c == EOF) { c = 0; break; } \ - M_F(name, _push_back)(array, item); \ + M_F(name, _push_back) M_R(array, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ M_ARRA4_CONTRACT(array); \ @@ -1099,25 +1083,24 @@ , /* no OUT_SERIAL */ ) \ \ M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(array_t array, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, array_t array, m_serial_read_t f) \ { \ M_ARRA4_CONTRACT(array); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_return_code_t ret; \ m_serial_local_t local; \ size_t estimated_size = 0; \ - M_F(name,_reset)(array); \ + M_F(name,_reset)M_R(array); \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { \ return ret; \ } \ - M_F(name, _reserve)(array, estimated_size); \ + M_F(name, _reserve) M_R(array, estimated_size); \ M_QLET(1, item, type, oplist) { \ do { \ ret = M_CALL_IN_SERIAL(oplist, item, f); \ if (ret != M_SERIAL_OK_DONE) { break; } \ - M_F(name, _push_back)(array, item); \ + M_F(name, _push_back)M_R(array, item); \ ret = f->m_interface->read_array_next(local, f); \ } while (ret == M_SERIAL_OK_CONTINUE); \ } \ @@ -1128,11 +1111,9 @@ /* Definition of the emplace_back function for arrays */ #define M_ARRA4_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_F(name, _subtype_ct) *data = M_F(name, _push_raw)(v); \ + M_F(name, _subtype_ct) *data = M_F(name, _push_raw) M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ M_IF_EXCEPTION( v->size --); \ diff --git a/m-core.h b/m-core.h index 1ef264d5..547b5e4f 100644 --- a/m-core.h +++ b/m-core.h @@ -379,11 +379,13 @@ M_BEGIN_PROTECTED_CODE #endif /* Define allocators for array - * void *M_MEMORY_REALLOC(type, ptr, o, n): Return a pointer to a new array of 'n' object of type 'type' + * void *M_MEMORY_REALLOC(type, ptr, o, n, perm): Return a pointer to a new array of 'n' object of type 'type'. * If ptr is NULL, it creates a new array of type 'type' and size 'n' * If ptr is not null, it reallocates the given array of type 'type' and size 'o' to the new size. * It returns NULL in case of memory allocation failure. * void M_MEMORY_FREE(type, ptr, o): Free the object associated to the array of type 'type' at base 'ptr' of size 'o'. + * By default, old size do nothing. + * Can use local optional named parameter "m_pool" which is defined by the called of the macro if M_USE_POOL is defined. */ #ifndef M_MEMORY_REALLOC #ifdef __cplusplus @@ -409,6 +411,40 @@ M_BEGIN_PROTECTED_CODE #endif +#ifndef M_USE_POOL +// Memory pool parameter not used for memory function. Stub it with 0 as it won't be used (global definition). +# define M_P_EXPAND +# define M_R_EXPAND +# define M_R +# define M_ASSERT_POOL() +#else +// Memory pool parameter is used for function using memory. (local definition to the function). +// Expand to a prototype to a function that may not trigger exception +# define M_P_EXPAND M_USE_POOL m_pool, +# define M_R_EXPAND m_pool , +# define M_R(...) (m_pool, __VA_ARGS__) +# define M_ASSERT_POOL() (void) m_pool +#endif + +// Expand to a prototype of a function that may trigger exception / accept memory context +// TODO: If not M_F, M_INLINE overloaded and no M_P_EXPAND, simplify M_P +// (faster build: 0.54s instead of 0.80s in extreme expanding +# define M_P(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(M_P_EXPAND __VA_ARGS__) +//#define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) + +// Expand to a prototype of a function that may not trigger exception or accept memory context +# define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__) + + +// TODO: Add for API special, the support of the POOL special keyword ==> m_pool +// Or document m_pool directly? Can still be overriden later. + +// TODO: Add for all Assertions: M_ASSERT_POOL() +// to avoid warnings about unused parameter m_pool. +// Pb: Also included for functions without the pool parameter! + +// FIXME: Not sense to do it for a shared pointer: it is shared across all memory contexts! + /************************************************************/ /********************* ERROR handling **********************/ /************************************************************/ @@ -440,6 +476,7 @@ M_BEGIN_PROTECTED_CODE * NOTE: Can be overriden by user if it needs to keep finer access * on the assertions. */ +//TODO: If NDEBUG, simply do nothing "no expression", to speed up compilation speed. #ifndef M_ASSERT #define M_ASSERT(expr) assert(expr) #endif @@ -450,6 +487,7 @@ M_BEGIN_PROTECTED_CODE * NOTE: Can be overriden by user if it needs to keep finer access * on the assertions. */ +//TODO: If NDEBUG, simply do nothing "no expression", to speed up compilation speed. #ifndef M_ASSERT_SLOW # if defined(M_USE_ADDITIONAL_CHECKS) && M_USE_ADDITIONAL_CHECKS # define M_ASSERT_SLOW(n) assert(n) @@ -2772,7 +2810,7 @@ M_INLINE char m_core_str_nospace(const char **str) /* Transform a C variable into a m_string_t (needs m-string.h) */ #define M_GET_STRING_ARG(str, x, append) \ - (append ? m_string_cat_printf : m_string_printf) (str, M_PRINTF_FORMAT(x), M_CORE_PRINTF_ARG(x)) + (append ? m_string_cat_printf : m_string_printf) M_R(str, M_PRINTF_FORMAT(x), M_CORE_PRINTF_ARG(x)) /* No use of GET_STR if no inclusion of m-string */ #define M_GET_STR_METHOD_FOR_DEFAULT_TYPE /* */ @@ -3662,6 +3700,14 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_OPLAPI_5(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, __VA_ARGS__) #define M_OPLAPI_6(method, oplist, x, ...) , M_DELAY3(method)(&x, &__VA_ARGS__) #define M_OPLAPI_7(method, oplist, x, ...) , M_DELAY3(method)(oplist, &x, &__VA_ARGS__) +#define M_OPLAPI_0P(method, oplist, ...) , M_DELAY3(method)(m_pool, __VA_ARGS__) +#define M_OPLAPI_1P(method, oplist, ...) , M_DELAY3(method)(oplist, m_pool, __VA_ARGS__) +#define M_OPLAPI_2P(method, oplist, ...) , M_DELAY3(method)(m_pool, & __VA_ARGS__) +#define M_OPLAPI_3P(method, oplist, ...) , M_DELAY3(method)(oplist, m_pool, &__VA_ARGS__) +#define M_OPLAPI_4P(method, oplist, x, ...) , x = M_DELAY3(method)(m_pool, __VA_ARGS__) +#define M_OPLAPI_5P(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, m_pool, __VA_ARGS__) +#define M_OPLAPI_6P(method, oplist, x, ...) , M_DELAY3(method)(m_pool, &x, &__VA_ARGS__) +#define M_OPLAPI_7P(method, oplist, x, ...) , M_DELAY3(method)(oplist, m_pool, &x, &__VA_ARGS__) /* API transformation support for indirection */ #define M_OPLAPI_INDIRECT_0 M_OPLAPI_ERROR #define M_OPLAPI_INDIRECT_API_0(...) M_OPLAPI_0 @@ -3680,6 +3726,22 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_OPLAPI_EXTRACT_API_6(...) __VA_ARGS__ #define M_OPLAPI_INDIRECT_API_7(...) M_OPLAPI_7 #define M_OPLAPI_EXTRACT_API_7(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_0P(...) M_OPLAPI_0P +#define M_OPLAPI_EXTRACT_API_0P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_1P(...) M_OPLAPI_1P +#define M_OPLAPI_EXTRACT_API_1P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_2P(...) M_OPLAPI_2P +#define M_OPLAPI_EXTRACT_API_2P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_3P(...) M_OPLAPI_3P +#define M_OPLAPI_EXTRACT_API_3P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_4P(...) M_OPLAPI_4P +#define M_OPLAPI_EXTRACT_API_4P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_5P(...) M_OPLAPI_5P +#define M_OPLAPI_EXTRACT_API_5P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_6P(...) M_OPLAPI_6P +#define M_OPLAPI_EXTRACT_API_6P(...) __VA_ARGS__ +#define M_OPLAPI_INDIRECT_API_7P(...) M_OPLAPI_7P +#define M_OPLAPI_EXTRACT_API_7P(...) __VA_ARGS__ /* Generic API transformation. @@ -3777,6 +3839,11 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) "The " #operator " operator has no method associated in the given OPLIST."),\ (return_type) 0) +// TODO: Use default INIT_MOVE which assume trivially movable type +// by getting throught API_2 the oplist and the size of the type +// If no type defined and no INIT_MOVE defined, just use sizeof (dst) +// Most types are trivially movable. Can remove macro M_DO_INIT_MOVE to use M_CALL_INIT_MOVE +// If disabled in oplist, M_CALL_INIT_MOVE will generate an error. #define M_NO_DEF_INIT_MOVE(...) M_NO_DEFAULT(INIT_MOVE, void) #define M_NO_DEF_INIT_WITH(...) M_NO_DEFAULT(INIT_WITH, void) #define M_NO_DEF_MOVE(...) M_NO_DEFAULT(MOVE, void) @@ -4150,7 +4217,7 @@ m_core_parse2_enum (const char str[], const char **endptr) #define M_ENUM_IN_SERIAL(oplist, var, serial) \ ( var = (M_GET_TYPE oplist)(true ? m_core_in_serial_enum(serial) : 0), (serial)->tmp.r) #define M_ENUM_GET_STR(str, var, append) \ - ((append ? m_string_cat_printf : m_string_printf) (str, "%lld", (long long) (var) )) + ((append ? m_string_cat_printf : m_string_printf) M_R(str, "%lld", (long long) (var) )) #define M_ENUM_PARSE(oplist, var, str, endptr) \ ( var = (M_GET_TYPE oplist) (true ? m_core_parse1_enum(str) : 0), m_core_parse2_enum(str, endptr)) @@ -4269,6 +4336,8 @@ m_core_parse2_enum (const char str[], const char **endptr) #define M_IPTR(...) ( & __VA_ARGS__ ) /* Perform an INIT_MOVE if present, or emulate it using INIT_SET/CLEAR */ +/* FIXME: Use INIT_MOVE if present or assume trivially movable otherwise? */ +/* A non trivially movable type shall provide an INIT_MOVE method or disable it */ #define M_DO_INIT_MOVE(oplist, dest, src) do { \ M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_INIT_MOVE(oplist, (dest), (src)), \ M_CALL_INIT_SET(oplist, (dest), (src)) ; \ @@ -4527,7 +4596,7 @@ m_core_parse2_enum (const char str[], const char **endptr) for( init; cont ; cont = false) \ M_DEFER_TRY_INJECT_POST(cont, clear) \ for( (void) 0; cont; cont = false) - + /* If exceptions are activated, M_CHAIN_OBJ enables support for chaining initialization at the begining of a constructor for the fields of the constructed diff --git a/m-string.h b/m-string.h index b5db698a..82562c9e 100644 --- a/m-string.h +++ b/m-string.h @@ -281,8 +281,7 @@ m_string_init(m_string_t s) } /* Clear the Dynamic string (destructor) */ -M_INLINE void -m_string_clear(m_string_t v) +M_P(void, m_string, _clear, m_string_t v) { M_STR1NG_CONTRACT(v); if (!m_str1ng_embedded_p(v)) { @@ -301,8 +300,7 @@ M_INLINE m_string_ptr m_str1ng_init_ref(m_string_t v) { m_string_init(v); return and return a heap pointer to the string. The ownership of the data is transferred back to the caller and the returned pointer has to be released by M_MEMORY_FREE. */ -M_INLINE char * -m_string_clear_get_cstr(m_string_t v) +M_P(char *, m_string, _clear_get_cstr, m_string_t v) { M_STR1NG_CONTRACT(v); char *p = v->u.heap.ptr; @@ -368,8 +366,7 @@ m_string_empty_p(const m_string_t v) The string 'v' no longer has a working size field. Return a pointer to the writable string. */ -M_INLINE char * -m_str1ng_fit2size (m_string_t v, size_t size_alloc) +M_P(char *, m_str1ng, _fit2size, m_string_t v, size_t size_alloc) { M_ASSERT_INDEX (0, size_alloc); // Note: this function may be called in context where the contract @@ -422,8 +419,7 @@ m_str1ng_fit2size (m_string_t v, size_t size_alloc) /* Modify the string capacity to be able to handle at least 'alloc' characters (including final nul char). It may reduce the allocation of the string if possible */ -M_INLINE void -m_string_reserve(m_string_t v, size_t alloc) +M_P(void, m_string, _reserve, m_string_t v, size_t alloc) { M_STR1NG_CONTRACT (v); const size_t size = m_string_size(v); @@ -474,13 +470,12 @@ m_string_reserve(m_string_t v, size_t alloc) } /* Set the string to the C string str */ -M_INLINE void -m_string_set_cstr(m_string_t v, const char str[]) +M_P(void, m_string, _set_cstr, m_string_t v, const char str[]) { M_STR1NG_CONTRACT (v); M_ASSERT(str != NULL); size_t size = strlen(str); - char *ptr = m_str1ng_fit2size(v, size+1); + char *ptr = m_str1ng_fit2size M_R(v, size+1); // The memcpy will also copy the final null char of the string memcpy(ptr, str, size+1); m_str1ng_set_size(v, size); @@ -488,14 +483,13 @@ m_string_set_cstr(m_string_t v, const char str[]) } /* Set the string to the n first characters of the C string str */ -M_INLINE void -m_string_set_cstrn(m_string_t v, const char str[], size_t n) +M_P(void, m_string, _set_cstrn, m_string_t v, const char str[], size_t n) { M_STR1NG_CONTRACT (v); M_ASSERT(str != NULL); size_t len = strlen(str); size_t size = M_MIN (len, n); - char *ptr = m_str1ng_fit2size(v, size+1); + char *ptr = m_str1ng_fit2size M_R(v, size+1); // The memcpy will not copy the final null char of the string memcpy(ptr, str, size); // Cannot copy the final null char using memcpy @@ -505,14 +499,13 @@ m_string_set_cstrn(m_string_t v, const char str[], size_t n) } /* Set the string to the other one */ -M_INLINE void -m_string_set (m_string_t v1, const m_string_t v2) +M_P(void, m_string, _set, m_string_t v1, const m_string_t v2) { M_STR1NG_CONTRACT (v1); M_STR1NG_CONTRACT (v2); if (M_LIKELY (v1 != v2)) { const size_t size = m_string_size(v2); - char *ptr = m_str1ng_fit2size(v1, size+1); + char *ptr = m_str1ng_fit2size M_R(v1, size+1); memcpy(ptr, m_string_get_cstr(v2), size+1); m_str1ng_set_size(v1, size); } @@ -520,14 +513,13 @@ m_string_set (m_string_t v1, const m_string_t v2) } /* Set the string to the n first characters of other one */ -M_INLINE void -m_string_set_n(m_string_t v, const m_string_t ref, size_t offset, size_t length) +M_P(void, m_string, _set_n, m_string_t v, const m_string_t ref, size_t offset, size_t length) { M_STR1NG_CONTRACT (v); M_STR1NG_CONTRACT (ref); M_ASSERT_INDEX (offset, m_string_size(ref) + 1); size_t size = M_MIN (m_string_size(ref) - offset, length); - char *ptr = m_str1ng_fit2size(v, size+1); + char *ptr = m_str1ng_fit2size M_R(v, size+1); // v may be equal to ref, so a memmove is needed instead of a memcpy memmove(ptr, m_string_get_cstr(ref) + offset, size); // Cannot copy the final null char using memcpy @@ -538,26 +530,24 @@ m_string_set_n(m_string_t v, const m_string_t ref, size_t offset, size_t length) /* Initialize the string and set it to the other one (constructor) */ -M_INLINE void -m_string_init_set(m_string_t v1, const m_string_t v2) +M_P(void, m_string, _init_set, m_string_t v1, const m_string_t v2) { // In case of exception, v1 remains initialized, // but without any allocation done. // Therefore it is safe, not to clear v1 on exception. m_string_init(v1); - m_string_set(v1,v2); + m_string_set M_R(v1,v2); } /* Initialize the string and set it to the C string (constructor) */ -M_INLINE void -m_string_init_set_cstr(m_string_t v1, const char str[]) +M_P(void, m_string, _init_set_cstr, m_string_t v1, const char str[]) { // In case of exception, v1 remains initialized, // but without any allocation done. // Therefore it is safe, not to clear v1 on exception. m_string_init(v1); - m_string_set_cstr(v1, str); + m_string_set_cstr M_R(v1, str); } /* Initialize the string, set it to the other one, @@ -591,20 +581,18 @@ m_string_swap(m_string_t v1, m_string_t v2) /* Set the string to the other one, and destroy the other one. (destructor) */ -M_INLINE void -m_string_move(m_string_t v1, m_string_t v2) +M_P(void, m_string, _move, m_string_t v1, m_string_t v2) { - m_string_clear(v1); + m_string_clear M_R(v1); m_string_init_move(v1,v2); } /* Push the byte-character 'c' in the string 'v' */ -M_INLINE void -m_string_push_back (m_string_t v, char c) +M_P(void, m_string, _push_back, m_string_t v, char c) { M_STR1NG_CONTRACT (v); const size_t size = m_string_size(v); - char *ptr = m_str1ng_fit2size(v, size+2); + char *ptr = m_str1ng_fit2size M_R(v, size+2); ptr[size+0] = c; ptr[size+1] = 0; m_str1ng_set_size(v, size+1); @@ -612,29 +600,27 @@ m_string_push_back (m_string_t v, char c) } /* Concatenate the string with the C string */ -M_INLINE void -m_string_cat_cstr(m_string_t v, const char str[]) +M_P(void, m_string, _cat_cstr, m_string_t v, const char str[]) { M_STR1NG_CONTRACT (v); M_ASSERT (str != NULL); const size_t old_size = m_string_size(v); const size_t size = strlen(str); - char *ptr = m_str1ng_fit2size(v, old_size + size + 1); + char *ptr = m_str1ng_fit2size M_R(v, old_size + size + 1); memcpy(&ptr[old_size], str, size + 1); m_str1ng_set_size(v, old_size + size); M_STR1NG_CONTRACT (v); } /* Concatenate the string with the other string */ -M_INLINE void -m_string_cat(m_string_t v, const m_string_t v2) +M_P(void, m_string, _cat, m_string_t v, const m_string_t v2) { M_STR1NG_CONTRACT (v2); M_STR1NG_CONTRACT (v); const size_t size = m_string_size(v2); if (M_LIKELY (size > 0)) { const size_t old_size = m_string_size(v); - char *ptr = m_str1ng_fit2size(v, old_size + size + 1); + char *ptr = m_str1ng_fit2size M_R(v, old_size + size + 1); memcpy(&ptr[old_size], m_string_get_cstr(v2), size); ptr[old_size + size] = 0; m_str1ng_set_size(v, old_size + size); @@ -876,8 +862,7 @@ m_string_mid (m_string_t v, size_t index, size_t size) into the C string str2 from start By default, start is zero. */ -M_INLINE size_t -m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_t start) +M_P(size_t, m_string, _replace_cstr, m_string_t v, const char str1[], const char str2[], size_t start) { M_STR1NG_CONTRACT (v); M_ASSERT (str1 != NULL && str2 != NULL); @@ -887,7 +872,7 @@ m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_ const size_t str2_l = strlen(str2); const size_t size = m_string_size(v); M_ASSERT(size + 1 + str2_l > str1_l); - char *ptr = m_str1ng_fit2size (v, size + str2_l - str1_l + 1); + char *ptr = m_str1ng_fit2size M_R(v, size + str2_l - str1_l + 1); if (str1_l != str2_l) { memmove(&ptr[i+str2_l], &ptr[i+str1_l], size - i - str1_l + 1); m_str1ng_set_size(v, size + str2_l - str1_l); @@ -902,19 +887,17 @@ m_string_replace_cstr (m_string_t v, const char str1[], const char str2[], size_ into the C string v2 from start By default, start is zero. */ -M_INLINE size_t -m_string_replace (m_string_t v, const m_string_t v1, const m_string_t v2, size_t start) +M_P(size_t, m_string, _replace, m_string_t v, const m_string_t v1, const m_string_t v2, size_t start) { M_STR1NG_CONTRACT (v); M_STR1NG_CONTRACT (v1); M_STR1NG_CONTRACT (v2); - return m_string_replace_cstr(v, m_string_get_cstr(v1), m_string_get_cstr(v2), start); + return m_string_replace_cstr M_R(v, m_string_get_cstr(v1), m_string_get_cstr(v2), start); } /* Replace in the string the sub-string at position 'pos' for 'len' bytes into the C string str2. */ -M_INLINE void -m_string_replace_at (m_string_t v, size_t pos, size_t len, const char str2[]) +M_P(void, m_string, _replace_at, m_string_t v, size_t pos, size_t len, const char str2[]) { M_STR1NG_CONTRACT (v); M_ASSERT(str2 != NULL); @@ -925,7 +908,7 @@ m_string_replace_at (m_string_t v, size_t pos, size_t len, const char str2[]) if (str1_l != str2_l) { // Move bytes from the string M_ASSERT_INDEX (str1_l, size + str2_l + 1); - ptr = m_str1ng_fit2size (v, size + str2_l - str1_l + 1); + ptr = m_str1ng_fit2size M_R(v, size + str2_l - str1_l + 1); M_ASSERT_INDEX (pos + str1_l, size + 1); M_ASSUME (pos + str1_l < size + 1); memmove(&ptr[pos+str2_l], &ptr[pos+str1_l], size - pos - str1_l + 1); @@ -1002,8 +985,7 @@ m_str1ng_strstr_r(char org[], char src[], const char pattern[], size_t pattern_s } /* Replace all occurences of str1 into str2 when strlen(str1) < strlen(str2) */ -M_INLINE void -m_str1ng_replace_all_cstr_1lo2 (m_string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len) +M_P(void, m_str1ng, _replace_all_cstr_1lo2, m_string_t v, const char str1[], size_t str1len, const char str2[], size_t str2len) { M_STR1NG_CONTRACT (v); M_ASSERT(str1len < str2len); @@ -1014,7 +996,7 @@ m_str1ng_replace_all_cstr_1lo2 (m_string_t v, const char str1[], size_t str1len, */ size_t vlen = m_string_size(v); size_t alloc = 1 + vlen / str1len * str2len; - char *org = m_str1ng_fit2size(v, alloc); + char *org = m_str1ng_fit2size M_R(v, alloc); char *src = org + vlen - 1; char *end = org + m_string_capacity(v); char *dst = end; @@ -1044,8 +1026,7 @@ m_str1ng_replace_all_cstr_1lo2 (m_string_t v, const char str1[], size_t str1len, M_STR1NG_CONTRACT (v); } -M_INLINE void -m_string_replace_all_cstr (m_string_t v, const char str1[], const char str2[]) +M_P(void, m_string, _replace_all_cstr, m_string_t v, const char str1[], const char str2[]) { size_t str1_l = strlen(str1); size_t str2_l = strlen(str2); @@ -1053,12 +1034,11 @@ m_string_replace_all_cstr (m_string_t v, const char str1[], const char str2[]) if (str1_l >= str2_l) { m_str1ng_replace_all_cstr_1ge2(v, str1, str1_l, str2, str2_l ); } else { - m_str1ng_replace_all_cstr_1lo2(v, str1, str1_l, str2, str2_l ); + m_str1ng_replace_all_cstr_1lo2 M_R(v, str1, str1_l, str2, str2_l); } } -M_INLINE void -m_string_replace_all (m_string_t v, const m_string_t str1, const m_string_t str2) +M_P(void, m_string, _replace_all, m_string_t v, const m_string_t str1, const m_string_t str2) { size_t str1_l = m_string_size(str1); size_t str2_l = m_string_size(str2); @@ -1067,7 +1047,7 @@ m_string_replace_all (m_string_t v, const m_string_t str1, const m_string_t str2 if (str1_l >= str2_l) { m_str1ng_replace_all_cstr_1ge2(v, m_string_get_cstr(str1), str1_l, m_string_get_cstr(str2), str2_l ); } else { - m_str1ng_replace_all_cstr_1lo2(v, m_string_get_cstr(str1), str1_l, m_string_get_cstr(str2), str2_l ); + m_str1ng_replace_all_cstr_1lo2 M_R(v, m_string_get_cstr(str1), str1_l, m_string_get_cstr(str2), str2_l); } } @@ -1084,12 +1064,11 @@ m_string_replace_all (m_string_t v, const m_string_t str1, const m_string_t str2 # error Unexpected UINT_MAX value (workaround: Define M_USE_FAST_STRING_CONV to 0). #endif -M_INLINE void -m_string_set_ui(m_string_t v, unsigned int n) +M_P(void, m_string, _set_ui, m_string_t v, unsigned int n) { M_STR1NG_CONTRACT (v); char buffer[M_STR1NG_INT_MAX_SIZE]; - m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE+1); + char *d = m_str1ng_fit2size M_R(v, M_STR1NG_INT_MAX_SIZE+1); unsigned i = 0, j = 0; do { // 0123456789 are mandatory in this order as characters, as per C standard. @@ -1097,7 +1076,6 @@ m_string_set_ui(m_string_t v, unsigned int n) n /= 10U; } while (n != 0); M_ASSERT_INDEX(i, M_STR1NG_INT_MAX_SIZE); - char *d = m_str1ng_get_cstr(v); while (i > 0) { d[j++] = buffer[--i]; } @@ -1106,13 +1084,12 @@ m_string_set_ui(m_string_t v, unsigned int n) M_STR1NG_CONTRACT (v); } -M_INLINE void -m_string_set_si(m_string_t v, int n) +M_P(void, m_string, _set_si, m_string_t v, int n) { M_STR1NG_CONTRACT (v); // Compute the maximum number of characters needed for the buffer. char buffer[M_STR1NG_INT_MAX_SIZE]; - m_str1ng_fit2size(v, M_STR1NG_INT_MAX_SIZE+1); + char *d = m_str1ng_fit2size M_R(v, M_STR1NG_INT_MAX_SIZE+1); unsigned i = 0, j = 0; bool neg = n < 0; unsigned n0 = neg ? 0U -(unsigned) n : (unsigned) n; @@ -1122,7 +1099,6 @@ m_string_set_si(m_string_t v, int n) n0 /= 10U; } while (n0 != 0); M_ASSERT_INDEX(i, M_STR1NG_INT_MAX_SIZE); - char *d = m_str1ng_get_cstr(v); if (neg) d[j++] = '-'; while (i > 0) { d[j++] = buffer[--i]; @@ -1136,8 +1112,7 @@ m_string_set_si(m_string_t v, int n) #if M_USE_STDARG /* Format in the string the given printf format */ -M_INLINE int -m_string_vprintf (m_string_t v, const char format[], va_list args) +M_P(int, m_string, _vprintf, m_string_t v, const char format[], va_list args) { M_STR1NG_CONTRACT (v); M_ASSERT (format != NULL); @@ -1153,7 +1128,7 @@ m_string_vprintf (m_string_t v, const char format[], va_list args) M_IF_EXCEPTION( m_str1ng_set_size(v, 0) ); M_IF_EXCEPTION( m_str1ng_get_cstr(v)[0] = 0 ); // We have to realloc our string to fit the needed size - ptr = m_str1ng_fit2size (v, (size_t) size + 1); + ptr = m_str1ng_fit2size M_R(v, (size_t) size + 1); alloc = m_string_capacity(v); // and redo the parsing. size = vsnprintf (ptr, alloc, format, args_org); @@ -1162,7 +1137,7 @@ m_string_vprintf (m_string_t v, const char format[], va_list args) if (M_LIKELY (size >= 0)) { m_str1ng_set_size(v, (size_t) size); } else { - // An error occured during the conversion: Assign an empty string. + // An error occurred during the conversion: Assign an empty string. m_str1ng_set_size(v, 0); ptr[0] = 0; } @@ -1172,21 +1147,20 @@ m_string_vprintf (m_string_t v, const char format[], va_list args) } /* Format in the string the given printf format */ -M_INLINE int -m_string_printf (m_string_t v, const char format[], ...) +// FIXME: BROKEN to add a parameter **after** the '...'! +M_P(int, m_string, _printf, m_string_t v, const char format[], ...) { M_STR1NG_CONTRACT (v); M_ASSERT (format != NULL); va_list args; va_start (args, format); - int ret = m_string_vprintf(v, format, args); + int ret = m_string_vprintf M_R(v, format, args); va_end (args); return ret; } /* Append to the string the formatted string of the given printf format */ -M_INLINE int -m_string_cat_vprintf (m_string_t v, const char format[], va_list args) +M_P(int, m_string, _cat_vprintf, m_string_t v, const char format[], va_list args) { M_STR1NG_CONTRACT (v); M_ASSERT (format != NULL); @@ -1203,7 +1177,7 @@ m_string_cat_vprintf (m_string_t v, const char format[], va_list args) M_IF_EXCEPTION( m_str1ng_set_size(v, old_size) ); M_IF_EXCEPTION( m_str1ng_get_cstr(v)[old_size] = 0 ); // We have to realloc our string to fit the needed size - ptr = m_str1ng_fit2size (v, old_size + (size_t) size + 1); + ptr = m_str1ng_fit2size M_R(v, old_size + (size_t) size + 1); alloc = m_string_capacity(v); // and redo the parsing. size = vsnprintf (&ptr[old_size], alloc - old_size, format, args_org); @@ -1222,28 +1196,26 @@ m_string_cat_vprintf (m_string_t v, const char format[], va_list args) } /* Append to the string the formatted string of the given printf format */ -M_INLINE int -m_string_cat_printf (m_string_t v, const char format[], ...) +//FIXME: +M_P(int, m_string, _cat_printf, m_string_t v, const char format[], ...) { M_STR1NG_CONTRACT (v); M_ASSERT (format != NULL); va_list args; va_start (args, format); - int ret = m_string_cat_vprintf(v, format, args); + int ret = m_string_cat_vprintf M_R(v, format, args); va_end (args); return ret; } #if M_USE_FAST_STRING_CONV == 0 -M_INLINE void -m_string_set_ui(m_string_t v, unsigned int n) +M_P(void, m_string, _set_ui, m_string_t v, unsigned int n) { - m_string_printf(v, "%u", n); + m_string_printf M_R(v, "%u", n); } -M_INLINE void -m_string_set_si(m_string_t v, int n) +M_P(void, m_string, _set_si, m_string_t v, int n) { - m_string_printf(v, "%d", n); + m_string_printf M_R(v, "%d", n); } #endif @@ -1252,12 +1224,11 @@ m_string_set_si(m_string_t v, int n) #if M_USE_STDIO /* Get a line/pure-line/file from the FILE and store it in the string */ -M_INLINE bool -m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg) +M_P(bool, m_string, _fgets, m_string_t v, FILE *f, m_string_fgets_t arg) { M_STR1NG_CONTRACT(v); M_ASSERT (f != NULL); - char *ptr = m_str1ng_fit2size (v, 100); + char *ptr = m_str1ng_fit2size M_R(v, 100); size_t size = 0; size_t alloc = m_string_capacity(v); ptr[0] = 0; @@ -1286,7 +1257,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg) /* The string buffer is not big enough: increase it and continue reading */ /* v cannot be a full embedded type */ - ptr = m_str1ng_fit2size (v, alloc + alloc/2); + ptr = m_str1ng_fit2size M_R(v, alloc + alloc/2); alloc = m_string_capacity(v); } } @@ -1299,8 +1270,7 @@ m_string_fgets(m_string_t v, FILE *f, m_string_fgets_t arg) Words are supposed to be separated each other by the given list of separator separator shall be a CONSTANT C array. */ -M_INLINE bool -m_string_fget_word (m_string_t v, const char separator[], FILE *f) +M_P(bool, m_string, _fget_word, m_string_t v, const char separator[], FILE *f) { char buffer[128]; char c = 0; @@ -1345,7 +1315,7 @@ m_string_fget_word (m_string_t v, const char separator[], FILE *f) /* Next char is not a separator: continue parsing */ m_str1ng_set_size(v, size); M_IF_EXCEPTION( m_str1ng_get_cstr(v)[size] = 0); - ptr = m_str1ng_fit2size (v, alloc + alloc/2); + ptr = m_str1ng_fit2size M_R(v, alloc + alloc/2); alloc = m_string_capacity(v); M_ASSERT (alloc > size + 1); ptr[size++] = c; @@ -1480,8 +1450,7 @@ m_string_oor_set(m_string_t s, unsigned char n) /* Transform the string 'v2' into a formatted string and set it to (or append in) the string 'v'. */ -M_INLINE void -m_string_get_str(m_string_t v, const m_string_t v2, bool append) +M_P(void, m_string, _get_str, m_string_t v, const m_string_t v2, bool append) { M_STR1NG_CONTRACT(v2); M_STR1NG_CONTRACT(v); @@ -1489,7 +1458,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append) size_t size = append ? m_string_size(v) : 0; size_t v2_size = m_string_size(v2); size_t targetSize = size + v2_size + 3; - char *ptr = m_str1ng_fit2size(v, targetSize); + char *ptr = m_str1ng_fit2size M_R(v, targetSize); ptr[size ++] = '"'; for(size_t i = 0 ; i < v2_size; i++) { const char c = m_string_get_char(v2,i); @@ -1501,7 +1470,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append) case '\r': // Special characters which can be displayed in a short form. m_str1ng_set_size(v, size); - ptr = m_str1ng_fit2size(v, ++targetSize); + ptr = m_str1ng_fit2size M_R(v, ++targetSize); ptr[size ++] = '\\'; // This string acts as a perfect hashmap which supposes an ASCII mapping // and (c^(c>>5)) is the hash function @@ -1512,7 +1481,7 @@ m_string_get_str(m_string_t v, const m_string_t v2, bool append) targetSize += 3; m_str1ng_set_size(v, size); M_IF_EXCEPTION(m_str1ng_get_cstr(v)[size] = 0); - ptr = m_str1ng_fit2size(v, targetSize); + ptr = m_str1ng_fit2size M_R(v, targetSize); int d1 = c & 0x07, d2 = (c>>3) & 0x07, d3 = (c>>6) & 0x07; ptr[size ++] = '\\'; ptr[size ++] = (char) ('0' + d3); @@ -1572,8 +1541,7 @@ m_string_out_str(FILE *f, const m_string_t v) /* Read the formatted string from the FILE and set the converted value in the string 'v'. Return true in case of success */ -M_INLINE bool -m_string_in_str(m_string_t v, FILE *f) +M_P(bool, m_string, _in_str, m_string_t v, FILE *f) { M_STR1NG_CONTRACT(v); M_ASSERT (f != NULL); @@ -1610,7 +1578,7 @@ m_string_in_str(m_string_t v, FILE *f) break; } } - m_string_push_back (v, (char) c); + m_string_push_back M_R(v, (char) c); c = fgetc(f); } return c == '"'; @@ -1623,8 +1591,7 @@ m_string_in_str(m_string_t v, FILE *f) Return true in case of success If endptr is not null, update the position of the parsing. */ -M_INLINE bool -m_string_parse_str(m_string_t v, const char str[], const char **endptr) +M_P(bool, m_string, _parse_str, m_string_t v, const char str[], const char **endptr) { M_STR1NG_CONTRACT(v); M_ASSERT (str != NULL); @@ -1662,7 +1629,7 @@ m_string_parse_str(m_string_t v, const char str[], const char **endptr) break; } } - m_string_push_back (v, (char) c); + m_string_push_back M_R(v, (char) c); c = *str++; } success = (c == '"'); @@ -1678,6 +1645,7 @@ m_string_parse_str(m_string_t v, const char str[], const char **endptr) M_INLINE m_serial_return_code_t m_string_out_serial(m_serial_write_t serial, const m_string_t v) { + //FIXME: What to do for memory context? Can be passed through serial M_ASSERT (serial != NULL && serial->m_interface != NULL); return serial->m_interface->write_string(serial, m_string_get_cstr(v), m_string_size(v) ); } @@ -1955,8 +1923,7 @@ m_string_cref (m_string_it_t it) } /* Update the value referenced by the iterator to the given value */ -M_INLINE void -m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u) +M_P(void, m_string, _it_set_ref, m_string_it_t it, m_string_t s, m_string_unicode_t new_u) { M_STR1NG_IT_CONTRACT(it); M_STR1NG_CONTRACT(s); @@ -1965,7 +1932,7 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u) M_ASSUME( it->ptr >= ptr); size_t offset = (size_t) (it->ptr - ptr); // Special case if the unicode codepoint is 0 - if (new_u == 0) { + if (M_UNLIKELY(new_u == 0)) { // Null the string m_str1ng_set_size(s, offset); ptr[offset] = 0; @@ -1989,8 +1956,8 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u) size_t old_u_size = (size_t) (str - it->ptr); // We need to replace old_u by new_u. Both are variable length size_t str_size = m_string_size(s); - if (new_u_size != old_u_size) { - ptr = m_str1ng_fit2size(s, str_size + new_u_size - old_u_size + 1); + if (M_UNLIKELY (new_u_size != old_u_size)) { + ptr = m_str1ng_fit2size M_R(s, str_size + new_u_size - old_u_size + 1); M_ASSUME( str_size+1 > (offset + old_u_size) ); memmove(&ptr[offset+new_u_size], &ptr[offset + old_u_size], str_size+1 - offset - old_u_size); @@ -2004,13 +1971,12 @@ m_string_it_set_ref(m_string_it_t it, m_string_t s, m_string_unicode_t new_u) } /* Push unicode code point into string, encoding it in UTF8 */ -M_INLINE void -m_string_push_u (m_string_t str, m_string_unicode_t u) +M_P(void, m_string, _push_u, m_string_t str, m_string_unicode_t u) { M_STR1NG_CONTRACT(str); char buffer[4+1]; m_str1ng_utf8_encode(buffer, u); - m_string_cat_cstr(str, buffer); + m_string_cat_cstr M_R(str, buffer); } /* Pop last unicode code point into string, encoding it in UTF8 */ @@ -2153,13 +2119,22 @@ namespace m_lib { m_lib::m_aligned_string(s).string #endif +#ifdef M_USE_POOL /* Initialize and set a string to the given formatted value. */ +#define m_string_init_printf(pool, v, ...) \ + (m_string_printf ( pool, m_str1ng_init_ref(v), __VA_ARGS__) ) + +/* Initialize and set a string to the given formatted value. */ +#define m_string_init_vprintf(pool, v, format, args) \ + (m_string_vprintf ( pool, m_str1ng_init_ref(v), format, args) ) +#else #define m_string_init_printf(v, ...) \ (m_string_printf ( m_str1ng_init_ref(v), __VA_ARGS__) ) /* Initialize and set a string to the given formatted value. */ #define m_string_init_vprintf(v, format, args) \ (m_string_vprintf ( m_str1ng_init_ref(v), format, args) ) +#endif /* Initialize a string with the given list of arguments. Check if it is a formatted input or not by counting the number of arguments. @@ -2169,10 +2144,10 @@ namespace m_lib { C string and string. */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) #define M_STR1NG_INIT_WITH(v, ...) \ - M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set, m_string_init_printf)(v, __VA_ARGS__) + M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set, m_string_init_printf)M_R(v, __VA_ARGS__) #else #define M_STR1NG_INIT_WITH(v, ...) \ - M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set_cstr, m_string_init_printf)(v, __VA_ARGS__) + M_IF_NARGS_EQ1(__VA_ARGS__)(m_string_init_set_cstr, m_string_init_printf)M_R(v, __VA_ARGS__) #endif /* Define the OPLIST of a STRING */ @@ -2201,6 +2176,31 @@ namespace m_lib { ,EMPLACE_TYPE(const char*) \ ) +#define M_STRING_POOL_OPLIST \ + (INIT(m_string_init),INIT_SET(API_0P(m_string_init_set)), SET(API_0P(m_string_set)), \ + INIT_WITH(M_STR1NG_INIT_WITH), \ + INIT_MOVE(m_string_init_move), MOVE(API_0P(m_string_move)), \ + SWAP(m_string_swap), RESET(m_string_reset), \ + EMPTY_P(m_string_empty_p), \ + CLEAR(API_0P(m_string_clear)), HASH(m_string_hash), EQUAL(m_string_equal_p), \ + CMP(m_string_cmp), TYPE(m_string_t), GENTYPE(struct m_string_s*), \ + PARSE_STR(API_0P(m_string_parse_str)), GET_STR(API_0P(m_string_get_str)), \ + OUT_STR(m_string_out_str), IN_STR(API_0P(m_string_in_str)), \ + OUT_SERIAL(m_string_out_serial), IN_SERIAL(m_string_in_serial), \ + EXT_ALGO(M_STR1NG_SPLIT), \ + OOR_EQUAL(m_string_oor_equal_p), OOR_SET(m_string_oor_set) \ + ,SUBTYPE(m_string_unicode_t) \ + ,IT_TYPE(m_string_it_t) \ + ,IT_FIRST(m_string_it) \ + ,IT_END(m_string_it_end) \ + ,IT_SET(m_string_it_set) \ + ,IT_END_P(m_string_end_p) \ + ,IT_EQUAL_P(m_string_it_equal_p) \ + ,IT_NEXT(m_string_next) \ + ,IT_CREF(m_string_cref), PUSH(m_string_push_u) \ + ,EMPLACE_TYPE(const char*) \ + ) + /* Register the OPLIST as a global one */ #define M_OPL_m_string_t() M_STRING_OPLIST @@ -2274,10 +2274,28 @@ namespace m_lib { )(a,b,c) /* Init & Set the string a to the string (or C string) b (constructor) */ +#ifdef M_USE_POOL +#define m_string_init_set(p, a,b) \ + _Generic((b)+0, \ + char*: m_string_init_set_cstr, \ + const char *: m_string_init_set_cstr, \ + default : m_string_init_set \ + )(p,a,b) +#else #define m_string_init_set(a,b) M_STR1NG_SELECT2(m_string_init_set, m_string_init_set_cstr, a, b) +#endif /* Set the string a to the string (or C string) b */ +#ifdef M_USE_POOL +#define m_string_set(p, a,b) \ + _Generic((b)+0, \ + char*: m_string_set_cstr, \ + const char *: m_string_set_cstr, \ + default : m_string_set \ + )(p,a,b) +#else #define m_string_set(a,b) M_STR1NG_SELECT2(m_string_set, m_string_set_cstr, a, b) +#endif /* Concatenate the string (or C string) b to the string a */ #define m_string_cat(a,b) M_STR1NG_SELECT2(m_string_cat, m_string_cat_cstr, a, b) From bf617ab6abf9e8a8a6f790a581ab6c2e25fcaa44 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 4 Mar 2025 00:16:40 +0100 Subject: [PATCH 12/91] Port to new memory interface (WIP) --- m-bitset.h | 100 ++++++++++++++++++++++++++++++++++------------------- m-string.h | 4 +++ 2 files changed, 68 insertions(+), 36 deletions(-) diff --git a/m-bitset.h b/m-bitset.h index 0ff8a975..b1932396 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -101,8 +101,7 @@ m_bitset_reset(m_bitset_t t) } /* Clear a bitset (DESTRUCTOR) */ -M_INLINE void -m_bitset_clear(m_bitset_t t) +M_P(void, m_bitset, _clear, m_bitset_t t) { m_bitset_reset(t); M_MEMORY_FREE(m_b1tset_limb_ct, t->ptr, t->alloc); @@ -114,8 +113,7 @@ m_bitset_clear(m_bitset_t t) } /* Set a bitset to another one */ -M_INLINE void -m_bitset_set(m_bitset_t d, const m_bitset_t s) +M_P(void, m_bitset, _set, m_bitset_t d, const m_bitset_t s) { M_B1TSET_CONTRACT(d); M_B1TSET_CONTRACT(s); @@ -141,15 +139,14 @@ m_bitset_set(m_bitset_t d, const m_bitset_t s) } /* Initialize & set a bitset to another one (CONSTRUCTOR) */ -M_INLINE void -m_bitset_init_set(m_bitset_t d, const m_bitset_t s) +M_P(void, m_bitset, _init_set, m_bitset_t d, const m_bitset_t s) { M_ASSERT (d != s); // In case of exception, d remains initialized, // but without any allocation done. // Therefore it is safe, not to clear d on exception. m_bitset_init(d); - m_bitset_set(d, s); + m_bitset_set M_R(d, s); } /* Initialize & move a bitset (CONSTRUCTOR) from another one (DESTRUCTOR) */ @@ -167,10 +164,9 @@ m_bitset_init_move(m_bitset_t d, m_bitset_t s) } /* Move a bitset from another one (DESTRUCTOR) */ -M_INLINE void -m_bitset_move(m_bitset_t d, m_bitset_t s) +M_P(void, m_bitset, _move, m_bitset_t d, m_bitset_t s) { - m_bitset_clear(d); + m_bitset_clear M_R(d); m_bitset_init_move (d, s); } @@ -203,8 +199,7 @@ m_bitset_flip_at(m_bitset_t v, size_t i) } /* Push back the boolean 'x' in the bitset (increasing the bitset) */ -M_INLINE void -m_bitset_push_back (m_bitset_t v, bool x) +M_P(void, m_bitset, _push_back, m_bitset_t v, bool x) { M_B1TSET_CONTRACT (v); if (M_UNLIKELY (v->size >= M_B1TSET_FROM_ALLOC (v->alloc))) { @@ -242,8 +237,7 @@ m_bitset_push_back (m_bitset_t v, bool x) } /* Resize the bitset to have exactly 'size' bits */ -M_INLINE void -m_bitset_resize (m_bitset_t v, size_t size) +M_P(void, m_bitset, _resize, m_bitset_t v, size_t size) { M_B1TSET_CONTRACT (v); // Check for overflow @@ -290,8 +284,7 @@ m_bitset_resize (m_bitset_t v, size_t size) } /* Reserve allocation in the bitset to accommodate at least 'size' bits without reallocation */ -M_INLINE void -m_bitset_reserve (m_bitset_t v, size_t alloc) +M_P(void, m_bitset, _reserve, m_bitset_t v, size_t alloc) { M_B1TSET_CONTRACT (v); size_t oldAlloc = M_B1TSET_TO_ALLOC (v->size); @@ -390,7 +383,7 @@ m_bitset_size(m_bitset_t v) return v->size; } -/* Return the capacity in limbs of the bitset */ +/* Return the capacity in bits of the bitset */ M_INLINE size_t m_bitset_capacity(m_bitset_t v) { @@ -456,12 +449,11 @@ m_b1tset_rshift(m_b1tset_limb_ct ptr[], size_t n, m_b1tset_limb_ct carry) /* Insert a new bit at position 'key' of value 'value' in the bitset 'set' shifting the set accordingly */ -M_INLINE void -m_bitset_push_at(m_bitset_t set, size_t key, bool value) +M_P(void, m_bitset, _push_at, m_bitset_t set, size_t key, bool value) { M_B1TSET_CONTRACT (set); // First push another value to extend the array to the right size - m_bitset_push_back(set, false); + m_bitset_push_back M_R(set, false); M_ASSERT (set->ptr != NULL); M_ASSERT_INDEX(key, set->size); @@ -517,7 +509,7 @@ m_bitset_equal_p (const m_bitset_t set1, const m_bitset_t set2) M_B1TSET_CONTRACT (set2); if (set1->size != set2->size) return false; - /* We won't compare each bit individualy, + /* We won't compare each bit individually, but instead compare them per limb */ const size_t limbSize = (set1->size + M_B1TSET_LIMB_BIT -1) / M_B1TSET_LIMB_BIT; for(size_t i = 0 ; i < limbSize;i++) @@ -526,7 +518,7 @@ m_bitset_equal_p (const m_bitset_t set1, const m_bitset_t set2) return true; } -/* Initialize an iterator to the first bit of the biset */ +/* Initialize an iterator to the first bit of the bitset */ M_INLINE void m_bitset_it(m_bitset_it_t it, m_bitset_t set) { @@ -632,8 +624,7 @@ m_bitset_out_str(FILE *file, const m_bitset_t set) } /* Input the bitset from a formatted text in a FILE */ -M_INLINE bool -m_bitset_in_str(m_bitset_t set, FILE *file) +M_P(bool, m_bitset, _in_str, m_bitset_t set, FILE *file) { M_B1TSET_CONTRACT (set); M_ASSERT(file != NULL); @@ -643,7 +634,7 @@ m_bitset_in_str(m_bitset_t set, FILE *file) c = fgetc(file); while (c == '0' || c == '1') { const bool b = (c == '1'); - m_bitset_push_back (set, b); + m_bitset_push_back M_R(set, b); c = fgetc(file); } M_B1TSET_CONTRACT (set); @@ -651,8 +642,7 @@ m_bitset_in_str(m_bitset_t set, FILE *file) } /* Parse the bitset from a formatted text in a C string */ -M_INLINE bool -m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr) +M_P(bool, m_bitset, _parse_str, m_bitset_t set, const char str[], const char **endptr) { M_B1TSET_CONTRACT (set); M_ASSERT(str != NULL); @@ -664,7 +654,7 @@ m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr) do { if (M_UNLIKELY(c != '0' && c != '1')) goto exit; const bool b = (c == '1'); - m_bitset_push_back (set, b); + m_bitset_push_back M_R(set, b); c = *str++; } while (c != ']' && c != 0); M_B1TSET_CONTRACT (set); @@ -675,10 +665,9 @@ m_bitset_parse_str(m_bitset_t set, const char str[], const char **endptr) } /* Set the bitset from a formatted text in a C string */ -M_INLINE bool -m_bitset_set_str(m_bitset_t dest, const char str[]) +M_P(bool, m_bitset, _set_str, m_bitset_t dest, const char str[]) { - return m_bitset_parse_str(dest, str, NULL); + return m_bitset_parse_str M_R(dest, str, NULL); } /* Perform an AND operation between the bitsets, @@ -886,8 +875,48 @@ m_bitset_popcount(const m_bitset_t set) ,EQUAL(m_bitset_equal_p) \ ) +/* Oplist for a bitset */ +#define M_BITSET_POOL_OPLIST \ + (INIT(m_bitset_init) \ + ,INIT_SET(API_0P(m_bitset_init_set)) \ + ,INIT_WITH(API_1(M_INIT_VAI)) \ + ,SET(API_0P(m_bitset_set)) \ + ,CLEAR(API_0P(m_bitset_clear)) \ + ,INIT_MOVE(m_bitset_init_move) \ + ,MOVE(API_0P(m_bitset_move)) \ + ,SWAP(m_bitset_swap) \ + ,TYPE(m_bitset_t) \ + ,SUBTYPE(bool) \ + ,EMPTY_P(m_bitset_empty_p), \ + ,GET_SIZE(m_bitset_size) \ + ,IT_TYPE(m_bitset_it_t) \ + ,IT_FIRST(m_bitset_it) \ + ,IT_SET(m_bitset_it_set) \ + ,IT_LAST(m_bitset_it_last) \ + ,IT_END(m_bitset_it_end) \ + ,IT_END_P(m_bitset_end_p) \ + ,IT_LAST_P(m_bitset_last_p) \ + ,IT_EQUAL_P(m_bitset_it_equal_p) \ + ,IT_NEXT(m_bitset_next) \ + ,IT_PREVIOUS(m_bitset_previous) \ + ,IT_CREF(m_bitset_cref) \ + ,RESET(m_bitset_reset) \ + ,PUSH(API_0P(m_bitset_push_back)) \ + ,POP(m_bitset_pop_back) \ + ,HASH(m_bitset_hash) \ + ,GET_STR(API_0P(m_bitset_get_str)) \ + ,OUT_STR(m_bitset_out_str) \ + ,PARSE_STR(API_0P(m_bitset_parse_str)) \ + ,IN_STR(API_0P(m_bitset_in_str)) \ + ,EQUAL(m_bitset_equal_p) \ + ) + /* Register the OPLIST as a global one */ +#ifdef M_USE_POOL +#define M_OPL_m_bitset_t() M_BITSET_POOL_OPLIST +#else #define M_OPL_m_bitset_t() M_BITSET_OPLIST +#endif // TODO: set_at2, insert_v, remove_v @@ -965,18 +994,17 @@ M_BEGIN_PROTECTED_CODE /* Output to a m_string_t 'str' the formatted text representation of the bitset 'set' or append it to the string (append=true) */ -M_INLINE void -m_bitset_get_str(m_string_t str, const m_bitset_t set, bool append) +M_P(void, m_bitset, _get_str, m_string_t str, const m_bitset_t set, bool append) { M_B1TSET_CONTRACT (set); M_ASSERT(str != NULL); - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); for(size_t i = 0; i < set->size; i++) { const bool b = m_bitset_get (set, i); const char c = b ? '1' : '0'; - m_string_push_back (str, c); + m_string_push_back M_R(str, c); } - m_string_push_back (str, ']'); + m_string_push_back M_R(str, ']'); } M_END_PROTECTED_CODE diff --git a/m-string.h b/m-string.h index 82562c9e..4d52ff11 100644 --- a/m-string.h +++ b/m-string.h @@ -2202,7 +2202,11 @@ namespace m_lib { ) /* Register the OPLIST as a global one */ +#ifdef M_USE_POOL +#define M_OPL_m_string_t() M_STRING_POOL_OPLIST +#else #define M_OPL_m_string_t() M_STRING_OPLIST +#endif /* Register the string_t oplist as a generic type */ #define M_GENERIC_ORG_MLIB_COMP_CORE_OPLIST_1() M_STRING_OPLIST From 9e63289a385880f157d53694c339f4bb050b020f Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 4 Mar 2025 23:18:07 +0100 Subject: [PATCH 13/91] Port to new memory model --- m-bstring.h | 82 +++++++++++++++++++++++++++++------------------------ m-deque.h | 2 +- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/m-bstring.h b/m-bstring.h index 9fce5b5d..40338ada 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -74,8 +74,7 @@ m_bstring_init(m_bstring_t s) M_BSTRING_CONTRACT(s); } -M_INLINE void -m_bstring_clear(m_bstring_t s) +M_P(void, m_bstring, _clear, m_bstring_t s) { M_BSTRING_CONTRACT(s); M_MEMORY_FREE(uint8_t, s->ptr, s->alloc); @@ -138,8 +137,7 @@ m_bstring_empty_p(const m_bstring_t v) allocations. Return a pointer to the writable string. */ -M_INLINE uint8_t * -m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc) +M_P(uint8_t *, m_bstr1ng, _fit2size, m_bstring_t v, size_t size_alloc, bool exact_alloc) { // Very unlikely overflow case if (M_UNLIKELY_NOMEM (v->offset > v->offset + size_alloc)) { @@ -187,52 +185,52 @@ m_bstr1ng_fit2size (m_bstring_t v, size_t size_alloc, bool exact_alloc) } /* Push the byte 'c' in the bstring 'v' */ -M_INLINE void -m_bstring_push_back (m_bstring_t v, uint8_t c) +M_P(void, m_bstring, _push_back, m_bstring_t v, uint8_t c) { M_BSTRING_CONTRACT (v); const size_t size = v->size; - uint8_t *ptr = m_bstr1ng_fit2size(v, size+1, false); + // To overflow size+1, we need to have exhausted all memory + // which is not possible. + uint8_t *ptr = m_bstr1ng_fit2size M_R(v, size+1, false); ptr[size] = c; v->size = size + 1; M_BSTRING_CONTRACT (v); } /* Push the array of bytes from 'buffer' in the bstring 'v' */ -M_INLINE void -m_bstring_push_back_bytes (m_bstring_t v, size_t n, const void *buffer) +M_P(void, m_bstring, _push_back_bytes, m_bstring_t v, size_t n, const void *buffer) { M_BSTRING_CONTRACT (v); const size_t size = v->size; M_ASSERT_INDEX (size, size + n); - uint8_t *ptr = m_bstr1ng_fit2size(v, size+n, false); + // If size+n overflows, it means we are giving two objects which sizes + // sum to be greater than the available memory. The memory should have exhausted before that. + // The case is not possible, or the given size of the buffer is "faked". + uint8_t *ptr = m_bstr1ng_fit2size M_R(v, size+n, false); memcpy(&ptr[size], buffer, n); v->size = size + n; M_BSTRING_CONTRACT (v); } -M_INLINE void -m_bstring_splice(m_bstring_t dst, m_bstring_t src) +M_P(void, m_bstring, _splice, m_bstring_t dst, m_bstring_t src) { M_BSTRING_CONTRACT (dst); M_BSTRING_CONTRACT (src); M_ASSERT(src != dst); - m_bstring_push_back_bytes(dst, m_bstring_size(src), m_bstr1ng_cstr(src)); + m_bstring_push_back_bytes M_R(dst, m_bstring_size(src), m_bstr1ng_cstr(src)); m_bstring_reset(src); } -M_INLINE void -m_bstring_init_set(m_bstring_t v, const m_bstring_t org) +M_P(void, m_bstring, _init_set, m_bstring_t v, const m_bstring_t org) { m_bstring_init(v); - m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org)); + m_bstring_push_back_bytes M_R(v, m_bstring_size(org), m_bstr1ng_cstr(org)); } -M_INLINE void -m_bstring_set(m_bstring_t v, const m_bstring_t org) +M_P(void, m_bstring, _set, m_bstring_t v, const m_bstring_t org) { m_bstring_reset(v); - m_bstring_push_back_bytes(v, m_bstring_size(org), m_bstr1ng_cstr(org)); + m_bstring_push_back_bytes M_R(v, m_bstring_size(org), m_bstr1ng_cstr(org)); } M_INLINE void @@ -240,13 +238,13 @@ m_bstring_init_move(m_bstring_t v, m_bstring_t org) { M_BSTRING_CONTRACT (org); memcpy(v, org, sizeof (m_bstring_t)); + // Make org an invalid representation org->offset = (size_t) -1; } -M_INLINE void -m_bstring_move(m_bstring_t v, m_bstring_t org) +M_P(void, m_bstring, _move, m_bstring_t v, m_bstring_t org) { - m_bstring_clear(v); + m_bstring_clear M_R(v); m_bstring_init_move(v, org); } @@ -351,14 +349,16 @@ m_bstring_pop_front_bytes(size_t n, void *buffer, m_bstring_t v) M_BSTRING_CONTRACT (v); } -M_INLINE void -m_bstring_push_bytes_at (m_bstring_t v, size_t pos, size_t n, const void *buffer) +M_P(void, m_bstring, _push_bytes_at, m_bstring_t v, size_t pos, size_t n, const void *buffer) { M_BSTRING_CONTRACT (v); const size_t size = v->size; M_ASSERT_INDEX (pos, size+1); //pos == size ==> equivalent to _push_back_bytes M_ASSERT_INDEX (size, size + n); - uint8_t *ptr = m_bstr1ng_fit2size(v, size+n, false); + // If size+n overflows, it means we are giving two objects which sizes + // sum to be greater than the available memory. The memory should have exhausted before that. + // The case is not possible. + uint8_t *ptr = m_bstr1ng_fit2size M_R(v, size+n, false); memmove(&ptr[pos+n], &ptr[pos], size-pos); memcpy(&ptr[pos], buffer, n); v->size = size + n; @@ -379,21 +379,19 @@ m_bstring_pop_bytes_at(size_t n, void *buffer, m_bstring_t v, size_t pos) M_BSTRING_CONTRACT (v); } -M_INLINE void -m_bstring_resize (m_bstring_t v, size_t n) +M_P(void, m_bstring, _resize, m_bstring_t v, size_t n) { M_BSTRING_CONTRACT (v); const size_t size = v->size; if (n > size) { - uint8_t *ptr = m_bstr1ng_fit2size(v, n, true); + uint8_t *ptr = m_bstr1ng_fit2size M_R(v, n, true); memset(&ptr[size], 0, n-size); } v->size = n; M_BSTRING_CONTRACT (v); } -M_INLINE void -m_bstring_reserve (m_bstring_t v, size_t n) +M_P(void, m_bstring, _reserve, m_bstring_t v, size_t n) { M_BSTRING_CONTRACT (v); const size_t size = v->size; @@ -411,7 +409,6 @@ m_bstring_reserve (m_bstring_t v, size_t n) if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(uint8_t, n); } - // The string cannot be fully embedded anymore. v->ptr = ptr; v->alloc = n; } @@ -423,6 +420,7 @@ m_bstring_view(const m_bstring_t v, size_t offset, size_t size_requested) { M_BSTRING_CONTRACT (v); M_ASSERT_INDEX (offset+size_requested, v->size+1); + (void) size_requested; return &m_bstr1ng_cstr(v)[offset]; } @@ -434,6 +432,7 @@ m_bstring_acquire_access(m_bstring_t v, size_t offset, size_t size_requested) { M_BSTRING_CONTRACT (v); M_ASSERT_INDEX (offset+size_requested, v->size+1); + (void) size_requested; // Break canonical representation (this will generate assertion if a normal API is called now) M_SWAP(size_t, v->size, v->alloc); return &m_bstr1ng_cstr(v)[offset]; @@ -460,8 +459,7 @@ m_bstring_fwrite(FILE *f, const m_bstring_t v) return fwrite(m_bstr1ng_cstr(v), 1, m_bstring_size(v), f); } -M_INLINE bool -m_bstring_fread(m_bstring_t v, FILE *f, size_t num) +M_P(bool, m_bstring, _fread, m_bstring_t v, FILE *f, size_t num) { M_BSTRING_CONTRACT (v); M_ASSERT (f != NULL); @@ -470,7 +468,7 @@ m_bstring_fread(m_bstring_t v, FILE *f, size_t num) if (M_UNLIKELY(num == 0)) { return true; } - uint8_t *ptr = m_bstr1ng_fit2size(v, num, true); + uint8_t *ptr = m_bstr1ng_fit2size M_R(v, num, true); size_t n = fread(ptr, 1, num, f); M_ASSERT (n <= num); v->size = n; @@ -510,8 +508,7 @@ m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v) and set the converted value in the byte string 'v'. See serialization for return code. */ -M_INLINE m_serial_return_code_t -m_bstring_in_serial(m_bstring_t v, m_serial_read_t f) +M_P(m_serial_return_code_t, m_bstring, _in_serial, m_bstring_t v, m_serial_read_t f) { M_ASSERT (f != NULL && f->m_interface != NULL); M_BSTRING_CONTRACT (v); @@ -523,7 +520,7 @@ m_bstring_in_serial(m_bstring_t v, m_serial_read_t f) if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) { return ret; } - uint8_t *ptr = m_bstr1ng_fit2size(v, estimated_size, true); + uint8_t *ptr = m_bstr1ng_fit2size M_R(v, estimated_size, true); do { long long val; ret = f->m_interface->read_integer(f, &val, 1); @@ -547,6 +544,17 @@ m_bstring_in_serial(m_bstring_t v, m_serial_read_t f) OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(m_bstring_in_serial), \ ) +/* Define the OPLIST of a BYTE STRING using POOL */ +#define M_BSTRING_POOL_OPLIST \ + (INIT(m_bstring_init),INIT_SET(API_0P(m_bstring_init_set)), SET(API_0P(m_bstring_set)), \ + INIT_MOVE(m_bstring_init_move), MOVE(API_0P(m_bstring_move)), \ + SWAP(m_bstring_swap), RESET(m_bstring_reset), \ + EMPTY_P(m_bstring_empty_p), \ + CLEAR(API_0P(m_bstring_clear)), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \ + CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \ + OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(API_0P(m_bstring_in_serial=) \ + ) + /********************************************************************************/ /* */ /* Define the small name (i.e. without the prefix) of the API provided by this */ diff --git a/m-deque.h b/m-deque.h index 2bb79e1a..410fac3d 100644 --- a/m-deque.h +++ b/m-deque.h @@ -131,7 +131,7 @@ { \ M_CALL_FREE(oplist, char, ptr, sizeof(node_t) + ptr->capacity * sizeof(type)); \ } \ - M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_F(name, _del_node))) ) \ + M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_F(name, _del_node))) ) \ \ /* Define an internal iterator */ \ typedef struct M_F(name, _it2_s) { \ From 6de8eab5c3ab7722525d292538f2c931c2993e88 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 5 Mar 2025 22:43:43 +0100 Subject: [PATCH 14/91] Add comments, rename macro for maintenance --- m-mempool.h | 3 +++ m-worker.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/m-mempool.h b/m-mempool.h index adb4ad71..1d600afc 100644 --- a/m-mempool.h +++ b/m-mempool.h @@ -27,6 +27,9 @@ #include "m-core.h" +// TODO: Full rework of the mempool module to provide a generic arena allocator +// instead using the new pool context pointer. + /* Fast, fixed size, thread unsafe allocator based on memory regions. No oplist is needed. USAGE: diff --git a/m-worker.h b/m-worker.h index 7022483e..dae7068e 100644 --- a/m-worker.h +++ b/m-worker.h @@ -269,7 +269,7 @@ typedef struct m_worker_sync_s { M_MEMORY_FULL(struct M_C3(m_worker_, name, _s), 1); \ } \ p->callback = callback; \ - M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_COPY, data, __VA_ARGS__) \ + M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_INIT_SET, data, __VA_ARGS__) \ const m_work3r_order_ct w = { block, p, M_C3(m_work3r_, name, _callback) M_WORK3R_EXTRA_ORDER }; \ if (m_work3r_queue_push (block->worker->queue_g, w) == true) { \ atomic_fetch_add (&block->num_spawn, 1); \ @@ -288,7 +288,7 @@ typedef struct m_worker_sync_s { #define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD(data, num, oplist) \ M_GET_TYPE oplist M_C(param, num) -#define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_COPY(data, num, oplist) \ +#define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_INIT_SET(data, num, oplist) \ M_CALL_INIT_SET(oplist, p-> M_C(field, num), M_C(param, num) ); #define M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_ALONE(data, num, oplist) \ From 66f376ea802614151568068e66be218643345df1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 5 Mar 2025 22:43:55 +0100 Subject: [PATCH 15/91] Port to new memory model --- m-genint.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/m-genint.h b/m-genint.h index b19596c2..3e3e7e52 100644 --- a/m-genint.h +++ b/m-genint.h @@ -103,8 +103,7 @@ typedef struct m_genint_s { * meaning it can be used to index global unique resources shared * for all threads. */ -M_INLINE void -m_genint_init(m_genint_t s, unsigned int n) +M_P(void, m_genint, _init, m_genint_t s, unsigned int n) { M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC); const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE; @@ -126,8 +125,7 @@ m_genint_init(m_genint_t s, unsigned int n) } /* Clear an integer generator (Destructor) */ -M_INLINE void -m_genint_clear(m_genint_t s) +M_P(void, m_genint, _clear, m_genint_t s) { M_GEN1NT_CONTRACT(s); M_MEMORY_FREE(atomic_ullong, s->data, s->max+1); From aa4cbfebdb6891262bf7d7203748484415d70ee0 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 5 Mar 2025 23:07:42 +0100 Subject: [PATCH 16/91] Port to new memory interface --- m-array.h | 1 + m-buffer.h | 6 ++--- m-concurrent.h | 2 +- m-core.h | 14 +++++------ m-prioqueue.h | 68 ++++++++++++++++++++------------------------------ m-rbtree.h | 2 +- 6 files changed, 40 insertions(+), 53 deletions(-) diff --git a/m-array.h b/m-array.h index c8c5b28c..2163203d 100644 --- a/m-array.h +++ b/m-array.h @@ -80,6 +80,7 @@ /* OPLIST definition of a dynamic array */ /* FIXME: Do we want to export some methods as they are slow and are not fit to be used for building other methods (like _it_remove)? */ +//TODO: ARRAY_POOL_OPLIST #define M_ARRA4_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_F(name, _init_set)),) \ diff --git a/m-buffer.h b/m-buffer.h index 16c23780..66a6563e 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -258,7 +258,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) M_BUFF3R_DEF_TYPE(name, type, m_size, policy, oplist, buffer_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \ - M_EMPLACE_QUEUE_DEF(name, buffer_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) /* Define the type of a buffer */ #define M_BUFF3R_DEF_TYPE(name, type, m_size, policy, oplist, buffer_t) \ @@ -798,7 +798,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_QU3UE_MPMC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \ - M_EMPLACE_QUEUE_DEF(name, buffer_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) /* Define the type of a MPMC queue */ #define M_QU3UE_MPMC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ @@ -1033,7 +1033,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \ - M_EMPLACE_QUEUE_DEF(name, buffer_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) /* Define the type of a SPSC queue */ #define M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ diff --git a/m-concurrent.h b/m-concurrent.h index 7e2f715c..af0b2704 100644 --- a/m-concurrent.h +++ b/m-concurrent.h @@ -522,7 +522,7 @@ M_F(name, _write_unlock)(out); \ } \ \ - M_EMPLACE_QUEUE_DEF(name, concurrent_t, M_F(name, _emplace), M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \ + M_EMPLACE_QUEUE_DEF(name, concurrent_t, _emplace, M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \ ,) \ \ M_IF_METHOD(POP, oplist)( \ diff --git a/m-core.h b/m-core.h index 547b5e4f..de836a1b 100644 --- a/m-core.h +++ b/m-core.h @@ -5081,10 +5081,10 @@ m_core_parse2_enum (const char str[], const char **endptr) M_ID( M_C(M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF, isSet)(name, name_t, key_oplist, val_oplist) ) #define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF0(name, name_t, key_oplist, val_oplist) \ M_EMPLACE_ASS_ARRAY_DEF(name, name_t, M_F(name, _emplace), key_oplist, val_oplist, M_EMPLACE_ASS_ARRA1_BOTH_GENE, M_EMPLACE_ASS_ARRA1_KEY_GENE, M_EMPLACE_ASS_ARRA1_VAL_GENE) \ - M_EMPLACE_QUEUE_DEF(name, name_t, M_F(name, _get_emplace), key_oplist, M_EMPLACE_GET_GENE) + M_EMPLACE_QUEUE_DEF(name, name_t, _get_emplace, key_oplist, M_EMPLACE_GET_GENE) #define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF1(name, name_t, key_oplist, val_oplist) \ - M_EMPLACE_QUEUE_DEF(name, name_t, M_F(name, _emplace), key_oplist, M_EMPLACE_QUEUE_GENE) \ - M_EMPLACE_QUEUE_DEF(name, name_t, M_F(name, _get_emplace), key_oplist, M_EMPLACE_GET_GENE) + M_EMPLACE_QUEUE_DEF(name, name_t, _emplace, key_oplist, M_EMPLACE_QUEUE_GENE) \ + M_EMPLACE_QUEUE_DEF(name, name_t, _get_emplace, key_oplist, M_EMPLACE_GET_GENE) /* Definition of the emplace_back function for associative arrays. @@ -5138,13 +5138,13 @@ m_core_parse2_enum (const char str[], const char **endptr) This definition is far from being efficient but works for the current interface. */ #define M_EMPLACE_QUEUE_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ + M_P(void, name, function_name, name_t v \ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_GET_TYPE oplist data; \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \ - M_F(name, _push)(v, data); \ + /* FIXME: Why name##_push and not M_CALL_PUSH? */ \ + M_F(name, _push) M_R(v, data); \ M_CALL_CLEAR(oplist, data); \ } @@ -5155,7 +5155,7 @@ m_core_parse2_enum (const char str[], const char **endptr) */ #define M_EMPLACE_GET_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ M_INLINE M_F(name, _value_ct) * \ - function_name(name_t const v \ + M_F(name, function_name)(name_t const v \ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_GET_TYPE oplist data; \ diff --git a/m-prioqueue.h b/m-prioqueue.h index 8c8fa829..6366e185 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -25,7 +25,6 @@ #ifndef MSTARLIB_PRIOQUEUE_H #define MSTARLIB_PRIOQUEUE_H -#include "m-core.h" #include "m-array.h" /* Priority queue are built upon array */ /* Priority queue based on binary heap implementation */ @@ -137,7 +136,7 @@ M_PR1OQUEUE_DEF_CORE(name, type, oplist, prioqueue_t, it_t) \ M_PR1OQUEUE_DEF_IT(name, type, oplist, prioqueue_t, it_t) \ M_PR1OQUEUE_DEF_IO(name, type, oplist, prioqueue_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, prioqueue_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, prioqueue_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) /* Define the types */ #define M_PR1OQUEUE_DEF_TYPE(name, type, oplist, prioqueue_t, it_t) \ @@ -167,22 +166,19 @@ M_F(name, _array_init)(p->array); \ } \ \ - M_INLINE void \ - M_F(name, _init_set)(prioqueue_t p, prioqueue_t const o) \ + M_P(void, name, _init_set, prioqueue_t p, prioqueue_t const o) \ { \ - M_F(name, _array_init_set)(p->array, o->array); \ + M_F(name, _array_init_set) M_R(p->array, o->array); \ } \ \ - M_INLINE void \ - M_F(name, _set)(prioqueue_t p, prioqueue_t const o) \ + M_P(void, name, _set, prioqueue_t p, prioqueue_t const o) \ { \ - M_F(name, _array_set)(p->array, o->array); \ + M_F(name, _array_set) M_R(p->array, o->array); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(prioqueue_t p) \ + M_P(void, name, _clear, prioqueue_t p) \ { \ - M_F(name, _array_clear)(p->array); \ + M_F(name, _array_clear) M_R(p->array); \ } \ \ M_INLINE void \ @@ -191,10 +187,9 @@ M_F(name, _array_init_move)(p->array, o->array); \ } \ \ - M_INLINE void \ - M_F(name, _move)(prioqueue_t p, prioqueue_t o) \ + M_P(void, name, _move, prioqueue_t p, prioqueue_t o) \ { \ - M_F(name, _array_move)(p->array, o->array); \ + M_F(name, _array_move) M_R(p->array, o->array); \ } \ \ M_INLINE void \ @@ -203,10 +198,9 @@ M_F(name, _array_swap)(p->array, o->array); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(prioqueue_t p) \ + M_P(void, name, _reset, prioqueue_t p) \ { \ - M_F(name, _array_reset)(p->array); \ + M_F(name, _array_reset)M_R(p->array); \ } \ \ M_INLINE size_t \ @@ -249,11 +243,10 @@ return M_F(name, _array_size)(p->array); \ } \ \ - M_INLINE void \ - M_F(name, _push)(prioqueue_t p, type const x) \ + M_P(void, name, _push, prioqueue_t p, type const x) \ { \ /* Push back the new element at the end of the array */ \ - M_F(name, _array_push_back)(p->array, x); \ + M_F(name, _array_push_back) M_R(p->array, x); \ \ /* Reorder the array by swapping with its parent \ * until it reaches the right position */ \ @@ -273,14 +266,13 @@ return M_F(name, _array_cget)(p->array, 0); \ } \ \ - M_INLINE void \ - M_F(name, _pop)(type *x, prioqueue_t p) \ + M_P(void, name, _pop, type *x, prioqueue_t p) \ { \ /* Swap the front element with the last element */ \ size_t size = M_F(name, _array_size)(p->array)-1; \ M_F(name, _array_swap_at) (p->array, 0, size); \ /* Swap the new last element */ \ - M_F(name, _array_pop_back)(x, p->array); \ + M_F(name, _array_pop_back) M_R(x, p->array); \ \ /* Reorder the heap */ \ size_t i = 0; \ @@ -323,8 +315,7 @@ return i; \ } \ \ - M_INLINE bool \ - M_F(name, _erase)(prioqueue_t p, type const x) \ + M_P(bool, name, _erase, prioqueue_t p, type const x) \ { \ /* First pass: search for an item EQUAL to x */ \ size_t size = M_F(name, _array_size)(p->array); \ @@ -335,7 +326,7 @@ /* Swap the found item and the last element */ \ size--; \ M_F(name, _array_swap_at) (p->array, i, size); \ - M_F(name, _array_pop_back)(NULL, p->array); \ + M_F(name, _array_pop_back) M_R(NULL, p->array); \ /* Move back the last swapped element to its right position in the heap */ \ while (true) { \ size_t child = M_F(name, _i_lchild)(i); \ @@ -352,8 +343,7 @@ return true; \ } \ \ - M_INLINE void \ - M_F(name, _update)(prioqueue_t p, type const xold, type const xnew) \ + M_P(void, name, _update, prioqueue_t p, type const xold, type const xnew) \ { \ /* NOTE: xold can be the same pointer than xnew */ \ /* First pass: search for an item EQUAL to x */ \ @@ -364,7 +354,7 @@ /* Test if the position of the old data is further or nearer than the new */ \ int cmp = M_CALL_CMP(oplist, *M_F(name, _array_cget)(p->array, i), xnew); \ /* Set the found item to the new element */ \ - M_F(name, _array_set_at) (p->array, i, xnew); \ + M_F(name, _array_set_at) M_R(p->array, i, xnew); \ if (cmp < 0) { \ /* Move back the updated element to its new position, further in the heap */ \ while (true) { \ @@ -467,26 +457,23 @@ ,/* No OUT_STR */) \ \ M_IF_METHOD(IN_STR, oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(prioqueue_t p, FILE *file) \ + M_P(bool, name, _in_str, prioqueue_t p, FILE *file) \ { \ - return M_F(name, _array_in_str)(p->array, file); \ + return M_F(name, _array_in_str)M_R(p->array, file); \ } \ ,/* No IN_STR */) \ \ M_IF_METHOD(GET_STR, oplist)( \ - M_INLINE void \ - M_F(name, _get_str)(m_string_t str, const prioqueue_t p, bool append) \ + M_P(void, name, _get_str, m_string_t str, const prioqueue_t p, bool append) \ { \ - M_F(name, _array_get_str)(str, p->array, append); \ + M_F(name, _array_get_str)M_R(str, p->array, append); \ } \ ,/* No GET_STR */) \ \ M_IF_METHOD(PARSE_STR, oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(prioqueue_t p, const char str[], const char **endp) \ + M_P(bool, name, _parse_str, prioqueue_t p, const char str[], const char **endp) \ { \ - return M_F(name, _array_parse_str)(p->array, str, endp); \ + return M_F(name, _array_parse_str)M_R(p->array, str, endp); \ } \ ,/* No PARSE_STR */) \ \ @@ -499,10 +486,9 @@ ,/* No OUT_SERIAL */) \ \ M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(prioqueue_t p, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, prioqueue_t p, m_serial_read_t f) \ { \ - return M_F(name, _array_in_serial)(p->array, f); \ + return M_F(name, _array_in_serial)M_R(p->array, f); \ } \ ,/* No in_SERIAL */) \ diff --git a/m-rbtree.h b/m-rbtree.h index d07e6173..75614df5 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -180,7 +180,7 @@ typedef enum { M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \ M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace), oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, tree_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) /* Define the types associated to a R/B Tree */ #define M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \ From e16c6987e455065e6bb84c0b970eda7f14f403c4 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 6 Mar 2025 23:32:11 +0100 Subject: [PATCH 17/91] Port to new memory interface (remove mempool support, but it was undocumented) --- m-rbtree.h | 122 ++++++++++++++++++----------------------------------- 1 file changed, 41 insertions(+), 81 deletions(-) diff --git a/m-rbtree.h b/m-rbtree.h index 75614df5..f9e8086d 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -176,7 +176,6 @@ typedef enum { */ #define M_RBTR33_DEF_P3(name, type, oplist, tree_t, node_t, it_t) \ M_RBTR33_DEF_TYPE(name, type, oplist, tree_t, node_t, it_t) \ - M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \ M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \ @@ -215,33 +214,6 @@ typedef enum { typedef tree_t M_F(name, _ct); \ typedef it_t M_F(name, _it_ct); \ -/* Define the mempool encapsulation */ -#define M_RBTR33_DEF_MEMPOOL(name, type, oplist, tree_t, node_t, it_t) \ - /* Link with fast memory allocator if requested */ \ - M_IF_METHOD(MEMPOOL, oplist)( \ - /* Definition of the memory pool of this kind of node */ \ - MEMPOOL_DEF(M_F(name, _mempool), node_t) \ - /* Definition of the global variable used to reference this pool */ \ - M_GET_MEMPOOL_LINKAGE oplist M_F(name, _mempool_t) M_GET_MEMPOOL oplist; \ - /* Allocator function */ \ - M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \ - return M_F(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \ - } \ - /* Deallocator function */ \ - M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \ - M_F(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \ - } \ - \ - , /* No mempool allocation */ \ - /* Classic Allocator function (common case) */ \ - M_INLINE node_t *M_C3(m_rbtr33_,name,_new)(void) { \ - return M_CALL_NEW(oplist, node_t); \ - } \ - /* Classic deallocator function (common case) */ \ - M_INLINE void M_C3(m_rbtr33_,name,_del)(node_t *ptr) { \ - M_CALL_DEL(oplist, ptr); \ - } ) \ - /* Define the core functions */ #define M_RBTR33_DEF_CORE(name, type, oplist, tree_t, node_t, it_t) \ \ @@ -254,8 +226,7 @@ typedef enum { M_RBTR33_CONTRACT(tree); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(tree_t tree) \ + M_P(void, name, _reset, tree_t tree) \ { \ M_RBTR33_CONTRACT(tree); \ node_t *stack[M_RBTR33_MAX_STACK]; \ @@ -289,7 +260,7 @@ typedef enum { M_ASSERT (n == stack[cpt - 1]); \ /* Clear the bottom left node */ \ M_CALL_CLEAR(oplist, n->data); \ - M_C3(m_rbtr33_,name,_del) (n); \ + M_CALL_DEL(oplist, n); \ M_ASSERT((stack[cpt-1] = NULL) == NULL); \ /* Go up to the parent */ \ cpt--; \ @@ -299,15 +270,13 @@ typedef enum { tree->size = 0; \ } \ \ - M_INLINE void \ - M_F(name, _clear)(tree_t tree) \ + M_P(void, name, _clear, tree_t tree) \ { \ /* Nothing more than clean the tree as everything is cleared */ \ - M_F(name, _reset)(tree); \ + M_F(name, _reset) M_R(tree); \ } \ \ - M_INLINE void \ - M_F(name, _push)(tree_t tree, type const data) \ + M_P(void, name, _push, tree_t tree, type const data) \ { \ M_RBTR33_CONTRACT(tree); \ node_t *tab[M_RBTR33_MAX_STACK]; \ @@ -316,7 +285,7 @@ typedef enum { node_t *n = tree->node; \ /* If there is no root node, create a new node */ \ if (n == NULL) { \ - n = M_C3(m_rbtr33_,name,_new)(); \ + n = M_CALL_NEW(oplist, node_t); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ M_MEMORY_FULL(node_t, 1); \ return; \ @@ -357,7 +326,7 @@ typedef enum { return; \ } \ /* Create new node to store the data */ \ - n = M_C3(m_rbtr33_,name,_new)(); \ + n = M_CALL_NEW(oplist, node_t); \ if (M_UNLIKELY_NOMEM (n == NULL) ) { \ M_MEMORY_FULL (node_t, 1); \ return; \ @@ -684,41 +653,38 @@ typedef enum { } \ \ /* Create a copy of the given node (recursively) */ \ - M_INLINE node_t * \ - M_C3(m_rbtr33_,name,_copy_node)(const node_t *o) \ + M_P(node_t *, name, _i_copy_node, const node_t *o) \ { \ - if (o == NULL) return NULL; \ - node_t *n = M_C3(m_rbtr33_,name,_new)(); \ + if (M_UNLIKELY(o == NULL)) return NULL; \ + node_t *n = M_CALL_NEW(oplist, node_t); \ if (M_UNLIKELY_NOMEM (n == NULL) ) { \ M_MEMORY_FULL (node_t, 1); \ return NULL; \ } \ M_CALL_INIT_SET(oplist, n->data, o->data); \ - n->child[0] = M_C3(m_rbtr33_,name,_copy_node)(o->child[0]); \ - n->child[1] = M_C3(m_rbtr33_,name,_copy_node)(o->child[1]); \ + n->child[0] = M_F(name,_i_copy_node)M_R(o->child[0]); \ + n->child[1] = M_F(name,_i_copy_node)M_R(o->child[1]); \ M_RBTR33_COPY_COLOR (n, o); \ return n; \ } \ \ - M_INLINE void \ - M_F(name, _init_set)(tree_t tree, const tree_t ref) \ + M_P(void, name, _init_set, tree_t tree, const tree_t ref) \ { \ M_RBTR33_CONTRACT (ref); \ M_ASSERT (tree != NULL && tree != ref); \ tree->size = ref->size; \ /* Copy the root node recursively */ \ - tree->node = M_C3(m_rbtr33_,name,_copy_node)(ref->node); \ + tree->node = M_F(name,_i_copy_node)M_R(ref->node); \ M_RBTR33_CONTRACT (tree); \ } \ \ - M_INLINE void \ - M_F(name, _set)(tree_t tree, const tree_t ref) \ + M_P(void, name, _set, tree_t tree, const tree_t ref) \ { \ M_RBTR33_CONTRACT (tree); \ M_RBTR33_CONTRACT (ref); \ if (tree == ref) return; \ - M_F(name,_clear)(tree); \ - M_F(name,_init_set)(tree, ref); \ + M_F(name,_clear)M_R(tree); \ + M_F(name,_init_set)M_R(tree, ref); \ } \ \ M_INLINE void \ @@ -728,18 +694,18 @@ typedef enum { M_ASSERT (tree != NULL && tree != ref); \ tree->size = ref->size; \ tree->node = ref->node; \ + /* Mark ref as an invalid representation */ \ ref->node = NULL; \ - ref->size = 0; \ + ref->size = 1; \ M_RBTR33_CONTRACT (tree); \ } \ \ - M_INLINE void \ - M_F(name, _move)(tree_t tree, tree_t ref) \ + M_P(void, name, _move, tree_t tree, tree_t ref) \ { \ M_RBTR33_CONTRACT (tree); \ M_RBTR33_CONTRACT (ref); \ M_ASSERT (tree != ref); \ - M_F(name,_clear)(tree); \ + M_F(name,_clear)M_R(tree); \ M_F(name,_init_move)(tree, ref); \ M_RBTR33_CONTRACT (tree); \ } \ @@ -801,8 +767,7 @@ typedef enum { } \ ) \ \ - M_INLINE bool \ - M_F(name, _pop_at)(type *data_ptr, tree_t tree, type const key) \ + M_P(bool, name, _pop_at, type *data_ptr, tree_t tree, type const key) \ { \ M_RBTR33_CONTRACT (tree); \ node_t *tab[M_RBTR33_MAX_STACK]; \ @@ -955,24 +920,22 @@ typedef enum { M_DO_MOVE(oplist, *data_ptr, n->data); \ else \ M_CALL_CLEAR(oplist, n->data); \ - M_C3(m_rbtr33_,name,_del) (n); \ + M_CALL_DEL(oplist, n); \ tree->size --; \ M_RBTR33_CONTRACT (tree); \ return true; \ } \ \ - M_INLINE void M_F(name,_remove)(tree_t t, it_t it) \ + M_P(void, name,_remove, tree_t t, it_t it) \ { \ /* Not optimum: another search in the tree is performed */ \ - type data; \ - M_CALL_INIT_SET(oplist, data, *M_F(name,_cref)(it)); \ + type const *data = M_F(name,_cref)(it); \ M_F(name,_next)(it); \ - M_F(name, _pop_at)(NULL, t, data); \ - /* We have changed the tree: the iterator is partialy invalid */ \ + M_F(name, _pop_at)M_R(NULL, t, *data); \ + /* We have changed the tree: the iterator is partially invalid */ \ if (!M_F(name, _end_p)(it)) { \ M_F(name, _it_from)(it, t, *M_F(name,_cref)(it)); \ } \ - M_CALL_CLEAR(oplist, data); \ } \ \ M_IF_METHOD(EQUAL, oplist)( \ @@ -1022,24 +985,24 @@ typedef enum { /* Define the I/O functions */ #define M_RBTR33_DEF_IO(name, type, oplist, tree_t, node_t, it_t) \ M_IF_METHOD(GET_STR, oplist)( \ - M_INLINE void M_F(name, _get_str)(m_string_t str, \ - tree_t const t1, bool append) { \ + M_P(void, name, _get_str, m_string_t str, tree_t const t1, bool append) \ + { \ M_RBTR33_CONTRACT(t1); \ M_ASSERT(str != NULL); \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \ /* NOTE: The print is really naive, and not really efficient */ \ bool commaToPrint = false; \ it_t it1; \ M_F(name, _it)(it1, t1); \ while (!M_F(name, _end_p)(it1)) { \ if (commaToPrint) \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ commaToPrint = true; \ type const *ref1 = M_F(name, _cref)(it1); \ M_CALL_GET_STR(oplist, str, *ref1, true); \ M_F(name, _next)(it1); \ } \ - m_string_push_back (str, ']'); \ + m_string_push_back M_R(str, ']'); \ } \ , /* NO GET_STR */ ) \ \ @@ -1066,12 +1029,11 @@ typedef enum { , /* no out_str */ ) \ \ M_IF_METHOD(PARSE_STR, oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(tree_t rbtree, const char str[], const char **endp) \ + M_P(bool, name, _parse_str, tree_t rbtree, const char str[], const char **endp) \ { \ M_RBTR33_CONTRACT(rbtree); \ M_ASSERT (str != NULL); \ - M_F(name,_reset)(rbtree); \ + M_F(name,_reset)M_R(rbtree); \ int c = m_core_str_nospace(&str); \ if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \ c = m_core_str_nospace(&str); \ @@ -1082,7 +1044,7 @@ typedef enum { bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ c = m_core_str_nospace(&str); \ if (b == false || c == 0) { c= 0 ; break; }; \ - M_F(name, _push)(rbtree, item); \ + M_F(name, _push)M_R(rbtree, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ exit: \ @@ -1092,12 +1054,11 @@ typedef enum { , /* no parse_str */ ) \ \ M_IF_METHOD(IN_STR, oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(tree_t rbtree, FILE *file) \ + M_P(bool, name, _in_str, tree_t rbtree, FILE *file) \ { \ M_RBTR33_CONTRACT(rbtree); \ M_ASSERT (file != NULL); \ - M_F(name,_reset)(rbtree); \ + M_F(name,_reset)M_R(rbtree); \ int c = fgetc(file); \ if (M_UNLIKELY (c != '[')) return false; \ c = fgetc(file); \ @@ -1109,7 +1070,7 @@ typedef enum { bool b = M_CALL_IN_STR(oplist, item, file); \ c = m_core_fgetc_nospace(file); \ if (b == false || c == EOF) { c = 0; break; } \ - M_F(name, _push)(rbtree, item); \ + M_F(name, _push)M_R(rbtree, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ return c == ']'; \ @@ -1143,22 +1104,21 @@ typedef enum { , /* no OUT_SERIAL */ ) \ \ M_IF_METHOD(IN_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, tree_t t1, m_serial_read_t f) \ { \ M_RBTR33_CONTRACT(t1); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ m_serial_return_code_t ret; \ size_t estimated_size = 0; \ - M_F(name,_reset)(t1); \ + M_F(name,_reset)M_R(t1); \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ M_QLET(1, key, type, oplist) { \ do { \ ret = M_CALL_IN_SERIAL(oplist, key, f); \ if (ret != M_SERIAL_OK_DONE) { break; } \ - M_F(name, _push)(t1, key); \ + M_F(name, _push)M_R(t1, key); \ ret = f->m_interface->read_array_next(local, f); \ } while (ret == M_SERIAL_OK_CONTINUE); \ } \ From 7677b13d8a32147b702576f4df92fcac5c55729c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 7 Mar 2025 23:49:36 +0100 Subject: [PATCH 18/91] Update contract comment. --- m-core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/m-core.h b/m-core.h index de836a1b..d7b04d44 100644 --- a/m-core.h +++ b/m-core.h @@ -401,6 +401,7 @@ M_BEGIN_PROTECTED_CODE /* This macro is called on memory allocation failure. * By default, it raises a fatal error and abort execution. + * It shall never continue execution. * NOTE: Can be overloaded by user code. */ #ifndef M_MEMORY_FULL From 6e828eabaf32f8698990b60e16d799c44b0e69b1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 7 Mar 2025 23:54:11 +0100 Subject: [PATCH 19/91] Port list to new memory pool Remove support for mempool. A new support for mempool should be provided later through the new memory context parameter (TODO / better API) --- m-list.h | 278 +++++++++++++++++++++---------------------------------- 1 file changed, 105 insertions(+), 173 deletions(-) diff --git a/m-list.h b/m-list.h index bdda2f60..3b48c6e7 100644 --- a/m-list.h +++ b/m-list.h @@ -86,6 +86,8 @@ /********************************** INTERNAL ************************************/ +//TODO: Provide an update scheme for mempool using new memory allocator context. + /* Deferred evaluation for the oplist definition, so that all arguments are evaluated before further expansion */ #define M_L1ST_OPLIST_P1(arg) M_L1ST_OPLIST_P2 arg @@ -155,29 +157,6 @@ #define M_L1ST_DEF_FAILURE(name, type, oplist, list_t, it_t) \ M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(LIST_DEF): the given argument is not a valid oplist: " #oplist) -/* Define allocation functions. If MEMPOOL, we need to define it */ -#define M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, list_it_t) \ - M_IF_METHOD(MEMPOOL, oplist)( \ - \ - MEMPOOL_DEF(M_F(name, _mempool), struct M_F(name, _s)) \ - M_GET_MEMPOOL_LINKAGE oplist M_F(name, _mempool_t) M_GET_MEMPOOL oplist; \ - M_INLINE struct M_F(name, _s) *M_C3(m_l1st_,name,_new)(void) { \ - return M_F(name, _mempool_alloc)(M_GET_MEMPOOL oplist); \ - } \ - M_INLINE void M_C3(m_l1st_,name,_del)(struct M_F(name, _s) *ptr) { \ - M_F(name, _mempool_free)(M_GET_MEMPOOL oplist, ptr); \ - } \ - \ - , /* No mempool allocation */ \ - \ - M_INLINE struct M_F(name, _s) *M_C3(m_l1st_,name,_new)(void) { \ - return M_CALL_NEW(oplist, struct M_F(name, _s)); \ - } \ - M_INLINE void M_C3(m_l1st_,name,_del)(struct M_F(name, _s) *ptr) { \ - M_CALL_DEL(oplist, ptr); \ - } \ - ) \ - /* Internal list definition - name: prefix to be used @@ -190,9 +169,8 @@ #define M_L1ST_DEF_P3(name, type, oplist, list_t, it_t) \ M_L1ST_DEF_TYPE(name, type, oplist, list_t, it_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \ M_L1ST_DEF_P4(name, type, oplist, list_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_DEF) \ + M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_DEF) \ M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) @@ -242,8 +220,7 @@ *v = NULL; \ } \ \ - M_INLINE void \ - M_F(name, _reset)(list_t v) \ + M_P(void,name, _reset, list_t v) \ { \ M_L1ST_CONTRACT(v); \ struct M_F(name, _s) *it = *v; \ @@ -251,16 +228,15 @@ while (it != NULL) { \ struct M_F(name, _s) *next = it->next; \ M_CALL_CLEAR(oplist, it->data); \ - M_C3(m_l1st_,name,_del)(it); \ + M_CALL_DEL(oplist, it); \ it = next; \ } \ M_L1ST_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(list_t v) \ + M_P(void, name, _clear, list_t v) \ { \ - M_F(name, _reset)(v); \ + M_F(name, _reset)M_R(v); \ } \ \ M_INLINE type * \ @@ -271,12 +247,10 @@ return &((*v)->data); \ } \ \ - M_INLINE type * \ - M_F(name, _push_raw)(list_t v) \ + M_P(type *, name, _push_raw, list_t v) \ { \ M_L1ST_CONTRACT(v); \ - struct M_F(name, _s) *next; \ - next = M_C3(m_l1st_,name,_new)(); \ + struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ return NULL; \ @@ -288,35 +262,32 @@ return ret; \ } \ \ - M_INLINE void \ - M_F(name, _push_back)(list_t v, type const x) \ + M_P(void, name, _push_back, list_t v, type const x) \ { \ - type *data = M_F(name, _push_raw)(v); \ + type *data = M_F(name, _push_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \ - M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \ + M_ON_EXCEPTION( *v = next->next, M_CALL_DEL(oplist, next)) { \ M_CALL_INIT_SET(oplist, *data, x); \ } \ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _push_new)(list_t v) \ + M_P(type *, name, _push_new, list_t v) \ { \ - type *data = M_F(name, _push_raw)(v); \ + type *data = M_F(name, _push_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return NULL; \ M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \ - M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \ + M_ON_EXCEPTION( *v = next->next, M_CALL_DEL(oplist, next)) { \ M_CALL_INIT(oplist, *data); \ } \ return data; \ } \ , /* No INIT */) \ \ - M_INLINE void \ - M_F(name, _pop_back)(type *data, list_t v) \ + M_P(void, name, _pop_back, type *data, list_t v) \ { \ M_L1ST_CONTRACT(v); \ M_ASSERT(*v != NULL); \ @@ -327,29 +298,27 @@ } \ struct M_F(name, _s) *tofree = *v; \ *v = (*v)->next; \ - M_C3(m_l1st_,name,_del)(tofree); \ + M_CALL_DEL(oplist, tofree); \ M_L1ST_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _push_move)(list_t v, type *x) \ + M_P(void, name, _push_move, list_t v, type *x) \ { \ M_ASSERT (x != NULL); \ - type *data = M_F(name, _push_raw)(v); \ + type *data = M_F(name, _push_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ M_DO_INIT_MOVE (oplist, *data, *x); \ } \ \ - M_INLINE void \ - M_F(name, _pop_move)(type *data, list_t v) \ + M_P(void, name, _pop_move, type *data, list_t v) \ { \ M_L1ST_CONTRACT(v); \ M_ASSERT(*v != NULL && data != NULL); \ M_DO_INIT_MOVE (oplist, *data, (*v)->data); \ struct M_F(name, _s) *tofree = *v; \ *v = (*v)->next; \ - M_C3(m_l1st_,name,_del)(tofree); \ + M_CALL_DEL(oplist, tofree); \ M_L1ST_CONTRACT(v); \ } \ \ @@ -490,19 +459,17 @@ return M_CONST_CAST(type, M_F(name, _get)(l,i)); \ } \ \ - M_INLINE void \ - M_F(name, _insert)(list_t list, it_t insertion_point, \ - type const x) \ + M_P(void, name, _insert, list_t list, it_t insertion_point, type const x) \ { \ M_L1ST_CONTRACT(list); \ M_ASSERT (insertion_point != NULL); \ - M_ASSERT(M_F(name, _sublist_p)(list, insertion_point)); \ - struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \ + M_ASSERT (M_F(name, _sublist_p)(list, insertion_point)); \ + struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ } \ - M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \ + M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \ M_CALL_INIT_SET(oplist, next->data, x); \ struct M_F(name, _s) *current = insertion_point->current; \ if (M_UNLIKELY (current == NULL)) { \ @@ -518,13 +485,12 @@ M_L1ST_CONTRACT(list); \ } \ \ - M_INLINE void \ - M_F(name, _remove)(list_t list, it_t removing_point) \ + M_P(void, name, _remove, list_t list, it_t removing_point) \ { \ M_L1ST_CONTRACT(list); \ M_ASSERT (removing_point != NULL); \ M_ASSERT (removing_point->current != NULL); \ - M_ASSERT(M_F(name, _sublist_p)(list, removing_point)); \ + M_ASSERT (M_F(name, _sublist_p)(list, removing_point)); \ struct M_F(name, _s) *next = removing_point->current->next; \ if (M_UNLIKELY (removing_point->previous == NULL)) { \ *list = next; \ @@ -532,13 +498,12 @@ removing_point->previous->next = next; \ } \ M_CALL_CLEAR(oplist, removing_point->current->data); \ - M_C3(m_l1st_,name,_del) (removing_point->current); \ + M_CALL_DEL(oplist, removing_point->current); \ removing_point->current = next; \ M_L1ST_CONTRACT(list); \ } \ \ - M_INLINE void \ - M_F(name, _init_set)(list_t list, const list_t org) \ + M_P(void, name, _init_set, list_t list, const list_t org) \ { \ M_L1ST_CONTRACT(org); \ struct M_F(name, _s) *m_volatile next = NULL; \ @@ -546,11 +511,12 @@ struct M_F(name, _s) **update_list; \ update_list = list; \ it_org = *org; \ - /* On exceptions, free node and clear list*/ \ + /* If exceptions, always keep list as a valid list */ \ M_IF_EXCEPTION(*update_list = NULL); \ - M_ON_EXCEPTION(M_C3(m_l1st_,name,_del)(next), M_F(name, _clear)(list) ) \ + /* On exceptions, free node and clear list*/ \ + M_ON_EXCEPTION(M_CALL_DEL(oplist, next), M_F(name, _clear)(list) ) \ while (it_org != NULL) { \ - next = M_C3(m_l1st_,name,_new)(); \ + next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ *update_list = NULL; \ @@ -566,13 +532,12 @@ M_L1ST_CONTRACT(list); \ } \ \ - M_INLINE void \ - M_F(name, _set)(list_t list, const list_t org) \ + M_P(void, name, _set, list_t list, const list_t org) \ { \ if (M_UNLIKELY (list == org)) return; \ M_ON_EXCEPTION(M_F(name, _init)(list) ) { \ - M_F(name, _clear)(list); \ - M_F(name, _init_set)(list, org); \ + M_F(name, _clear)M_R(list); \ + M_F(name, _init_set)M_R(list, org); \ } \ } \ \ @@ -585,11 +550,10 @@ *org = NULL; /* safer */ \ } \ \ - M_INLINE void \ - M_F(name, _move)(list_t list, list_t org) \ + M_P(void, name, _move, list_t list, list_t org) \ { \ M_ASSERT (list != org); \ - M_F(name, _clear)(list); \ + M_F(name, _clear)M_R(list); \ M_F(name, _init_move)(list, org); \ } \ \ @@ -699,12 +663,10 @@ #define M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) \ \ M_IF_METHOD(GET_STR, oplist)( \ - M_INLINE void \ - M_F(name, _get_str)(m_string_t str, const list_t list, \ - bool append) \ + M_P(void, name, _get_str, m_string_t str, const list_t list, bool append) \ { \ M_ASSERT (str != NULL && list != NULL); \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \ it_t it; \ for (M_F(name, _it)(it, list) ; \ !M_F(name, _end_p)(it); \ @@ -712,9 +674,9 @@ type const *item = M_F(name, _cref)(it); \ M_CALL_GET_STR(oplist, str, *item, true); \ if (!M_F(name, _last_p)(it)) \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ } \ - m_string_push_back (str, ']'); \ + m_string_push_back M_R(str, ']'); \ } \ , /* no str */ ) \ \ @@ -738,11 +700,10 @@ , /* no out_str */ ) \ \ M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(list_t list, const char str[], const char **endp) \ + M_P(bool, name, _parse_str, list_t list, const char str[], const char **endp) \ { \ M_ASSERT (str != NULL && list != NULL); \ - M_F(name,_reset)(list); \ + M_F(name,_reset)M_R(list); \ bool success = false; \ int c = *str++; \ if (M_UNLIKELY (c != '[')) goto exit; \ @@ -755,7 +716,7 @@ bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ c = m_core_str_nospace(&str); \ if (b == false || c == 0) { c = 0; break; } \ - M_F(name, _push_back)(list, item); \ + M_F(name, _push_back)M_R(list, item); \ } while (c == M_GET_SEPARATOR oplist); \ success = (c == ']'); \ } \ @@ -767,11 +728,10 @@ , /* no PARSE_STR & INIT */ ) \ \ M_IF_METHOD2(IN_STR, INIT, oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(list_t list, FILE *file) \ + M_P(bool, name, _in_str, list_t list, FILE *file) \ { \ M_ASSERT (file != NULL && list != NULL); \ - M_F(name,_reset)(list); \ + M_F(name,_reset)M_R(list); \ int c = fgetc(file); \ if (M_UNLIKELY (c != '[')) return false; \ c = fgetc(file); \ @@ -783,7 +743,7 @@ bool b = M_CALL_IN_STR(oplist, item, file); \ c = m_core_fgetc_nospace(file); \ if (b == false || c == EOF) { c = 0; break; } \ - M_F(name, _push_back)(list, item); \ + M_F(name, _push_back)M_R(list, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ M_F(name, _reverse)(list); \ @@ -821,22 +781,21 @@ , /* no OUT_SERIAL */ ) \ \ M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(list_t list, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, list_t list, m_serial_read_t f) \ { \ M_ASSERT (list != NULL); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_return_code_t ret; \ m_serial_local_t local; \ size_t estimated_size = 0; \ - M_F(name,_reset)(list); \ + M_F(name,_reset)M_R(list); \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ M_QLET(1, item, type, oplist) { \ do { \ ret = M_CALL_IN_SERIAL(oplist, item, f); \ if (ret != M_SERIAL_OK_DONE) { break; } \ - M_F(name, _push_back)(list, item); \ + M_F(name, _push_back)M_R(list, item); \ ret = f->m_interface->read_array_next(local, f); \ } while (ret == M_SERIAL_OK_CONTINUE); \ } \ @@ -890,15 +849,13 @@ /* Definition of the emplace_back function for single list */ #define M_L1ST_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_F(name, _subtype_ct) *data = M_F(name, _push_raw)(v); \ + M_F(name, _subtype_ct) *data = M_F(name, _push_raw)M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ M_IF_EXCEPTION(struct M_F(name, _s) *next = *v ); \ - M_ON_EXCEPTION( *v = next->next, M_C3(m_l1st_,name,_del)(next)) { \ + M_ON_EXCEPTION( *v = next->next, M_CALL_DEL(oplist, next)) { \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ } \ } @@ -906,15 +863,13 @@ /* Definition of the emplace_back function for dual push list */ #define M_L1ST_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)(v); \ + M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \ - M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \ + M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ } \ } @@ -922,17 +877,15 @@ /* Definition of the emplace_front function for dual push list */ #define M_L1ST_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ - M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)(v); \ + M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \ - M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \ + M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ } \ } @@ -969,10 +922,9 @@ #define M_L1ST_DUAL_PUSH_DEF_P3(name, type, oplist, list_t, it_t) \ M_L1ST_DUAL_PUSH_DEF_TYPE(name, type, oplist, list_t, it_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_L1ST_MEMPOOL_DEF(name, type, oplist, list_t, it_t) \ M_L1ST_DUAL_PUSH_DEF_P4(name, type, oplist, list_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_back), oplist, M_L1ST_EMPLACE_BACK_DEF) \ - M_EMPLACE_QUEUE_DEF(name, list_t, M_F(name, _emplace_front), oplist, M_L1ST_EMPLACE_FRONT_DEF) \ + M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_back, oplist, M_L1ST_EMPLACE_BACK_DEF) \ + M_EMPLACE_QUEUE_DEF(name, list_t, _emplace_front, oplist, M_L1ST_EMPLACE_FRONT_DEF) \ M_L1ST_ITBASE_DEF(name, type, oplist, list_t, it_t) @@ -1026,15 +978,14 @@ M_L1ST_DUAL_PUSH_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(list_t v) \ + M_P(void, name, _reset, list_t v) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(v); \ struct M_F(name, _s) *it = v->back; \ while (it != NULL) { \ struct M_F(name, _s) *next = it->next; \ M_CALL_CLEAR(oplist, it->data); \ - M_C3(m_l1st_,name,_del)(it); \ + M_CALL_DEL(oplist, it); \ it = next; \ } \ v->front = NULL; \ @@ -1042,10 +993,9 @@ M_L1ST_DUAL_PUSH_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(list_t v) \ + M_P(void, name, _clear, list_t v) \ { \ - M_F(name, _reset)(v); \ + M_F(name, _reset)M_R(v); \ } \ \ M_INLINE type * \ @@ -1056,11 +1006,10 @@ return &(v->back->data); \ } \ \ - M_INLINE type * \ - M_F(name, _push_back_raw)(list_t v) \ + M_P(type *, name, _push_back_raw, list_t v) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(v); \ - struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \ + struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ return NULL; \ @@ -1069,7 +1018,7 @@ next->next = v->back; \ v->back = next; \ /* Update front too if the list was empty */ \ - /* This C code shall generate branchless code */ \ + /* This C code should generate branchless code */ \ struct M_F(name, _s) *front = v->front; \ front = (front == NULL) ? next : front; \ v->front = front; \ @@ -1078,57 +1027,51 @@ } \ \ /* Internal, for INIT_WITH */ \ - M_INLINE type * \ - M_F(name, _push_raw)(list_t d) \ + M_P(type *, name, _push_raw, list_t d) \ { \ - return M_F(name, _push_back_raw)(d); \ + return M_F(name, _push_back_raw)M_R(d); \ } \ \ - M_INLINE void \ - M_F(name, _push_back)(list_t v, type const x) \ + M_P(void, name, _push_back, list_t v, type const x) \ { \ - type *data = M_F(name, _push_back_raw)(v); \ + type *data = M_F(name, _push_back_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \ - M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \ + M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \ M_CALL_INIT_SET(oplist, *data, x); \ } \ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _push_back_new)(list_t v) \ + M_P(type *, name, _push_back_new, list_t v) \ { \ - type *data = M_F(name, _push_back_raw)(v); \ + type *data = M_F(name, _push_back_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return NULL; \ M_IF_EXCEPTION(struct M_F(name, _s) *next = v->back); \ - M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_C3(m_l1st_,name,_del)(next)) { \ + M_ON_EXCEPTION( v->back = next->next, v->front = (v->front == next) ? NULL : v->front, M_CALL_DEL(oplist, next)) { \ M_CALL_INIT(oplist, *data); \ } \ return data; \ } \ , /* No INIT */ ) \ \ - M_INLINE void \ - M_F(name, _push_back_move)(list_t v, type *x) \ + M_P(void, name, _push_back_move, list_t v, type *x) \ { \ M_ASSERT (x != NULL); \ - type *data = M_F(name, _push_back_raw)(v); \ + type *data = M_F(name, _push_back_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ M_DO_INIT_MOVE (oplist, *data, *x); \ } \ \ - M_INLINE void \ - M_F(name, _push_move)(list_t v, type *x) \ + M_P(void, name, _push_move, list_t v, type *x) \ { \ - M_F(name, _push_back_move)(v, x); \ + M_F(name, _push_back_move)M_R(v, x); \ } \ \ - M_INLINE void \ - M_F(name, _pop_back)(type *data, list_t v) \ + M_P(void, name, _pop_back, type *data, list_t v) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_ASSERT (v->back != NULL); \ @@ -1139,7 +1082,7 @@ M_CALL_CLEAR(oplist, tofree->data); \ } \ v->back = tofree->next; \ - M_C3(m_l1st_,name,_del)(tofree); \ + M_CALL_DEL(oplist, tofree); \ /* Update front too if the list became empty */ \ /* This C code shall generate branchless code */ \ struct M_F(name, _s) *front = v->front; \ @@ -1148,8 +1091,7 @@ M_L1ST_DUAL_PUSH_CONTRACT(v); \ } \ \ - M_INLINE void \ - M_F(name, _pop_move)(type *data, list_t v) \ + M_P(void, name, _pop_move, type *data, list_t v) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(v); \ M_ASSERT (v->back != NULL); \ @@ -1157,7 +1099,7 @@ struct M_F(name, _s) *tofree = v->back; \ M_DO_INIT_MOVE (oplist, *data, tofree->data); \ v->back = tofree->next; \ - M_C3(m_l1st_,name,_del)(tofree); \ + M_CALL_DEL(oplist, tofree); \ /* Update front too if the list became empty */ \ /* This C code shall generate branchless code */ \ struct M_F(name, _s) *front = v->front; \ @@ -1174,11 +1116,10 @@ return &(v->front->data); \ } \ \ - M_INLINE type * \ - M_F(name, _push_front_raw)(list_t v) \ + M_P(type *, name, _push_front_raw, list_t v) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(v); \ - struct M_F(name, _s) *next = M_C3(m_l1st_,name,_new)(); \ + struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ return NULL; \ @@ -1196,22 +1137,20 @@ return ret; \ } \ \ - M_INLINE void \ - M_F(name, _push_front)(list_t v, type const x) \ + M_P(void, name, _push_front, list_t v, type const x) \ { \ M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ - type *data = M_F(name, _push_front_raw)(v); \ + type *data = M_F(name, _push_front_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \ - M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \ + M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \ M_CALL_INIT_SET(oplist, *data, x); \ } \ } \ \ - M_INLINE void \ - M_F(name, _push_front_move)(list_t v, type *x) \ + M_P(void, name, _push_front_move, list_t v, type *x) \ { \ M_ASSERT (x != NULL); \ type *data = M_F(name, _push_front_raw)(v); \ @@ -1221,8 +1160,7 @@ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _push_front_new)(list_t v) \ + M_P(type *, name, _push_front_new, list_t v) \ { \ M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ type *data = M_F(name, _push_front_raw)(v); \ @@ -1230,7 +1168,7 @@ return NULL; \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ M_IF_EXCEPTION(M_ASSERT(tofree != NULL)); \ - M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_C3(m_l1st_,name,_del)(tofree)) { \ + M_ON_EXCEPTION( v->back = back, v->front = front, (front != NULL ? front : tofree)->next = NULL, M_CALL_DEL(oplist, tofree)) { \ M_CALL_INIT(oplist, *data); \ } \ return data; \ @@ -1336,18 +1274,16 @@ return size; \ } \ \ - M_INLINE void \ - M_F(name, _insert)(list_t list, it_t insertion_point, \ - type const x) \ + M_P(void, name, _insert, list_t list, it_t insertion_point, type const x) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(list); \ M_ASSERT (insertion_point != NULL); \ - struct M_F(name, _s) *m_volatile next = M_C3(m_l1st_,name,_new)(); \ + struct M_F(name, _s) *m_volatile next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ } \ - M_ON_EXCEPTION( M_C3(m_l1st_,name,_del)(next)) \ + M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \ M_CALL_INIT_SET(oplist, next->data, x); \ if (M_UNLIKELY (insertion_point->current == NULL)) { \ next->next = list->back; \ @@ -1366,8 +1302,7 @@ } \ } \ \ - M_INLINE void \ - M_F(name, _remove)(list_t list, it_t removing_point) \ + M_P(void, name, _remove, list_t list, it_t removing_point) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(list); \ M_ASSERT (removing_point != NULL); \ @@ -1385,12 +1320,11 @@ list->front = front; \ /* Remove node */ \ M_CALL_CLEAR(oplist, removing_point->current->data); \ - M_C3(m_l1st_,name,_del) (removing_point->current); \ + M_CALL_DEL(oplist, removing_point->current); \ removing_point->current = next; \ } \ \ - M_INLINE void \ - M_F(name, _set)(list_t list, const list_t org) \ + M_P(void, name, _set, list_t list, const list_t org) \ { \ M_L1ST_DUAL_PUSH_CONTRACT(list); \ M_L1ST_DUAL_PUSH_CONTRACT(org); \ @@ -1398,13 +1332,13 @@ struct M_F(name, _s) *it_org; \ struct M_F(name, _s) **update_list; \ if (M_UNLIKELY (list == org)) return; \ - M_F(name, _reset)(list); \ + M_F(name, _reset)M_R(list); \ update_list = &list->back; \ it_org = org->back; \ M_ASSERT(*update_list == NULL); \ - M_ON_EXCEPTION(M_C3(m_l1st_,name,_del)(next) ) \ + M_ON_EXCEPTION(M_CALL_DEL(oplist, next) ) \ while (it_org != NULL) { \ - next = M_C3(m_l1st_,name,_new)(); \ + next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ return; \ @@ -1421,8 +1355,7 @@ } \ } \ \ - M_INLINE void \ - M_F(name, _init_set)(list_t list, const list_t org) \ + M_P(void, name, _init_set, list_t list, const list_t org) \ { \ M_ASSERT (list != org); \ M_ON_EXCEPTION( M_F(name, _clear)(list)) { \ @@ -1441,10 +1374,9 @@ org->front = NULL; \ } \ \ - M_INLINE void \ - M_F(name, _move)(list_t list, list_t org) \ + M_P(void, name, _move, list_t list, list_t org) \ { \ - M_F(name, _clear)(list); \ + M_F(name, _clear)M_R(list); \ M_F(name, _init_move)(list, org); \ } \ \ From bcc9f2c894b2e83e4cc981a00c0f64cf8937acd8 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 9 Mar 2025 20:41:17 +0100 Subject: [PATCH 20/91] Port B+TREE to new memory model --- m-bptree.h | 142 ++++++++++++++++++++++++++--------------------------- m-core.h | 24 +++++---- 2 files changed, 85 insertions(+), 81 deletions(-) diff --git a/m-bptree.h b/m-bptree.h index a99e03c9..a10af74c 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -343,6 +343,7 @@ M_BPTR33_DEF_IT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ M_BPTR33_DEF_EXT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist) + /* TODO: Check if key type has not disabled INIT_MOVE */ /* Define the types of a B+Tree */ #define M_BPTR33_DEF_TYPE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ @@ -406,7 +407,7 @@ \ /* Allocate a new node */ \ /* TODO: Can be specialized to alloc for leaf or for non leaf */ \ - M_INLINE node_t M_F(name, _new_node)(void) \ + M_INLINE node_t M_F(name, _new_node)(M_P_EXPAND_void) \ { \ M_STATIC_ASSERT(N >= 2, M_LIB_ILLEGAL_PARAM, \ "Number of items per node shall be >= 2."); \ @@ -420,9 +421,9 @@ return n; \ } \ \ - M_INLINE void M_F(name, _init)(tree_t b) \ + M_P(void, name, _init, tree_t b) \ { \ - b->root = M_F(name, _new_node)(); \ + b->root = M_F(name, _new_node)(M_R_EXPAND_void); \ b->size = 0; \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ } \ @@ -443,7 +444,7 @@ return num; \ } \ \ - M_INLINE void M_F(name, _reset)(tree_t b) \ + M_P(void, name, _reset, tree_t b) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ node_t next, n = b->root; \ @@ -486,19 +487,19 @@ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ } \ \ - M_INLINE void M_F(name, _clear)(tree_t b) \ + M_P(void, name, _clear, tree_t b) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ - M_F(name, _reset)(b); \ + M_F(name, _reset)M_R(b); \ /* Once the tree is clean, only the root remains */ \ M_CALL_DEL(key_oplist, b->root); \ b->root = NULL; \ } \ \ /* Copy recursively the node 'o' of root node 'root' */ \ - M_INLINE node_t M_F(name, _copy_node)(const node_t o, const node_t root) \ + M_P(node_t, name, _copy_node, const node_t o, const node_t root) \ { \ - node_t n = M_F(name, _new_node)(); \ + node_t n = M_F(name, _new_node)(M_R_EXPAND_void); \ /* Set default number of keys and type to copy */ \ n->num = o->num; \ /* By default it is not linked to its brother. \ @@ -520,7 +521,7 @@ /* Copy recursively the associated nodes if it is not a leaf */ \ for(int i = 0; i <= num; i++) { \ M_ASSERT(o->kind.node[i] != root); \ - n->kind.node[i] = M_F(name, _copy_node)(o->kind.node[i], root); \ + n->kind.node[i] = M_F(name, _copy_node)M_R(o->kind.node[i], root); \ } \ /* The copied nodes don't have their next field correct */ \ /* Fix the next field for the copied nodes */ \ @@ -542,22 +543,22 @@ return n; \ } \ \ - M_INLINE void M_F(name, _init_set)(tree_t b, const tree_t o) \ + M_P(void, name, _init_set, tree_t b, const tree_t o) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, o); \ M_ASSERT (b != NULL); \ /* Just copy recursively the root node */ \ - b->root = M_F(name, _copy_node)(o->root, o->root); \ + b->root = M_F(name, _copy_node)M_R(o->root, o->root); \ b->size = o->size; \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ } \ \ - M_INLINE void M_F(name, _set)(tree_t b, const tree_t o) \ + M_P(void, name, _set, tree_t b, const tree_t o) \ { \ /* NOTE: We could reuse the already allocated nodes of 'b'. \ Not sure if it worth the effort */ \ - M_F(name, _clear)(b); \ - M_F(name, _init_set)(b, o); \ + M_F(name, _clear)M_R(b); \ + M_F(name, _init_set)M_R(b, o); \ } \ \ M_INLINE bool M_F(name, _empty_p)(const tree_t b) \ @@ -573,7 +574,7 @@ return b->size; \ } \ \ - M_INLINE node_t M_F(name, _search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \ + M_INLINE node_t M_F(name, _i_search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \ { \ node_t n = b->root; \ int np = 0; \ @@ -607,7 +608,7 @@ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ pit_t pit; \ /* Get the leaf node where the key can be */ \ - node_t n = M_F(name, _search_for_leaf)(pit, b, key); \ + node_t n = M_F(name, _i_search_for_leaf)(pit, b, key); \ int cmp = 0; \ M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ /* Search in the leaf for key */ \ @@ -627,11 +628,11 @@ return M_CONST_CAST(value_t, M_F(name, _get)(b, key)); \ } \ \ - M_INLINE int \ - M_F(name, _search_and_insert_in_leaf)(node_t n, key_t const key \ + M_P(int, name, _i_search_and_insert_in_leaf, node_t n, key_t const key \ M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \ { \ M_ASSERT (M_F(name, _is_leaf)(n)); \ + M_ASSERT_POOL(); \ int i, num = M_F(name, _get_num)(n); \ M_ASSERT (num <= N); \ /* Search for the key in the node n (a leaf) for insertion */ \ @@ -659,10 +660,10 @@ return i; \ } \ \ - M_INLINE int \ - M_F(name, _search_and_insert_in_node)(node_t n, node_t l, key_t key) \ + M_P(int, name, _i_search_and_insert_in_node, node_t n, node_t l, key_t key) \ { \ M_ASSERT (!M_F(name, _is_leaf)(n)); \ + M_ASSERT_POOL(); \ int i, num = M_F(name, _get_num)(n); \ M_ASSERT (num <= N); \ /* Search for the key in the node n (not a leaf) for insertion */ \ @@ -682,16 +683,16 @@ return i; \ } \ \ - M_INLINE void \ - M_IF(isMap)(M_F(name, _set_at),M_F(name,_push))(tree_t b, key_t const key \ - M_IF(isMap)(M_DEFERRED_COMMA value_t const value,)) \ + M_IF(isMap)( \ + M_P(void, name, _set_at, tree_t b, key_t const key, value_t const value) , \ + M_P(void, name, _push, tree_t b, key_t const key) ) \ { \ pit_t pit; \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ - node_t leaf = M_F(name, _search_for_leaf)(pit, b, key); \ + node_t leaf = M_F(name, _i_search_for_leaf)(pit, b, key); \ /* Insert key into the leaf.*/ \ /* NOTE: Even if there is N elements, we can still add one more.*/ \ - int i = M_F(name, _search_and_insert_in_leaf)(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \ + int i = M_F(name, _i_search_and_insert_in_leaf)M_R(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \ if (i < 0) { \ /* Nothing to do anymore. key already exists in the tree. \ value has been updated if needed */ \ @@ -713,7 +714,7 @@ /* leaf is full: need to slip the leaf in two */ \ int nnum = (N + 1) / 2; \ num = N + 1 - nnum; \ - node_t nleaf = M_F(name, _new_node)(); \ + node_t nleaf = M_F(name, _new_node)(M_R_EXPAND_void); \ /* Move half objects to the new node */ \ memmove(&nleaf->key[0], &leaf->key[num], sizeof(key_t)*(unsigned int)nnum); \ M_IF(isMap)(memmove(&nleaf->kind.value[0], &leaf->kind.value[num], sizeof(value_t)*(unsigned int)nnum);,) \ @@ -728,7 +729,7 @@ while (true) { \ if (pit->num == 0) { \ /* We reach root ==> Need to increase the height of the tree.*/ \ - node_t parent = M_F(name, _new_node)(); \ + node_t parent = M_F(name, _new_node)(M_R_EXPAND_void); \ parent->num = 1; \ /* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \ M_CALL_INIT_SET(key_oplist, parent->key[0], *key_ptr); \ @@ -741,7 +742,7 @@ /* Non root node. Get the parent node */ \ node_t parent = pit->parent[--pit->num]; \ /* Insert into parent (It is big enough to receive temporary one more) */ \ - i = M_F(name, _search_and_insert_in_node)(parent, leaf, *key_ptr); \ + i = M_F(name, _i_search_and_insert_in_node)M_R(parent, leaf, *key_ptr); \ parent->kind.node[i] = leaf; \ parent->kind.node[i+1] = nleaf; \ /* Test if parent node is full? */ \ @@ -754,7 +755,7 @@ int nnp = N / 2; \ int np = N - nnp; \ M_ASSERT (nnp > 0 && np > 0 && nnp+np+1 == N+1); \ - node_t nparent = M_F(name, _new_node)(); \ + node_t nparent = M_F(name, _new_node)(M_R_EXPAND_void); \ /* Move half items to new node (Like a classic B-TREE) \ and the median key to the grand-parent*/ \ memmove(&nparent->key[0], &parent->key[np+1], sizeof(key_t)*(unsigned int)nnp); \ @@ -772,7 +773,7 @@ } \ } \ \ - M_INLINE value_t *M_F(name, _safe_get)(tree_t b, key_t const key) \ + M_P(value_t *, name, _safe_get, tree_t b, key_t const key) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ /* Not optimized implementation */ \ @@ -781,7 +782,7 @@ M_IF(isMap)( \ value_t v; \ M_CALL_INIT(value_oplist, v); \ - M_F(name, _set_at)(b, key, v); \ + M_F(name, _set_at)M_R(b, key, v); \ M_CALL_CLEAR(value_oplist, v); \ , \ M_F(name, _push)(b, key); \ @@ -791,10 +792,10 @@ return ret; \ } \ \ - M_INLINE int \ - M_F(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \ + M_P(int, name, _i_search_and_remove_in_leaf, node_t n, key_t const key) \ { \ M_ASSERT(M_F(name, _is_leaf)(n)); \ + M_ASSERT_POOL(); \ const int num = M_F(name, _get_num)(n); \ for(int i = 0; i < num; i++) { \ const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ @@ -811,10 +812,11 @@ return -1; /* Not found */ \ } \ \ - M_INLINE void M_F(name, _left_shift)(node_t parent, int k) \ + M_P(void, name, _i_left_shift, node_t parent, int k) \ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ + M_ASSERT_POOL(); \ node_t left = parent->kind.node[k]; \ node_t right = parent->kind.node[k+1]; \ M_ASSERT (left != NULL && right != NULL); \ @@ -846,10 +848,11 @@ M_ASSERT (left->num != 0); \ } \ \ - M_INLINE void M_F(name, _right_shift)(node_t parent, int k) \ + M_P(void, name, _i_right_shift, node_t parent, int k) \ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ + M_ASSERT_POOL(); \ node_t left = parent->kind.node[k]; \ node_t right = parent->kind.node[k+1]; \ M_ASSERT (left != NULL && right != NULL); \ @@ -880,7 +883,7 @@ M_ASSERT (left->num != 0); \ } \ \ - M_INLINE void M_F(name, _merge_node)(node_t parent, int k, bool leaf) \ + M_P(void, name, _i_merge_node, node_t parent, int k, bool leaf) \ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num(parent))); \ @@ -916,7 +919,7 @@ /* We can also cache the index when we descend the tree. \ TODO: Bench if this is worth the effort.*/ \ M_INLINE int \ - M_F(name, _search_for_node)(node_t parent, node_t child) \ + M_F(name, _i_search_for_node)(node_t parent, node_t child) \ { \ M_ASSERT (!M_F(name, _is_leaf)(parent)); \ int i = 0; \ @@ -928,12 +931,12 @@ } \ } \ \ - M_INLINE bool M_F(name, _erase)(tree_t b, key_t const key) \ + M_P(bool, name, _erase, tree_t b, key_t const key) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ pit_t pit; \ - node_t leaf = M_F(name, _search_for_leaf)(pit, b, key); \ - int k = M_F(name, _search_and_remove_in_leaf)(leaf, key); \ + node_t leaf = M_F(name, _i_search_for_leaf)(pit, b, key); \ + int k = M_F(name, _i_search_and_remove_in_leaf)M_R(leaf, key); \ /* If key is not found ==> erase failed */ \ if (k < 0) return false; \ /* Remove one item from the B+TREE */ \ @@ -949,15 +952,15 @@ /* Search for node 'leaf' in parent */ \ node_t parent = pit->parent[--pit->num]; \ M_ASSERT (parent != NULL); \ - k = M_F(name, _search_for_node)(parent, leaf); \ + k = M_F(name, _i_search_for_node)(parent, leaf); \ /* Look for the neighbour of the removed key. */ \ /* if we can steal one key from them to keep our node balanced */ \ if (k > 0 && M_F(name, _get_num)(parent->kind.node[k-1]) > N/2) { \ - M_F(name, _left_shift)(parent, k-1); \ + M_F(name, _i_left_shift)M_R(parent, k-1); \ return true; \ } else if (k < M_F(name, _get_num)(parent) \ && M_F(name, _get_num)(parent->kind.node[k+1]) > N/2) { \ - M_F(name, _right_shift)(parent, k); \ + M_F(name, _i_right_shift)M_R(parent, k); \ return true; \ } \ /* Merge both nodes, removing 'k' from parent */ \ @@ -965,7 +968,7 @@ k--; \ M_ASSERT(k >= 0 && k < M_F(name, _get_num)(parent)); \ /* Merge 'k' & 'k+1' & remove 'k' from parent */ \ - M_F(name, _merge_node)(parent, k, pass1); \ + M_F(name, _i_merge_node)M_R(parent, k, pass1); \ /* Check if we need to continue */ \ if (M_F(name, _get_num)(parent) >= N/2) \ return true; \ @@ -984,16 +987,17 @@ } \ } \ \ - M_INLINE bool M_F(name, _pop_at)(value_t *ptr, tree_t b, key_t const key) \ + M_P(bool, name, _pop_at, value_t *ptr, tree_t b, key_t const key) \ { \ if (ptr != NULL) { \ + /* Not optimized tree parsing */ \ value_t *ref = M_F(name, _get)(b, key); \ if (ref == NULL) { \ return false; \ } \ M_CALL_SET(value_oplist, *ptr, *ref); \ } \ - return M_F(name, _erase)(b, key); \ + return M_F(name, _erase)M_R(b, key); \ } \ \ M_INLINE value_t * \ @@ -1046,13 +1050,12 @@ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ } \ \ - M_INLINE void \ - M_F(name, _move)(tree_t b, tree_t ref) \ + M_P(void, name, _move, tree_t b, tree_t ref) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \ M_ASSERT (b != ref); \ - M_F(name,_clear)(b); \ + M_F(name,_clear)M_R(b); \ M_F(name,_init_move)(b, ref); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ } \ @@ -1161,7 +1164,7 @@ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_ASSERT (it != NULL); \ pit_t pit; \ - node_t n = M_F(name, _search_for_leaf)(pit, b, key); \ + node_t n = M_F(name, _i_search_for_leaf)(pit, b, key); \ it->node = n; \ int i; \ M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ @@ -1259,29 +1262,29 @@ , /* NO HASH METHOD */ ) \ \ M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ - M_INLINE void M_F(name, _get_str)(m_string_t str, \ - const tree_t t1, bool append) { \ + M_P(void, name, _get_str, m_string_t str, const tree_t t1, bool append) \ + { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_ASSERT(str != NULL); \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \ bool commaToPrint = false; \ it_t it; \ for (M_F(name, _it)(it, t1) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)) { \ if (commaToPrint) \ - m_string_push_back (str, M_GET_SEPARATOR key_oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR key_oplist); \ commaToPrint = true; \ subtype_t const *ref1 = M_F(name, _cref)(it); \ M_IF(isMap)( \ M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \ - m_string_cat_cstr(str, ":"); \ + m_string_cat_cstr M_R(str, ":"); \ M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \ , \ M_CALL_GET_STR(key_oplist, str, *ref1, true); \ ); \ } \ - m_string_push_back (str, ']'); \ + m_string_push_back M_R(str, ']'); \ } \ , /* NO GET_STR */ ) \ \ @@ -1314,12 +1317,11 @@ , /* no out_str */ ) \ \ M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(tree_t t1, const char str[], const char **endp) \ + M_P(bool, name, _parse_str, tree_t t1, const char str[], const char **endp) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_ASSERT (str != NULL); \ - M_F(name,_reset)(t1); \ + M_F(name,_reset)M_R(t1); \ int c = *str++; \ if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \ c = *str++; \ @@ -1335,9 +1337,9 @@ b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ c = m_core_str_nospace(&str); \ if (b == false || c == 0) { c = 0; break; } \ - M_F(name, _set_at)(t1, key, value); \ + M_F(name, _set_at)M_R(t1, key, value); \ , \ - M_F(name, _push)(t1, key); \ + M_F(name, _push)M_R(t1, key); \ ) \ } while (c == M_GET_SEPARATOR key_oplist); \ } \ @@ -1349,12 +1351,11 @@ , /* no parse_str */ ) \ \ M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(tree_t t1, FILE *file) \ + M_P(bool, name, _in_str, tree_t t1, FILE *file) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_ASSERT (file != NULL); \ - M_F(name,_reset)(t1); \ + M_F(name,_reset)M_R(t1); \ int c = fgetc(file); \ if (M_UNLIKELY (c != '[')) return false; \ c = fgetc(file); \ @@ -1371,9 +1372,9 @@ b = M_CALL_IN_STR(value_oplist,value, file); \ c = m_core_fgetc_nospace(file); \ if (b == false || c == EOF) { c = 0; break; } \ - M_F(name, _set_at)(t1, key, value) \ + M_F(name, _set_at)M_R(t1, key, value) \ , \ - M_F(name, _push)(t1, key) \ + M_F(name, _push)M_R(t1, key) \ ); \ } while (c == M_GET_SEPARATOR key_oplist); \ } \ @@ -1427,15 +1428,14 @@ , /* no OUT_SERIAL */ ) \ \ M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, tree_t t1, m_serial_read_t f) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ m_serial_return_code_t ret; \ size_t estimated_size = 0; \ - M_F(name,_reset)(t1); \ + M_F(name,_reset)M_R(t1); \ M_QLET(1, key, key_t, key_oplist) \ M_IF(isMap)(M_QLET(2, value, value_t, value_oplist) , /*nothing*/) { \ M_IF(isMap)( \ @@ -1448,7 +1448,7 @@ if (ret != M_SERIAL_OK_CONTINUE) break; \ ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ if (ret != M_SERIAL_OK_DONE) break; \ - M_F(name, _set_at)(t1, key, value); \ + M_F(name, _set_at)M_R(t1, key, value); \ } while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \ , /* queue style */ \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ @@ -1456,7 +1456,7 @@ do { \ ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ if (ret != M_SERIAL_OK_DONE) break; \ - M_F(name, _push)(t1, key); \ + M_F(name, _push)M_R(t1, key); \ } while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \ ) /* End of IF isMap */ \ } \ diff --git a/m-core.h b/m-core.h index d7b04d44..7e8166d4 100644 --- a/m-core.h +++ b/m-core.h @@ -412,33 +412,37 @@ M_BEGIN_PROTECTED_CODE #endif +// FIXME: Rename to M_USE_MEMORY_CONTEXT? #ifndef M_USE_POOL // Memory pool parameter not used for memory function. Stub it with 0 as it won't be used (global definition). # define M_P_EXPAND +# define M_P_EXPAND_void void # define M_R_EXPAND +# define M_R_EXPAND_void # define M_R # define M_ASSERT_POOL() #else // Memory pool parameter is used for function using memory. (local definition to the function). // Expand to a prototype to a function that may not trigger exception # define M_P_EXPAND M_USE_POOL m_pool, +# define M_P_EXPAND_void M_USE_POOL m_pool # define M_R_EXPAND m_pool , +# define M_R_EXPAND_void m_pool # define M_R(...) (m_pool, __VA_ARGS__) # define M_ASSERT_POOL() (void) m_pool #endif -// Expand to a prototype of a function that may trigger exception / accept memory context -// TODO: If not M_F, M_INLINE overloaded and no M_P_EXPAND, simplify M_P -// (faster build: 0.54s instead of 0.80s in extreme expanding +// M_P: Expand to a prototype of a function that may trigger exception / accept memory context +// M_N: Expand to a prototype of a function that may not trigger exception or accept memory context +// If not M_F, no overloaded M_INLINE and no M_P_EXPAND, simplify M_P +// (faster build: 0.54s instead of 0.80s in extreme expanding) +#if !defined(M_USE_POOL) && !defined(M_F) && !defined(M_USE_FINE_GRAINED_LINKAGE) && !defined(M_USE_DEF) && !defined(M_USE_DECL) +# define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) +# define M_N(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) +#else # define M_P(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(M_P_EXPAND __VA_ARGS__) -//#define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) - -// Expand to a prototype of a function that may not trigger exception or accept memory context # define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__) - - -// TODO: Add for API special, the support of the POOL special keyword ==> m_pool -// Or document m_pool directly? Can still be overriden later. +#endif // TODO: Add for all Assertions: M_ASSERT_POOL() // to avoid warnings about unused parameter m_pool. From e959c001aa6a051f251ef0f3bbb06a95d531bcf1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 13 Mar 2025 23:19:21 +0100 Subject: [PATCH 21/91] Port to new memory model --- m-core.h | 21 +++--- m-dict.h | 204 +++++++++++++++++++++++-------------------------------- 2 files changed, 93 insertions(+), 132 deletions(-) diff --git a/m-core.h b/m-core.h index 7e8166d4..0d894e68 100644 --- a/m-core.h +++ b/m-core.h @@ -5085,7 +5085,7 @@ m_core_parse2_enum (const char str[], const char **endptr) #define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(isSet, name, name_t, key_oplist, val_oplist) \ M_ID( M_C(M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF, isSet)(name, name_t, key_oplist, val_oplist) ) #define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF0(name, name_t, key_oplist, val_oplist) \ - M_EMPLACE_ASS_ARRAY_DEF(name, name_t, M_F(name, _emplace), key_oplist, val_oplist, M_EMPLACE_ASS_ARRA1_BOTH_GENE, M_EMPLACE_ASS_ARRA1_KEY_GENE, M_EMPLACE_ASS_ARRA1_VAL_GENE) \ + M_EMPLACE_ASS_ARRAY_DEF(name, name_t, _emplace, key_oplist, val_oplist, M_EMPLACE_ASS_ARRA1_BOTH_GENE, M_EMPLACE_ASS_ARRA1_KEY_GENE, M_EMPLACE_ASS_ARRA1_VAL_GENE) \ M_EMPLACE_QUEUE_DEF(name, name_t, _get_emplace, key_oplist, M_EMPLACE_GET_GENE) #define M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF1(name, name_t, key_oplist, val_oplist) \ M_EMPLACE_QUEUE_DEF(name, name_t, _emplace, key_oplist, M_EMPLACE_QUEUE_GENE) \ @@ -5100,39 +5100,36 @@ m_core_parse2_enum (const char str[], const char **endptr) one for value only. */ #define M_EMPLACE_ASS_ARRA1_BOTH_GENE(name, name_t, function_name, key_oplist, val_oplist, key_init_func, val_init_func, key_emplace_type, val_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ + M_P(void, name, function_name, name_t v \ M_EMPLACE_LIST_TYPE_VAR(akey, key_emplace_type) \ M_EMPLACE_LIST_TYPE_VAR(aval, val_emplace_type) \ ){ \ M_F(name, _key_ct) key; \ M_EMPLACE_CALL_FUNC(akey, key_init_func, key_oplist, key, key_emplace_type); \ M_F(name, _value_ct) *val; \ - val = M_F(name, _safe_get)(v, key); \ + val = M_F(name, _safe_get)M_R(v, key); \ M_CALL_CLEAR(val_oplist, *val); \ M_EMPLACE_CALL_FUNC(aval, val_init_func, val_oplist, *val, val_emplace_type); \ M_CALL_CLEAR(key_oplist, key); \ } \ #define M_EMPLACE_ASS_ARRA1_KEY_GENE(name, name_t, function_name, key_oplist, val_oplist, key_init_func, val_init_func, key_emplace_type, val_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ + M_P(void, name, function_name, name_t v \ M_EMPLACE_LIST_TYPE_VAR(akey, key_emplace_type) \ , M_F(name, _value_ct) const val \ ){ \ M_F(name, _key_ct) key; \ M_EMPLACE_CALL_FUNC(akey, key_init_func, key_oplist, key, key_emplace_type); \ - M_F(name, _set_at)(v, key, val); \ + M_F(name, _set_at)M_R(v, key, val); \ M_CALL_CLEAR(key_oplist, key); \ } \ #define M_EMPLACE_ASS_ARRA1_VAL_GENE(name, name_t, function_name, key_oplist, val_oplist, key_init_func, val_init_func, key_emplace_type, val_emplace_type) \ - M_INLINE void \ - function_name(name_t v, M_F(name, _key_ct) const key \ + M_P(void, name, function_name, name_t v, M_F(name, _key_ct) const key \ M_EMPLACE_LIST_TYPE_VAR(aval, val_emplace_type) \ ){ \ M_F(name, _value_ct) *val; \ - val = M_F(name, _safe_get)(v, key); \ + val = M_F(name, _safe_get)M_R(v, key); \ M_CALL_CLEAR(val_oplist, *val); \ M_EMPLACE_CALL_FUNC(aval, val_init_func, val_oplist, *val, val_emplace_type); \ } \ @@ -5159,9 +5156,7 @@ m_core_parse2_enum (const char str[], const char **endptr) This definition is far from being efficient but works for the current interface. */ #define M_EMPLACE_GET_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE M_F(name, _value_ct) * \ - M_F(name, function_name)(name_t const v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(M_F(name, _value_ct) *, name, function_name, name_t const v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_GET_TYPE oplist data; \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \ diff --git a/m-dict.h b/m-dict.h index cfec705f..ed576162 100644 --- a/m-dict.h +++ b/m-dict.h @@ -27,7 +27,6 @@ #include "m-array.h" - /* Define a dictionary associating the key key_type to the value value_type and its associated functions. USAGE: DICT_DEF2(name, key_type, key_oplist, value_type, value_oplist) @@ -155,14 +154,14 @@ /******************************** INTERNAL ***********************************/ /*****************************************************************************/ -// Define the maximum index +// Define the maximum index type (implying the maximum allowed size) #ifdef M_USE_DICT_LARGE_INDEX typedef uint64_t m_index_t; #else typedef uint32_t m_index_t; #endif -// Define a pair index / hash +// Define a pair index of the cell where the (key,value) is stored / hash of the key. typedef struct { m_index_t index; m_index_t hash; @@ -328,8 +327,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) map->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (m_index_t) ((double) size * M_D1CT_OA_LOWER_BOUND) ; \ } \ \ - M_INLINE void \ - M_F(name, _init)(dict_t map) \ + M_P(void, name, _init, dict_t map) \ { \ M_ASSERT (map != NULL); \ map->mask = M_D1CT_INITIAL_SIZE-1; \ @@ -358,8 +356,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_D1CT_CONTRACT(map); \ } \ \ - M_INLINE void \ - M_F(name,_clear)(dict_t map) \ + M_P(void, name,_clear, dict_t map) \ { \ M_D1CT_CONTRACT(map); \ /* Clear objects */ \ @@ -384,7 +381,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) { \ M_D1CT_CONTRACT(org); \ memcpy(map, org, sizeof (dict_t)); \ - /* Mark the original dictionary as cleared */ \ + /* Mark the original dictionary as cleared (invalid representation) */ \ org->data = NULL; \ org->index = NULL; \ } \ @@ -452,8 +449,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) } \ } \ \ - M_INLINE void \ - M_C3(m_d1ct_,name,_resize_up)(dict_t h, m_index_t newSize, bool updateLimit) \ + M_P(void, name, _i_resize_up, dict_t h, m_index_t newSize, bool updateLimit) \ { \ /* NOTE: Contract may not be fulfilled here */ \ m_index_t oldSize = h->mask+1; \ @@ -512,7 +508,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) h->index[p].hash = hash; \ } else { \ m_indexhash_t t = { ind, hash }; \ - m_array_index_push_back(tmp, t); \ + m_array_index_push_back M_R(tmp, t); \ } \ } \ } \ @@ -522,7 +518,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) which contains what we weren't be able to fit in the first pass */ \ while (m_array_index_size(tmp) > 0) { \ m_indexhash_t ind; \ - m_array_index_pop_back(&ind, tmp); \ + m_array_index_pop_back M_R(&ind, tmp); \ m_index_t p = ind.hash & mask; \ /* NOTE: since the first pass, the bucket might be free now */ \ m_index_t s = 1; \ @@ -534,14 +530,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) h->index[p].hash = ind.hash; \ } \ \ - m_array_index_clear(tmp); \ + m_array_index_clear M_R(tmp); \ h->mask = newSize-1; \ h->count_delete = h->count; \ M_IF_DEBUG( M_C3(m_d1ct_,name,_control_after_resize)(h); ) \ } \ \ - M_INLINE void \ - M_C3(m_d1ct_,name,_resize_down)(dict_t h, m_index_t newSize) \ + M_P(void, name, _i_resize_down, dict_t h, m_index_t newSize) \ { \ /* NOTE: Contract may not be fulfilled here */ \ m_index_t oldSize = h->mask+1; \ @@ -564,7 +559,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) h->index[p].hash = hash; \ } else { \ m_indexhash_t t = { ind, hash }; \ - m_array_index_push_back(tmp, t); \ + m_array_index_push_back M_R(tmp, t); \ } \ } \ } \ @@ -584,7 +579,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* Pass 3: scan failed moved entries and move them back */ \ while (m_array_index_size(tmp) > 0) { \ m_indexhash_t ind; \ - m_array_index_pop_back(&ind, tmp); \ + m_array_index_pop_back M_R(&ind, tmp); \ m_index_t p = ind.hash & mask; \ m_index_t s = 1; \ while (h->index[p].index != 0) { \ @@ -595,7 +590,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) h->index[p].hash = ind.hash; \ } \ \ - m_array_index_clear(tmp); \ + m_array_index_clear M_R(tmp); \ h->count_delete = h->count; \ if (newSize != oldSize) { \ h->mask = newSize-1; \ @@ -608,10 +603,9 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_D1CT_CONTRACT(h); \ } \ \ - M_INLINE void \ - M_IF(isSet)(M_F(name, _push), M_F(name, _set_at)) \ - (dict_t map, key_type const key \ - M_IF(isSet)(, M_DEFERRED_COMMA value_type const value)) \ + M_IF(isSet)( \ + M_P(void, name, _push, dict_t map, key_type const key) , \ + M_P(void, name, _set_at, dict_t map, key_type const key, value_type const value)) \ { \ M_D1CT_CONTRACT(map); \ const m_index_t mask = map->mask; \ @@ -657,13 +651,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ - M_C3(m_d1ct_,name,_resize_up)(map, newSize, true); \ + M_F(name,_i_resize_up)M_R(map, newSize, true); \ } \ M_D1CT_CONTRACT(map); \ } \ \ - M_INLINE value_type * \ - M_F(name, _safe_get)(dict_t map, key_type const key) \ + M_P(value_type *, name, _safe_get, dict_t map, key_type const key) \ { \ M_D1CT_CONTRACT(map); \ const m_index_t mask = map->mask; \ @@ -716,15 +709,14 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ - M_C3(m_d1ct_,name,_resize_up)(map, newSize, true); \ + M_F(name,_i_resize_up)M_R(map, newSize, true); \ } \ M_D1CT_CONTRACT(map); \ /* bucket index won't move even if resize is done */ \ return &map->data[d].pair.M_IF(isSet)(key, value); \ } \ \ - M_INLINE bool \ - M_F(name, _erase)(dict_t map, key_type const key) \ + M_P(bool, name, _erase, dict_t map, key_type const key) \ { \ M_D1CT_CONTRACT(map); \ \ @@ -755,7 +747,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) M_ASSERT (map->count >= 1); \ map->count--; \ if (M_UNLIKELY (map->count < map->lower_limit)) { \ - M_C3(m_d1ct_,name,_resize_down)(map, (map->mask+1) >> 1); \ + M_F(name,_i_resize_down)M_R(map, (map->mask+1) >> 1); \ } \ M_D1CT_CONTRACT(map); \ return true; \ @@ -880,40 +872,36 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) #define M_D1CT_FUNC_ADDITIONAL_DEF2(name, key_type, key_oplist, value_type, value_oplist, isSet, dict_t, dict_it_t, it_deref_t) \ \ \ - M_INLINE void \ - M_F(name, _init_set)(dict_t map, const dict_t org) \ + M_P(void, name, _init_set, dict_t map, const dict_t org) \ { \ dict_it_t it; \ M_ASSERT (map != org); \ - M_F(name, _init)(map); \ + M_F(name, _init)M_R(map); \ /* Naive implementation. No need to optimize such access */ \ for (M_F(name,_it)(it, org); !M_F(name,_end_p)(it); M_F(name,_next)(it)){ \ M_IF(isSet)( \ - M_F(name,_push)(map, * M_F(name,_ref)(it) ) \ - , M_F(name,_set_at)(map, M_F(name,_ref)(it)->key, M_F(name,_ref)(it)->value) \ + M_F(name,_push)M_R(map, * M_F(name,_ref)(it) ) \ + , M_F(name,_set_at)M_R(map, M_F(name,_ref)(it)->key, M_F(name,_ref)(it)->value) \ ); \ } \ } \ \ - M_INLINE void \ - M_F(name, _set)(dict_t map, const dict_t org) \ + M_P(void, name, _set, dict_t map, const dict_t org) \ { \ if (M_LIKELY (map != org)) { \ /* Naive implementation. No need to optimize such access */ \ - M_F(name, _clear)(map); \ - M_F(name, _init_set)(map, org); \ + M_F(name, _clear)M_R(map); \ + M_F(name, _init_set)M_R(map, org); \ } \ } \ \ - M_INLINE void \ - M_F(name, _move)(dict_t map, dict_t org) \ + M_P(void, name, _move, dict_t map, dict_t org) \ { \ M_ASSERT (map != org); \ - M_F(name,_clear)(map); \ + M_F(name,_clear)M_R(map); \ M_F(name,_init_move)(map, org); \ } \ \ - \ M_INLINE void \ M_F(name, _swap)(dict_t d1, dict_t d2) \ { \ @@ -924,13 +912,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) memcpy( d2, tmp, sizeof (dict_t)); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(dict_t d) \ + M_P(void, name, _reset, dict_t d) \ { \ if (d->count == 0) return; \ /* Naive algorithm. Not work optimizing it */ \ - M_F(name, _clear)(d); \ - M_F(name, _init)(d); \ + M_F(name, _clear)M_R(d); \ + M_F(name, _init)M_R(d); \ } \ \ M_INLINE value_type const * \ @@ -953,14 +940,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) return map->count; \ } \ \ - M_INLINE void \ - M_F(name,_reserve)(dict_t dict, size_t capacity) \ + M_P(void, name,_reserve, dict_t dict, size_t capacity) \ { \ if (capacity == 0) { \ /* Perform a shrink to fit: copy everything to a new dict properly, and move it back */ \ dict_t tmp; \ - M_F(name, _init_set)(tmp, dict); \ - M_F(name, _move)(dict, tmp); \ + M_F(name, _init_set)M_R(tmp, dict); \ + M_F(name, _move)M_R(dict, tmp); \ return; \ } \ /* Get the size which will allow to fit this capacity \ @@ -975,7 +961,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) } \ if (size > dict->mask+1) { \ dict->upper_limit = (M_F(name, _index_ct)) ((double) size * M_D1CT_OA_UPPER_BOUND) - 1; \ - M_C3(m_d1ct_,name,_resize_up)(dict, size, false); \ + M_F(name,_i_resize_up)M_R(dict, size, false); \ } \ } \ \ @@ -1010,28 +996,27 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) , /* no value equal */ ) \ \ M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ - M_INLINE void \ - M_F(name, _get_str)(m_string_t str, const dict_t dict, const bool append) \ + M_P(void, name, _get_str, m_string_t str, const dict_t dict, const bool append) \ { \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "{"); \ + (append ? m_string_cat_cstr : m_string_set_cstr)M_R(str, "{"); \ dict_it_t it; \ bool print_comma = false; \ for (M_F(name, _it)(it, dict) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ if (print_comma) \ - m_string_push_back (str, ','); \ + m_string_push_back M_R(str, ','); \ const it_deref_t *item = M_F(name, _cref)(it); \ M_IF(isSet)( \ M_CALL_GET_STR(key_oplist, str, *item, true); \ , \ M_CALL_GET_STR(key_oplist, str, item->key, true); \ - m_string_push_back (str, ':'); \ + m_string_push_back M_R(str, ':'); \ M_CALL_GET_STR(value_oplist, str, item->value, true); \ ) \ print_comma = true; \ } \ - m_string_push_back (str, '}'); \ + m_string_push_back M_R(str, '}'); \ } \ , /* no GET_STR */ ) \ \ @@ -1063,11 +1048,10 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) , /* no OUT_STR */ ) \ \ M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(dict_t dict, const char str[], const char **endp) \ + M_P(bool, name, _parse_str, dict_t dict, const char str[], const char **endp) \ { \ M_ASSERT (str != NULL); \ - M_F(name, _reset)(dict); \ + M_F(name, _reset)M_R(dict); \ int c = m_core_str_nospace(&str); \ if (M_UNLIKELY (c != '{')) { c = 0; goto exit; } \ c = m_core_str_nospace(&str); \ @@ -1081,7 +1065,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) bool b = M_CALL_PARSE_STR(key_oplist, key, str, &str); \ M_IF(isSet)( \ if (b == false) { c = 0; break; } \ - M_F(name, _push)(dict, key); \ + M_F(name, _push)M_R(dict, key); \ , /* is a map */ \ c = m_core_str_nospace(&str); \ if (b == false || c != ':') { c = 0; break; } \ @@ -1089,7 +1073,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) str--; \ b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ if (b == false) { c = 0; break; } \ - M_F(name, _set_at)(dict, key, value); \ + M_F(name, _set_at)M_R(dict, key, value); \ ) \ c = m_core_str_nospace(&str); \ } while (c == ','); \ @@ -1101,11 +1085,10 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) , /* no PARSE_STR */ ) \ \ M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(dict_t dict, FILE *file) \ + M_P(bool, name, _in_str, dict_t dict, FILE *file) \ { \ M_ASSERT (file != NULL); \ - M_F(name, _reset)(dict); \ + M_F(name, _reset)M_R(dict); \ int c = m_core_fgetc_nospace(file); \ if (M_UNLIKELY (c != '{')) return false; \ c = m_core_fgetc_nospace(file); \ @@ -1121,7 +1104,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) bool b = M_CALL_IN_STR(key_oplist, key, file); \ M_IF(isSet)( \ if (M_UNLIKELY (b == false)) { c = 0; break; } \ - M_F(name, _push)(dict, key); \ + M_F(name, _push)M_R(dict, key); \ , /* is map */ \ c = m_core_fgetc_nospace(file); \ if (M_UNLIKELY (b == false || c != ':')) { c = 0; break; } \ @@ -1130,7 +1113,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) ungetc(c, file); \ b = M_CALL_IN_STR(value_oplist, value, file); \ if (M_UNLIKELY (b == false)) { c = 0; break; } \ - M_F(name, _set_at)(dict, key, value); \ + M_F(name, _set_at)M_R(dict, key, value); \ ) \ c = m_core_fgetc_nospace(file); \ } while (c == ','); \ @@ -1183,14 +1166,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) , /* no OUT_SERIAL */ ) \ \ M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(dict_t t1, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, dict_t t1, m_serial_read_t f) \ { \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ m_serial_return_code_t ret; \ size_t estimated_size = 0; \ - M_F(name,_reset)(t1); \ + M_F(name,_reset)M_R(t1); \ M_QLET(1, key, key_type, key_oplist) \ M_IF(isSet)(,M_QLET(2, value, value_type, value_oplist)) { \ M_IF(isSet)( \ @@ -1199,7 +1181,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) do { \ ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ if (ret != M_SERIAL_OK_DONE) break; \ - M_F(name, _push)(t1, key); \ + M_F(name, _push)M_R(t1, key); \ } while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \ , /* is map */ \ ret = f->m_interface->read_map_start(local, f, &estimated_size); \ @@ -1211,7 +1193,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) if (ret != M_SERIAL_OK_CONTINUE) break; \ ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ if (ret != M_SERIAL_OK_DONE) break; \ - M_F(name, _set_at)(t1, key, value); \ + M_F(name, _set_at)M_R(t1, key, value); \ } while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \ ) /* End of IF isSet */ \ } \ @@ -1220,8 +1202,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) , /* no in_serial */ ) \ \ M_IF(isSet)( \ - M_INLINE void \ - M_F(name, _splice)(dict_t d1, dict_t d2) \ + M_P(void, name, _splice, dict_t d1, dict_t d2) \ { \ dict_it_t it; \ M_ASSERT(d1 != d2); \ @@ -1230,14 +1211,13 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) uses the same order than d1 */ \ for (M_F(name, _it)(it, d2); !M_F(name, _end_p)(it); M_F(name, _next)(it)){ \ const it_deref_t *item = M_F(name, _cref)(it); \ - M_F(name, _push)(d1, *item); \ + M_F(name, _push)M_R(d1, *item); \ } \ - M_F(name, _reset)(d2); \ + M_F(name, _reset)M_R(d2); \ } \ , \ M_IF_METHOD(ADD, value_oplist)( \ - M_INLINE void \ - M_F(name, _splice)(dict_t d1, dict_t d2) \ + M_P(void, name, _splice, dict_t d1, dict_t d2) \ { \ dict_it_t it; \ /* NOTE: Despite using set_at, the accessing of the item in d1 \ @@ -1247,12 +1227,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) const struct M_F(name, _pair_s) *item = M_F(name, _cref)(it); \ value_type *ptr = M_F(name, _get)(d1, item->key); \ if (ptr == NULL) { \ - M_F(name, _set_at)(d1, item->key, item->value); \ + M_F(name, _set_at)M_R(d1, item->key, item->value); \ } else { \ M_CALL_ADD(value_oplist, *ptr, *ptr, item->value); \ } \ } \ - M_F(name, _reset)(d2); \ + M_F(name, _reset)M_R(d2); \ } \ , /* NO UPDATE */) ) \ \ @@ -1478,8 +1458,7 @@ enum m_d1ct_oa_element_e { dict->lower_limit = (size <= M_D1CT_INITIAL_SIZE) ? 0 : (size_t) ((double) size * coeff_down) ; \ } \ \ - M_INLINE void \ - M_F(name, _init)(dict_t dict) \ + M_P(void, name, _init, dict_t dict) \ { \ M_ASSERT(0 <= (coeff_down) && (coeff_down)*2 < (coeff_up) && (coeff_up) < 1); \ dict->mask = M_D1CT_INITIAL_SIZE-1; \ @@ -1499,8 +1478,7 @@ enum m_d1ct_oa_element_e { M_D1CT_OA_CONTRACT(dict); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(dict_t dict) \ + M_P(void, name, _clear, dict_t dict) \ { \ M_D1CT_OA_CONTRACT(dict); \ for(size_t i = 0; i <= dict->mask; i++) { \ @@ -1558,8 +1536,7 @@ enum m_d1ct_oa_element_e { } \ ) \ \ - M_INLINE void M_ATTR_COLD_FUNCTION \ - M_C3(m_d1ct_,name,_resize_up)(dict_t h, size_t newSize, bool updateLimit) \ + M_P(void, name, _i_resize_up, dict_t h, size_t newSize, bool updateLimit) \ { \ size_t oldSize = h->mask+1; \ M_ASSERT (newSize >= oldSize); \ @@ -1596,7 +1573,7 @@ enum m_d1ct_oa_element_e { Reserve a little bit of array to avoid reallocation if possible */ \ M_F(name, _array_pair_ct) tmp; \ M_F(name, _array_pair_init)(tmp); \ - M_F(name, _array_pair_reserve)(tmp, oldSize >> 2); \ + M_F(name, _array_pair_reserve)M_R(tmp, oldSize >> 2); \ const size_t mask = (newSize -1); \ \ for(size_t i = 0 ; i < oldSize; i++) { \ @@ -1609,7 +1586,7 @@ enum m_d1ct_oa_element_e { M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ } else { \ - M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw) (tmp); \ + M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \ M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ } \ @@ -1636,7 +1613,7 @@ enum m_d1ct_oa_element_e { M_F(name, _array_pair_pop_move)(&data[p], tmp); \ } \ \ - M_F(name, _array_pair_clear) (tmp); \ + M_F(name, _array_pair_clear)M_R(tmp); \ h->mask = newSize-1; \ h->count_delete = h->count; \ if (updateLimit == true) { \ @@ -1647,10 +1624,9 @@ enum m_d1ct_oa_element_e { M_D1CT_OA_CONTRACT(h); \ } \ \ - M_INLINE void M_ATTR_HOT_FUNCTION \ - M_IF(isSet)(M_F(name, _push), M_F(name,_set_at)) \ - (dict_t dict, key_type const key \ - M_IF(isSet)(, M_DEFERRED_COMMA value_type const value) ) \ + M_IF(isSet)( \ + M_P(void, name, _push, dict_t dict, key_type const key) , \ + M_P(void, name, _set_at, dict_t dict, key_type const key, value_type const value)) \ { \ M_D1CT_OA_CONTRACT(dict); \ /* NOTE: key can not be the representation of empty or deleted */ \ @@ -1697,13 +1673,12 @@ enum m_d1ct_oa_element_e { M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ - M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ + M_F(name,_i_resize_up)M_R(dict, newSize, true); \ } \ M_D1CT_OA_CONTRACT(dict); \ } \ \ - M_INLINE value_type * M_ATTR_HOT_FUNCTION \ - M_F(name,_safe_get)(dict_t dict, key_type const key) \ + M_P(value_type *, name,_safe_get, dict_t dict, key_type const key) \ { \ M_D1CT_OA_CONTRACT(dict); \ /* NOTE: key can not be the representation of empty or deleted */ \ @@ -1751,21 +1726,15 @@ enum m_d1ct_oa_element_e { M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ - M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ + M_F(name,_i_resize_up)M_R(dict, newSize, true); \ /* data is now invalid */ \ return M_F(name, _get)(dict, key); \ } \ M_D1CT_OA_CONTRACT(dict); \ return &data[p].M_IF(isSet)(key, value); \ - } \ - M_INLINE M_ATTR_DEPRECATED value_type * \ - M_F(name,_get_at)(dict_t dict, key_type const key) \ - { \ - return M_F(name,_safe_get)(dict, key); \ } \ \ - M_INLINE void M_ATTR_COLD_FUNCTION \ - M_C3(m_d1ct_,name,_resize_down)(dict_t h, size_t newSize) \ + M_P(void, name, _i_resize_down, dict_t h, size_t newSize) \ { \ size_t oldSize = h->mask+1; \ M_ASSERT (newSize <= oldSize && M_POWEROF2_P(newSize)); \ @@ -1791,7 +1760,7 @@ enum m_d1ct_oa_element_e { M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ } else { \ - M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw) (tmp); \ + M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \ M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ } \ @@ -1829,7 +1798,7 @@ enum m_d1ct_oa_element_e { M_F(name, _array_pair_pop_move)(&data[p], tmp); \ } \ \ - M_F(name, _array_pair_clear) (tmp); \ + M_F(name, _array_pair_clear) M_R(tmp); \ h->count_delete = h->count; \ if (newSize != oldSize) { \ h->mask = newSize-1; \ @@ -1842,8 +1811,7 @@ enum m_d1ct_oa_element_e { M_D1CT_OA_CONTRACT(h); \ } \ \ - M_INLINE bool \ - M_F(name,_erase)(dict_t dict, key_type const key) \ + M_P(bool, name,_erase, dict_t dict, key_type const key) \ { \ M_D1CT_OA_CONTRACT(dict); \ /* NOTE: key can't be the representation of empty or deleted */ \ @@ -1872,7 +1840,7 @@ enum m_d1ct_oa_element_e { M_ASSERT (dict->count >= 1); \ dict->count--; \ if (M_UNLIKELY (dict->count < dict->lower_limit)) { \ - M_C3(m_d1ct_,name,_resize_down)(dict, (dict->mask+1) >> 1); \ + M_F(name,_i_resize_down)M_R(dict, (dict->mask+1) >> 1); \ } \ M_D1CT_OA_CONTRACT(dict); \ return true; \ @@ -2028,13 +1996,13 @@ enum m_d1ct_oa_element_e { #define M_USE_MAX_PREFETCH 16 #endif -// WIP. Only if isSet is true for the time being +// WIP. Only if isSet is false for the time being #define M_D1CT_OA_DEF_BULK(name, key_type, key_oplist, value_type, value_oplist, isSet, coeff_down, coeff_up, dict_t, dict_it_t, it_deref_t) \ \ -M_INLINE void \ -M_F(name, _bulk_get)(unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type const key[M_VLA(n)], value_type def) \ +M_P(void, name, _bulk_get, unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type const key[M_VLA(n)], value_type def) \ { \ M_D1CT_OA_CONTRACT (dict); \ + M_ASSERT_POOL(); \ size_t h[M_USE_MAX_PREFETCH]; \ M_F(name, _pair_ct) *data = dict->data; \ const size_t mask = dict->mask; \ @@ -2064,8 +2032,7 @@ M_F(name, _bulk_get)(unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type } \ } \ \ -M_INLINE void \ -M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], key_type const key[M_VLA(n)]) \ +M_P(void, name, _bulk_set, dict_t dict, unsigned n, value_type const val[M_VLA(n)], key_type const key[M_VLA(n)]) \ { \ M_D1CT_OA_CONTRACT (dict); \ size_t h[M_USE_MAX_PREFETCH]; \ @@ -2116,7 +2083,7 @@ M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], ke M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ - M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ + M_F(name,_i_resize_up)M_R(dict, newSize, true); \ } \ next: \ (void)0; \ @@ -2125,9 +2092,8 @@ M_F(name, _bulk_set)(dict_t dict, unsigned n, value_type const val[M_VLA(n)], ke } \ \ \ -M_INLINE void \ -M_F(name, _bulk_update)(dict_t dict, unsigned n, value_type val[M_VLA(n)], key_type const key[M_VLA(n)], value_type def, \ - void (*update)(dict_t dict, key_type const key, value_type *storeval, value_type *newval)) \ +M_P(void, name, _bulk_update, dict_t dict, unsigned n, value_type val[M_VLA(n)], key_type const key[M_VLA(n)], value_type def, \ + void (*update)(dict_t dict, key_type const key, value_type *storedval, value_type *newval)) \ { \ M_D1CT_OA_CONTRACT (dict); \ size_t h[M_USE_MAX_PREFETCH]; \ @@ -2179,7 +2145,7 @@ M_F(name, _bulk_update)(dict_t dict, unsigned n, value_type val[M_VLA(n)], key_t M_MEMORY_FULL(char, (size_t)-1); \ } \ } \ - M_C3(m_d1ct_,name,_resize_up)(dict, newSize, true); \ + M_F(name,_i_resize_up)M_R(dict, newSize, true); \ } \ next: \ (void)0; \ From 06e30462682882c1043cbcf718b40596f2abf68c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 14 Mar 2025 22:45:38 +0100 Subject: [PATCH 22/91] Port to new memory interface --- m-buffer.h | 107 ++++++++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 63 deletions(-) diff --git a/m-buffer.h b/m-buffer.h index 66a6563e..5fda050c 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -300,10 +300,10 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) /* Define the core functionalities of a buffer */ #define M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \ \ -M_INLINE void \ -M_F(name, _init)(buffer_t v, size_t size) \ +M_P(void, name, _init, buffer_t v, size_t size) \ { \ M_ASSERT(size <= UINT_MAX); \ + M_ASSERT_POOL(); \ M_BUFF3R_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = size); \ v->idx_prod = v->idx_cons = v->overwrite = 0; \ m_buff3r_number_init (v->number[0], policy); \ @@ -334,17 +334,16 @@ M_F(name, _init)(buffer_t v, size_t size) \ } \ \ M_BUFF3R_IF_CTE_SIZE(m_size)( \ - M_INLINE void \ - M_C3(m_buff3r_,name,_init)(buffer_t v) \ + M_P(void, name,_i_init, buffer_t v) \ { \ - M_F(name, _init)(v, m_size); \ + M_F(name, _init)M_R(v, m_size); \ } \ , ) \ \ - M_INLINE void \ - M_C3(m_buff3r_,name,_clear_obj)(buffer_t v) \ + M_P(void, name, _i_clear_obj, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ + M_ASSERT_POOL(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \ M_CALL_CLEAR(oplist, v->data[i].x); \ @@ -365,11 +364,10 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_BUFF3R_CONTRACT(v,m_size); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(buffer_t v) \ + M_P(void, name, _clear, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_C3(m_buff3r_,name,_clear_obj)(v); \ + M_F(name,_i_clear_obj)M_R(v); \ M_BUFF3R_IF_CTE_SIZE(m_size)( , \ M_CALL_FREE(oplist, M_F(name, _el_ct), v->data, M_BUFF3R_SIZE(m_size)); \ v->data = NULL; \ @@ -383,8 +381,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ } \ } \ \ - M_INLINE void \ - M_F(name, _reset)(buffer_t v) \ + M_P(void, name, _reset, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ @@ -393,7 +390,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ } \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ if (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) \ - M_C3(m_buff3r_,name,_clear_obj)(v); \ + M_F(name,_i_clear_obj)M_R(v); \ v->idx_prod = v->idx_cons = 0; \ m_buff3r_number_store (v->number[0], 0U, policy); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ @@ -406,14 +403,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_BUFF3R_CONTRACT(v,m_size); \ } \ \ - M_INLINE void M_ATTR_DEPRECATED \ - M_F(name, _clean)(buffer_t v) \ - { \ - M_F(name,_reset)(v); \ - } \ - \ - M_INLINE void \ - M_F(name, _init_set)(buffer_t dest, const buffer_t src) \ + M_P(void, name, _init_set, buffer_t dest, const buffer_t src) \ { \ /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ @@ -421,7 +411,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_F(name, _ptr) v = vu.ptr; \ M_ASSERT (dest != v); \ M_BUFF3R_CONTRACT(v,m_size); \ - M_F(name, _init)(dest, M_BUFF3R_SIZE(m_size)); \ + M_F(name, _init)M_R(dest, M_BUFF3R_SIZE(m_size)); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ m_mutex_lock(v->mutexPush); \ m_mutex_lock(v->mutexPop); \ @@ -456,8 +446,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_BUFF3R_CONTRACT(dest, m_size); \ } \ \ - M_INLINE void \ - M_F(name, _set)(buffer_t dest, const buffer_t src) \ + M_P(void, name, _set, buffer_t dest, const buffer_t src) \ { \ /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ @@ -484,7 +473,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ } \ \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ - M_C3(m_buff3r_,name,_clear_obj)(dest); \ + M_F(name,_i_clear_obj)M_R(dest); \ \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \ @@ -555,11 +544,10 @@ M_F(name, _init)(buffer_t v, size_t size) \ return m_buff3r_number_load (v->number[0], policy); \ } \ \ - M_INLINE bool \ - M_F(name, _push_blocking)(buffer_t v, type const data, bool blocking) \ + M_P(bool, name, _push_blocking, buffer_t v, type const data, bool blocking) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - \ + M_ASSERT_POOL(); \ /* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ m_mutex_lock(v->mutexPush); \ @@ -635,12 +623,11 @@ M_F(name, _init)(buffer_t v, size_t size) \ return true; \ } \ \ - M_INLINE bool \ - M_F(name, _pop_blocking)(type *data, buffer_t v, bool blocking) \ + M_P(bool, name, _pop_blocking, type *data, buffer_t v, bool blocking) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ M_ASSERT (data != NULL); \ - \ + M_ASSERT_POOL(); \ /* consumer lock (mutex lock performs an acquire memory barrier) */ \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ m_mutex_lock(v->mutexPop); \ @@ -706,17 +693,15 @@ M_F(name, _init)(buffer_t v, size_t size) \ } \ \ \ - M_INLINE bool \ - M_F(name, _push)(buffer_t v, type const data) \ + M_P(bool, name, _push, buffer_t v, type const data) \ { \ - return M_F(name, _push_blocking)(v, data, \ + return M_F(name, _push_blocking)M_R(v, data, \ !M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_PUSH)); \ } \ \ - M_INLINE bool \ - M_F(name, _pop)(type *data, buffer_t v) \ + M_P(bool, name, _pop, type *data, buffer_t v) \ { \ - return M_F(name, _pop_blocking)(data, v, \ + return M_F(name, _pop_blocking)M_R(data, v, \ !M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_POP)); \ } \ \ @@ -833,10 +818,10 @@ M_F(name, _init)(buffer_t v, size_t size) \ /* Define the core functionalities of a MPMC queue */ #define M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \ - M_INLINE bool \ - M_F(name, _push)(buffer_t table, type const x) \ + M_P(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ + M_ASSERT_POOL(); \ unsigned int idx = atomic_load_explicit(&table->ProdIdx, \ memory_order_relaxed); \ const unsigned int i = idx & (table->size -1); \ @@ -867,18 +852,18 @@ M_F(name, _init)(buffer_t v, size_t size) \ return true; \ } \ \ - M_INLINE bool \ - M_F(name, _pop)(type *ptr, buffer_t table) \ + M_P(bool, name, _pop, type *ptr, buffer_t table) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ + M_ASSERT_POOL(); \ unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \ memory_order_relaxed); \ const unsigned int i = (iC & (table->size -1)); \ const unsigned int seq = atomic_load_explicit(&table->Tab[i].seq, \ memory_order_acquire); \ if (seq != 2 * iC) { \ - /* Nothing in buffer to consumme (or unlikely preemption) */ \ + /* Nothing in buffer to consume (or unlikely preemption) */ \ return false; \ } \ if (M_UNLIKELY (!atomic_compare_exchange_strong_explicit(&table->ConsoIdx, \ @@ -896,8 +881,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ return true; \ } \ \ - M_INLINE void \ - M_F(name, _init)(buffer_t buffer, size_t size) \ + M_P(void, name, _init, buffer_t buffer, size_t size) \ { \ M_ASSERT (buffer != NULL); \ M_ASSERT( M_POWEROF2_P(size)); \ @@ -920,8 +904,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_QU3UE_MPMC_CONTRACT(buffer); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(buffer_t buffer) \ + M_P(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_MPMC_CONTRACT(buffer); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ @@ -1060,10 +1043,10 @@ M_F(name, _init)(buffer_t v, size_t size) \ /* Define the core functionalities of a SPSC queue */ #define M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \ \ - M_INLINE bool \ - M_F(name, _push)(buffer_t table, type const x) \ + M_P(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ + M_ASSERT_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1081,10 +1064,10 @@ M_F(name, _init)(buffer_t v, size_t size) \ return true; \ } \ \ - M_INLINE bool \ - M_F(name, _push_move)(buffer_t table, type *x) \ + M_P(bool, name, _push_move, buffer_t table, type *x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ + M_ASSERT_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1102,11 +1085,11 @@ M_F(name, _init)(buffer_t v, size_t size) \ return true; \ } \ \ - M_INLINE bool \ - M_F(name, _pop)(type *ptr, buffer_t table) \ + M_P(bool, name, _pop, type *ptr, buffer_t table) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ + M_ASSERT_POOL(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1124,12 +1107,12 @@ M_F(name, _init)(buffer_t v, size_t size) \ return true; \ } \ \ - M_INLINE unsigned \ - M_F(name, _push_bulk)(buffer_t table, unsigned n, type const x[]) \ + M_P(unsigned, name, _push_bulk, buffer_t table, unsigned n, type const x[]) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (x != NULL); \ M_ASSERT (n <= table->size); \ + M_ASSERT_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1150,12 +1133,12 @@ M_F(name, _init)(buffer_t v, size_t size) \ return max; \ } \ \ - M_INLINE unsigned \ - M_F(name, _pop_bulk)(unsigned int n, type ptr[], buffer_t table) \ + M_P(unsigned, name, _pop_bulk, unsigned n, type ptr[], buffer_t table) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ M_ASSERT (n <= table->size); \ + M_ASSERT_POOL(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1176,10 +1159,10 @@ M_F(name, _init)(buffer_t v, size_t size) \ return max; \ } \ \ - M_INLINE void \ - M_F(name, _push_force)(buffer_t table, type const x) \ + M_P(void, name, _push_force, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ + M_ASSERT_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1238,8 +1221,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ return M_F(name, _size)(v) >= v->size; \ } \ \ - M_INLINE void \ - M_F(name, _init)(buffer_t buffer, size_t size) \ + M_P(void, name, _init, buffer_t buffer, size_t size) \ { \ M_ASSERT (buffer != NULL); \ M_ASSERT( M_POWEROF2_P(size)); \ @@ -1261,8 +1243,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ M_QU3UE_SPSC_CONTRACT(buffer); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(buffer_t buffer) \ + M_P(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_SPSC_CONTRACT(buffer); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ @@ -1303,7 +1284,7 @@ M_F(name, _init)(buffer_t v, size_t size) \ /* OPLIST definition of a buffer */ #define M_BUFF3R_OPLIST_P3(name, oplist) \ - (INIT(M_C3(m_buff3r_,name, _init)) \ + (INIT(M_F(name, _i_init)) \ ,INIT_SET(M_F(name, _init_set)) \ ,SET(M_F(name, _set)) \ ,CLEAR(M_F(name, _clear)) \ From 839e7c2957eb593e99ebfab33695159ee951e69b Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 16 Mar 2025 16:34:45 +0100 Subject: [PATCH 23/91] Port to new memory model --- m-deque.h | 191 +++++++++++++++++++++++------------------------------ m-i-list.h | 16 ++--- 2 files changed, 90 insertions(+), 117 deletions(-) diff --git a/m-deque.h b/m-deque.h index 410fac3d..c33dd12f 100644 --- a/m-deque.h +++ b/m-deque.h @@ -99,8 +99,15 @@ M_D3QU3_DEF_TYPE(name, type, oplist, deque_t, it_t, node_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_D3QU3_DEF_CORE(name, type, oplist, deque_t, it_t, node_t) \ - M_EMPLACE_QUEUE_DEF(name, deque_t, M_F(name, _emplace_back), oplist, M_D3QUE_EMPLACE_BACK_DEF) \ - M_EMPLACE_QUEUE_DEF(name, deque_t, M_F(name, _emplace_front), oplist, M_D3QUE_EMPLACE_FRONT_DEF) + M_EMPLACE_QUEUE_DEF(name, deque_t, _emplace_back, oplist, M_D3QUE_EMPLACE_BACK_DEF) \ + M_EMPLACE_QUEUE_DEF(name, deque_t, _emplace_front, oplist, M_D3QUE_EMPLACE_FRONT_DEF) + +// OPLIST for the node deletion +#ifdef M_USE_POOL +#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API_0P(M_F(name, _node_list_i_del)))) +#else +#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(M_F(name, _node_list_i_del))) +#endif /* Define the types. It is a linked list of buckets of the types, @@ -124,14 +131,13 @@ M_GET_REALLOC for the allocation). But we want to delete the nodes \ automatically with the intrusive list used for storing the nodes: \ so we register as a DEL operator the FREE operator of the oplist. \ - The interfaces are compatible. \ */ \ /* FIXME: How can I separate public types and private implementation? */ \ - static inline void M_F(name, _del_node)(node_t *ptr) \ + M_P(void, name, _node_list_i_del, node_t *ptr) \ { \ M_CALL_FREE(oplist, char, ptr, sizeof(node_t) + ptr->capacity * sizeof(type)); \ } \ - M_ILIST_DEF(M_F(name, _node_list), node_t, (DEL(M_F(name, _del_node))) ) \ + M_ILIST_DEF(M_F(name, _node_list), node_t, M_D3QU3_NODE_DEL_OPLIST(name) ) \ \ /* Define an internal iterator */ \ typedef struct M_F(name, _it2_s) { \ @@ -174,24 +180,18 @@ #define M_D3QU3_DEF_CORE(name, type, oplist, deque_t, it_t, node_t) \ \ /* Allocate a new node for a deque */ \ - M_INLINE node_t* \ - M_C3(m_d3qu3_,name,_new_node)(deque_t d) \ + M_P(node_t*, name, _i_new_node, deque_t d) \ { \ size_t def = d->default_size; \ /* Test for overflow of the size computation */ \ if (M_UNLIKELY_NOMEM (def > SIZE_MAX / sizeof (type) - sizeof(node_t))) { \ M_MEMORY_FULL(char, sizeof(node_t)+def * sizeof(type)); \ - abort(); \ - return NULL; \ } \ /* Alloc a new node with dynamic size */ \ node_t*n = (node_t*) (void*) \ - M_CALL_REALLOC(oplist, char, NULL, 0, \ - sizeof(node_t) + def * sizeof(type) ); \ + M_CALL_REALLOC(oplist, char, NULL, 0, sizeof(node_t) + def * sizeof(type) ); \ if (M_UNLIKELY_NOMEM (n==NULL)) { \ M_MEMORY_FULL(char, sizeof(node_t)+def * sizeof(type)); \ - abort(); \ - return NULL; \ } \ /* Initialize the node */ \ n->size = def; \ @@ -205,13 +205,12 @@ return n; \ } \ \ - M_INLINE void \ - M_F(name, _init)(deque_t d) \ + M_P(void, name, _init, deque_t d) \ { \ M_F(name, _node_list_init)(d->list); \ d->default_size = M_USE_DEQUE_DEFAULT_SIZE; \ d->count = 0; \ - node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \ + node_t *n = M_F(name,_i_new_node)M_R(d); \ M_F(name, _node_list_push_back)(d->list, n); \ d->front->node = n; \ d->front->index = M_USE_DEQUE_DEFAULT_SIZE/2; \ @@ -220,10 +219,10 @@ M_D3QU3_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(deque_t d) \ + M_P(void, name, _reset, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ + M_ASSERT_POOL(); \ node_t *min_node = NULL; \ for(node_t *n = d->front->node; \ n != NULL ; \ @@ -245,31 +244,29 @@ M_D3QU3_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(deque_t d) \ + M_P(void, name, _clear, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ - M_F(name, _reset)(d); \ - /* We have registered the delete operator to clear all objects */ \ - M_F(name, _node_list_clear)(d->list); \ - /* It is safer to clean some variables */ \ + M_F(name, _reset)M_R(d); \ + /* We have registered the delete operator to clear all node objects */ \ + M_F(name, _node_list_clear)M_R(d->list); \ + /* It is safer to clean some variables to mark d as invalid */ \ d->front->node = NULL; \ d->back->node = NULL; \ d->count = 0; \ } \ \ - M_INLINE type * \ - M_F(name, _push_back_raw)(deque_t d) \ + M_P(type *, name, _push_back_raw, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ node_t *n = d->back->node; \ size_t index = d->back->index; \ if (M_UNLIKELY (n->size <= index)) { \ - /* try to get an already allocated node */ \ + /* Cannot fit in the current node, try to get another allocated node */ \ n = M_F(name, _node_list_next_obj)(d->list, n); \ if (n == NULL) { \ - /* No node exists, allocate a new one */ \ - n = M_C3(m_d3qu3_,name,_new_node)(d); \ + /* No another node exists: allocate a new one */ \ + n = M_F(name,_i_new_node)M_R(d); \ M_F(name, _node_list_push_back)(d->list, n); \ } \ d->back->node = n; \ @@ -283,27 +280,24 @@ return ret; \ } \ \ - /* Internal, for INIT_WITH */ \ - M_INLINE type * \ - M_F(name, _push_raw)(deque_t d) \ + /* Internal, for generic INIT_WITH */ \ + M_P(type *, name, _push_raw, deque_t d) \ { \ - return M_F(name, _push_back_raw)(d); \ + return M_F(name, _push_back_raw)M_R(d); \ } \ \ - M_INLINE void \ - M_F(name, _push_back)(deque_t d, type const x) \ + M_P(void, name, _push_back, deque_t d, type const x) \ { \ - type *p = M_F(name, _push_back_raw)(d); \ + type *p = M_F(name, _push_back_raw)M_R(d); \ M_ON_EXCEPTION(d->back->index --, d->count--) { \ M_CALL_INIT_SET(oplist, *p, x); \ } \ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _push_back_new)(deque_t d) \ + M_P(type *, name, _push_back_new, deque_t d) \ { \ - type *p = M_F(name, _push_back_raw)(d); \ + type *p = M_F(name, _push_back_raw)M_R(d); \ M_ON_EXCEPTION(d->back->index --, d->count--) { \ M_CALL_INIT(oplist, *p); \ } \ @@ -311,16 +305,14 @@ } \ , ) \ \ - M_INLINE void \ - M_F(name, _push_back_move)(deque_t d, type *x) \ + M_P(void, name, _push_back_move, deque_t d, type *x) \ { \ M_ASSERT (x != NULL); \ - type *p = M_F(name, _push_back_raw)(d); \ + type *p = M_F(name, _push_back_raw)M_R(d); \ M_DO_INIT_MOVE (oplist, *p, *x); \ } \ \ - M_INLINE type* \ - M_F(name, _push_front_raw)(deque_t d) \ + M_P(type *, name, _push_front_raw, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ node_t *n = d->front->node; \ @@ -330,7 +322,7 @@ if (M_UNLIKELY (n->size <= index)) { \ n = M_F(name, _node_list_previous_obj)(d->list, n); \ if (n == NULL) { \ - n = M_C3(m_d3qu3_,name,_new_node)(d); \ + n = M_F(name,_i_new_node)M_R(d); \ M_F(name, _node_list_push_front)(d->list, n); \ } \ d->front->node = n; \ @@ -343,20 +335,18 @@ return ret; \ } \ \ - M_INLINE void \ - M_F(name, _push_front)(deque_t d, type const x) \ + M_P(void, name, _push_front, deque_t d, type const x) \ { \ - type *p = M_F(name, _push_front_raw)(d); \ + type *p = M_F(name, _push_front_raw)M_R(d); \ M_ON_EXCEPTION(d->front->index ++, d->count--) { \ M_CALL_INIT_SET(oplist, *p, x); \ } \ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE type * \ - M_F(name, _push_front_new)(deque_t d) \ + M_P(type *, name, _push_front_new, deque_t d) \ { \ - type *p = M_F(name, _push_front_raw)(d); \ + type *p = M_F(name, _push_front_raw)M_R(d); \ M_ON_EXCEPTION(d->front->index ++, d->count--) { \ M_CALL_INIT(oplist, *p); \ } \ @@ -364,19 +354,18 @@ } \ ,) \ \ - M_INLINE void \ - M_F(name, _push_front_move)(deque_t d, type *x) \ + M_P(void, name, _push_front_move, deque_t d, type *x) \ { \ M_ASSERT (x != NULL); \ - type *p = M_F(name, _push_front_raw)(d); \ + type *p = M_F(name, _push_front_raw)M_R(d); \ M_DO_INIT_MOVE (oplist, *p, *x); \ } \ \ - M_INLINE void \ - M_F(name, _pop_back)(type *ptr, deque_t d) \ + M_P(void, name, _pop_back, type *ptr, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT(d->count > 0); \ + M_ASSERT_POOL(); \ node_t *n = d->back->node; \ size_t index = d->back->index; \ index --; \ @@ -396,34 +385,35 @@ index = n->size-1; \ } \ if (ptr != NULL) \ - M_DO_MOVE(oplist, *ptr, n->data[index]); else \ - M_CALL_CLEAR(oplist, n->data[index]); \ + M_DO_MOVE(oplist, *ptr, n->data[index]); \ + else \ + M_CALL_CLEAR(oplist, n->data[index]); \ d->count --; \ d->back->index = index; \ M_D3QU3_CONTRACT(d); \ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _pop_back_move)(type *ptr, deque_t d) \ + M_P(void, name, _pop_back_move, type *ptr, deque_t d) \ { \ M_ASSERT(ptr != NULL); \ /* Note: Lazy implementation. Can be improved if needed */ \ M_CALL_INIT(oplist, *ptr); \ - M_F(name, _pop_back)(ptr, d); \ + M_F(name, _pop_back)M_R(ptr, d); \ } \ , ) \ \ - M_INLINE void \ - M_F(name, _pop_front)(type *ptr, deque_t d) \ + M_P(void, name, _pop_front, type *ptr, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT(d->count > 0); \ + M_ASSERT_POOL(); \ node_t *n = d->front->node; \ size_t index = d->front->index; \ if (ptr != NULL) \ - M_DO_MOVE(oplist, *ptr, n->data[index]); else \ - M_CALL_CLEAR(oplist, n->data[index]); \ + M_DO_MOVE(oplist, *ptr, n->data[index]); \ + else \ + M_CALL_CLEAR(oplist, n->data[index]); \ index++; \ if (M_UNLIKELY (n->size <= index)) { \ /* If there is a previous node, \ @@ -456,13 +446,12 @@ } \ \ M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _pop_front_move)(type *ptr, deque_t d) \ + M_P(void, name, _pop_front_move, type *ptr, deque_t d) \ { \ M_ASSERT(ptr != NULL); \ /* Note: Lazy implementation */ \ M_CALL_INIT(oplist, *ptr); \ - M_F(name, _pop_front)(ptr, d); \ + M_F(name, _pop_front)M_R(ptr, d); \ } \ ,) \ \ @@ -668,8 +657,7 @@ return M_CONST_CAST(type, &it->node->data[it->index]); \ } \ \ - M_INLINE void \ - M_F(name, _remove)(deque_t d, it_t it) \ + M_P(void, name, _remove, deque_t d, it_t it) \ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT (it != NULL && it->node != NULL); \ @@ -731,14 +719,13 @@ M_D3QU3_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _init_set)(deque_t d, const deque_t src) \ + M_P(void, name, _init_set, deque_t d, const deque_t src) \ { \ M_D3QU3_CONTRACT(src); \ M_ASSERT (d != NULL); \ M_F(name, _node_list_init)(d->list); \ d->default_size = M_USE_DEQUE_DEFAULT_SIZE + src->count; \ - node_t *n = M_C3(m_d3qu3_,name,_new_node)(d); \ + node_t *n = M_F(name,_i_new_node)M_R(d); \ d->count = src->count; \ d->default_size /= 2; \ M_F(name, _node_list_push_back)(d->list, n); \ @@ -758,15 +745,14 @@ M_D3QU3_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _set)(deque_t d, deque_t const src) \ + M_P(void, name, _set, deque_t d, deque_t const src) \ { \ if (M_UNLIKELY (src == d)) \ return; \ /* TODO: Reuse memory of d! */ \ M_ON_EXCEPTION( M_F(name, _init)(d) ) { \ - M_F(name, _clear)(d); \ - M_F(name, _init_set)(d, src); \ + M_F(name, _clear)M_R(d); \ + M_F(name, _init_set)M_R(d, src); \ } \ } \ \ @@ -786,12 +772,11 @@ M_D3QU3_CONTRACT(d); \ } \ \ - M_INLINE void \ - M_F(name, _move)(deque_t d, deque_t src) \ + M_P(void, name, _move, deque_t d, deque_t src) \ { \ M_D3QU3_CONTRACT(d); \ M_D3QU3_CONTRACT(src); \ - M_F(name, _clear)(d); \ + M_F(name, _clear)M_R(d); \ M_F(name, _init_move)(d, src); \ M_D3QU3_CONTRACT(d); \ } \ @@ -837,10 +822,10 @@ return M_CONST_CAST(type, M_F(name, _get)(d, key)); \ } \ \ - M_INLINE void \ - M_F(name, _set_at)(deque_t d, size_t key, type const x) \ + M_P(void, name, _set_at, deque_t d, size_t key, type const x) \ { \ M_D3QU3_CONTRACT(d); \ + M_ASSERT_POOL(); \ M_ASSERT_INDEX (key, d->count); \ type *p = M_F(name, _get)(d, key); \ M_CALL_SET(oplist, *p, x); \ @@ -900,11 +885,10 @@ , /* NO SWAP */) \ \ M_IF_METHOD(GET_STR, oplist)( \ - M_INLINE void \ - M_F(name, _get_str)(m_string_t str, deque_t const deque, bool append) \ + M_P(void, name, _get_str, m_string_t str, deque_t const deque, bool append) \ { \ M_D3QU3_CONTRACT(deque); \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \ it_t it; \ for (M_F(name, _it)(it, deque) ; \ !M_F(name, _end_p)(it); \ @@ -912,9 +896,9 @@ type const *item = M_F(name, _cref)(it); \ M_CALL_GET_STR(oplist, str, *item, true); \ if (!M_F(name, _last_p)(it)) \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ } \ - m_string_push_back (str, ']'); \ + m_string_push_back M_R(str, ']'); \ } \ , /* no GET_STR */ ) \ \ @@ -939,12 +923,11 @@ , /* no OUT_STR */ ) \ \ M_IF_METHOD2(PARSE_STR, INIT, oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(deque_t deque, const char str[], const char **endp) \ + M_P(bool, name, _parse_str, deque_t deque, const char str[], const char **endp) \ { \ M_D3QU3_CONTRACT(deque); \ M_ASSERT (str != NULL); \ - M_F(name,_reset)(deque); \ + M_F(name,_reset)M_R(deque); \ int c = *str++; \ if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \ c = *str++; \ @@ -955,7 +938,7 @@ bool b = M_CALL_PARSE_STR(oplist, item, str, &str); \ c = m_core_str_nospace(&str); \ if (b == false || c == 0) { c = 0; break; } \ - M_F(name, _push_back)(deque, item); \ + M_F(name, _push_back)M_R(deque, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ exit: \ @@ -966,12 +949,11 @@ , /* no PARSE_STR */ ) \ \ M_IF_METHOD2(IN_STR, INIT, oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(deque_t deque, FILE *file) \ + M_P(bool, name, _in_str, deque_t deque, FILE *file) \ { \ M_D3QU3_CONTRACT(deque); \ M_ASSERT (file != NULL); \ - M_F(name,_reset)(deque); \ + M_F(name,_reset)M_R(deque); \ int c = fgetc(file); \ if (M_UNLIKELY (c != '[')) return false; \ c = fgetc(file); \ @@ -983,7 +965,7 @@ bool b = M_CALL_IN_STR(oplist, item, file); \ c = m_core_fgetc_nospace(file); \ if (b == false || c == EOF) { c = 0; break; } \ - M_F(name, _push_back)(deque, item); \ + M_F(name, _push_back)M_R(deque, item); \ } while (c == M_GET_SEPARATOR oplist); \ } \ M_D3QU3_CONTRACT(deque); \ @@ -1017,22 +999,21 @@ , /* no OUT_SERIAL */ ) \ \ M_IF_METHOD2(IN_SERIAL, INIT, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(deque_t deque, m_serial_read_t f) \ + M_P(m_serial_return_code_t, name, _in_serial, deque_t deque, m_serial_read_t f) \ { \ M_D3QU3_CONTRACT(deque); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ m_serial_return_code_t ret; \ size_t estimated_size = 0; \ - M_F(name,_reset)(deque); \ + M_F(name,_reset)M_R(deque); \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \ if (M_UNLIKELY (ret != M_SERIAL_OK_CONTINUE)) return ret; \ M_QLET(1, item, type, oplist) { \ do { \ ret = M_CALL_IN_SERIAL(oplist, item, f); \ if (ret != M_SERIAL_OK_DONE) { break; } \ - M_F(name, _push_back)(deque, item); \ + M_F(name, _push_back)M_R(deque, item); \ ret = f->m_interface->read_array_next(local, f); \ } while (ret == M_SERIAL_OK_CONTINUE); \ } \ @@ -1042,11 +1023,9 @@ /* Definition of the emplace_back function for deque */ #define M_D3QUE_EMPLACE_BACK_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)(v); \ + M_F(name, _subtype_ct) *data = M_F(name, _push_back_raw)M_R(v); \ M_ON_EXCEPTION(v->back->index --, v->count--) { \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ } \ @@ -1055,11 +1034,9 @@ /* Definition of the emplace_front function for deque */ #define M_D3QUE_EMPLACE_FRONT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(name_t v \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)(v); \ + M_F(name, _subtype_ct) *data = M_F(name, _push_front_raw)M_R(v); \ M_ON_EXCEPTION(v->front->index ++, v->count--) { \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ } \ diff --git a/m-i-list.h b/m-i-list.h index 107c6aae..3dfd9c04 100644 --- a/m-i-list.h +++ b/m-i-list.h @@ -210,8 +210,7 @@ typedef struct m_il1st_head_s { M_IL1ST_CONTRACT(name, list); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(list_t list) \ + M_P(void, name, _reset, list_t list) \ { \ M_IL1ST_CONTRACT(name, list); \ for(struct m_il1st_head_s *it = list->name.next, *next ; \ @@ -232,11 +231,10 @@ typedef struct m_il1st_head_s { M_IL1ST_CONTRACT(name, list); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(list_t list) \ + M_P(void, name, _clear, list_t list) \ { \ /* Nothing to do more than clean the list itself */ \ - M_F(name, _reset)(list); \ + M_F(name, _reset)M_R(list); \ /* For safety purpose (create invalid representation of object) */ \ list->name.next = NULL; \ list->name.prev = NULL; \ @@ -267,10 +265,9 @@ typedef struct m_il1st_head_s { M_IL1ST_CONTRACT(name, list); \ } \ \ - M_INLINE void \ - M_F(name, _move)(list_t list, list_t ref) \ + M_P(void, name, _move, list_t list, list_t ref) \ { \ - M_F(name, _clear)(list); \ + M_F(name, _clear)M_R(list); \ M_F(name, _init_move)(list, ref); \ } \ \ @@ -511,8 +508,7 @@ typedef struct m_il1st_head_s { return M_CONST_CAST(type, ptr); \ } \ \ - M_INLINE void \ - M_F(name, _remove)(list_t list, it_t it) \ + M_P(void, name, _remove, list_t list, it_t it) \ { \ M_IL1ST_CONTRACT(name, list); \ M_IL1ST_NODE_CONTRACT(it->current); \ From 1cf7c4fa4d3c9d718b2da61e6dd437b256badf29 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 16 Mar 2025 21:00:58 +0100 Subject: [PATCH 24/91] Port to new memory model: M_MEMORY_FULL cannot return anymore --- m-array.h | 21 ++++----------------- m-bitset.h | 8 +------- m-buffer.h | 3 --- m-c-mempool.h | 4 ---- m-dict.h | 8 +------- m-genint.h | 1 - m-i-shared.h | 1 - m-list.h | 8 -------- m-mempool.h | 2 -- m-rbtree.h | 3 --- m-shared-ptr.h | 4 ---- m-shared.h | 4 ---- m-snapshot.h | 2 -- m-string.h | 9 --------- m-tree.h | 5 ----- m-worker.h | 1 - 16 files changed, 6 insertions(+), 78 deletions(-) diff --git a/m-array.h b/m-array.h index 2163203d..e09a2469 100644 --- a/m-array.h +++ b/m-array.h @@ -246,7 +246,6 @@ type *ptr = M_CALL_REALLOC(oplist, type, d->ptr, d->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ M_MEMORY_FULL(type, alloc); \ - return ; \ } \ d->ptr = ptr; \ d->alloc = alloc; \ @@ -323,14 +322,12 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -1U); \ - return NULL; \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ M_ASSERT (alloc > v->size); \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(type, alloc); \ - return NULL; \ } \ v->ptr = ptr; \ v->alloc = alloc; \ @@ -388,14 +385,12 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -1U); \ - return ; \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ M_ASSERT (alloc > v->size); \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(type, alloc); \ - return; \ } \ v->ptr = ptr; \ v->alloc = alloc; \ @@ -426,7 +421,6 @@ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(type, alloc); \ - return; \ } \ v->ptr = ptr; \ v->alloc = alloc; \ @@ -456,7 +450,6 @@ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(type, alloc); \ - return; \ } \ v->ptr = ptr; \ v->alloc = alloc; \ @@ -476,13 +469,11 @@ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ /* In case of overflow of size_t */ \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -1U); \ - return NULL; \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(type, alloc); \ - return NULL; \ } \ v->ptr = ptr; \ v->alloc = alloc; \ @@ -602,19 +593,16 @@ /* Unlikely case of nothing to do */ \ if (num == 0) return; \ M_MEMORY_FULL(type, v->size); \ - return ; \ } \ /* Test if alloc array is sufficient */ \ if (size > v->alloc) { \ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -1U); \ - return ; \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(type, alloc); \ - return; \ } \ v->ptr = ptr; \ v->alloc = alloc; \ @@ -901,7 +889,6 @@ type *temp = M_CALL_REALLOC(oplist, type, NULL, 0, l->size); \ if (M_UNLIKELY_NOMEM (temp == NULL)) { \ M_MEMORY_FULL(type, l->size); \ - return ; \ } \ M_C3(m_arra4_,name,_stable_sort_noalloc)(l->ptr, l->size, temp); \ M_CALL_FREE(oplist, type, temp, l->size); \ diff --git a/m-bitset.h b/m-bitset.h index b1932396..f9a41e3d 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -125,7 +125,6 @@ M_P(void, m_bitset, _set, m_bitset_t d, const m_bitset_t s) m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); - return ; } d->ptr = ptr; d->alloc = needAlloc; @@ -208,14 +207,12 @@ M_P(void, m_bitset, _push_back, m_bitset_t v, bool x) // Check for integer overflow if (M_UNLIKELY_NOMEM (needAlloc <= v->alloc)) { M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); - return; } // Alloc memory m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc); // Check if success if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); - return; } v->ptr = ptr; v->alloc = needAlloc; @@ -242,8 +239,7 @@ M_P(void, m_bitset, _resize, m_bitset_t v, size_t size) M_B1TSET_CONTRACT (v); // Check for overflow if (M_UNLIKELY_NOMEM (size >= ((size_t)-1) - M_B1TSET_LIMB_BIT)) { - M_MEMORY_FULL(char, (size_t) -1); - return; + M_MEMORY_FULL(char, -(size_t)1); } // Compute the needed allocation. size_t newAlloc = M_B1TSET_TO_ALLOC (size); @@ -252,7 +248,6 @@ M_P(void, m_bitset, _resize, m_bitset_t v, size_t size) m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc); - return; } v->ptr = ptr; v->alloc = newAlloc; @@ -303,7 +298,6 @@ M_P(void, m_bitset, _reserve, m_bitset_t v, size_t alloc) m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc); - return; } v->ptr = ptr; v->alloc = newAlloc; diff --git a/m-buffer.h b/m-buffer.h index 5fda050c..a537689c 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -322,7 +322,6 @@ M_P(void, name, _init, buffer_t v, size_t size) \ v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, M_BUFF3R_SIZE(m_size)); \ if (M_UNLIKELY_NOMEM (v->data == NULL)) { \ M_MEMORY_FULL (M_F(name, _el_ct), M_BUFF3R_SIZE(m_size)); \ - return; \ } \ ) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ @@ -893,7 +892,6 @@ M_P(void, name, _init, buffer_t v, size_t size) \ buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \ if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \ M_MEMORY_FULL (M_F(name, _el_ct), size); \ - return; \ } \ for(unsigned int j = 0; j < (unsigned int) size; j++) { \ atomic_init(&buffer->Tab[j].seq, 2*j+1U); \ @@ -1233,7 +1231,6 @@ M_P(void, name, _init, buffer_t v, size_t size) \ buffer->Tab = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, size); \ if (M_UNLIKELY_NOMEM (buffer->Tab == NULL)) { \ M_MEMORY_FULL (M_F(name, _el_ct), size); \ - return; \ } \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < (unsigned int) size; j++) { \ diff --git a/m-c-mempool.h b/m-c-mempool.h index a1b0633f..cc7aa6fa 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -313,7 +313,6 @@ M_BEGIN_PROTECTED_CODE node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \ if (M_UNLIKELY_NOMEM (node == NULL)) { \ M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ - return NULL; \ } \ atomic_init(&node->next, (M_F(name, _lf_node_t) *) 0); \ atomic_init(&node->cpt, 0UL); \ @@ -323,7 +322,6 @@ M_BEGIN_PROTECTED_CODE n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ - return NULL; \ } \ M_F(name, _slist_push)(node->list, n); \ } \ @@ -467,7 +465,6 @@ M_BEGIN_PROTECTED_CODE mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \ if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \ M_MEMORY_FULL(M_F(name, _lfmp_thread_ct), max_thread); \ - return; \ } \ for(unsigned i = 0; i < max_thread;i++) { \ M_F(name, _lfmp_thread_init)(&mem->thread_data[i]); \ @@ -590,7 +587,6 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread) gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) { M_MEMORY_FULL(m_gc_lfmp_thread_ct, max_thread); - return; } for(unsigned i = 0; i < max_thread;i++) { atomic_init(&gc_mem->thread_data[i].ticket, ULONG_MAX); diff --git a/m-dict.h b/m-dict.h index ed576162..93db9be8 100644 --- a/m-dict.h +++ b/m-dict.h @@ -338,7 +338,6 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) map->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), NULL, 0, (size_t) 1+2+map->upper_limit); \ if (M_UNLIKELY_NOMEM (map->data == NULL)) { \ M_MEMORY_FULL(M_F(name, _freelist_ct), 2+M_D1CT_INITIAL_SIZE); \ - return ; \ } \ map->freelist_first_data = 0; \ map->freelist_count = 2; \ @@ -346,7 +345,6 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) map->index = M_CALL_REALLOC(key_oplist, m_indexhash_t, NULL, 0, (size_t)(0+M_D1CT_INITIAL_SIZE)); \ if (M_UNLIKELY_NOMEM (map->index == NULL)) { \ M_MEMORY_FULL(m_indexhash_t, 2+M_D1CT_INITIAL_SIZE); \ - return ; \ } \ /* Populate the initial table with the 'empty' representation which is 0 */ \ for(m_index_t i = 0; i < M_D1CT_INITIAL_SIZE; i++) { \ @@ -470,14 +468,12 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) h->data = M_CALL_REALLOC(key_oplist, M_F(name, _freelist_ct), h->data, h->freelist_cap, (size_t) 1+2+h->upper_limit); \ if (M_UNLIKELY_NOMEM (h->data == NULL) ) { \ M_MEMORY_FULL(M_F(name, _freelist_ct), 2+newSize); \ - return ; \ } \ h->freelist_cap = 1+2+h->upper_limit; \ } \ m_indexhash_t *index = M_CALL_REALLOC(key_oplist, m_indexhash_t, h->index, oldSize, (size_t)0+newSize); \ if (M_UNLIKELY_NOMEM (index == NULL) ) { \ M_MEMORY_FULL(m_indexhash_t, newSize); \ - return ; \ } \ h->index = index; \ \ @@ -1468,7 +1464,6 @@ enum m_d1ct_oa_element_e { dict->data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), NULL, 0, M_D1CT_INITIAL_SIZE); \ if (M_UNLIKELY_NOMEM (dict->data == NULL)) { \ M_MEMORY_FULL(M_F(name, _pair_ct), M_D1CT_INITIAL_SIZE); \ - return ; \ } \ /* Populate the initial table with the 'empty' representation */ \ for(size_t i = 0; i < M_D1CT_INITIAL_SIZE; i++) { \ @@ -1547,7 +1542,6 @@ enum m_d1ct_oa_element_e { data = M_CALL_REALLOC(key_oplist, M_F(name, _pair_ct), data, oldSize, newSize); \ if (M_UNLIKELY_NOMEM (data == NULL) ) { \ M_MEMORY_FULL(M_F(name, _pair_ct), newSize); \ - return ; \ } \ \ /* First mark the extended space as empty */ \ @@ -1670,7 +1664,7 @@ enum m_d1ct_oa_element_e { if (dict->count > (dict->mask / 2)) { \ newSize += newSize; \ if (M_UNLIKELY_NOMEM (newSize <= dict->mask+1)) { \ - M_MEMORY_FULL(char, (size_t)-1); \ + M_MEMORY_FULL(char, -(size_t)1); \ } \ } \ M_F(name,_i_resize_up)M_R(dict, newSize, true); \ diff --git a/m-genint.h b/m-genint.h index 3e3e7e52..49b6a8ae 100644 --- a/m-genint.h +++ b/m-genint.h @@ -111,7 +111,6 @@ M_P(void, m_genint, _init, m_genint_t s, unsigned int n) atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(atomic_ullong, alloc); - return; } s->n = n; s->data = ptr; diff --git a/m-i-shared.h b/m-i-shared.h index d1bcc1cd..1dfe6ae4 100644 --- a/m-i-shared.h +++ b/m-i-shared.h @@ -193,7 +193,6 @@ M_BEGIN_PROTECTED_CODE type *ptr = M_CALL_NEW(oplist, type); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ M_MEMORY_FULL(type, 1); \ - return NULL; \ } \ M_CALL_INIT(oplist, *ptr); \ atomic_init (&ptr->M_F(name, _cpt), 2); \ diff --git a/m-list.h b/m-list.h index 3b48c6e7..d082905d 100644 --- a/m-list.h +++ b/m-list.h @@ -253,7 +253,6 @@ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return NULL; \ } \ type *ret = &next->data; \ next->next = *v; \ @@ -467,7 +466,6 @@ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return; \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \ M_CALL_INIT_SET(oplist, next->data, x); \ @@ -519,8 +517,6 @@ next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - *update_list = NULL; \ - return; \ } \ M_CALL_INIT_SET(oplist, next->data, it_org->data); \ *update_list = next; \ @@ -1012,7 +1008,6 @@ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return NULL; \ } \ type *ret = &next->data; \ next->next = v->back; \ @@ -1122,7 +1117,6 @@ struct M_F(name, _s) *next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return NULL; \ } \ type *ret = &next->data; \ next->next = NULL; \ @@ -1281,7 +1275,6 @@ struct M_F(name, _s) *m_volatile next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return; \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, next)) \ M_CALL_INIT_SET(oplist, next->data, x); \ @@ -1341,7 +1334,6 @@ next = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (next == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return; \ } \ M_CALL_INIT_SET(oplist, next->data, it_org->data); \ /* Link new node to the previous one*/ \ diff --git a/m-mempool.h b/m-mempool.h index 1d600afc..c8d9b301 100644 --- a/m-mempool.h +++ b/m-mempool.h @@ -119,7 +119,6 @@ mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \ if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \ M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ - return; \ } \ mem->current_segment->next = NULL; \ mem->current_segment->count = 0; \ @@ -161,7 +160,6 @@ M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \ if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \ M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ - return NULL; \ } \ new_segment->next = segment; \ new_segment->count = 0; \ diff --git a/m-rbtree.h b/m-rbtree.h index f9e8086d..aca9f769 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -288,7 +288,6 @@ typedef enum { n = M_CALL_NEW(oplist, node_t); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ M_MEMORY_FULL(node_t, 1); \ - return; \ } \ /* Copy the data in the root node */ \ M_CALL_INIT_SET(oplist, n->data, data); \ @@ -329,7 +328,6 @@ typedef enum { n = M_CALL_NEW(oplist, node_t); \ if (M_UNLIKELY_NOMEM (n == NULL) ) { \ M_MEMORY_FULL (node_t, 1); \ - return; \ } \ /* Copy the data and mark the node as red */ \ M_CALL_INIT_SET(oplist, n->data, data); \ @@ -659,7 +657,6 @@ typedef enum { node_t *n = M_CALL_NEW(oplist, node_t); \ if (M_UNLIKELY_NOMEM (n == NULL) ) { \ M_MEMORY_FULL (node_t, 1); \ - return NULL; \ } \ M_CALL_INIT_SET(oplist, n->data, o->data); \ n->child[0] = M_F(name,_i_copy_node)M_R(o->child[0]); \ diff --git a/m-shared-ptr.h b/m-shared-ptr.h index 059811a9..a68f0f64 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -616,7 +616,6 @@ M_IF_METHOD(INIT, oplist)( \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ - abort(); \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ M_CALL_INIT(oplist, out->data); \ @@ -632,7 +631,6 @@ M_IF_METHOD(INIT_SET, oplist)( \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ - abort(); \ } \ M_F(name, _read_lock)(src); \ M_ON_EXCEPTION( M_F(name, _read_unlock)(src), M_CALL_DEL(oplist, out) ) \ @@ -649,7 +647,6 @@ M_IF_METHOD(INIT_SET, oplist)( \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ - abort(); \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ M_CALL_INIT_SET(oplist, out->data, src); \ @@ -707,7 +704,6 @@ M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ - abort(); \ } \ M_ON_EXCEPTION( M_CALL_DEL(oplist, out) ) \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, out->data, exp_emplace_type); \ diff --git a/m-shared.h b/m-shared.h index 59622be6..3509533a 100644 --- a/m-shared.h +++ b/m-shared.h @@ -212,7 +212,6 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } ptr = M_CALL_NEW(oplist, struct M_F(name, _s)); \ if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _s), 1); \ - return; \ } \ ptr->data = data; \ M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \ @@ -230,7 +229,6 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \ if (M_UNLIKELY_NOMEM (p == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _combine_s), 1); \ - return; \ } \ struct M_F(name, _s) *ptr = &p->ptr; \ ptr->combineAlloc = true; \ @@ -377,7 +375,6 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \ if (M_UNLIKELY_NOMEM (p == NULL)) { \ M_MEMORY_FULL(struct M_F(name, _combine_s), 1); \ - return; \ } \ struct M_F(name, _s) *ptr = &p->ptr; \ ptr->combineAlloc = true; \ @@ -448,7 +445,6 @@ M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, 0, n); \ if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \ M_MEMORY_FULL(M_F(name, _atype_ct), n); \ - return; \ } \ for(size_t i = 0; i < n; i++) { \ M_CALL_INIT(oplist, s->buffer[i].x); \ diff --git a/m-snapshot.h b/m-snapshot.h index 3ebfc379..614e346d 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -394,7 +394,6 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n) atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, 0, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(atomic_uint, n); - return; } s->cptTab = ptr; for(size_t i = 0; i < n; i++) @@ -649,7 +648,6 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) if (M_UNLIKELY_NOMEM (snap->data == NULL)) { \ M_MEMORY_FULL(M_F(name, _aligned_type_ct), \ (nReader+M_SNAPSH0T_SPMC_EXTRA_BUFFER)); \ - return; \ } \ for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \ M_CALL_INIT(oplist, snap->data[i].x); \ diff --git a/m-string.h b/m-string.h index 4d52ff11..b4d12237 100644 --- a/m-string.h +++ b/m-string.h @@ -312,7 +312,6 @@ M_P(char *, m_string, _clear_get_cstr, m_string_t v) char *ptr = M_MEMORY_REALLOC (char, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(char, alloc); - return NULL; } M_ASSERT(ptr != NULL && p != NULL); memcpy(ptr, p, alloc); @@ -384,18 +383,12 @@ M_P(char *, m_str1ng, _fit2size, m_string_t v, size_t size_alloc) if (M_UNLIKELY_NOMEM (alloc <= size_alloc)) { /* Overflow in alloc computation */ M_MEMORY_FULL(char, alloc); - // NOTE: Return is currently broken. - abort(); - return NULL; } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; //FIXME: old_alloc may not be NULL if ptr is NULL. ptr = M_MEMORY_REALLOC (char, ptr, old_alloc, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(char, alloc); - // NOTE: Return is currently broken. - abort(); - return NULL; } // The pointer cannot be the embedded buffer of the string as it is heap allocated M_ASSERT(ptr != &v->u.buffer[0]); @@ -449,13 +442,11 @@ M_P(void, m_string, _reserve, m_string_t v, size_t alloc) size_t r_alloc = m_str1ng_round_capacity(&m, &e, (m_str1ng_size_t) alloc); if (M_UNLIKELY_NOMEM (alloc > r_alloc)) { M_MEMORY_FULL(char, alloc); - return; } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; ptr = M_MEMORY_REALLOC (char, ptr, m_string_capacity(v), r_alloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(char, alloc); - return; } if (m_str1ng_embedded_p(v)) { // Copy the characters embedded in the structure to the allocated heap space diff --git a/m-tree.h b/m-tree.h index c767f118..4610022f 100644 --- a/m-tree.h +++ b/m-tree.h @@ -261,7 +261,6 @@ typedef int32_t m_tr33_index_t; /* Realloc the array */ \ if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ - return; \ } \ /* Allocate one more term in the array so that tab[-1] exists. \ This enables performing latter tab[M_TR33_NO_NODE].x = something; \ @@ -271,7 +270,6 @@ typedef int32_t m_tr33_index_t; ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1), alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ - return; \ } \ /* Skip the first term to keep it as empty & unused */ \ ptr++; \ @@ -315,7 +313,6 @@ typedef int32_t m_tr33_index_t; alloc += tree->allow_realloc; \ if (M_UNLIKELY_NOMEM (alloc >= INT32_MAX)) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ - return M_TR33_NO_NODE; \ } \ /* Allocate one more term in the array so that tab[-1] exists. \ This enables performing latter tab[M_TR33_NO_NODE].x = something; \ @@ -325,7 +322,6 @@ typedef int32_t m_tr33_index_t; ptr = M_CALL_REALLOC(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1), alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ - return M_TR33_NO_NODE; \ } \ /* Skip the first term to keep it as empty & unused */ \ ptr++; \ @@ -1137,7 +1133,6 @@ typedef int32_t m_tr33_index_t; M_CALL_REALLOC(oplist, struct M_F(name, _node_s), NULL, 0, alloc+1); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ M_MEMORY_FULL(struct M_F(name, _node_s), alloc); \ - return; \ } \ tree->tab = ++ptr; \ /* We don't scan recursively the node tree, but sequentially */ \ diff --git a/m-worker.h b/m-worker.h index dae7068e..e8d58d70 100644 --- a/m-worker.h +++ b/m-worker.h @@ -412,7 +412,6 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st); if (M_UNLIKELY_NOMEM (g->worker == NULL)) { M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st); - return; } m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue); g->numWorker_g = (unsigned int) numWorker_st; From 8939b4d046c75b09fcf005be5647b9d27b367240 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 16 Mar 2025 21:16:32 +0100 Subject: [PATCH 25/91] New memory model is for 0.8.0 version --- Makefile | 2 +- doc/API.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 416f3858..148eb33b 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ DESTDIR= # Package name & version. PACKAGE=m_lib-$(VERSION) -VERSION=0.7.4 +VERSION=0.8.0 # Define the contain of the distribution tarball HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h diff --git a/doc/API.txt b/doc/API.txt index 7017a405..248acfef 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -86,7 +86,7 @@ V0.7.2: * Rename m-mutex.h header in m-thread.h V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated. Use DICT_DEF2 / DICT_DEF2_AS -V0.7.4 : * REALLOC / FREE operators are incompatible: +V0.8.0 : * REALLOC / FREE operators are incompatible: Add the old number of elements of the array as argument of REALLOC Add the number of elements of the array and its base type as arguments of FREE. You need to ignore the new arguments. From 324ba5d256723b31faedb1698a4c8297228ec34d Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 19 Mar 2025 20:57:44 +0100 Subject: [PATCH 26/91] Port to new memory model: M_MEMORY_FULL cannot return anymore --- m-bptree.h | 1 - m-bstring.h | 3 --- m-c-mempool.h | 1 - 3 files changed, 5 deletions(-) diff --git a/m-bptree.h b/m-bptree.h index a10af74c..68c6449f 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -414,7 +414,6 @@ node_t n = M_CALL_NEW(key_oplist, struct M_F(name, _node_s)); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ M_MEMORY_FULL(node_t, 1); \ - M_ASSERT (0); \ } \ n->next = NULL; \ n->num = 0; \ diff --git a/m-bstring.h b/m-bstring.h index 40338ada..fe984b06 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -179,9 +179,6 @@ M_P(uint8_t *, m_bstr1ng, _fit2size, m_bstring_t v, size_t size_alloc, bool exac return &v->ptr[v->offset]; allocation_error: M_MEMORY_FULL(uint8_t, size_alloc); - // NOTE: Return is currently broken. - abort(); - return NULL; } /* Push the byte 'c' in the bstring 'v' */ diff --git a/m-c-mempool.h b/m-c-mempool.h index cc7aa6fa..d2059016 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -756,7 +756,6 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem) mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { M_MEMORY_FULL(m_vlapool_lfmp_thread_ct, max_thread); - return; } for(unsigned i = 0; i < max_thread;i++) { m_vlapool_lfmp_thread_init(&mem->thread_data[i]); From 57e7510ae7424a3b64b269a7496e0925ce6ac2c8 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 19 Mar 2025 21:10:59 +0100 Subject: [PATCH 27/91] Format --- m-array.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/m-array.h b/m-array.h index e09a2469..1c057382 100644 --- a/m-array.h +++ b/m-array.h @@ -322,7 +322,7 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -(size_t)1); \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ M_ASSERT (alloc > v->size); \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ @@ -385,7 +385,7 @@ M_ASSERT(v->size == v->alloc); \ size_t alloc = M_CALL_INC_ALLOC(oplist, v->alloc); \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -(size_t)1); \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ M_ASSERT (alloc > v->size); \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ @@ -469,7 +469,7 @@ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ /* In case of overflow of size_t */ \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -(size_t)1); \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ @@ -598,7 +598,7 @@ if (size > v->alloc) { \ size_t alloc = M_CALL_INC_ALLOC(oplist, size) ; \ if (M_UNLIKELY_NOMEM (alloc <= v->alloc)) { \ - M_MEMORY_FULL(type, -(size_t)1); \ + M_MEMORY_FULL(type, -(size_t)1); \ } \ type *ptr = M_CALL_REALLOC(oplist, type, v->ptr, v->alloc, alloc); \ if (M_UNLIKELY_NOMEM (ptr == NULL) ) { \ From 76170480733f742e875222eb60ab59d31d75a0c5 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 19 Mar 2025 21:17:52 +0100 Subject: [PATCH 28/91] Port to new memory model --- m-snapshot.h | 52 +++++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/m-snapshot.h b/m-snapshot.h index 614e346d..4b82afe3 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -150,6 +150,7 @@ M_BEGIN_PROTECTED_CODE #define M_SNAPSH0T_SPSC_CONTRACT(snap) do { \ M_ASSERT((snap) != NULL); \ unsigned char f = atomic_load (&(snap)->flags); \ + (void) f; \ M_SNAPSH0T_SPSC_FLAGS_CONTRACT(f); \ } while (0) @@ -197,10 +198,10 @@ M_BEGIN_PROTECTED_CODE /* Define the core functions */ #define M_SNAPSH0T_SPSC_DEF_CORE(name, type, oplist, snapshot_t) \ \ - M_INLINE void \ - M_F(name, _init)(snapshot_t snap) \ + M_P(void, name, _init, snapshot_t snap) \ { \ M_ASSERT(snap != NULL); \ + M_ASSERT_POOL(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_INIT(oplist, snap->data[i].x); \ } \ @@ -208,20 +209,20 @@ M_BEGIN_PROTECTED_CODE M_SNAPSH0T_SPSC_CONTRACT(snap); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(snapshot_t snap) \ + M_P(void, name, _clear, snapshot_t snap) \ { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ + M_ASSERT_POOL(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_CLEAR(oplist, snap->data[i].x); \ } \ } \ \ /* const is missing for org due to use of atomic_load of org */ \ - M_INLINE void \ - M_F(name, _init_set)(snapshot_t snap, snapshot_t org) \ + M_P(void, name, _init_set, snapshot_t snap, snapshot_t org) \ { \ M_SNAPSH0T_SPSC_CONTRACT(org); \ + M_ASSERT_POOL(); \ M_ASSERT(snap != NULL && snap != org); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \ @@ -231,11 +232,11 @@ M_BEGIN_PROTECTED_CODE } \ \ /* const is missing for org due to use of atomic_load of org */ \ - M_INLINE void \ - M_F(name, _set)(snapshot_t snap, snapshot_t org) \ + M_P(void, name, _set, snapshot_t snap, snapshot_t org) \ { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ M_SNAPSH0T_SPSC_CONTRACT(org); \ + M_ASSERT_POOL(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \ } \ @@ -259,12 +260,11 @@ M_BEGIN_PROTECTED_CODE ,) /* IF_METHOD (INIT_MOVE) */ \ \ M_IF_METHOD(MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _move)(snapshot_t snap, \ - snapshot_t org) \ + M_P(void, name, _move, snapshot_t snap, snapshot_t org) \ { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ M_SNAPSH0T_SPSC_CONTRACT(org); \ + M_ASSERT_POOL(); \ M_ASSERT(snap != org); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \ @@ -382,8 +382,7 @@ typedef struct m_snapsh0t_mrsw_s { } while (0) /* Initialize m_snapsh0t_mrsw_ct for n readers (constructor) */ -M_INLINE void -m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n) +M_P(void, m_snapsh0t, _mrsw_init, m_snapsh0t_mrsw_ct s, size_t n) { M_ASSERT (s != NULL); M_ASSERT (n >= 1 && n <= M_SNAPSH0T_SPMC_MAX_READER); @@ -398,7 +397,7 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n) s->cptTab = ptr; for(size_t i = 0; i < n; i++) atomic_init(&s->cptTab[i], 0U); - m_genint_init (s->freeList, (unsigned int) n); + m_genint_init M_R(s->freeList, (unsigned int) n); // Get a free buffer and set it as available for readers unsigned int w = m_genint_pop(s->freeList); @@ -414,12 +413,11 @@ m_snapsh0t_mrsw_init(m_snapsh0t_mrsw_ct s, size_t n) } /* Clear m_snapsh0t_mrsw_ct (destructor) */ -M_INLINE void -m_snapsh0t_mrsw_clear(m_snapsh0t_mrsw_ct s) +M_P(void, m_snapsh0t, _mrsw_clear, m_snapsh0t_mrsw_ct s) { M_SNAPSH0T_SPMC_INT_CONTRACT(s); M_MEMORY_FREE (atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); - m_genint_clear(s->freeList); + m_genint_clear M_R(s->freeList); s->cptTab = NULL; s->n_reader = 0; } @@ -638,8 +636,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) /* Define the core functions */ #define M_SNAPSH0T_SPMC_DEF_CORE(name, type, oplist, snapshot_t) \ \ - M_INLINE void \ - M_F(name, _init)(snapshot_t snap, size_t nReader) \ + M_P(void, name, _init, snapshot_t snap, size_t nReader) \ { \ M_ASSERT (snap != NULL); \ M_ASSERT (nReader > 0 && nReader <= M_SNAPSH0T_SPMC_MAX_READER); \ @@ -652,12 +649,11 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) for(size_t i = 0; i < nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER; i++) { \ M_CALL_INIT(oplist, snap->data[i].x); \ } \ - m_snapsh0t_mrsw_init(snap->core, nReader); \ + m_snapsh0t_mrsw_init M_R(snap->core, nReader); \ M_SNAPSH0T_SPMC_CONTRACT(snap); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(snapshot_t snap) \ + M_P(void, name, _clear, snapshot_t snap) \ { \ M_SNAPSH0T_SPMC_CONTRACT(snap); \ size_t nReader = m_snapsh0t_mrsw_size(snap->core); \ @@ -665,7 +661,7 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) M_CALL_CLEAR(oplist, snap->data[i].x); \ } \ M_CALL_FREE(oplist, M_F(name, _aligned_type_ct), snap->data, nReader + M_SNAPSH0T_SPMC_EXTRA_BUFFER); \ - m_snapsh0t_mrsw_clear(snap->core); \ + m_snapsh0t_mrsw_clear M_R(snap->core); \ } \ \ M_INLINE type * \ @@ -744,19 +740,17 @@ m_snapsh0t_mrsw_read_end(m_snapsh0t_mrsw_ct s, unsigned int idx) /* Define the core functions */ #define M_SNAPSH0T_MPMC_DEF_CORE(name, type, oplist, snapshot_t) \ \ - M_INLINE void \ - M_F(name, _init)(snapshot_t snap, size_t nReader, size_t nWriter) \ + M_P(void, name, _init, snapshot_t snap, size_t nReader, size_t nWriter) \ { \ - M_F(name, _mrsw_init)(snap->core, nReader + nWriter -1 ); \ + M_F(name, _mrsw_init)M_R(snap->core, nReader + nWriter -1 ); \ unsigned int idx = snap->core->core->currentWrite; \ snap->core->core->currentWrite = M_GENINT_ERROR; \ m_snapsh0t_mrsw_write_end(snap->core->core, idx); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(snapshot_t snap) \ + M_P(void, name, _clear, snapshot_t snap) \ { \ - M_F(name, _mrsw_clear)(snap->core); \ + M_F(name, _mrsw_clear)M_R(snap->core); \ } \ \ M_INLINE type * \ From 26fc2bcffe0dfee04a71921e179f32a01e677b8c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 20 Mar 2025 23:22:57 +0100 Subject: [PATCH 29/91] Port tree to new memory model --- m-tree.h | 216 +++++++++++++++++++++++-------------------------------- 1 file changed, 89 insertions(+), 127 deletions(-) diff --git a/m-tree.h b/m-tree.h index 4610022f..c1e76f58 100644 --- a/m-tree.h +++ b/m-tree.h @@ -215,9 +215,9 @@ typedef int32_t m_tr33_index_t; M_TR33_CONTRACT(tree); \ } \ \ - M_INLINE void \ - M_F(name, _reset)(tree_t tree) { \ + M_P(void, name, _reset, tree_t tree) { \ M_TR33_CONTRACT(tree); \ + M_ASSERT_POOL(); \ if (tree->size > 0) { \ /* We don't scan recursively the node tree, but sequentially */ \ m_tr33_index_t free_index = tree->free_index; \ @@ -241,9 +241,8 @@ typedef int32_t m_tr33_index_t; M_TR33_CONTRACT(tree); \ } \ \ - M_INLINE void \ - M_F(name, _clear)(tree_t tree) { \ - M_F(name, _reset)(tree); \ + M_P(void, name, _clear, tree_t tree) { \ + M_F(name, _reset)M_R(tree); \ struct M_F(name,_node_s)*ptr = tree->tab == NULL ? NULL : tree->tab-1;\ M_CALL_FREE(oplist, struct M_F(name, _node_s), ptr, (size_t)(tree->capacity+1)); \ /* This is so reusing the object implies an assertion failure */ \ @@ -251,8 +250,7 @@ typedef int32_t m_tr33_index_t; tree->tab = NULL; \ } \ \ - M_INLINE void \ - M_F(name, _reserve)(tree_t tree, size_t alloc) { \ + M_P(void, name, _reserve, tree_t tree, size_t alloc) { \ M_TR33_CONTRACT(tree); \ /* Nothing to do if the request is lower than the current capacity. */ \ if (alloc <= (size_t) tree->capacity) { \ @@ -303,8 +301,7 @@ typedef int32_t m_tr33_index_t; M_TR33_CONTRACT(tree); \ } \ \ - M_INLINE m_tr33_index_t \ - M_C3(m_tr33_, name, _alloc_node)(tree_t tree) { \ + M_P(m_tr33_index_t, name, _i_alloc_node, tree_t tree) { \ m_tr33_index_t ret = tree->free_index; \ if (M_UNLIKELY(ret < 0)) { \ /* No more enough space: realloc the array */ \ @@ -356,11 +353,10 @@ typedef int32_t m_tr33_index_t; tree->free_index = i; \ } \ \ - M_INLINE it_t \ - M_F(name, _set_root)(tree_t tree, type const data) { \ + M_P(it_t, name, _set_root, tree_t tree, type const data) { \ M_TR33_CONTRACT(tree); \ - M_F(name, _reset)(tree); \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(tree); \ + M_F(name, _reset)M_R(tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(tree); \ tree->tab[i].parent = M_TR33_ROOT_NODE; \ tree->tab[i].left = M_TR33_NO_NODE; \ tree->tab[i].right = M_TR33_NO_NODE; \ @@ -442,10 +438,9 @@ typedef int32_t m_tr33_index_t; return i < 0 ? NULL : &it.tree->tab[i].data; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_up_raw)(it_t it) { \ + M_P(it_t, name, _insert_up_raw, it_t it) { \ M_TR33_IT_CONTRACT(it, true); \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \ m_tr33_index_t parent = it.tree->tab[it.index].parent; \ m_tr33_index_t left = it.tree->tab[it.index].left; \ m_tr33_index_t right = it.tree->tab[it.index].right; \ @@ -472,26 +467,23 @@ typedef int32_t m_tr33_index_t; return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_up)(it_t pos, type const data) { \ - it_t it = M_F(name, _insert_up_raw)(pos); \ + M_P(it_t, name, _insert_up, it_t pos, type const data) { \ + it_t it = M_F(name, _insert_up_raw)M_R(pos); \ M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _move_up)(it_t pos, type *data) { \ - it_t it = M_F(name, _insert_up_raw)(pos); \ + M_P(it_t, name, _move_up, it_t pos, type *data) { \ + it_t it = M_F(name, _insert_up_raw)M_R(pos); \ M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_down_raw)(it_t it) { \ + M_P(it_t, name, _insert_down_raw, it_t it) { \ M_TR33_IT_CONTRACT(it, true); \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \ m_tr33_index_t child = it.tree->tab[it.index].child; \ it.tree->tab[i].parent = it.index; \ it.tree->tab[i].left = M_TR33_NO_NODE; \ @@ -509,28 +501,25 @@ typedef int32_t m_tr33_index_t; return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_down)(it_t pos, type const data) { \ - it_t it = M_F(name, _insert_down_raw)(pos); \ + M_P(it_t, name, _insert_down, it_t pos, type const data) { \ + it_t it = M_F(name, _insert_down_raw)M_R(pos); \ M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _move_down)(it_t pos, type *data) { \ - it_t it = M_F(name, _insert_down_raw)(pos); \ + M_P(it_t, name, _move_down, it_t pos, type *data) { \ + it_t it = M_F(name, _insert_down_raw)M_R(pos); \ M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_child_raw)(it_t it) { \ + M_P(it_t, name, _insert_child_raw, it_t it) { \ M_TR33_IT_CONTRACT(it, true); \ /* Insert a node as a child of another, making the current children \ of the nodes their siblings */ \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \ m_tr33_index_t child = it.tree->tab[it.index].child; \ it.tree->tab[i].parent = it.index; \ it.tree->tab[i].left = M_TR33_NO_NODE; \ @@ -546,27 +535,24 @@ typedef int32_t m_tr33_index_t; return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_child)(it_t pos, type const data) { \ - it_t it = M_F(name, _insert_child_raw)(pos); \ + M_P(it_t, name, _insert_child, it_t pos, type const data) { \ + it_t it = M_F(name, _insert_child_raw)M_R(pos); \ M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _move_child)(it_t pos, type *data) { \ - it_t it = M_F(name, _insert_child_raw)(pos); \ + M_P(it_t, name, _move_child, it_t pos, type *data) { \ + it_t it = M_F(name, _insert_child_raw)M_R(pos); \ M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_left_raw)(it_t it) { \ + M_P(it_t, name, _insert_left_raw, it_t it) { \ M_TR33_IT_CONTRACT(it, true); \ M_ASSERT(it.index != it.tree->root_index); \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \ m_tr33_index_t left = it.tree->tab[it.index].left; \ m_tr33_index_t parent = it.tree->tab[it.index].parent; \ it.tree->tab[i].parent = parent; \ @@ -586,27 +572,24 @@ typedef int32_t m_tr33_index_t; return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_left)(it_t pos, type const data) { \ - it_t it = M_F(name, _insert_left_raw)(pos); \ + M_P(it_t, name, _insert_left, it_t pos, type const data) { \ + it_t it = M_F(name, _insert_left_raw)M_R(pos); \ M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _move_left)(it_t pos, type *data) { \ - it_t it = M_F(name, _insert_left_raw)(pos); \ + M_P(it_t, name, _move_left, it_t pos, type *data) { \ + it_t it = M_F(name, _insert_left_raw)M_R(pos); \ M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_right_raw)(it_t it) { \ + M_P(it_t, name, _insert_right_raw, it_t it) { \ M_TR33_IT_CONTRACT(it, true); \ M_ASSERT(it.index != it.tree->root_index); \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(it.tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(it.tree); \ m_tr33_index_t right = it.tree->tab[it.index].right; \ it.tree->tab[i].parent = it.tree->tab[it.index].parent; \ it.tree->tab[i].left = it.index; \ @@ -620,17 +603,15 @@ typedef int32_t m_tr33_index_t; return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _insert_right)(it_t pos, type const data) { \ - it_t it = M_F(name, _insert_right_raw)(pos); \ + M_P(it_t, name, _insert_right, it_t pos, type const data) { \ + it_t it = M_F(name, _insert_right_raw)M_R(pos); \ M_CALL_INIT_SET(oplist, it.tree->tab[it.index].data, data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ \ - M_INLINE it_t \ - M_F(name, _move_right)(it_t pos, type *data) { \ - it_t it = M_F(name, _insert_right_raw)(pos); \ + M_P(it_t, name, _move_right, it_t pos, type *data) { \ + it_t it = M_F(name, _insert_right_raw)M_R(pos); \ M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ @@ -880,9 +861,9 @@ typedef int32_t m_tr33_index_t; return &it.tree->tab[it.index].data; \ } \ \ - M_INLINE bool \ - M_F(name, _remove)(it_t it) { \ + M_P(bool, name, _remove, it_t it) { \ M_TR33_IT_CONTRACT(it, false); \ + M_ASSERT_POOL(); \ if (M_UNLIKELY(it.index < 0)) { return false; } \ type *ptr = M_F(name, _unlink)(it); \ M_CALL_CLEAR(oplist, *ptr); \ @@ -1014,15 +995,14 @@ typedef int32_t m_tr33_index_t; assert(b); \ } \ \ - M_INLINE void \ - M_F(name, _prune)(it_t it) { \ + M_P(void, name, _prune, it_t it) { \ M_TR33_IT_CONTRACT(it, true); \ /* remove the node, including its childs */ \ it_t child = M_F(name, _it_subpost)(it); \ while (!M_F(name, _end_p)(child)) { \ it_t next = child; \ M_F(name, _next_subpost)(&next, it); \ - bool b = M_F(name, _remove)(child); \ + bool b = M_F(name, _remove)M_R(child); \ (void) b; /* parameter not used */ \ M_ASSERT(b); \ child = next; \ @@ -1118,8 +1098,7 @@ typedef int32_t m_tr33_index_t; /* Define the classic extended missing methods of a tree */ #define M_TR33_DEF_P4_EXT(name, type, oplist, tree_t, it_t) \ - M_INLINE void \ - M_F(name, _init_set)(tree_t tree, const tree_t ref) { \ + M_P(void, name, _init_set, tree_t tree, const tree_t ref) { \ tree->size = ref->size; \ tree->capacity = ref->capacity; \ tree->root_index = ref->root_index; \ @@ -1150,11 +1129,10 @@ typedef int32_t m_tr33_index_t; M_TR33_CONTRACT(tree); \ } \ \ - M_INLINE void \ - M_F(name, _set)(tree_t tree, const tree_t ref) { \ + M_P(void, name, _set, tree_t tree, const tree_t ref) { \ /* No optimum, but good enough currently */ \ - M_F(name, _clear)(tree); \ - M_F(name, _init_set)(tree, ref); \ + M_F(name, _clear)M_R(tree); \ + M_F(name, _init_set)M_R(tree, ref); \ } \ \ M_INLINE void \ @@ -1170,9 +1148,8 @@ typedef int32_t m_tr33_index_t; ref->tab = NULL; \ } \ \ - M_INLINE void \ - M_F(name, _move)(tree_t tree, tree_t ref) { \ - M_F(name, _clear)(tree); \ + M_P(void, name, _move, tree_t tree, tree_t ref) { \ + M_F(name, _clear)M_R(tree); \ M_F(name, _init_move)(tree, ref); \ } \ \ @@ -1294,30 +1271,29 @@ typedef int32_t m_tr33_index_t; /* Define the IO methods of a tree */ #define M_TR33_DEF_P4_IO(name, type, oplist, tree_t, it_t) \ M_IF_METHOD(GET_STR, oplist)( \ -M_INLINE void \ -M_F(name, _get_str)(m_string_t str, /*const*/ tree_t tree, bool append) { \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ +M_P(void, name, _get_str, m_string_t str, /*const*/ tree_t tree, bool append) { \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \ it_t it = M_F(name, _it)(tree); \ while (!M_F(name, _end_p)(it)) { \ - m_string_push_back (str, '{'); \ + m_string_push_back M_R(str, '{'); \ type const *item = M_F(name, _cref)(it); \ M_CALL_GET_STR(oplist, str, *item, true); \ /* Go down the tree */ \ if (M_F(name, _it_down)(&it)) { \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ - m_string_push_back (str, '['); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, '['); \ continue; \ } \ - m_string_push_back (str, '}'); \ + m_string_push_back M_R(str, '}'); \ if (M_F(name, _it_right)(&it)) { \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ continue; \ } \ while (M_F(name, _it_up)(&it)) { \ - m_string_push_back (str, ']'); \ - m_string_push_back (str, '}'); \ + m_string_push_back M_R(str, ']'); \ + m_string_push_back M_R(str, '}'); \ if (M_F(name, _it_right)(&it)) { \ - m_string_push_back (str, M_GET_SEPARATOR oplist); \ + m_string_push_back M_R(str, M_GET_SEPARATOR oplist); \ goto continue_tree; \ } \ } \ @@ -1325,17 +1301,16 @@ M_F(name, _get_str)(m_string_t str, /*const*/ tree_t tree, bool append) { \ continue_tree: \ (void) 0; \ } \ - m_string_push_back (str, ']'); \ + m_string_push_back M_R(str, ']'); \ } \ , /* No GET_STR */ ) \ \ M_IF_METHOD(PARSE_STR, oplist)( \ -M_INLINE bool \ -M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) { \ +M_P(bool, name, _parse_str, tree_t tree, const char str[], const char **endp) { \ M_TR33_CONTRACT(tree); \ int cmd = 0; \ it_t it; \ - M_F(name, _reset)(tree); \ + M_F(name, _reset)M_R(tree); \ bool success = false; \ int c = *str; \ if (M_UNLIKELY (c != '[')) goto exit; \ @@ -1352,9 +1327,9 @@ M_F(name, _parse_str)(tree_t tree, const char str[], const char **endp) { \ if (b == false || c == 0) break; \ /* Insert the item as the root or as a right sibling or as a child */ \ switch (cmd) { \ - case 0: it = M_F(name, _set_root)(tree, item); break; \ - case 1: it = M_F(name, _insert_right)(it, item); break; \ - case 2: it = M_F(name, _insert_child)(it, item); break; \ + case 0: it = M_F(name, _set_root)M_R(tree, item); break; \ + case 1: it = M_F(name, _insert_right)M_R(it, item); break; \ + case 2: it = M_F(name, _insert_child)M_R(it, item); break; \ default: M_ASSERT(0); \ } \ if (c == ',') { \ @@ -1427,12 +1402,11 @@ M_F(name, _out_str)(FILE *f, /*const*/ tree_t tree) { \ , /* No OUT_STR */ ) \ \ M_IF_METHOD(IN_STR, oplist)( \ -M_INLINE bool \ -M_F(name, _in_str)(tree_t tree, FILE *f) { \ +M_P(bool, name, _in_str, tree_t tree, FILE *f) { \ M_TR33_CONTRACT(tree); \ int cmd = 0; \ it_t it; \ - M_F(name, _reset)(tree); \ + M_F(name, _reset)M_R(tree); \ bool success = false; \ int c = fgetc(f); \ if (M_UNLIKELY (c != '[')) goto exit; \ @@ -1450,9 +1424,9 @@ M_F(name, _in_str)(tree_t tree, FILE *f) { \ if (b == false || c == 0) break; \ /* Insert the item as the root or as a right sibling or as a child */ \ switch (cmd) { \ - case 0: it = M_F(name, _set_root)(tree, item); break; \ - case 1: it = M_F(name, _insert_right)(it, item); break; \ - case 2: it = M_F(name, _insert_child)(it, item); break; \ + case 0: it = M_F(name, _set_root)M_R(tree, item); break; \ + case 1: it = M_F(name, _insert_right)M_R(it, item); break; \ + case 2: it = M_F(name, _insert_child)M_R(it, item); break; \ default: M_ASSERT(0); \ } \ if (c == ',') { \ @@ -1489,22 +1463,20 @@ exit: \ /* Define the emplace methods of a tree */ #define M_TR33_DEF_P4_EMPLACE(name, type, oplist, tree_t, it_t) \ - M_EMPLACE_QUEUE_DEF(name, tree_t, M_F(name, _emplace_root), oplist, M_TR33_EMPLACE_ROOT_DEF) \ - M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_up), oplist, M_TR33_EMPLACE_UP_DEF) \ - M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_down), oplist, M_TR33_EMPLACE_DOWN_DEF) \ - M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_child), oplist, M_TR33_EMPLACE_CHILD_DEF) \ - M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_left), oplist, M_TR33_EMPLACE_LEFT_DEF) \ - M_EMPLACE_QUEUE_DEF(name, it_t, M_F(name, _emplace_right), oplist, M_TR33_EMPLACE_RIGHT_DEF) + M_EMPLACE_QUEUE_DEF(name, tree_t, _emplace_root, oplist, M_TR33_EMPLACE_ROOT_DEF) \ + M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_up, oplist, M_TR33_EMPLACE_UP_DEF) \ + M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_down, oplist, M_TR33_EMPLACE_DOWN_DEF) \ + M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_child, oplist, M_TR33_EMPLACE_CHILD_DEF) \ + M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_left, oplist, M_TR33_EMPLACE_LEFT_DEF) \ + M_EMPLACE_QUEUE_DEF(name, it_t, _emplace_right, oplist, M_TR33_EMPLACE_RIGHT_DEF) /* Definition of the emplace_back functions */ #define M_TR33_EMPLACE_ROOT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE M_F(name, _it_ct) \ - function_name(name_t tree \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(M_F(name, _it_ct), name, function_name, name_t tree M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_TR33_CONTRACT(tree); \ - M_F(name, _reset)(tree); \ - m_tr33_index_t i = M_C3(m_tr33_, name, _alloc_node)(tree); \ + M_F(name, _reset)M_R(tree); \ + m_tr33_index_t i = M_F(name, _i_alloc_node)M_R(tree); \ tree->tab[i].parent = M_TR33_ROOT_NODE; \ tree->tab[i].left = M_TR33_NO_NODE; \ tree->tab[i].right = M_TR33_NO_NODE; \ @@ -1520,55 +1492,45 @@ exit: \ } #define M_TR33_EMPLACE_UP_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE name_t \ - function_name(name_t pos \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - name_t it = M_F(name, _insert_up_raw)(pos); \ + name_t it = M_F(name, _insert_up_raw)M_R(pos); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \ exp_emplace_type); \ return it; \ } #define M_TR33_EMPLACE_DOWN_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE name_t \ - function_name(name_t pos \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - name_t it = M_F(name, _insert_down_raw)(pos); \ + name_t it = M_F(name, _insert_down_raw)M_R(pos); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \ exp_emplace_type); \ return it; \ } #define M_TR33_EMPLACE_CHILD_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE name_t \ - function_name(name_t pos \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - name_t it = M_F(name, _insert_child_raw)(pos); \ + name_t it = M_F(name, _insert_child_raw)M_R(pos); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \ exp_emplace_type); \ return it; \ } #define M_TR33_EMPLACE_LEFT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE name_t \ - function_name(name_t pos \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - name_t it = M_F(name, _insert_left_raw)(pos); \ + name_t it = M_F(name, _insert_left_raw)M_R(pos); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \ exp_emplace_type); \ return it; \ } #define M_TR33_EMPLACE_RIGHT_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE name_t \ - function_name(name_t pos \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ + M_P(name_t, name, function_name, name_t pos M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - name_t it = M_F(name, _insert_right_raw)(pos); \ + name_t it = M_F(name, _insert_right_raw)M_R(pos); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, it.tree->tab[it.index].data, \ exp_emplace_type); \ return it; \ From d08aeb32fe357a530f24da8b3d86c5168bb48f23 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 23 Mar 2025 13:15:11 +0100 Subject: [PATCH 30/91] Port to new memory model --- m-tuple.h | 72 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/m-tuple.h b/m-tuple.h index c2efbc05..f7402ae8 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -243,7 +243,8 @@ namespace m_lib { /* Define the INIT method calling the INIT method for all params */ #define M_TUPL3_DEFINE_INIT(name, ...) \ - M_INLINE void M_F(name, _init)(M_F(name,_ct) my) { \ + M_P(void, name, _init, M_F(name,_ct) my) { \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_INIT_FUNC , __VA_ARGS__) {} \ } @@ -252,8 +253,9 @@ namespace m_lib { /* Define the INIT_SET method calling the INIT_SET method for all params */ #define M_TUPL3_DEFINE_INIT_SET(name, ...) \ - M_INLINE void M_F(name, _init_set)(M_F(name,_ct) my , M_F(name,_ct) const org) { \ + M_P(void, name, _init_set, M_F(name,_ct) my , M_F(name,_ct) const org) { \ M_TUPL3_CONTRACT(org); \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_INIT_SET_FUNC , __VA_ARGS__) {} \ } #define M_TUPL3_DEFINE_INIT_SET_FUNC(a) \ @@ -262,15 +264,11 @@ namespace m_lib { /* Define the INIT_WITH method calling the INIT_SET method for all params. */ #define M_TUPL3_DEFINE_INIT_SET2(name, ...) \ - M_INLINE void M_F(name, _init_emplace)(M_F(name,_ct) my \ - M_MAP(M_TUPL3_DEFINE_INIT_SET2_PROTO, __VA_ARGS__) \ - ) { \ + M_P(void, name, _init_emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) {} \ } -#define M_TUPL3_DEFINE_INIT_SET2_PROTO(a) \ - , M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a - #define M_TUPL3_DEFINE_INIT_SET2_FUNC(a) \ M_CHAIN_OBJ(M_TUPL3_GET_FIELD a, M_TUPL3_GET_OPLIST a, \ my -> M_TUPL3_GET_FIELD a , M_TUPL3_GET_FIELD a ) @@ -278,10 +276,10 @@ namespace m_lib { /* Define the SET method calling the SET method for all params. */ #define M_TUPL3_DEFINE_SET(name, ...) \ - M_INLINE void M_F(name, _set)(M_F(name,_ct) my , \ - M_F(name,_ct) const org) { \ + M_P(void, name, _set, M_F(name,_ct) my, M_F(name,_ct) const org) { \ M_TUPL3_CONTRACT(my); \ M_TUPL3_CONTRACT(org); \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_SET_FUNC , __VA_ARGS__) \ } @@ -291,10 +289,9 @@ namespace m_lib { /* Define the SET_WITH method calling the SET method for all params. */ #define M_TUPL3_DEFINE_SET2(name, ...) \ - M_INLINE void M_F(name, _emplace)(M_F(name,_ct) my \ - M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) \ - ) { \ + M_P(void, name, _emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \ M_TUPL3_CONTRACT(my); \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_SET2_FUNC , __VA_ARGS__) \ } #define M_TUPL3_DEFINE_SET2_PROTO(a) \ @@ -306,8 +303,9 @@ namespace m_lib { /* Define the CLEAR method calling the CLEAR method for all params. */ #define M_TUPL3_DEFINE_CLEAR(name, ...) \ - M_INLINE void M_F(name, _clear)(M_F(name,_ct) my) { \ + M_P(void, name, _clear, M_F(name,_ct) my) { \ M_TUPL3_CONTRACT(my); \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_CLEAR_FUNC , __VA_ARGS__) \ } @@ -343,8 +341,9 @@ namespace m_lib { #define M_TUPL3_DEFINE_SETTER_FIELD_PROTO(name, a) \ M_INLINE void M_C3(name, _set_, M_TUPL3_GET_FIELD a) \ - (M_F(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \ + (M_P_EXPAND M_F(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \ M_TUPL3_CONTRACT(my); \ + M_ASSERT_POOL(); \ M_TUPL3_CALL_SET(a, my ->M_TUPL3_GET_FIELD a, M_TUPL3_GET_FIELD a); \ } @@ -360,9 +359,10 @@ namespace m_lib { #define M_TUPL3_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ M_INLINE void \ - function_name(name_t v \ + function_name(M_P_EXPAND name_t v \ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ + M_ASSERT_POOL(); \ M_CALL_CLEAR(oplist, v->name); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->name, exp_emplace_type); \ } @@ -468,27 +468,26 @@ namespace m_lib { /* Define a GET_STR method by calling the GET_STR methods for all params */ #define M_TUPL3_DEFINE_GET_STR(name, ...) \ - M_INLINE void M_F(name, _get_str)(m_string_t str, \ - M_F(name,_ct) const el, \ - bool append) { \ + M_P(void, name, _get_str, m_string_t str, M_F(name,_ct) const el, bool append) \ + { \ bool comma = false; \ M_TUPL3_CONTRACT(el); \ M_ASSERT (str != NULL); \ - (append ? m_string_cat_cstr : m_string_set_cstr) (str, "("); \ + (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "("); \ M_MAP(M_TUPL3_DEFINE_GET_STR_FUNC , __VA_ARGS__) \ - m_string_push_back (str, ')'); \ + m_string_push_back M_R(str, ')'); \ } #define M_TUPL3_DEFINE_GET_STR_FUNC(a) \ - if (comma) m_string_push_back (str, ','); \ + if (comma) m_string_push_back M_R(str, ','); \ comma = true; \ M_TUPL3_CALL_GET_STR(a, str, el -> M_TUPL3_GET_FIELD a, true); \ /* Define a OUT_STR method by calling the OUT_STR methods for all params */ #define M_TUPL3_DEFINE_OUT_STR(name, ...) \ - M_INLINE void M_F(name, _out_str)(FILE *f, \ - M_F(name,_ct) const el) { \ + M_INLINE void M_F(name, _out_str)(FILE *f, M_F(name,_ct) const el) \ + { \ bool comma = false; \ M_TUPL3_CONTRACT(el); \ M_ASSERT (f != NULL); \ @@ -505,9 +504,11 @@ namespace m_lib { /* Define a IN_STR method by calling the IN_STR methods for all params */ #define M_TUPL3_DEFINE_IN_STR(name, ...) \ - M_INLINE bool M_F(name, _in_str)(M_F(name,_ct) el, FILE *f) { \ + M_P(bool, name, _in_str, M_F(name,_ct) el, FILE *f) \ + { \ bool comma = false; \ M_TUPL3_CONTRACT(el); \ + M_ASSERT_POOL(); \ M_ASSERT (f != NULL); \ int c = fgetc(f); \ if (c != '(') return false; \ @@ -528,11 +529,11 @@ namespace m_lib { /* Define a PARSE_STR method by calling the PARSE_STR methods for all params */ #define M_TUPL3_DEFINE_PARSE_STR(name, ...) \ - M_INLINE bool M_F(name, _parse_str)(M_F(name,_ct) el, \ - const char str[], \ - const char **endptr) { \ + M_P(bool, name, _parse_str, M_F(name,_ct) el, const char str[], const char **endptr) \ + { \ M_TUPL3_CONTRACT(el); \ M_ASSERT (str != NULL); \ + M_ASSERT_POOL(); \ bool success = false; \ bool comma = false; \ int c = *str++; \ @@ -563,8 +564,8 @@ namespace m_lib { /* Define a OUT_SERIAL method by calling the OUT_SERIAL methods for all params */ #define M_TUPL3_DEFINE_OUT_SERIAL(name, ...) \ M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, \ - M_F(name,_ct) const el) { \ + M_F(name, _out_serial)(m_serial_write_t f, M_F(name,_ct) const el) \ + { \ M_TUPL3_CONTRACT(el); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ const int field_max = M_NARGS(__VA_ARGS__); \ @@ -589,9 +590,10 @@ namespace m_lib { /* Define a IN_SERIAL method by calling the IN_SERIAL methods for all params */ #define M_TUPL3_DEFINE_IN_SERIAL(name, ...) \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(M_F(name,_ct) el, m_serial_read_t f) { \ + M_P(m_serial_return_code_t, name, _in_serial, M_F(name,_ct) el, m_serial_read_t f) \ + { \ M_TUPL3_CONTRACT(el); \ + M_ASSERT_POOL(); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ int index = -1; \ const int field_max = M_NARGS(__VA_ARGS__); \ @@ -634,8 +636,9 @@ namespace m_lib { /* Define a MOVE method by calling the MOVE methods for all params */ #define M_TUPL3_DEFINE_MOVE(name, ...) \ - M_INLINE void M_F(name, _move)(M_F(name,_ct) el, M_F(name,_ct) org) { \ + M_P(void, name, _move, M_F(name,_ct) el, M_F(name,_ct) org) { \ M_TUPL3_CONTRACT(el); \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_MOVE_FUNC , __VA_ARGS__) \ } @@ -657,8 +660,9 @@ namespace m_lib { /* Define a RESET method by calling the RESET methods for all params */ #define M_TUPL3_DEFINE_RESET(name, ...) \ - M_INLINE void M_F(name, _reset)(M_F(name,_ct) el1) { \ + M_P(void, name, _reset, M_F(name,_ct) el1) { \ M_TUPL3_CONTRACT(el1); \ + M_ASSERT_POOL(); \ M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \ } \ From 32a3d95104ca69cabb42af0977712e08502a5616 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 25 Mar 2025 00:19:53 +0100 Subject: [PATCH 31/91] Port to new memory model --- m-variant.h | 109 +++++++++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/m-variant.h b/m-variant.h index f47590d6..4c86d6bc 100644 --- a/m-variant.h +++ b/m-variant.h @@ -224,15 +224,17 @@ /* Define the INIT_SET function. */ #define M_VAR1ANT_DEFINE_INIT_SET(name, ...) \ - M_INLINE void M_F(name, _init_set)(M_F(name,_ct) my , \ - M_F(name,_ct) const org) { \ + M_P(void, name, _init_set, M_F(name,_ct) my, M_F(name,_ct) const org) \ + { \ M_VAR1ANT_CONTRACT(name, org); \ + M_ASSERT_POOL(); \ my->type = org->type; \ switch (org->type) { \ M_MAP2(M_VAR1ANT_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \ case M_F(name, _EMPTY): /* fallthrough */ \ default: M_ASSUME(org->type == M_F(name, _EMPTY)); break; \ } \ + M_VAR1ANT_CONTRACT(name, my); \ } #define M_VAR1ANT_DEFINE_INIT_SET_FUNC(name, a) \ @@ -244,14 +246,14 @@ /* Define the SET function. */ #define M_VAR1ANT_DEFINE_SET(name, ...) \ - M_INLINE void M_F(name, _set)(M_F(name,_ct) my , \ - M_F(name,_ct) const org) { \ + M_P(void, name, _set, M_F(name,_ct) my, M_F(name,_ct) const org) \ + { \ M_VAR1ANT_CONTRACT(name, my); \ M_VAR1ANT_CONTRACT(name, org); \ if (my->type != org->type) { \ /* Different types: clear previous one and create new */ \ - M_F(name, _clear)(my); \ - M_F(name, _init_set)(my, org); \ + M_F(name, _clear)M_R(my); \ + M_F(name, _init_set)M_R(my, org); \ } else { \ /* Same type: optimize the set */ \ switch (org->type) { \ @@ -260,6 +262,8 @@ default: M_ASSUME(org->type == M_F(name, _EMPTY)); break; \ } \ } \ + M_ASSERT( my->type == org->type ); \ + M_VAR1ANT_CONTRACT(name, my); \ } #define M_VAR1ANT_DEFINE_SET_FUNC(name, a) \ @@ -271,14 +275,17 @@ /* Define the CLEAR function. */ #define M_VAR1ANT_DEFINE_CLEAR(name, ...) \ - M_INLINE void M_F(name, _clear)(M_F(name,_ct) my) { \ + M_P(void, name, _clear, M_F(name,_ct) my) \ + { \ M_VAR1ANT_CONTRACT(name, my); \ + M_ASSERT_POOL(); \ switch (my->type) { \ M_MAP2(M_VAR1ANT_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \ case M_F(name, _EMPTY): /* fallthrough */ \ default: M_ASSUME(my->type == M_F(name, _EMPTY)); break; \ } \ - my->type = M_F(name, _EMPTY); \ + /* Invalid representation */ \ + my->type = M_F(name, _EMPTY) - 1; \ } #define M_VAR1ANT_DEFINE_CLEAR_FUNC(name, a) \ @@ -314,7 +321,9 @@ #define M_VAR1ANT_DEFINE_INIT_FIELD_FUNC(name, a) \ M_INLINE void \ - M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my) { \ + M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my) \ + { \ + M_ASSERT_POOL(); \ /* Reinit variable with the given value */ \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT(a, my -> value. M_VAR1ANT_GET_FIELD a); \ @@ -327,15 +336,17 @@ #define M_VAR1ANT_DEFINE_INIT_SETTER_FIELD_FUNC(name, num, a) \ M_INLINE void \ - M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \ - M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \ + M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \ + { \ + M_ASSERT_POOL(); \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ } \ M_INLINE void \ - M_C4(m_var1ant_, name, _init_set_, num)(M_F(name,_ct) my, \ - M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \ + M_C4(m_var1ant_, name, _init_set_, num)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \ + { \ + M_ASSERT_POOL(); \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ @@ -348,14 +359,14 @@ #define M_VAR1ANT_DEFINE_SETTER_FIELD_FUNC(name, a) \ M_INLINE void \ - M_C3(name, _set_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \ + M_C3(name, _set_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, \ M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a ) { \ M_VAR1ANT_CONTRACT(name, my); \ if (my->type == M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) ) { \ M_VAR1ANT_CALL_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ } else { \ - M_F(name, _clear)(my); \ + M_F(name, _clear)M_R(my); \ /* Reinit variable with the given value */ \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ @@ -403,8 +414,7 @@ #define M_VAR1ANT_DEFINE_INIT_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ M_INLINE void \ - function_name(name_t my \ - M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \ + function_name(M_P_EXPAND name_t my M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \ { \ my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \ M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \ @@ -412,13 +422,13 @@ M_INLINE void \ #define M_VAR1ANT_DEFINE_EMPLACE_DEF(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ M_INLINE void \ - function_name(name_t my \ - M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \ + function_name(M_P_EXPAND name_t my M_EMPLACE_LIST_TYPE_VAR(ab, exp_emplace_type) ) \ { \ /* No optimization done */ \ - M_C(M_PAIR_1 name, _clear)(my); \ - my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \ + M_C(M_PAIR_1 name, _clear)M_R(my); \ + my->type = M_F(M_PAIR_1 name, _EMPTY); \ M_EMPLACE_CALL_FUNC(ab, init_func, oplist, my -> value. M_PAIR_2 name, exp_emplace_type); \ + my->type = M_C4(M_PAIR_1 name, _, M_PAIR_2 name, _value); \ } \ /* Define the EQUAL_P function. */ @@ -491,11 +501,9 @@ M_INLINE void \ It can be optimized if both types are the same. */ #define M_VAR1ANT_DEFINE_MOVE(name, ...) \ - M_INLINE void \ - M_F(name, _move)(M_F(name,_ct) el, M_F(name,_ct) org) { \ - M_VAR1ANT_CONTRACT(name, el); \ - M_VAR1ANT_CONTRACT(name, org); \ - M_F(name, _clear)(el); \ + M_P(void, name, _move, M_F(name,_ct) el, M_F(name,_ct) org) \ + { \ + M_F(name, _clear)M_R(el); \ M_F(name, _init_move)(el , org); \ } @@ -506,10 +514,10 @@ M_INLINE void \ #define M_VAR1ANT_DEFINE_MOVER_FUNC(name, a) \ M_INLINE void \ - M_C3(name, _move_, M_VAR1ANT_GET_FIELD a)(M_F(name,_ct) my, \ + M_C3(name, _move_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, \ M_VAR1ANT_GET_TYPE a M_VAR1ANT_GET_FIELD a ) { \ M_VAR1ANT_CONTRACT(name, my); \ - M_F(name, _clear)(my); \ + M_F(name, _clear)M_R(my); \ /* Reinit variable with the given value */ \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_MOVE(a, my -> value. M_VAR1ANT_GET_FIELD a, \ @@ -555,40 +563,38 @@ M_INLINE void \ /* Define the GET_STR function */ #define M_VAR1ANT_DEFINE_GET_STR(name, ...) \ - M_INLINE void M_F(name, _get_str)(m_string_t str, \ - M_F(name,_ct) const el, \ - bool append) { \ + M_P(void, name, _get_str, m_string_t str, M_F(name,_ct) const el, bool append) \ + { \ M_VAR1ANT_CONTRACT(name, el); \ M_ASSERT (str != NULL); \ - void (*func)(m_string_t, const char *); \ + void (*func)(M_P_EXPAND m_string_t, const char *); \ func = append ? m_string_cat_cstr : m_string_set_cstr; \ switch (el->type) { \ - case M_F(name, _EMPTY): func(str, "@EMPTY@"); break; \ + case M_F(name, _EMPTY): func M_R(str, "@EMPTY@"); break; \ M_MAP2(M_VAR1ANT_DEFINE_GET_STR_FUNC , name, __VA_ARGS__) \ default: M_ASSUME(false); break; \ } \ - m_string_push_back (str, '@'); \ + m_string_push_back M_R(str, '@'); \ } #define M_VAR1ANT_DEFINE_GET_STR_FUNC(name, a) \ case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \ - func(str, "@" M_AS_STR(M_VAR1ANT_GET_FIELD a) "@"); \ + func M_R(str, "@" M_AS_STR(M_VAR1ANT_GET_FIELD a) "@"); \ M_VAR1ANT_CALL_GET_STR(a, str, el -> value . M_VAR1ANT_GET_FIELD a, true); \ break; /* Define the PARSE_STR function */ #define M_VAR1ANT_DEFINE_PARSE_STR(name, ...) \ - M_INLINE bool M_F(name, _parse_str)(M_F(name,_ct) el, \ - const char str[], \ - const char **endp) { \ + M_P(bool, name, _parse_str, M_F(name,_ct) el, const char str[], const char **endp) \ + { \ M_VAR1ANT_CONTRACT(name, el); \ M_ASSERT (str != NULL); \ bool success = false; \ char variantTypeBuf[M_USE_IDENTIFIER_ALLOC+1]; \ int c = *str++; \ unsigned int i = 0; \ - M_F(name, _reset)(el); \ + M_F(name, _reset)M_R(el); \ if (c != '@') goto exit; \ /* First read the name of the type */ \ c = *str++; \ @@ -622,8 +628,8 @@ M_INLINE void \ /* Define the OUT_STR function */ #define M_VAR1ANT_DEFINE_OUT_STR(name, ...) \ - M_INLINE void M_F(name, _out_str)(FILE *f, \ - M_F(name,_ct) const el) { \ + M_INLINE void M_F(name, _out_str)(FILE *f, M_F(name,_ct) const el) \ + { \ M_VAR1ANT_CONTRACT(name, el); \ M_ASSERT (f != NULL); \ switch (el->type) { \ @@ -643,12 +649,12 @@ M_INLINE void \ /* Define the IN_STR function */ #define M_VAR1ANT_DEFINE_IN_STR(name, ...) \ - M_INLINE bool M_F(name, _in_str)(M_F(name,_ct) el, \ - FILE *f) { \ + M_P(bool, name, _in_str, M_F(name,_ct) el, FILE *f) \ + { \ M_VAR1ANT_CONTRACT(name, el); \ M_ASSERT (f != NULL); \ char variantTypeBuf[M_USE_IDENTIFIER_ALLOC+1]; \ - M_F(name, _reset)(el); \ + M_F(name, _reset)M_R(el); \ if (fgetc(f) != '@') return false; \ /* First read the name of the type */ \ bool b = true; \ @@ -686,8 +692,8 @@ M_INLINE void \ /* Define the OUT_SERIAL function */ #define M_VAR1ANT_DEFINE_OUT_SERIAL(name, ...) \ M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, \ - M_F(name,_ct) const el) { \ + M_F(name, _out_serial)(m_serial_write_t f, M_F(name,_ct) const el) \ + { \ M_VAR1ANT_CONTRACT(name, el); \ const int field_max = M_NARGS(__VA_ARGS__); \ static const char *const field_name[] = \ @@ -716,9 +722,8 @@ M_INLINE void \ /* Define the IN_SERIAL function */ #define M_VAR1ANT_DEFINE_IN_SERIAL(name, ...) \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(M_F(name,_ct) el, \ - m_serial_read_t f) { \ + M_P(m_serial_return_code_t, name, _in_serial, M_F(name,_ct) el, m_serial_read_t f) \ + { \ M_VAR1ANT_CONTRACT(name, el); \ const int field_max = M_NARGS(__VA_ARGS__); \ static const char *const field_name[] = \ @@ -727,7 +732,7 @@ M_INLINE void \ m_serial_local_t local; \ m_serial_return_code_t ret; \ int id = -1; \ - M_F(name, _reset)(el); \ + M_F(name, _reset)M_R(el); \ ret = f->m_interface->read_variant_start(local, f, field_name, field_max, &id); \ if (ret != M_SERIAL_OK_CONTINUE) return ret; \ M_ASSERT (id >= 0 && id < field_max); \ @@ -750,10 +755,10 @@ M_INLINE void \ /* Define the RESET function */ #define M_VAR1ANT_DEFINE_RESET_FUNC(name, ...) \ - M_INLINE void M_F(name, _reset)(M_F(name,_ct) my) \ + M_P(void, name, _reset, M_F(name,_ct) my) \ { \ M_VAR1ANT_CONTRACT(name, my); \ - M_F(name, _clear)(my); \ + M_F(name, _clear)M_R(my); \ M_F(name, _init)(my); \ } \ From 94dd0a5571374a5c98641d7f958b3f6fdbfaf61e Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 25 Mar 2025 00:21:39 +0100 Subject: [PATCH 32/91] Add example of using pool --- example/ex11-use-pool.c | 146 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 example/ex11-use-pool.c diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c new file mode 100644 index 00000000..382cb816 --- /dev/null +++ b/example/ex11-use-pool.c @@ -0,0 +1,146 @@ +#include + +typedef int *context_t; + +static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context) +{ + (void) context; + (void) old; + return realloc(ptr, new*base); +} + +static void my_free(void *ptr, size_t old, size_t base, context_t context) +{ + (void) context; + (void) old; + (void) base; + free(ptr); +} + +# define M_USE_POOL context_t +# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_pool) +# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (*ptr), m_pool) + +# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_pool) +# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_pool) + +#include "m-string.h" +#include "m-bitset.h" +#include "m-bstring.h" +#include "m-genint.h" + +context_t my_pool = NULL; +extern int f(string_t, bitset_t b, bstring_t y); + +int f(string_t x, bitset_t b, bstring_t y) +{ + string_init(x); + string_set_str(my_pool, x, "Hello world"); + string_clear(my_pool, x); + + bitset_init(b); + bitset_push_back(my_pool, b, true); + bitset_clear(my_pool, b); + + bstring_init(y); + bstring_push_back(my_pool, y, 0); + bstring_clear(my_pool, y); + + return 0; +} + +#include "m-array.h" + +ARRAY_DEF(array, int) +ARRAY_DEF(array_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-prioqueue.h" + +PRIOQUEUE_DEF(prio, int) +PRIOQUEUE_DEF(prio_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-rbtree.h" + +RBTREE_DEF(rbtree, int) +RBTREE_DEF(rbtree_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-list.h" + +LIST_DEF(list, int) +LIST_DEF(list_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-bptree.h" + +BPTREE_DEF2(bptree, 5, int, int) + +#include "m-dict.h" + +DICT_DEF2(dict, int, int) +DICT_DEF2(dict_str, string_t, M_STRING_POOL_OPLIST, string_t, M_STRING_POOL_OPLIST) + +DICT_SET_DEF(set, int) +DICT_SET_DEF(set_str, string_t, M_STRING_POOL_OPLIST) + +static inline bool oor_equal_p(int k, char n) +{ + return k == INT_MIN + n; +} + +static inline int oor_set(char n) +{ + return INT_MIN + n; +} + +DICT_OA_DEF2(dict_oa, + int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))), + int, M_BASIC_OPLIST) +DICT_OA_DEF2(dict2_str, string_t, M_STRING_POOL_OPLIST, string_t, M_STRING_POOL_OPLIST) + +DICT_OASET_DEF(set_oa, + int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))) ) +DICT_OASET_DEF(set2_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-buffer.h" + +BUFFER_DEF(buffer1, int, 10, M_BUFFER_QUEUE) +BUFFER_DEF(buffer2, int, 0, M_BUFFER_STACK) + +M_QUEUE_MPMC_DEF(queue1, int, M_BUFFER_STACK) +M_QUEUE_SPSC_DEF(queue2, int, M_BUFFER_STACK) + +BUFFER_DEF(buffer11, string_t, 10, M_BUFFER_QUEUE, M_STRING_POOL_OPLIST) +BUFFER_DEF(buffer22, string_t, 0, M_BUFFER_STACK, M_STRING_POOL_OPLIST) + +M_QUEUE_MPMC_DEF(queue11, string_t, M_BUFFER_STACK, M_STRING_POOL_OPLIST) +M_QUEUE_SPSC_DEF(queue22, string_t, M_BUFFER_STACK, M_STRING_POOL_OPLIST) + +#include "m-deque.h" + +M_DEQUE_DEF(deque, int) +M_DEQUE_DEF(deque_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-snapshot.h" + +M_SNAPSHOT_SPSC_DEF(snap1, int) +M_SNAPSHOT_SPMC_DEF(snap2, int) +M_SNAPSHOT_MPMC_DEF(snap3, int) + +#include "m-tree.h" + +M_TREE_DEF(tree, int) +M_TREE_DEF(tree_str, string_t, M_STRING_POOL_OPLIST) + +#include "m-tuple.h" + +M_TUPLE_DEF2(tuple1, (num, int) ) +M_TUPLE_DEF2(tuple2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) + +#include "m-variant.h" + +M_VARIANT_DEF2(variant1, (num, int) ) +M_VARIANT_DEF2(variant2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) + +int main(void) +{ + return 0; +} From 8069fae3d50a8dc0a00dda89a668811588d90dc7 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 25 Mar 2025 07:53:05 +0100 Subject: [PATCH 33/91] Remove use of invalid representation, which is refused by clang & C++ --- m-variant.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/m-variant.h b/m-variant.h index 4c86d6bc..0c08e598 100644 --- a/m-variant.h +++ b/m-variant.h @@ -284,8 +284,7 @@ case M_F(name, _EMPTY): /* fallthrough */ \ default: M_ASSUME(my->type == M_F(name, _EMPTY)); break; \ } \ - /* Invalid representation */ \ - my->type = M_F(name, _EMPTY) - 1; \ + my->type = M_F(name, _EMPTY); \ } #define M_VAR1ANT_DEFINE_CLEAR_FUNC(name, a) \ From 10d918bbc9dd9c133b8b42f6b35626fa30a9a953 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 26 Mar 2025 23:57:41 +0100 Subject: [PATCH 34/91] Port to new memory model (add global context 0) --- example/ex11-use-pool.c | 5 +++++ m-core.h | 17 +++++++++++++++++ m-worker.h | 27 ++++++++++++++++++--------- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 382cb816..4b2b34b6 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -140,6 +140,11 @@ M_TUPLE_DEF2(tuple2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) M_VARIANT_DEF2(variant1, (num, int) ) M_VARIANT_DEF2(variant2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) +#include "m-worker.h" + +M_WORKER_SPAWN_DEF2(worker_int, (in, int) ) +M_WORKER_SPAWN_DEF2(worker_str, (str, string_t, M_STRING_POOL_OPLIST) ) + int main(void) { return 0; diff --git a/m-core.h b/m-core.h index 0d894e68..5fdecb70 100644 --- a/m-core.h +++ b/m-core.h @@ -413,6 +413,21 @@ M_BEGIN_PROTECTED_CODE // FIXME: Rename to M_USE_MEMORY_CONTEXT? +/* In order to support context for memory functions, the prototypes and usages of some functions are modified + * so that they accept a first argument 'm_pool' which is the memory context parameter. + * For some functions, there is no meaning of a local memory context parameter: for all data shared between threads, + * only a global memory context has any meaning. For such cases, the memory context parameter is not requested to + * the used but set to 0. + * several macros are defined **globally**. Theses macros expand to nothing if memory context is not requested. + * * M_P_EXPAND: expand to the first parameter 'm_pool' of type M_USE_POOL for a function that may use memory context. + * * M_P_EXPAND_void: same but assume that there is no argument + * * M_R_EXPAND: expand to the first parameter 'm_pool' + * * M_R_EXPAND_void: same but assume that there is no argument + * * M_R: add the parameter m_pool to the function call if needed, + * * M_P: define the prototype of a function that may have the parameter m_pool. + * * M_ASSERT_POOL: avoid warning of unused m_pool argument + * * M_GLOBAL_POOL: define m_pool to zero, meaning it is a global memory context. + */ #ifndef M_USE_POOL // Memory pool parameter not used for memory function. Stub it with 0 as it won't be used (global definition). # define M_P_EXPAND @@ -421,6 +436,7 @@ M_BEGIN_PROTECTED_CODE # define M_R_EXPAND_void # define M_R # define M_ASSERT_POOL() +# define M_GLOBAL_POOL() #else // Memory pool parameter is used for function using memory. (local definition to the function). // Expand to a prototype to a function that may not trigger exception @@ -430,6 +446,7 @@ M_BEGIN_PROTECTED_CODE # define M_R_EXPAND_void m_pool # define M_R(...) (m_pool, __VA_ARGS__) # define M_ASSERT_POOL() (void) m_pool +# define M_GLOBAL_POOL() M_USE_POOL m_pool = { 0 } #endif // M_P: Expand to a prototype of a function that may trigger exception / accept memory context diff --git a/m-worker.h b/m-worker.h index e8d58d70..c70a0d1f 100644 --- a/m-worker.h +++ b/m-worker.h @@ -235,6 +235,7 @@ typedef struct m_worker_sync_s { M_INLINE void \ M_C3(m_work3r_, name, _clear)(struct M_C3(m_worker_, name, _s) *p) \ { \ + M_GLOBAL_POOL(); \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_CALLBACK_CLEAR, data, __VA_ARGS__) \ /* TODO: Overload */ \ M_MEMORY_DEL(p); \ @@ -263,6 +264,7 @@ typedef struct m_worker_sync_s { M_MAP3_C(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD, data, __VA_ARGS__) \ ) \ { \ + M_GLOBAL_POOL(); \ if (!m_work3r_queue_full_p(block->worker->queue_g)) { \ struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \ if (M_UNLIKELY_NOMEM(p == NULL)) { \ @@ -271,7 +273,7 @@ typedef struct m_worker_sync_s { p->callback = callback; \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_INIT_SET, data, __VA_ARGS__) \ const m_work3r_order_ct w = { block, p, M_C3(m_work3r_, name, _callback) M_WORK3R_EXTRA_ORDER }; \ - if (m_work3r_queue_push (block->worker->queue_g, w) == true) { \ + if (m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { \ atomic_fetch_add (&block->num_spawn, 1); \ return; \ } \ @@ -361,6 +363,7 @@ m_work3r_thread(void *arg) { // Get back the given argument struct m_worker_s *g = M_ASSIGN_CAST(struct m_worker_s *, arg); + M_GLOBAL_POOL(); while (true) { m_work3r_order_ct w; // If needed, reset the global state of the worker @@ -369,7 +372,7 @@ m_work3r_thread(void *arg) } // Waiting for data M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", m_work3r_queue_size(g->queue_g), m_work3r_queue_capacity(g->queue_g)); - m_work3r_queue_pop(&w, g->queue_g); + m_work3r_queue_pop M_R(&w, g->queue_g); // We received a work order // Note: that the work order is still present in the queue // preventing further work order to be pushed in the queue until it finishes doing the work @@ -409,11 +412,12 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset // numWorker can still be 0 if it is a single core cpu (no worker available) M_ASSERT(numWorker >= 0); size_t numWorker_st = (size_t) numWorker; + M_GLOBAL_POOL(); g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st); if (M_UNLIKELY_NOMEM (g->worker == NULL)) { M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st); } - m_work3r_queue_init(g->queue_g, numWorker_st + extraQueue); + m_work3r_queue_init M_R(g->queue_g, numWorker_st + extraQueue); g->numWorker_g = (unsigned int) numWorker_st; g->resetFunc_g = resetFunc; g->clearFunc_g = clearFunc; @@ -440,13 +444,14 @@ M_INLINE void m_worker_clear(m_worker_t g) { M_ASSERT (m_work3r_queue_empty_p (g->queue_g)); + M_GLOBAL_POOL(); // 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; // 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); + m_work3r_queue_push_blocking M_R(g->queue_g, w, true); } // Wait for thread termination for(unsigned int i = 0; i < g->numWorker_g; i++) { @@ -456,7 +461,7 @@ m_worker_clear(m_worker_t g) M_MEMORY_FREE(m_work3r_thread_ct, g->worker, g->numWorker_g); m_mutex_clear(g->lock); m_cond_clear(g->a_thread_ends); - m_work3r_queue_clear(g->queue_g); + m_work3r_queue_clear M_R(g->queue_g); } /* Start a new collaboration between workers of pool 'g' @@ -478,8 +483,9 @@ M_INLINE void m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data) { const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER }; + M_GLOBAL_POOL(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) - && m_work3r_queue_push (block->worker->queue_g, w) == true) { + && m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { M_WORK3R_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); atomic_fetch_add (&block->num_spawn, 1); return; @@ -496,8 +502,9 @@ M_INLINE void m_work3r_spawn_block(m_worker_sync_t block, void (^func)(void *data), void *data) { const m_work3r_order_ct w = { block, data, NULL, func }; + M_GLOBAL_POOL(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) - && m_work3r_queue_push (block->worker->queue_g, w) == true) { + && m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); atomic_fetch_add (&block->num_spawn, 1); return; @@ -515,8 +522,9 @@ M_INLINE void m_work3r_spawn_function(m_worker_sync_t block, std::function func, void *data) { const m_work3r_order_ct w = { block, data, NULL, func }; + M_GLOBAL_POOL(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) - && m_work3r_queue_push (block->worker->queue_g, w) == true) { + && m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); atomic_fetch_add (&block->num_spawn, 1); return; @@ -557,7 +565,8 @@ M_INLINE void m_worker_flush(m_worker_t g) { m_work3r_order_ct w; - while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) { + M_GLOBAL_POOL(); + while (m_work3r_queue_pop_blocking M_R(&w, g->queue_g, false) == true) { m_work3r_exec(&w); m_work3r_queue_pop_release(g->queue_g); } From 5d1ebdf5bbf1b0a5c96a1896b791202254ad090d Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 29 Mar 2025 00:25:49 +0100 Subject: [PATCH 35/91] Update obsolete header files: * remove obsolete m-mutex header file * mark m-concurrent, m-shared and m-i-shared as obsolete (They won't support new memory model) --- m-concurrent.h | 4 ++++ m-i-shared.h | 4 ++++ m-mutex.h | 28 ---------------------------- m-shared.h | 4 ++++ 4 files changed, 12 insertions(+), 28 deletions(-) delete mode 100644 m-mutex.h diff --git a/m-concurrent.h b/m-concurrent.h index af0b2704..53e7ade2 100644 --- a/m-concurrent.h +++ b/m-concurrent.h @@ -29,6 +29,10 @@ #include "m-thread.h" #include "m-atomic.h" +#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L +#warning The header m-concurrent.h is obsolete. Use m-shared-ptr header instead. +#endif + /* Define a protected concurrent container and its associated functions based on the given container. USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */ diff --git a/m-i-shared.h b/m-i-shared.h index 1dfe6ae4..b9324b14 100644 --- a/m-i-shared.h +++ b/m-i-shared.h @@ -28,6 +28,10 @@ #include "m-core.h" #include "m-atomic.h" +#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L +#warning The header m-i-shared.h is obsolete. Use m-shared-ptr header instead. +#endif + M_BEGIN_PROTECTED_CODE /* Define the oplist of a intrusive shared pointer. diff --git a/m-mutex.h b/m-mutex.h deleted file mode 100644 index 9a81ca42..00000000 --- a/m-mutex.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * M*LIB - Thin Mutex & Thread wrapper (compatibility layer) - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#if defined(__GNUC__) && __GNUC__ >= 4 -#warning "m-mutex.h is an obsolete header. Use m-thread.h instead." -#endif -#include "m-thread.h" diff --git a/m-shared.h b/m-shared.h index 3509533a..f79d5562 100644 --- a/m-shared.h +++ b/m-shared.h @@ -29,6 +29,10 @@ #include "m-atomic.h" #include "m-genint.h" +#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L +#warning The header m-shared.h is obsolete. Use m-shared-ptr header instead. +#endif + M_BEGIN_PROTECTED_CODE /* Define shared pointer and its function. From 689527c2dce9a95ea5f6e16cc413b80a2cd8d5ee Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 29 Mar 2025 00:52:39 +0100 Subject: [PATCH 36/91] Port m-shared-ptr to new memory model (use global pool) --- example/ex11-use-pool.c | 5 +++++ m-core.h | 2 +- m-shared-ptr.h | 36 +++++++++++++++++++++++++++++++++--- m-string.h | 2 +- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 4b2b34b6..81a93c27 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -145,6 +145,11 @@ M_VARIANT_DEF2(variant2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) M_WORKER_SPAWN_DEF2(worker_int, (in, int) ) M_WORKER_SPAWN_DEF2(worker_str, (str, string_t, M_STRING_POOL_OPLIST) ) +#include "m-shared-ptr.h" + +M_SHARED_PTR_DEF(shared_int, int) +M_SHARED_PTR_DEF(shared_str, string_t, M_STRING_POOL_OPLIST) + int main(void) { return 0; diff --git a/m-core.h b/m-core.h index 5fdecb70..105c4355 100644 --- a/m-core.h +++ b/m-core.h @@ -446,7 +446,7 @@ M_BEGIN_PROTECTED_CODE # define M_R_EXPAND_void m_pool # define M_R(...) (m_pool, __VA_ARGS__) # define M_ASSERT_POOL() (void) m_pool -# define M_GLOBAL_POOL() M_USE_POOL m_pool = { 0 } +# define M_GLOBAL_POOL() M_USE_POOL m_pool = { 0 }; (void) m_pool #endif // M_P: Expand to a prototype of a function that may trigger exception / accept memory context diff --git a/m-shared-ptr.h b/m-shared-ptr.h index a68f0f64..064e1e23 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -613,6 +613,7 @@ extern shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type M_IF_METHOD(INIT, oplist)( \ fattr shared_t *M_F(name, _new)(void) \ { \ + M_GLOBAL_POOL(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -628,6 +629,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ fattr shared_t *M_F(name, _clone)(const shared_t *src) \ { \ M_ASSERT(src != NULL); \ + M_GLOBAL_POOL(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -644,6 +646,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ fattr shared_t *M_F(name, _new_from)(type const src); ) \ fattr shared_t *M_F(name, _new_from)(type const src) \ { \ + M_GLOBAL_POOL(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -660,6 +663,7 @@ M_IF_METHOD(SET, oplist)( \ { \ M_ASSERT(out != NULL); \ M_ASSERT(src != NULL); \ + M_GLOBAL_POOL(); \ if (M_UNLIKELY (out == src)) return; \ M_F(name, _write_read_lock)(out, src); \ M_ON_EXCEPTION( M_F(name, _write_read_unlock)(out, src) ) \ @@ -678,6 +682,7 @@ fattr shared_t *M_F(name, _acquire)(shared_t *out) \ \ fattr void M_F(name, _release)(shared_t *out) \ { \ + M_GLOBAL_POOL(); \ if (out != NULL && M_C3(m_shar3d_, name, _dec_owner)(out)) { \ M_CALL_CLEAR(oplist, out->data); \ M_F(name, _clear_lock)(out); \ @@ -701,6 +706,7 @@ M_EMPLACE_QUEUE_DEF( (name, fattr), shared_t, M_F(name, _make), oplist, M_SHAR3D #define M_SHAR3D_PTR_DEF_BASIC_MAKE(name_attr, shared_t, function_name, oplist, init_func, exp_emplace_type) \ M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type)) \ { \ + M_GLOBAL_POOL(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -747,6 +753,7 @@ M_IF_METHOD(RESET, oplist)( \ fattr void M_F(name, _reset)(shared_t *out) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ /* RESET cannot throw exception */ \ M_CALL_RESET(oplist, out->data); \ @@ -859,6 +866,7 @@ M_IF_METHOD(ADD, oplist)( \ fattr void M_F(name, _add)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_ADD(oplist, out->data, src1->data, src2->data); \ @@ -870,6 +878,7 @@ M_IF_METHOD(SUB, oplist)( \ fattr void M_F(name, _sub)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_SUB(oplist, out->data, src1->data, src2->data); \ @@ -881,6 +890,7 @@ M_IF_METHOD(MUL, oplist)( \ fattr void M_F(name, _mul)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_MUL(oplist, out->data, src1->data, src2->data); \ @@ -892,6 +902,7 @@ M_IF_METHOD(DIV, oplist)( \ fattr void M_F(name, _div)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_DIV(oplist, out->data, src1->data, src2->data); \ @@ -903,6 +914,7 @@ M_IF_METHOD(SPLICE, oplist)( \ fattr void M_F(name, _splice)(shared_t *out, shared_t *src) \ { \ M_ASSERT(out != NULL && src != NULL); \ + M_GLOBAL_POOL(); \ if (out < src) { \ M_F(name, _write_lock)(out); \ M_F(name, _write_lock)(src); \ @@ -932,6 +944,7 @@ M_IF_METHOD(GET_KEY, oplist)( \ { \ M_ASSERT (out != NULL); \ M_ASSERT (value != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _read_lock)(out); \ /* No exception */ \ value_type *p = M_CALL_GET_KEY(oplist, out->data, key); \ @@ -948,6 +961,7 @@ M_IF_METHOD(SAFE_GET_KEY, oplist)( \ { \ M_ASSERT (out != NULL); \ M_ASSERT (value != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) { \ value_type *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \ @@ -963,6 +977,7 @@ M_IF_METHOD(SET_KEY, oplist)( \ fattr void M_F(name, _set_at)(shared_t *out, key_type const key, value_type const value) \ { \ M_ASSERT (out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ M_CALL_SET_KEY(oplist, out->data, key, value); \ @@ -975,6 +990,7 @@ M_IF_METHOD(ERASE_KEY, oplist)( \ fattr bool M_F(name, _erase)(shared_t *out, key_type const key) \ { \ M_ASSERT (out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ /* No exception */ \ bool r = M_CALL_ERASE_KEY(oplist, out->data, key); \ @@ -1005,6 +1021,7 @@ M_IF_METHOD(PUSH, oplist)( \ fattr void M_F(name, _push)(shared_t *out, sub_type const value) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1021,6 +1038,7 @@ M_IF_METHOD(PUSH, oplist)( \ fattr bool M_F(name, _try_push)(shared_t *out, sub_type const value) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1037,6 +1055,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr void M_F(name, _push_move)(shared_t *out, sub_type *value) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1053,6 +1072,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr bool M_F(name, _try_push_move)(shared_t *out, sub_type *value) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1074,6 +1094,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1096,6 +1117,7 @@ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_ty fattr bool function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1124,6 +1146,7 @@ M_IF_METHOD(POP, oplist)( \ fattr void M_F(name, _pop)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1140,6 +1163,7 @@ M_IF_METHOD(POP, oplist)( \ fattr bool M_F(name, _try_pop)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1156,6 +1180,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \ fattr void M_F(name, _pop_move)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1172,6 +1197,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \ fattr bool M_F(name, _try_pop_move)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ + M_GLOBAL_POOL(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1300,6 +1326,7 @@ M_IF_METHOD(IN_STR, oplist)( \ fattr bool M_F(name, _in_str)(shared_t *out, FILE *file) \ { \ M_ASSERT (out != NULL && file != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ m_volatile bool r = false; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ @@ -1314,9 +1341,10 @@ M_IF_METHOD(GET_STR, oplist)( \ fattr void M_F(name, _get_str)(m_string_t str, const shared_t *out, bool append) \ { \ M_ASSERT (out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _read_lock)(out); \ - /* No exception */ \ - M_CALL_GET_STR(oplist, str, out->data, append); \ + M_ON_EXCEPTION( M_F(name, _read_unlock)(out) ) \ + M_CALL_GET_STR(oplist, str, out->data, append); \ M_F(name, _read_unlock)(out); \ } \ , ) \ @@ -1324,6 +1352,7 @@ M_IF_METHOD(PARSE_STR, oplist)( \ fattr bool M_F(name, _parse_str)(shared_t *out, const char str[], const char **endp) \ { \ M_ASSERT (out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ m_volatile bool r = false; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ @@ -1339,7 +1368,7 @@ M_IF_METHOD(OUT_SERIAL, oplist)( \ { \ M_ASSERT (out != NULL); \ M_F(name, _read_lock)(out); \ - /* No exception */ \ + /* FIXME: No exception. Really? */ \ m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, serial, out->data); \ M_F(name, _read_unlock)(out); \ return r; \ @@ -1349,6 +1378,7 @@ M_IF_METHOD(IN_SERIAL, oplist)( \ fattr m_serial_return_code_t M_F(name, _in_serial)(shared_t *out, m_serial_read_t serial) \ { \ M_ASSERT (out != NULL); \ + M_GLOBAL_POOL(); \ M_F(name, _write_lock)(out); \ m_volatile m_serial_return_code_t r = M_SERIAL_FAIL; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ diff --git a/m-string.h b/m-string.h index b4d12237..10e24a15 100644 --- a/m-string.h +++ b/m-string.h @@ -2188,7 +2188,7 @@ namespace m_lib { ,IT_END_P(m_string_end_p) \ ,IT_EQUAL_P(m_string_it_equal_p) \ ,IT_NEXT(m_string_next) \ - ,IT_CREF(m_string_cref), PUSH(m_string_push_u) \ + ,IT_CREF(m_string_cref), PUSH(API_0P(m_string_push_u)) \ ,EMPLACE_TYPE(const char*) \ ) From 77e566680269c6c87aa1aa3bdd1ca8de71d44344 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 29 Mar 2025 23:11:42 +0100 Subject: [PATCH 37/91] Update string oplist definition with pool --- example/ex11-use-pool.c | 36 ++++++++++++++++++------------------ m-string.h | 10 ++++------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 81a93c27..c56a0dff 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -52,22 +52,22 @@ int f(string_t x, bitset_t b, bstring_t y) #include "m-array.h" ARRAY_DEF(array, int) -ARRAY_DEF(array_str, string_t, M_STRING_POOL_OPLIST) +ARRAY_DEF(array_str, string_t) #include "m-prioqueue.h" PRIOQUEUE_DEF(prio, int) -PRIOQUEUE_DEF(prio_str, string_t, M_STRING_POOL_OPLIST) +PRIOQUEUE_DEF(prio_str, string_t) #include "m-rbtree.h" RBTREE_DEF(rbtree, int) -RBTREE_DEF(rbtree_str, string_t, M_STRING_POOL_OPLIST) +RBTREE_DEF(rbtree_str, string_t) #include "m-list.h" LIST_DEF(list, int) -LIST_DEF(list_str, string_t, M_STRING_POOL_OPLIST) +LIST_DEF(list_str, string_t) #include "m-bptree.h" @@ -76,10 +76,10 @@ BPTREE_DEF2(bptree, 5, int, int) #include "m-dict.h" DICT_DEF2(dict, int, int) -DICT_DEF2(dict_str, string_t, M_STRING_POOL_OPLIST, string_t, M_STRING_POOL_OPLIST) +DICT_DEF2(dict_str, string_t, string_t) DICT_SET_DEF(set, int) -DICT_SET_DEF(set_str, string_t, M_STRING_POOL_OPLIST) +DICT_SET_DEF(set_str, string_t) static inline bool oor_equal_p(int k, char n) { @@ -94,11 +94,11 @@ static inline int oor_set(char n) DICT_OA_DEF2(dict_oa, int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))), int, M_BASIC_OPLIST) -DICT_OA_DEF2(dict2_str, string_t, M_STRING_POOL_OPLIST, string_t, M_STRING_POOL_OPLIST) +DICT_OA_DEF2(dict2_str, string_t, string_t) DICT_OASET_DEF(set_oa, int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))) ) -DICT_OASET_DEF(set2_str, string_t, M_STRING_POOL_OPLIST) +DICT_OASET_DEF(set2_str, string_t) #include "m-buffer.h" @@ -108,16 +108,16 @@ BUFFER_DEF(buffer2, int, 0, M_BUFFER_STACK) M_QUEUE_MPMC_DEF(queue1, int, M_BUFFER_STACK) M_QUEUE_SPSC_DEF(queue2, int, M_BUFFER_STACK) -BUFFER_DEF(buffer11, string_t, 10, M_BUFFER_QUEUE, M_STRING_POOL_OPLIST) -BUFFER_DEF(buffer22, string_t, 0, M_BUFFER_STACK, M_STRING_POOL_OPLIST) +BUFFER_DEF(buffer11, string_t, 10, M_BUFFER_QUEUE) +BUFFER_DEF(buffer22, string_t, 0, M_BUFFER_STACK) -M_QUEUE_MPMC_DEF(queue11, string_t, M_BUFFER_STACK, M_STRING_POOL_OPLIST) -M_QUEUE_SPSC_DEF(queue22, string_t, M_BUFFER_STACK, M_STRING_POOL_OPLIST) +M_QUEUE_MPMC_DEF(queue11, string_t, M_BUFFER_STACK) +M_QUEUE_SPSC_DEF(queue22, string_t, M_BUFFER_STACK) #include "m-deque.h" M_DEQUE_DEF(deque, int) -M_DEQUE_DEF(deque_str, string_t, M_STRING_POOL_OPLIST) +M_DEQUE_DEF(deque_str, string_t) #include "m-snapshot.h" @@ -128,27 +128,27 @@ M_SNAPSHOT_MPMC_DEF(snap3, int) #include "m-tree.h" M_TREE_DEF(tree, int) -M_TREE_DEF(tree_str, string_t, M_STRING_POOL_OPLIST) +M_TREE_DEF(tree_str, string_t) #include "m-tuple.h" M_TUPLE_DEF2(tuple1, (num, int) ) -M_TUPLE_DEF2(tuple2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) +M_TUPLE_DEF2(tuple2, (num, int), (name, string_t) ) #include "m-variant.h" M_VARIANT_DEF2(variant1, (num, int) ) -M_VARIANT_DEF2(variant2, (num, int), (name, string_t, M_STRING_POOL_OPLIST) ) +M_VARIANT_DEF2(variant2, (num, int), (name, string_t) ) #include "m-worker.h" M_WORKER_SPAWN_DEF2(worker_int, (in, int) ) -M_WORKER_SPAWN_DEF2(worker_str, (str, string_t, M_STRING_POOL_OPLIST) ) +M_WORKER_SPAWN_DEF2(worker_str, (str, string_t) ) #include "m-shared-ptr.h" M_SHARED_PTR_DEF(shared_int, int) -M_SHARED_PTR_DEF(shared_str, string_t, M_STRING_POOL_OPLIST) +M_SHARED_PTR_DEF(shared_str, string_t) int main(void) { diff --git a/m-string.h b/m-string.h index 10e24a15..fefef8b7 100644 --- a/m-string.h +++ b/m-string.h @@ -2142,6 +2142,7 @@ namespace m_lib { #endif /* Define the OPLIST of a STRING */ +#ifndef M_USE_POOL #define M_STRING_OPLIST \ (INIT(m_string_init),INIT_SET(m_string_init_set), SET(m_string_set), \ INIT_WITH(M_STR1NG_INIT_WITH), \ @@ -2166,8 +2167,8 @@ namespace m_lib { ,IT_CREF(m_string_cref), PUSH(m_string_push_u) \ ,EMPLACE_TYPE(const char*) \ ) - -#define M_STRING_POOL_OPLIST \ +#else +#define M_STRING_OPLIST \ (INIT(m_string_init),INIT_SET(API_0P(m_string_init_set)), SET(API_0P(m_string_set)), \ INIT_WITH(M_STR1NG_INIT_WITH), \ INIT_MOVE(m_string_init_move), MOVE(API_0P(m_string_move)), \ @@ -2191,13 +2192,10 @@ namespace m_lib { ,IT_CREF(m_string_cref), PUSH(API_0P(m_string_push_u)) \ ,EMPLACE_TYPE(const char*) \ ) +#endif /* Register the OPLIST as a global one */ -#ifdef M_USE_POOL -#define M_OPL_m_string_t() M_STRING_POOL_OPLIST -#else #define M_OPL_m_string_t() M_STRING_OPLIST -#endif /* Register the string_t oplist as a generic type */ #define M_GENERIC_ORG_MLIB_COMP_CORE_OPLIST_1() M_STRING_OPLIST From a7294abe0cd1495fa078c63c685d1d7b0b6a2ff1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 29 Mar 2025 23:53:38 +0100 Subject: [PATCH 38/91] Update documentation and error message --- README.md | 16 +++++++++------- m-core.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e4196281..e3f2ec34 100644 --- a/README.md +++ b/README.md @@ -1142,23 +1142,25 @@ The list of errors it can generate: * `M_LIB_MISSING_METHOD`: a required operator doesn't define any method in the given oplist. You need to complete the oplist with the missing method. * `M_LIB_TYPE_MISMATCH`: the given oplist and the type do not match each other. You need to give the right oplist for this type. * `M_LIB_NOT_A_BASIC_TYPE`: The oplist `M_BASIC_OPLIST` (directly or indirectly) has been used with the given type, but the given type is not a basic C type (int/float). You need to give the right oplist for this type. +* `M_LIB_DIMENSION_ERROR`: a macro expects a number of arguments and doesn't get it. +Compilers can be very verbose on the error message: You should focus mainly on the first reported error/warning even if the link between what the compiler report and what the error is -is not immediate. The error is always in one of the **oplist definition**. +is not immediate. The error is likely in one of the **oplist definition**. Examples of typical errors: * lack of inclusion of an header, * overriding locally operator names by macros (like `NEW`, `DEL`, `INIT`, `OPLIST`, `...`), * lack of `( )` or double level of `( )` around the oplist, -* an unknown variable (example using `BASIC_OPLIST` instead of `M_BASIC_OPLIST`), -* the name given to the oplist is not the same as the one used to define the methods, -* use of a type instead of an oplist in the `OPLIST` definition, +* an unknown or incorrectly spelled variable (example using `BASIC_OPLIST` instead of `M_BASIC_OPLIST`), +* the `name` parameter given to the oplist is not the same as the one used to expand the methods, +* use of a non registered type instead of an oplist in the `OPLIST` definition (there is no registered type using `M_OPL_` or the registered type doesn't match the name of the type), * a missing sub oplist in the `OPLIST` definition. -A good way to avoid these errors is to register the oplist globally as soon -as you define the container. +A good way to avoid these errors is to register the oplist of the type globally as soon +as you define the container (to associated its oplist to the type). In case of difficulties, debugging can be done by generating the preprocessed file (by usually calling the compiler with the `-E` option instead of `-c`) @@ -1182,7 +1184,7 @@ your compiler. There are often completely useless and misleading: Due to the unfortunate [weak](https://en.wikipedia.org/wiki/Strong_and_weak_typing#Pointers) nature of the C language for pointers, you should turn incompatible pointer type warning into an error in your compiler. -For GCC / CLANG, uses `-Werror=incompatible-pointer-types` +For GCC / CLANG, uses `-Werror=incompatible-pointer-types` or compile in C23 mode. For MS Visual C++ compiler , you need the following options: diff --git a/m-core.h b/m-core.h index 105c4355..95bc138a 100644 --- a/m-core.h +++ b/m-core.h @@ -4514,7 +4514,7 @@ m_core_parse2_enum (const char str[], const char **endptr) M_IF_OPLIST(oplist)(M_LETI3, M_LETI2_FAILURE)(cont, oplist, __VA_ARGS__) // Stop with a failure (invalid oplist) #define M_LETI2_FAILURE(cont, oplist, ...) \ - M_STATIC_ASSERT(false, M_LIB_NOT_AN_OPLIST, "(M_LET): the given argument is not a valid oplist: " M_AS_STR(oplist)) + M_STATIC_ASSERT(false, M_LIB_NOT_AN_OPLIST, "the last argument of M_LET is not a valid oplist or a registered type: " M_AS_STR(oplist)) // 4. Map all variables to their own LET #define M_LETI3(cont, oplist, ...) \ for(bool cont = true; cont ; /* unused */) \ From 01f5228a36bc739132d703882bde80f0c38cec16 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 5 Apr 2025 19:59:18 +0200 Subject: [PATCH 39/91] Port to new memory model: Communication thread buffer needs to use the global pool, and not a local pool, since the allocation is done accross several threads. Therefore the non thread fixed queue & stack interfaces are moved into a dedicated header (m-queue) and remove support for non thread stack & queue into m-buffer Remove also deprecated policy too. --- Makefile | 2 +- README.md | 4 +- doc/API.txt | 4 +- example/ex11-use-pool.c | 6 + m-buffer.h | 450 ++++++++++++++++------------------------ m-core.h | 8 +- m-worker.h | 21 +- tests/Makefile | 1 + tests/coverage.h | 3 + tests/test-mbuffer.c | 96 ++------- 10 files changed, 224 insertions(+), 371 deletions(-) diff --git a/Makefile b/Makefile index 148eb33b..fe1ab31a 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ PACKAGE=m_lib-$(VERSION) VERSION=0.8.0 # Define the contain of the distribution tarball -HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h +HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h m-queue.h DOC1=LICENSE README.md DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c example/ex-bptree02.c example/ex-i-list.c example/ex11-generic02.c example/ex11-small-name.c example/ex11-variant01.c diff --git a/README.md b/README.md index e3f2ec34..f3ed1cdf 100644 --- a/README.md +++ b/README.md @@ -3878,8 +3878,8 @@ void name_reset(buffer_t buffer) /* Thread safe */ bool name_empty_p(const buffer_t buffer) /* Thread safe */ size_t name_size(const buffer_t buffer) /* Thread safe */ size_t name_capacity(const buffer_t buffer) /* Thread safe */ -bool name_push(buffer_t buffer, const type data) -bool name_pop(type *data, buffer_t buffer) +void name_push(buffer_t buffer, const type data) +void name_pop(type *data, buffer_t buffer) ``` #### Specialized methods diff --git a/doc/API.txt b/doc/API.txt index 248acfef..5cea1ec0 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -94,4 +94,6 @@ V0.8.0 : * REALLOC / FREE operators are incompatible: This allows more and efficient integration into custom allocators. * M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated. - + * m-buffer: non-thread safe queue & stack are moved into their dedicated header (m-queue) + * m-buffer: Remove buffer blocking policy and thread safe (_push / _pop returns now void) + diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index c56a0dff..785ad189 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -150,6 +150,12 @@ M_WORKER_SPAWN_DEF2(worker_str, (str, string_t) ) M_SHARED_PTR_DEF(shared_int, int) M_SHARED_PTR_DEF(shared_str, string_t) +#include "m-queue.h" + +M_QUEUE_DEF(queue_10, int, 10 ) +M_STACK_DEF(stack_20, string_t, 20) + + int main(void) { return 0; diff --git a/m-buffer.h b/m-buffer.h index a537689c..cdcdb779 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -1,5 +1,5 @@ /* - * M*LIB - Fixed size (Bounded) QUEUE & STACK interface + * M*LIB - Fixed size (Bounded) QUEUE & STACK interface (Thread safe) * * Copyright (c) 2017-2025, Patrick Pelissier * All rights reserved. @@ -31,20 +31,12 @@ /* Define the different kind of policy a lock-based buffer can have: * - the buffer can be either a queue (policy is FIFO) or a stack (policy is FILO), - * - if the push method is by default blocking (waiting for the buffer to has some space) or not, *** deprecated *** - * - if the pop method is by default blocking (waiting for the buffer to has some data) or not, *** deprecated *** - * - if both methods are blocking, *** deprecated *** - * - if it shall be thread safe or not (i.e. remove the mutex lock and atomic costs), * - if the buffer has to be init with empty elements, or if it shall init an element when it is pushed (and moved when popped), * - if the buffer has to overwrite the last element if the buffer is full, * - if the pop of an element is not complete until the call to pop_release (preventing push until this call). */ typedef enum { M_BUFFER_QUEUE = 0, M_BUFFER_STACK = 1, - M_BUFFER_BLOCKING_PUSH = 0, M_BUFFER_UNBLOCKING_PUSH = 2, - M_BUFFER_BLOCKING_POP = 0, M_BUFFER_UNBLOCKING_POP = 4, - M_BUFFER_BLOCKING = 0, M_BUFFER_UNBLOCKING = 6, - M_BUFFER_THREAD_SAFE = 0, M_BUFFER_THREAD_UNSAFE = 8, M_BUFFER_PUSH_INIT_POP_MOVE = 16, M_BUFFER_PUSH_OVERWRITE = 32, M_BUFFER_DEFERRED_POP = 64 @@ -138,80 +130,6 @@ typedef enum { #define M_BUFF3R_POLICY_P(policy, val) \ (((policy) & (val)) != 0) -/* Handle either atomic integer or normal integer in function of the policy - parameter of the buffer BUFFER_THREAD_UNSAFE (BUFFER_THREAD_SAFE is the - default). This enables avoiding to pay the cost of atomic operations if not - applicable. - */ -typedef union m_buff3r_number_s { - unsigned int u; - atomic_uint a; -#ifdef __cplusplus - // Not sure why, but C++ needs an explicit default constructor for this union. - m_buff3r_number_s() : u(0) {}; -#endif -} m_buff3r_number_ct[1]; - -M_INLINE void -m_buff3r_number_init(m_buff3r_number_ct n, unsigned int policy) -{ - if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE)) - atomic_init(&n->a, 0U); - else - n->u = 0UL; -} - -M_INLINE unsigned int -m_buff3r_number_load(const m_buff3r_number_ct n, unsigned int policy) -{ - if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE)) - // Perform a memory acquire so that further usage of the buffer - // is synchronized. - return atomic_load_explicit(&n->a, memory_order_acquire); - else - return n->u; -} - -M_INLINE void -m_buff3r_number_store(m_buff3r_number_ct n, unsigned int v, unsigned int policy) -{ - if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE)) - // This function is used in context where a relaxed access is sufficient. - atomic_store_explicit(&n->a, v, memory_order_relaxed); - else - n->u = v; -} - -M_INLINE void -m_buff3r_number_set(m_buff3r_number_ct n, m_buff3r_number_ct v, unsigned int policy) -{ - if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE)) - // This function is used in context where a relaxed access is sufficient. - atomic_store_explicit(&n->a, atomic_load_explicit(&v->a, memory_order_relaxed), memory_order_relaxed); - else - n->u = v->u; -} - -M_INLINE unsigned int -m_buff3r_number_inc(m_buff3r_number_ct n, unsigned int policy) -{ - if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE)) - return atomic_fetch_add(&n->a, 1U); - else - return n->u ++; -} - -M_INLINE unsigned int -m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) -{ - if (!M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE)) - return atomic_fetch_sub(&n->a, 1U); - else - return n->u --; -} - -/********************************** INTERNAL *********************************/ - /* Test if the size is only run-time or build time */ #define M_BUFF3R_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size)) @@ -230,7 +148,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) /* Contract of a buffer within a protected section */ #define M_BUFF3R_PROTECTED_CONTRACT(policy, buffer, size) do { \ - M_ASSERT (m_buff3r_number_load(buffer->number[0], policy) <= M_BUFF3R_SIZE(size)); \ + M_ASSERT (atomic_load_explicit(&buffer->number[0], memory_order_acquire) <= M_BUFF3R_SIZE(size)); \ } while (0) @@ -258,7 +176,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) M_BUFF3R_DEF_TYPE(name, type, m_size, policy, oplist, buffer_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \ - M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_BUFF3R_EMPLACE_QUEUE_GENE) /* Define the type of a buffer */ #define M_BUFF3R_DEF_TYPE(name, type, m_size, policy, oplist, buffer_t) \ @@ -267,7 +185,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) by multiple writing threads. No need to align if there is no thread */ \ typedef union M_F(name, _el_s) { \ type x; \ - char align[M_BUFF3R_POLICY_P(policy, M_BUFFER_THREAD_UNSAFE) ? 1 : M_ALIGN_FOR_CACHELINE_EXCLUSION]; \ + char align[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \ } M_F(name, _el_ct); \ \ typedef struct M_F(name, _s) { \ @@ -284,7 +202,7 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) size_t idx_cons; /* Index of the consumption threads */ \ /* number[0] := Number of elements in the buffer */ \ /* number[1] := [OPTION] Number of elements being deferred in the buffer */ \ - m_buff3r_number_ct number[1 + M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)]; \ + atomic_uint number[1 + M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)]; \ /* If fixed size, array of elements, otherwise pointer to element */ \ M_F(name, _el_ct) M_BUFF3R_IF_CTE_SIZE(m_size)(data[m_size], *data); \ } buffer_t[1]; \ @@ -300,23 +218,19 @@ m_buff3r_number_dec(m_buff3r_number_ct n, unsigned int policy) /* Define the core functionalities of a buffer */ #define M_BUFF3R_DEF_CORE(name, type, m_size, policy, oplist, buffer_t) \ \ -M_P(void, name, _init, buffer_t v, size_t size) \ +M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_ASSERT(size <= UINT_MAX); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ M_BUFF3R_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = size); \ v->idx_prod = v->idx_cons = v->overwrite = 0; \ - m_buff3r_number_init (v->number[0], policy); \ + atomic_init (&v->number[0], 0U); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - m_buff3r_number_init (v->number[1], policy); \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_init(v->mutexPush); \ - m_mutex_init(v->mutexPop); \ - m_cond_init(v->there_is_data); \ - m_cond_init(v->there_is_room_for_data); \ - } else { \ - M_ASSERT(M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING)); \ - } \ + atomic_init (&v->number[1], 0U); \ + m_mutex_init(v->mutexPush); \ + m_mutex_init(v->mutexPop); \ + m_cond_init(v->there_is_data); \ + m_cond_init(v->there_is_room_for_data); \ \ M_BUFF3R_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \ v->data = M_CALL_REALLOC(oplist, M_F(name, _el_ct), NULL, 0, M_BUFF3R_SIZE(m_size)); \ @@ -333,16 +247,16 @@ M_P(void, name, _init, buffer_t v, size_t size) \ } \ \ M_BUFF3R_IF_CTE_SIZE(m_size)( \ - M_P(void, name,_i_init, buffer_t v) \ + M_N(void, name,_i_init, buffer_t v) \ { \ - M_F(name, _init)M_R(v, m_size); \ + M_F(name, _init)(v, m_size); \ } \ , ) \ \ - M_P(void, name, _i_clear_obj, buffer_t v) \ + M_N(void, name, _i_clear_obj, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \ M_CALL_CLEAR(oplist, v->data[i].x); \ @@ -357,64 +271,59 @@ M_P(void, name, _init, buffer_t v, size_t size) \ } \ } \ v->idx_prod = v->idx_cons = 0; \ - m_buff3r_number_store (v->number[0], 0U, policy); \ + atomic_store_explicit (&v->number[0], 0U, memory_order_relaxed); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - m_buff3r_number_store(v->number[1], 0U, policy); \ + atomic_store_explicit (&v->number[1], 0U, memory_order_relaxed); \ M_BUFF3R_CONTRACT(v,m_size); \ } \ \ - M_P(void, name, _clear, buffer_t v) \ + M_N(void, name, _clear, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_F(name,_i_clear_obj)M_R(v); \ + M_GLOBAL_POOL(); \ + M_F(name,_i_clear_obj)(v); \ M_BUFF3R_IF_CTE_SIZE(m_size)( , \ M_CALL_FREE(oplist, M_F(name, _el_ct), v->data, M_BUFF3R_SIZE(m_size)); \ v->data = NULL; \ ) \ v->overwrite = 0; \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_clear(v->mutexPush); \ - m_mutex_clear(v->mutexPop); \ - m_cond_clear(v->there_is_data); \ - m_cond_clear(v->there_is_room_for_data); \ - } \ + m_mutex_clear(v->mutexPush); \ + m_mutex_clear(v->mutexPop); \ + m_cond_clear(v->there_is_data); \ + m_cond_clear(v->there_is_room_for_data); \ } \ \ - M_P(void, name, _reset, buffer_t v) \ + M_N(void, name, _reset, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - } \ + M_GLOBAL_POOL(); \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ if (M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) \ - M_F(name,_i_clear_obj)M_R(v); \ + M_F(name,_i_clear_obj)(v); \ v->idx_prod = v->idx_cons = 0; \ - m_buff3r_number_store (v->number[0], 0U, policy); \ + atomic_store_explicit (&v->number[0], 0U, memory_order_relaxed); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - m_buff3r_number_store(v->number[1], 0U, policy); \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - } \ + atomic_store_explicit(&v->number[1], 0U, memory_order_relaxed); \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ M_BUFF3R_CONTRACT(v,m_size); \ } \ \ - M_P(void, name, _init_set, buffer_t dest, const buffer_t src) \ + M_N(void, name, _init_set, buffer_t dest, const buffer_t src) \ { \ - /* un-const 'src', so that we can lock it (semantically it is const) */ \ + M_GLOBAL_POOL(); \ + /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ vu.cptr = src; \ M_F(name, _ptr) v = vu.ptr; \ M_ASSERT (dest != v); \ M_BUFF3R_CONTRACT(v,m_size); \ - M_F(name, _init)M_R(dest, M_BUFF3R_SIZE(m_size)); \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - } \ + M_F(name, _init)(dest, M_BUFF3R_SIZE(m_size)); \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ @@ -433,21 +342,20 @@ M_P(void, name, _init, buffer_t v, size_t size) \ \ dest->idx_prod = v->idx_prod; \ dest->idx_cons = v->idx_cons; \ - m_buff3r_number_set (dest->number[0], v->number[0], policy); \ + atomic_store_explicit (&dest->number[0], v->number[0], memory_order_relaxed); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - m_buff3r_number_set(dest->number[1], v->number[1], policy); \ + atomic_store_explicit(&dest->number[1], v->number[1], memory_order_relaxed); \ \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - } \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ M_BUFF3R_CONTRACT(v,m_size); \ M_BUFF3R_CONTRACT(dest, m_size); \ } \ \ - M_P(void, name, _set, buffer_t dest, const buffer_t src) \ + M_N(void, name, _set, buffer_t dest, const buffer_t src) \ { \ - /* un-const 'src', so that we can lock it (semantically it is const) */ \ + M_GLOBAL_POOL(); \ + /* 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; \ @@ -455,24 +363,22 @@ M_P(void, name, _init, buffer_t v, size_t size) \ M_BUFF3R_CONTRACT(v,m_size); \ \ if (dest == v) return; \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - /* Case of deadlock: A := B, B:=C, C:=A (all in //) \ - Solution: order the lock by increasing memory */ \ - if (dest < v) { \ - m_mutex_lock(dest->mutexPush); \ - m_mutex_lock(dest->mutexPop); \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - } else { \ - m_mutex_lock(v->mutexPush); \ - m_mutex_lock(v->mutexPop); \ - m_mutex_lock(dest->mutexPush); \ - m_mutex_lock(dest->mutexPop); \ - } \ + /* Case of deadlock: A := B, B:=C, C:=A (all in //) \ + Solution: order the lock by increasing memory */ \ + if (dest < v) { \ + m_mutex_lock(dest->mutexPush); \ + m_mutex_lock(dest->mutexPop); \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ + } else { \ + m_mutex_lock(v->mutexPush); \ + m_mutex_lock(v->mutexPop); \ + m_mutex_lock(dest->mutexPush); \ + m_mutex_lock(dest->mutexPop); \ } \ \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ - M_F(name,_i_clear_obj)M_R(dest); \ + M_F(name,_i_clear_obj)(dest); \ \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \ @@ -490,25 +396,22 @@ M_P(void, name, _init, buffer_t v, size_t size) \ \ dest->idx_prod = v->idx_prod; \ dest->idx_cons = v->idx_cons; \ - m_buff3r_number_set (dest->number[0], v->number[0], policy); \ + atomic_store_explicit(&dest->number[0], v->number[0], memory_order_relaxed); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - m_buff3r_number_set(dest->number[1], v->number[1], policy); \ + atomic_store_explicit(&dest->number[1], v->number[1], memory_order_relaxed); \ \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - /* It may be false, but it is not wrong! */ \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_cond_broadcast(v->there_is_data); \ - if (dest < v) { \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - m_mutex_unlock(dest->mutexPop); \ - m_mutex_unlock(dest->mutexPush); \ - } else { \ - m_mutex_unlock(dest->mutexPop); \ - m_mutex_unlock(dest->mutexPush); \ - m_mutex_unlock(v->mutexPop); \ - m_mutex_unlock(v->mutexPush); \ - } \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_cond_broadcast(v->there_is_data); \ + if (dest < v) { \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ + m_mutex_unlock(dest->mutexPop); \ + m_mutex_unlock(dest->mutexPush); \ + } else { \ + m_mutex_unlock(dest->mutexPop); \ + m_mutex_unlock(dest->mutexPush); \ + m_mutex_unlock(v->mutexPop); \ + m_mutex_unlock(v->mutexPush); \ } \ M_BUFF3R_CONTRACT(v,m_size); \ M_BUFF3R_CONTRACT(dest, m_size); \ @@ -523,16 +426,16 @@ M_P(void, name, _init, buffer_t v, size_t size) \ deferred pop has reached 0, not the number of items in the \ buffer is 0. */ \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - return m_buff3r_number_load (v->number[1], policy) == 0; \ + return atomic_load_explicit (&v->number[1], memory_order_relaxed) == 0; \ else \ - return m_buff3r_number_load (v->number[0], policy) == 0; \ + return atomic_load_explicit (&v->number[0], memory_order_relaxed) == 0; \ } \ \ M_INLINE bool \ M_F(name, _full_p)(const buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - return m_buff3r_number_load (v->number[0], policy) \ + return atomic_load_explicit (&v->number[0], memory_order_relaxed) \ == M_BUFF3R_SIZE(m_size); \ } \ \ @@ -540,27 +443,23 @@ M_P(void, name, _init, buffer_t v, size_t size) \ M_F(name, _size)(const buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - return m_buff3r_number_load (v->number[0], policy); \ + return atomic_load_explicit (&v->number[0], memory_order_relaxed); \ } \ \ - M_P(bool, name, _push_blocking, buffer_t v, type const data, bool blocking) \ + M_N(bool, name, _push_blocking, buffer_t v, type const data, bool blocking) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ /* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPush); \ - while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \ - && M_F(name, _full_p)(v)) { \ - if (!blocking) { \ - m_mutex_unlock(v->mutexPush); \ - return false; \ - } \ - m_cond_wait(v->there_is_room_for_data, v->mutexPush); \ - } \ - } else if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \ - && M_F(name, _full_p)(v)) \ - return false; \ + m_mutex_lock(v->mutexPush); \ + while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \ + && M_F(name, _full_p)(v)) { \ + if (!blocking) { \ + m_mutex_unlock(v->mutexPush); \ + return false; \ + } \ + m_cond_wait(v->there_is_room_for_data, v->mutexPush); \ + } \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ \ size_t previousSize, idx = v->idx_prod; \ @@ -598,47 +497,42 @@ M_P(void, name, _init, buffer_t v, size_t size) \ thread which has the push lock. As such, it is an atomic variable \ that performs a release memory barrier. */ \ /* Increment number of elements of the buffer */ \ - previousSize = m_buff3r_number_inc (v->number[0], policy); \ + previousSize = atomic_fetch_add (&v->number[0], 1U); \ if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \ - previousSize = m_buff3r_number_inc (v->number[1], policy); \ + previousSize = atomic_fetch_add (&v->number[1], 1U); \ } \ /* From this point, consumer may read the data in the table */ \ } \ \ /* Producer unlock (mutex unlock performs a release memory barrier) */ \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_unlock(v->mutexPush); \ - /* If the number of items in the buffer was 0, some consumer \ - may be waiting. Signal to them the availability of the data \ - We cannot only signal one thread. */ \ - if (previousSize == 0) { \ - m_mutex_lock(v->mutexPop); \ - m_cond_broadcast(v->there_is_data); \ - m_mutex_unlock(v->mutexPop); \ - } \ + m_mutex_unlock(v->mutexPush); \ + /* If the number of items in the buffer was 0, some consumer \ + may be waiting. Signal to them the availability of the data \ + We cannot only signal one thread. */ \ + if (previousSize == 0) { \ + m_mutex_lock(v->mutexPop); \ + m_cond_broadcast(v->there_is_data); \ + m_mutex_unlock(v->mutexPop); \ } \ \ M_BUFF3R_CONTRACT(v,m_size); \ return true; \ } \ \ - M_P(bool, name, _pop_blocking, type *data, buffer_t v, bool blocking) \ + M_N(bool, name, _pop_blocking, type *data, buffer_t v, bool blocking) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ M_ASSERT (data != NULL); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ /* consumer lock (mutex lock performs an acquire memory barrier) */ \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_lock(v->mutexPop); \ - while (M_F(name, _empty_p)(v)) { \ - if (!blocking) { \ - m_mutex_unlock(v->mutexPop); \ - return false; \ - } \ - m_cond_wait(v->there_is_data, v->mutexPop); \ - } \ - } else if (M_F(name, _empty_p)(v)) \ - return false; \ + m_mutex_lock(v->mutexPop); \ + while (M_F(name, _empty_p)(v)) { \ + if (!blocking) { \ + m_mutex_unlock(v->mutexPop); \ + return false; \ + } \ + m_cond_wait(v->there_is_data, v->mutexPop); \ + } \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ \ /* POP data from the buffer and update INDEX */ \ @@ -667,24 +561,22 @@ M_P(void, name, _init, buffer_t v, size_t size) \ /* Decrement number of elements in the buffer */ \ size_t previousSize; \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \ - previousSize = m_buff3r_number_dec (v->number[0], policy); \ + previousSize = atomic_fetch_sub (&v->number[0], 1U); \ } else { \ - m_buff3r_number_dec (v->number[1], policy); \ + atomic_fetch_sub (&v->number[1], 1U); \ } \ /* Space may be reused by a producer thread from this point */ \ \ /* consumer unlock (mutex unlock performs a release memory barrier) */ \ - if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_THREAD_UNSAFE)) { \ - m_mutex_unlock(v->mutexPop); \ - /* If the number of items in the buffer was the max, some producer \ - may be waiting. Signal to them the availability of the free room \ - We cannot only signal one thread. */ \ - if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \ - && previousSize == M_BUFF3R_SIZE(m_size)) { \ - m_mutex_lock(v->mutexPush); \ - m_cond_broadcast(v->there_is_room_for_data); \ - m_mutex_unlock(v->mutexPush); \ - } \ + m_mutex_unlock(v->mutexPop); \ + /* If the number of items in the buffer was the max, some producer \ + may be waiting. Signal to them the availability of the free room \ + We cannot only signal one thread. */ \ + if ((!M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) \ + && previousSize == M_BUFF3R_SIZE(m_size)) { \ + m_mutex_lock(v->mutexPush); \ + m_cond_broadcast(v->there_is_room_for_data); \ + m_mutex_unlock(v->mutexPush); \ } \ \ M_BUFF3R_CONTRACT(v,m_size); \ @@ -692,16 +584,18 @@ M_P(void, name, _init, buffer_t v, size_t size) \ } \ \ \ - M_P(bool, name, _push, buffer_t v, type const data) \ + M_N(void, name, _push, buffer_t v, type const data) \ { \ - return M_F(name, _push_blocking)M_R(v, data, \ - !M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_PUSH)); \ + bool b = M_F(name, _push_blocking)(v, data, true); \ + assert(b); \ + (void) b; \ } \ \ - M_P(bool, name, _pop, type *data, buffer_t v) \ + M_N(void, name, _pop, type *data, buffer_t v) \ { \ - return M_F(name, _pop_blocking)M_R(data, v, \ - !M_BUFF3R_POLICY_P((policy), M_BUFFER_UNBLOCKING_POP)); \ + bool b = M_F(name, _pop_blocking)(data, v, true); \ + assert(b); \ + (void) b; \ } \ \ M_INLINE size_t \ @@ -722,7 +616,7 @@ M_P(void, name, _init, buffer_t v, size_t size) \ { \ /* Decrement the effective number of elements in the buffer */ \ if (M_BUFF3R_POLICY_P((policy), M_BUFFER_DEFERRED_POP)) { \ - size_t previousSize = m_buff3r_number_dec (v->number[0], policy); \ + size_t previousSize = atomic_fetch_sub (&v->number[0], 1U); \ if (previousSize == M_BUFF3R_SIZE(m_size)) { \ m_mutex_lock(v->mutexPush); \ m_cond_broadcast(v->there_is_room_for_data); \ @@ -782,7 +676,7 @@ M_P(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_MPMC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \ - M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_BUFF3R_EMPLACE_QUEUE_GENE) /* Define the type of a MPMC queue */ #define M_QU3UE_MPMC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ @@ -817,10 +711,10 @@ M_P(void, name, _init, buffer_t v, size_t size) \ /* Define the core functionalities of a MPMC queue */ #define M_QU3UE_MPMC_DEF_CORE(name, type, policy, oplist, buffer_t) \ - M_P(bool, name, _push, buffer_t table, type const x) \ + M_N(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int idx = atomic_load_explicit(&table->ProdIdx, \ memory_order_relaxed); \ const unsigned int i = idx & (table->size -1); \ @@ -851,11 +745,11 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return true; \ } \ \ - M_P(bool, name, _pop, type *ptr, buffer_t table) \ + M_N(bool, name, _pop, type *ptr, buffer_t table) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \ memory_order_relaxed); \ const unsigned int i = (iC & (table->size -1)); \ @@ -880,12 +774,12 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return true; \ } \ \ - M_P(void, name, _init, buffer_t buffer, size_t size) \ + M_N(void, name, _init, buffer_t buffer, size_t size) \ { \ M_ASSERT (buffer != NULL); \ - M_ASSERT( M_POWEROF2_P(size)); \ - M_ASSERT (0 < size && size <= UINT_MAX); \ - M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \ + M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \ + M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \ + M_GLOBAL_POOL(); \ atomic_init(&buffer->ProdIdx, (unsigned int) size); \ atomic_init(&buffer->ConsoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ @@ -902,9 +796,10 @@ M_P(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_MPMC_CONTRACT(buffer); \ } \ \ - M_P(void, name, _clear, buffer_t buffer) \ + M_N(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_MPMC_CONTRACT(buffer); \ + M_GLOBAL_POOL(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < buffer->size; j++) { \ M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ @@ -1014,7 +909,7 @@ M_P(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \ - M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) + M_EMPLACE_QUEUE_DEF(name, buffer_t, _emplace, oplist, M_BUFF3R_EMPLACE_QUEUE_GENE) /* Define the type of a SPSC queue */ #define M_QU3UE_SPSC_DEF_TYPE(name, type, policy, oplist, buffer_t) \ @@ -1031,7 +926,7 @@ M_P(void, name, _init, buffer_t v, size_t size) \ atomic_uint consoIdx; /* Can only increase until overflow */ \ unsigned int size; \ M_F(name, _el_ct) *Tab; \ - M_CACHELINE_ALIGN(align, atomic_uint, size_t, M_F(name, _el_ct) *); \ + M_CACHELINE_ALIGN(align, atomic_uint, unsigned int, M_F(name, _el_ct) *); \ atomic_uint prodIdx; /* Can only increase until overflow */ \ } buffer_t[1]; \ \ @@ -1041,10 +936,10 @@ M_P(void, name, _init, buffer_t v, size_t size) \ /* Define the core functionalities of a SPSC queue */ #define M_QU3UE_SPSC_DEF_CORE(name, type, policy, oplist, buffer_t) \ \ - M_P(bool, name, _push, buffer_t table, type const x) \ + M_N(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1062,10 +957,10 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return true; \ } \ \ - M_P(bool, name, _push_move, buffer_t table, type *x) \ + M_N(bool, name, _push_move, buffer_t table, type *x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1083,11 +978,11 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return true; \ } \ \ - M_P(bool, name, _pop, type *ptr, buffer_t table) \ + M_N(bool, name, _pop, type *ptr, buffer_t table) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1105,12 +1000,12 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return true; \ } \ \ - M_P(unsigned, name, _push_bulk, buffer_t table, unsigned n, type const x[]) \ + M_N(unsigned, name, _push_bulk, buffer_t table, unsigned n, type const x[]) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (x != NULL); \ M_ASSERT (n <= table->size); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1131,12 +1026,12 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return max; \ } \ \ - M_P(unsigned, name, _pop_bulk, unsigned n, type ptr[], buffer_t table) \ + M_N(unsigned, name, _pop_bulk, unsigned n, type ptr[], buffer_t table) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ M_ASSERT (n <= table->size); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1157,10 +1052,10 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return max; \ } \ \ - M_P(void, name, _push_force, buffer_t table, type const x) \ + M_N(void, name, _push_force, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_ASSERT_POOL(); \ + M_GLOBAL_POOL(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1219,12 +1114,12 @@ M_P(void, name, _init, buffer_t v, size_t size) \ return M_F(name, _size)(v) >= v->size; \ } \ \ - M_P(void, name, _init, buffer_t buffer, size_t size) \ + M_N(void, name, _init, buffer_t buffer, size_t size) \ { \ M_ASSERT (buffer != NULL); \ - M_ASSERT( M_POWEROF2_P(size)); \ - M_ASSERT (0 < size && size <= UINT_MAX); \ - M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_THREAD_UNSAFE|M_BUFFER_PUSH_OVERWRITE)) == 0); \ + M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \ + M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \ + M_GLOBAL_POOL(); \ atomic_init(&buffer->prodIdx, (unsigned int) size); \ atomic_init(&buffer->consoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ @@ -1240,9 +1135,10 @@ M_P(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_SPSC_CONTRACT(buffer); \ } \ \ - M_P(void, name, _clear, buffer_t buffer) \ + M_N(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_SPSC_CONTRACT(buffer); \ + M_GLOBAL_POOL(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < buffer->size; j++) { \ M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ @@ -1297,8 +1193,18 @@ M_P(void, name, _init, buffer_t v, size_t size) \ ,GET_SIZE(M_F(name, _size)) \ ) - -/********************************** INTERNAL *********************************/ +/* Same as M_EMPLACE_QUEUE_GENE but use M_GLOBAL_POOL */ +#define M_BUFF3R_EMPLACE_QUEUE_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ +M_N(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ +{ \ + M_GET_TYPE oplist data; \ + M_GLOBAL_POOL(); \ + M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \ + M_F(name, _push)(v, data); \ + M_CALL_CLEAR(oplist, data); \ +} + + /********************************** INTERNAL *********************************/ #if M_USE_SMALL_NAME #define BUFFER_DEF M_BUFFER_DEF @@ -1312,14 +1218,6 @@ M_P(void, name, _init, buffer_t v, size_t size) \ #define buffer_policy_e m_buffer_policy_e #define BUFFER_QUEUE M_BUFFER_QUEUE #define BUFFER_STACK M_BUFFER_STACK -#define BUFFER_BLOCKING_PUSH M_BUFFER_BLOCKING_PUSH -#define BUFFER_UNBLOCKING_PUSH M_BUFFER_UNBLOCKING_PUSH -#define BUFFER_BLOCKING_POP M_BUFFER_BLOCKING_POP -#define BUFFER_UNBLOCKING_POP M_BUFFER_UNBLOCKING_POP -#define BUFFER_BLOCKING M_BUFFER_BLOCKING -#define BUFFER_UNBLOCKING M_BUFFER_UNBLOCKING -#define BUFFER_THREAD_SAFE M_BUFFER_THREAD_SAFE -#define BUFFER_THREAD_UNSAFE M_BUFFER_THREAD_UNSAFE #define BUFFER_PUSH_INIT_POP_MOVE M_BUFFER_PUSH_INIT_POP_MOVE #define BUFFER_PUSH_OVERWRITE M_BUFFER_PUSH_OVERWRITE #define BUFFER_DEFERRED_POP M_BUFFER_DEFERRED_POP diff --git a/m-core.h b/m-core.h index 95bc138a..51eba8bf 100644 --- a/m-core.h +++ b/m-core.h @@ -461,11 +461,8 @@ M_BEGIN_PROTECTED_CODE # define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__) #endif -// TODO: Add for all Assertions: M_ASSERT_POOL() -// to avoid warnings about unused parameter m_pool. -// Pb: Also included for functions without the pool parameter! - -// FIXME: Not sense to do it for a shared pointer: it is shared across all memory contexts! +// TODO: 'pool' seems not the right term. Rename 'pool' into 'localmem' ? 'arena'? memcontext? context? +// TODO: M_USE_GLOBAL_POOL , value for setting the global pool. /************************************************************/ /********************* ERROR handling **********************/ @@ -5162,7 +5159,6 @@ m_core_parse2_enum (const char str[], const char **endptr) { \ M_GET_TYPE oplist data; \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \ - /* FIXME: Why name##_push and not M_CALL_PUSH? */ \ M_F(name, _push) M_R(v, data); \ M_CALL_CLEAR(oplist, data); \ } diff --git a/m-worker.h b/m-worker.h index c70a0d1f..50ca1bc3 100644 --- a/m-worker.h +++ b/m-worker.h @@ -142,8 +142,7 @@ typedef struct m_work3r_thread_s { } m_work3r_thread_ct; /* Definition of the queue that will record the work orders */ -M_BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0, - M_BUFFER_QUEUE|M_BUFFER_UNBLOCKING_PUSH|M_BUFFER_BLOCKING_POP|M_BUFFER_THREAD_SAFE|M_BUFFER_DEFERRED_POP, M_WORK3R_OPLIST) +M_BUFFER_DEF(m_work3r_queue, m_work3r_order_ct, 0, M_BUFFER_QUEUE|M_BUFFER_DEFERRED_POP, M_WORK3R_OPLIST) /* Definition the global pool of workers */ typedef struct m_worker_s { @@ -273,7 +272,7 @@ typedef struct m_worker_sync_s { p->callback = callback; \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD_INIT_SET, data, __VA_ARGS__) \ const m_work3r_order_ct w = { block, p, M_C3(m_work3r_, name, _callback) M_WORK3R_EXTRA_ORDER }; \ - if (m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { \ + if (m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { \ atomic_fetch_add (&block->num_spawn, 1); \ return; \ } \ @@ -372,7 +371,7 @@ m_work3r_thread(void *arg) } // Waiting for data M_WORK3R_DEBUG ("Waiting for data (queue: %lu / %lu)\n", m_work3r_queue_size(g->queue_g), m_work3r_queue_capacity(g->queue_g)); - m_work3r_queue_pop M_R(&w, g->queue_g); + m_work3r_queue_pop (&w, g->queue_g); // We received a work order // Note: that the work order is still present in the queue // preventing further work order to be pushed in the queue until it finishes doing the work @@ -417,7 +416,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset if (M_UNLIKELY_NOMEM (g->worker == NULL)) { M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st); } - m_work3r_queue_init M_R(g->queue_g, numWorker_st + extraQueue); + m_work3r_queue_init (g->queue_g, numWorker_st + extraQueue); g->numWorker_g = (unsigned int) numWorker_st; g->resetFunc_g = resetFunc; g->clearFunc_g = clearFunc; @@ -451,7 +450,7 @@ m_worker_clear(m_worker_t g) // 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 M_R(g->queue_g, w, true); + m_work3r_queue_push_blocking (g->queue_g, w, true); } // Wait for thread termination for(unsigned int i = 0; i < g->numWorker_g; i++) { @@ -461,7 +460,7 @@ m_worker_clear(m_worker_t g) M_MEMORY_FREE(m_work3r_thread_ct, g->worker, g->numWorker_g); m_mutex_clear(g->lock); m_cond_clear(g->a_thread_ends); - m_work3r_queue_clear M_R(g->queue_g); + m_work3r_queue_clear (g->queue_g); } /* Start a new collaboration between workers of pool 'g' @@ -485,7 +484,7 @@ m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data) const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER }; M_GLOBAL_POOL(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) - && m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { + && m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { M_WORK3R_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); atomic_fetch_add (&block->num_spawn, 1); return; @@ -504,7 +503,7 @@ m_work3r_spawn_block(m_worker_sync_t block, void (^func)(void *data), void *data const m_work3r_order_ct w = { block, data, NULL, func }; M_GLOBAL_POOL(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) - && m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { + && m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); atomic_fetch_add (&block->num_spawn, 1); return; @@ -524,7 +523,7 @@ m_work3r_spawn_function(m_worker_sync_t block, std::function f const m_work3r_order_ct w = { block, data, NULL, func }; M_GLOBAL_POOL(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) - && m_work3r_queue_push M_R(block->worker->queue_g, w) == true) { + && m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); atomic_fetch_add (&block->num_spawn, 1); return; @@ -566,7 +565,7 @@ m_worker_flush(m_worker_t g) { m_work3r_order_ct w; M_GLOBAL_POOL(); - while (m_work3r_queue_pop_blocking M_R(&w, g->queue_g, false) == true) { + while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) { m_work3r_exec(&w); m_work3r_queue_pop_release(g->queue_g); } diff --git a/tests/Makefile b/tests/Makefile index 532fd3bc..c8eff7ec 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -198,6 +198,7 @@ SYNTHESIS_DATA= M-ALGO test-malgo.c.c test-malgo.synt \ M-GENINT ../m-genint.h test-mgenint.synt \ M-I-LIST test-milist.c.c test-milist.synt \ M-I-SHARED test-mishared.c.c test-mishared.synt \ + M-QUEUE test-mqueue.c.c test-mqueue.synt \ M-LIST test-mlist.c.c test-mlist.synt \ M-MEMPOOL test-mmempool.c.c test-mmempool.synt \ M-PRIOQUEUE test-mprioqueue.c.c test-mprioqueue.synt \ diff --git a/tests/coverage.h b/tests/coverage.h index 076fa28e..a3cb5a30 100644 --- a/tests/coverage.h +++ b/tests/coverage.h @@ -125,6 +125,9 @@ #define M_TR33_CONTRACT(...) (void)0 #undef M_TR33_IT_CONTRACT #define M_TR33_IT_CONTRACT(...) (void)0 +#undef M_QUEU3_CONTRACT +#define M_QUEU3_CONTRACT(...) (void)0 + /* Overwrite M_UNLIKELY_NOMEM so that it can never fails, to avoid spurious coverage */ #undef M_UNLIKELY_NOMEM #define M_UNLIKELY_NOMEM(...) 0 diff --git a/tests/test-mbuffer.c b/tests/test-mbuffer.c index 6fc2032d..435dd771 100644 --- a/tests/test-mbuffer.c +++ b/tests/test-mbuffer.c @@ -26,19 +26,16 @@ START_COVERAGE // Define a fixed queue of unsigned int -BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE|BUFFER_BLOCKING) +BUFFER_DEF(buffer_uint, unsigned int, 10, BUFFER_QUEUE) QUEUE_MPMC_DEF(queue_uint, unsigned int, BUFFER_QUEUE) QUEUE_SPSC_DEF(squeue_uint, unsigned int, BUFFER_QUEUE) END_COVERAGE // Define a variable stack of float -BUFFER_DEF(buffer_floats, float, 0, BUFFER_STACK|BUFFER_BLOCKING) +BUFFER_DEF(buffer_floats, float, 0, BUFFER_STACK) // Define a fixed stack of char -BUFFER_DEF(buffer_char, char, 10, BUFFER_STACK|BUFFER_UNBLOCKING) - -// Define a fixed queue of long long -BUFFER_DEF(buffer_llong, long long, 16, BUFFER_QUEUE|BUFFER_THREAD_UNSAFE|BUFFER_UNBLOCKING) +BUFFER_DEF(buffer_char, char, 10, BUFFER_STACK) // Define a buffer of complex structure. BUFFER_DEF(buffer_mpz, testobj_t, 32, BUFFER_QUEUE, TESTOBJ_OPLIST) @@ -170,8 +167,7 @@ static void test_global(void) assert (buffer_uint_size(g_buffB) == 5); for(unsigned int i = 0; i < 5;i++) { unsigned int j; - bool b= buffer_uint_pop(&j, g_buffB); - assert(b); + buffer_uint_pop(&j, g_buffB); assert(j == i); } assert (buffer_uint_empty_p(g_buffB)); @@ -182,8 +178,7 @@ static void test_global(void) assert (buffer_uint_size(g_buffB) == 5); for(unsigned int i = 0; i < 5;i++) { unsigned int j; - bool b= buffer_uint_pop(&j, g_buffB); - assert(b); + buffer_uint_pop(&j, g_buffB); assert(j == i); } assert (buffer_uint_empty_p(g_buffB)); @@ -231,56 +226,25 @@ static void test_stack2(void) buffer_char_init(buff, 10); for(int i = 0; i < 10; i++) { c = (char) i; - b = buffer_char_push(buff, c); + b = buffer_char_push_blocking(buff, c, false); assert (b == true); assert (buffer_char_empty_p(buff) == false); } - b = buffer_char_push(buff, c); + b = buffer_char_push_blocking(buff, c, false); assert (b == false); assert (buffer_char_full_p(buff) == true); for(int i = 0; i < 10; i++) { - buffer_char_pop(&c, buff); + b = buffer_char_pop_blocking(&c, buff, false); + assert(b); assert(c == 9-i); assert (buffer_char_full_p(buff) == false); } - b = buffer_char_pop(&c, buff); + b = buffer_char_pop_blocking(&c, buff, false); assert (b == false); assert (buffer_char_empty_p(buff) == true); buffer_char_clear(buff); } -static void test_no_thread(void) -{ - buffer_llong_t buff; - bool b; - long long c; - buffer_llong_init(buff, 16); - for(int i = 0; i < 16; i++) { - c = i; - b = buffer_llong_push(buff, c); - assert (b == true); - assert (buffer_llong_empty_p(buff) == false); - } - b = buffer_llong_push(buff, c); - assert (b == false); - assert (buffer_llong_full_p(buff) == true); - for(int i = 0; i < 16; i++) { - buffer_llong_pop(&c, buff); - assert(c == i); - assert (buffer_llong_full_p(buff) == false); - } - b = buffer_llong_pop(&c, buff); - assert (b == false); - assert (buffer_llong_empty_p(buff) == true); - - b = buffer_llong_push(buff, c); - assert (b == true); - buffer_llong_reset(buff); - assert (buffer_llong_empty_p(buff) == true); - - buffer_llong_clear(buff); -} - static void test_emplace(void) { buffer_mpz_t b; @@ -582,56 +546,41 @@ static void test_spsc(void) static void test_double1(void) { - bool b; M_LET(buffer, BufferDouble1) { - b = BufferDouble1_push(buffer, 0.0); - assert(b); - b= BufferDouble1_push(buffer, 1.0); - assert(b); + BufferDouble1_push(buffer, 0.0); + BufferDouble1_push(buffer, 1.0); double d; - b = BufferDouble1_pop(&d, buffer); - assert(b); + BufferDouble1_pop(&d, buffer); assert(d == 0.0); - b = BufferDouble1_pop(&d, buffer); - assert(b); + BufferDouble1_pop(&d, buffer); assert(d == 1.0); } } static void test_double2(void) { - bool b; BufferDouble2 buffer; BufferDouble2_init(buffer, 2); - b = BufferDouble2_push(buffer, 0.0); - assert(b); - b= BufferDouble2_push(buffer, 1.0); - assert(b); + BufferDouble2_push(buffer, 0.0); + BufferDouble2_push(buffer, 1.0); double d; - b = BufferDouble2_pop(&d, buffer); - assert(b); + BufferDouble2_pop(&d, buffer); assert(d == 0.0); - b = BufferDouble2_pop(&d, buffer); - assert(b); + BufferDouble2_pop(&d, buffer); assert(d == 1.0); BufferDouble2_clear(buffer); } static void test_double3(void) { - bool b; BufferDouble3 buffer; BufferDouble3_init(buffer, 2); - b = BufferDouble3_push(buffer, 0.0); - assert(b); - b= BufferDouble3_push(buffer, 1.0); - assert(b); + BufferDouble3_push(buffer, 0.0); + BufferDouble3_push(buffer, 1.0); double d; - b = BufferDouble3_pop(&d, buffer); - assert(b); + BufferDouble3_pop(&d, buffer); assert(d == 0.0); - b = BufferDouble3_pop(&d, buffer); - assert(b); + BufferDouble3_pop(&d, buffer); assert(d == 1.0); BufferDouble3_clear(buffer); } @@ -668,7 +617,6 @@ int main(void) test_global(); test_stack(); test_stack2(); - test_no_thread(); test_emplace(); test_global_ishared(); test_queue(1000000, 2, 2148371710223136ULL); From ce3f674ba8084f725fce83315da71b205250d4cc Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 5 Apr 2025 20:01:07 +0200 Subject: [PATCH 40/91] Add new header m-queue (Doc to do) --- m-queue.h | 323 ++++++++++++++++++++++++++++++++++++++++++++ tests/test-mqueue.c | 171 +++++++++++++++++++++++ 2 files changed, 494 insertions(+) create mode 100644 m-queue.h create mode 100644 tests/test-mqueue.c diff --git a/m-queue.h b/m-queue.h new file mode 100644 index 00000000..c1bc3c71 --- /dev/null +++ b/m-queue.h @@ -0,0 +1,323 @@ +/* + * M*LIB - Fixed size (Bounded) QUEUE & STACK interface (Not Thread safe) + * + * Copyright (c) 2017-2025, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#ifndef MSTARLIB_QUEUE_H +#define MSTARLIB_QUEUE_H + +#include "m-core.h" + +/* Define a fixed size queue. + If size is 0, then the size will only be defined at run-time when initializing the queue, + otherwise the size will be a compile time constant embedded in the structure. + USAGE: QUEUE_DEF(name, type, size_of_QUEUE_or_0[, oplist]) */ +#define M_QUEUE_DEF(name, ... ) M_QUEUE_DEF_AS(name, M_F(name, _t), __VA_ARGS__) + + +/* Define a fixed size queue + as the provided type name_t. + USAGE: QUEUE_DEF_AS(name, name_t, type, size_of_QUEUE_or_0[, oplist of type]) */ +#define M_QUEUE_DEF_AS(name, name_t, type, ... ) \ + M_BEGIN_PROTECTED_CODE \ + M_QUEU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t, 0), \ + (name, type, __VA_ARGS__, name_t, 0))) \ + M_END_PROTECTED_CODE + +/* Define a fixed size stack. + If size is 0, then the size will only be defined at run-time when initializing the stack, + otherwise the size will be a compile time constant embedded in the structure. + USAGE: STACK_DEF(name, type, size_of_stack_or_0[, oplist]) */ +#define M_STACK_DEF(name, ... ) M_STACK_DEF_AS(name, M_F(name, _t), __VA_ARGS__) + + +/* Define a fixed size stack + as the provided type name_t. + USAGE: QUEUE_DEF_AS(name, name_t, type, size_of_stack_or_0[, oplist of type]) */ +#define M_STACK_DEF_AS(name, name_t, type, ... ) \ + M_BEGIN_PROTECTED_CODE \ + M_QUEU3_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((name, type, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(type)(), name_t, 1), \ + (name, type, __VA_ARGS__, name_t, 1))) \ + M_END_PROTECTED_CODE + +/* Define the oplist of a fixed size queue given its name and its oplist. + USAGE: QUEUE_OPLIST(name[, oplist of the type]) */ +#define M_QUEUE_OPLIST(...) \ + M_QUEU3_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ + ((__VA_ARGS__, M_BASIC_OPLIST), \ + (__VA_ARGS__ ))) + + +/*****************************************************************************/ +/********************************** INTERNAL *********************************/ +/*****************************************************************************/ + +/* Deferred evaluation for the definition, + so that all arguments are evaluated before further expansion */ +#define M_QUEU3_OPLIST_P1(arg) M_QUEU3_OPLIST_P2 arg + +/* Validation of the given oplist */ +#define M_QUEU3_OPLIST_P2(name, oplist) \ + M_IF_OPLIST(oplist)(M_QUEU3_OPLIST_P3, M_QUEU3_OPLIST_FAILURE)(name, oplist) + +/* Prepare a clean compilation failure */ +#define M_QUEU3_OPLIST_FAILURE(name, oplist) \ + ((M_LIB_ERROR(ARGUMENT_OF_BUFFER_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) + +/* OPLIST definition of a buffer */ +#define M_QUEU3_OPLIST_P3(name, oplist) \ + (INIT(M_F(name, _i_init)) \ + ,INIT_SET(M_F(name, _init_set)) \ + ,SET(M_F(name, _set)) \ + ,CLEAR(M_F(name, _clear)) \ + ,NAME(name) \ + ,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \ + ,SUBTYPE(M_F(name, _subtype_ct)) \ + ,RESET(M_F(name,_reset)) \ + ,PUSH(M_F(name,_push)) \ + ,POP(M_F(name,_pop)) \ + ,OPLIST(oplist) \ + ,EMPTY_P(M_F(name, _empty_p)), \ + ,FULL_P(M_F(name, _full_p)), \ + ,GET_SIZE(M_F(name, _size)) \ + ) + + + +/* Test if the size is only run-time or build time */ +#define M_QUEU3_IF_CTE_SIZE(m_size) M_IF(M_BOOL(m_size)) + +/* Return the size (run time or build time). + NOTE: It assumed that the queue variable name is 'v' */ +#define M_QUEU3_SIZE(v, m_size) \ + M_QUEU3_IF_CTE_SIZE(m_size) (m_size, v->capacity) + +/* Contract of a queue. */ +#define M_QUEU3_CONTRACT(queue, size) do { \ + M_ASSERT (queue != NULL); \ + M_ASSERT (queue->data != NULL); \ + }while (0) + +/* Deferred evaluation for the definition, + so that all arguments are evaluated before further expansion */ +#define M_QUEU3_DEF_P1(arg) M_ID( M_QUEU3_DEF_P2 arg ) + +/* Validate the value oplist before going further */ +#define M_QUEU3_DEF_P2(name, type, m_size, oplist, queue_t, stack_mode) \ + M_IF_OPLIST(oplist)(M_QUEU3_DEF_P3, M_QUEU3_DEF_FAILURE)(name, type, m_size, oplist, queue_t, stack_mode) + +/* Stop processing with a compilation failure */ +#define M_QUEU3_DEF_FAILURE(name, type, m_size, oplist, queue_t, stack_mode) \ + M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(M_QUEUE_DEF/M_STACK_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) + +/* Define the queue type using mutex lock and its functions. + - name: main prefix of the container + - type: type of an element of the queue + - m_size: constant to 0 if variable runtime size, or else the fixed size of the queue + - oplist: the oplist of the type of an element of the queue + - queue_t: name of the queue + */ +#define M_QUEU3_DEF_P3(name, type, m_size, oplist, queue_t, stack_mode) \ + M_QUEU3_DEF_TYPE(name, type, m_size, oplist, queue_t) \ + M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ + M_QUEU3_DEF_CORE(name, type, m_size, oplist, queue_t, stack_mode) \ + M_EMPLACE_QUEUE_DEF(name, queue_t, _emplace, oplist, M_EMPLACE_QUEUE_GENE) + +/* Define the type of a queue */ +#define M_QUEU3_DEF_TYPE(name, type, m_size, oplist, queue_t) \ + \ + typedef struct M_F(name, _s) { \ + unsigned idx_prod; /* Index of the production threads */ \ + M_QUEU3_IF_CTE_SIZE(m_size)( ,unsigned capacity;) /* Capacity of the queue */ \ + unsigned idx_cons; /* Index of the consumption threads */ \ + unsigned number; /* Number of elements in the queue */ \ + /* If fixed size, array of elements, otherwise pointer to element */ \ + type M_QUEU3_IF_CTE_SIZE(m_size)(data[m_size], *data); \ + } queue_t[1]; \ + \ + typedef struct M_F(name, _s) *M_F(name, _ptr); \ + typedef const struct M_F(name, _s) *M_F(name, _srcptr); \ + /* Internal types used by the oplist */ \ + typedef type M_F(name, _subtype_ct); \ + typedef queue_t M_F(name, _ct); \ + +/* Define the core functionalities of a queue */ +#define M_QUEU3_DEF_CORE(name, type, m_size, oplist, queue_t, stack_mode) \ + \ +M_P(void, name, _init, queue_t v, size_t size) \ +{ \ + M_ASSERT(size <= UINT_MAX); \ + M_ASSERT_POOL(); \ + M_QUEU3_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = (unsigned) size); \ + v->idx_prod = v->idx_cons = v->number = 0; \ + \ + M_QUEU3_IF_CTE_SIZE(m_size)( /* Statically allocated */ , \ + v->data = M_CALL_REALLOC(oplist, type, NULL, 0, M_QUEU3_SIZE(v, m_size)); \ + if (M_UNLIKELY_NOMEM (v->data == NULL)) { \ + M_MEMORY_FULL (type, M_QUEU3_SIZE(v, m_size)); \ + } \ + ) \ + for(size_t i = 0; i < size; i++) { \ + M_CALL_INIT(oplist, v->data[i]); \ + } \ + M_QUEU3_CONTRACT(v,m_size); \ +} \ + \ +M_QUEU3_IF_CTE_SIZE(m_size)( \ + M_P(void, name,_i_init, queue_t v) \ + { \ + M_F(name, _init)M_R(v, m_size); \ + } \ + , ) \ + \ + M_P(void, name, _i_clear_obj, queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + M_ASSERT_POOL(); \ + for(size_t i = 0; i < M_QUEU3_SIZE(v, m_size); i++) { \ + M_CALL_CLEAR(oplist, v->data[i]); \ + } \ + v->idx_prod = v->idx_cons = v->number = 0; \ + M_QUEU3_CONTRACT(v,m_size); \ + } \ + \ + M_P(void, name, _clear, queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + M_ASSERT_POOL(); \ + M_F(name,_i_clear_obj)M_R(v); \ + M_QUEU3_IF_CTE_SIZE(m_size)( , \ + M_CALL_FREE(oplist, type, v->data, M_QUEU3_SIZE(v, m_size)); \ + v->data = NULL; \ + ) \ + } \ + \ + M_N(void, name, _reset, queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + v->idx_prod = v->idx_cons = v->number = 0; \ + M_QUEU3_CONTRACT(v,m_size); \ + } \ + \ + M_P(void, name, _init_set, queue_t dest, const queue_t src) \ + { \ + M_ASSERT (dest != src); \ + M_QUEU3_CONTRACT(src,m_size); \ + M_F(name, _init) M_R(dest, M_QUEU3_SIZE(src, m_size)); \ + for(size_t i = 0; i < M_QUEU3_SIZE(src, m_size); i++) { \ + M_CALL_SET(oplist, dest->data[i], src->data[i]); \ + } \ + dest->idx_prod = src->idx_prod; \ + dest->idx_cons = src->idx_cons; \ + dest->number = src->number; \ + M_QUEU3_CONTRACT(dest, m_size); \ + } \ + \ + M_P(void, name, _set, queue_t dest, const queue_t src) \ + { \ + M_F(name, _clear) M_R(dest); \ + M_F(name, _init_set) M_R(dest, src); \ + } \ + \ + M_INLINE bool \ + M_F(name, _empty_p)(const queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + return v->number == 0; \ + } \ + \ + M_INLINE bool \ + M_F(name, _full_p)(const queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + return v->number == M_QUEU3_SIZE(v, m_size); \ + } \ + \ + M_INLINE size_t \ + M_F(name, _size)(const queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + return v->number; \ + } \ + \ + M_P(bool, name, _push, queue_t v, type const data) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + M_ASSERT_POOL(); \ + if (M_F(name, _full_p)(v)) \ + return false; \ + \ + unsigned idx = v->idx_prod; \ + M_CALL_SET(oplist, v->data[idx], data); \ + idx++; \ + M_IF(stack_mode)(, idx = (idx == M_QUEU3_SIZE(v, m_size)) ? 0 : idx); \ + v->idx_prod = idx; \ + \ + v->number++; \ + \ + M_QUEU3_CONTRACT(v,m_size); \ + return true; \ + } \ + \ + M_P(bool, name, _pop, type *data, queue_t v) \ + { \ + M_QUEU3_CONTRACT(v,m_size); \ + M_ASSERT (data != NULL); \ + M_ASSERT_POOL(); \ + if (M_F(name, _empty_p)(v)) \ + return false; \ + \ + /* POP data from the queue and update INDEX */ \ + M_IF(stack_mode)( \ + /* STACK queue */ \ + v->idx_prod --; \ + M_CALL_SET(oplist, *data, v->data[v->idx_prod]); \ + , \ + /* FIFO queue */ \ + M_CALL_SET(oplist, *data, v->data[v->idx_cons]); \ + v->idx_cons = (v->idx_cons == M_QUEU3_SIZE(v, m_size)-1) ? 0 : (v->idx_cons + 1); \ + ) \ + v->number--; \ + \ + M_QUEU3_CONTRACT(v,m_size); \ + return true; \ + } \ + \ + M_INLINE size_t \ + M_F(name, _capacity)(const queue_t v) \ + { \ + (void) v; /* may be unused */ \ + return M_QUEU3_SIZE(v, m_size); \ + } \ + + +#if M_USE_SMALL_NAME +#define QUEUE_DEF M_QUEUE_DEF +#define QUEUE_DEF_AS M_QUEUE_DEF_AS +#define STACK_DEF M_STACK_DEF +#define STACK_DEF_AS M_STACK_DEF_AS +#define QUEUE_OPLIST M_QUEUE_OPLIST +#endif + +#endif diff --git a/tests/test-mqueue.c b/tests/test-mqueue.c new file mode 100644 index 00000000..8e3c75ba --- /dev/null +++ b/tests/test-mqueue.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2017-2025, Patrick Pelissier + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "test-obj.h" +#include "m-queue.h" +#include "coverage.h" + +START_COVERAGE +STACK_DEF(stack_obj, testobj_t, 0, TESTOBJ_OPLIST) +END_COVERAGE + +M_QUEUE_DEF(queue_obj, testobj_t, 10, TESTOBJ_OPLIST) +M_STACK_DEF(stack, int, 15) +QUEUE_DEF(buffer_llong, long long, 0) + +static void test_obj(void) +{ + stack_obj_t b1, b2; + testobj_t o; + bool b; + + testobj_init(o); + stack_obj_init(b1, 24); + assert( stack_obj_empty_p(b1) == true); + assert( stack_obj_full_p(b1) == false); + assert( stack_obj_size(b1) == 0); + assert( stack_obj_capacity(b1) == 24); + + stack_obj_reset(b1); + assert( stack_obj_empty_p(b1) == true); + assert( stack_obj_full_p(b1) == false); + assert( stack_obj_size(b1) == 0); + + for(unsigned i = 0; i < 24; i++) { + testobj_set_ui(o, i); + assert( stack_obj_full_p(b1) == false); + b = stack_obj_push(b1, o); + assert(b); + assert( stack_obj_empty_p(b1) == false); + assert( stack_obj_size(b1) == i+1); + } + + assert( stack_obj_full_p(b1) == true); + assert( stack_obj_size(b1) == 24); + b = stack_obj_push(b1, o); + assert(!b); + assert( stack_obj_size(b1) == 24); + + for(unsigned i = 23; i < 24; i--) { + testobj_set_ui(o, i); + assert( stack_obj_empty_p(b1) == false); + b = stack_obj_pop(&o, b1); + assert(b); + assert( stack_obj_full_p(b1) == false); + assert( stack_obj_size(b1) == i); + assert( testobj_cmp_ui(o, i) == 0); + } + + assert( stack_obj_empty_p(b1) == true); + assert( stack_obj_size(b1) == 0); + b = stack_obj_pop(&o, b1); + assert(!b); + assert( stack_obj_size(b1) == 0); + + for(unsigned i = 0; i < 24; i++) { + testobj_set_ui(o, i); + assert( stack_obj_full_p(b1) == false); + b = stack_obj_push(b1, o); + assert(b); + assert( stack_obj_empty_p(b1) == false); + assert( stack_obj_size(b1) == i+1); + } + + stack_obj_init_set(b2, b1); + stack_obj_reset(b1); + assert( stack_obj_empty_p(b1) == true); + assert( stack_obj_size(b1) == 0); + b = stack_obj_pop(&o, b1); + assert(!b); + assert( stack_obj_size(b1) == 0); + + assert( stack_obj_full_p(b2) == true); + assert( stack_obj_size(b2) == 24); + b = stack_obj_push(b2, o); + assert(!b); + assert( stack_obj_size(b2) == 24); + + stack_obj_set(b1, b2); + assert( stack_obj_size(b1) == 24); + + stack_obj_clear(b1); + stack_obj_clear(b2); + testobj_clear(o); +} + +static void test_queue_llong(void) +{ + buffer_llong_t buff; + bool b; + long long c; + buffer_llong_init(buff, 16); + assert (buffer_llong_empty_p(buff) == true); + for(int i = 0; i < 16; i++) { + assert (buffer_llong_full_p(buff) == false); + c = i; + b = buffer_llong_push(buff, c); + assert (b == true); + assert (buffer_llong_empty_p(buff) == false); + } + assert (buffer_llong_full_p(buff) == true); + b = buffer_llong_push(buff, c); + assert (b == false); + for(int i = 0; i < 16; i++) { + assert (buffer_llong_empty_p(buff) == false); + buffer_llong_pop(&c, buff); + assert(c == i); + assert (buffer_llong_full_p(buff) == false); + } + assert (buffer_llong_empty_p(buff) == true); + b = buffer_llong_pop(&c, buff); + assert (b == false); + + b = buffer_llong_push(buff, c); + assert (b == true); + assert (buffer_llong_empty_p(buff) == false); + buffer_llong_reset(buff); + assert (buffer_llong_empty_p(buff) == true); + + buffer_llong_clear(buff); +} + +static void test_emplace(void) +{ + stack_obj_t b; + stack_obj_init(b, 32); + stack_obj_emplace_str(b, "56"); + testobj_t o; + testobj_init(o); + stack_obj_pop(&o, b); + assert( testobj_cmp_ui(o, 56) == 0 ); + testobj_clear(o); + stack_obj_clear(b); +} + +int main(void) +{ + test_obj(); + test_queue_llong(); + test_emplace(); + testobj_final_check(); + exit(0); +} From decec8f7aeca0ceee012ae2567c54cdf0139ba5a Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 6 Apr 2025 00:35:55 +0200 Subject: [PATCH 41/91] Fix for tcc --- m-buffer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/m-buffer.h b/m-buffer.h index cdcdb779..9bbebde7 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -342,9 +342,9 @@ M_N(void, name, _init, buffer_t v, size_t size) \ \ dest->idx_prod = v->idx_prod; \ dest->idx_cons = v->idx_cons; \ - atomic_store_explicit (&dest->number[0], v->number[0], memory_order_relaxed); \ + atomic_store_explicit (&dest->number[0], atomic_load_explicit(&v->number[0], memory_order_relaxed), memory_order_relaxed); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - atomic_store_explicit(&dest->number[1], v->number[1], memory_order_relaxed); \ + atomic_store_explicit(&dest->number[1], atomic_load_explicit(&v->number[1], memory_order_relaxed), memory_order_relaxed); \ \ m_mutex_unlock(v->mutexPop); \ m_mutex_unlock(v->mutexPush); \ @@ -396,9 +396,9 @@ M_N(void, name, _init, buffer_t v, size_t size) \ \ dest->idx_prod = v->idx_prod; \ dest->idx_cons = v->idx_cons; \ - atomic_store_explicit(&dest->number[0], v->number[0], memory_order_relaxed); \ + atomic_store_explicit(&dest->number[0], atomic_load_explicit(&v->number[0], memory_order_relaxed), memory_order_relaxed); \ if (M_BUFF3R_POLICY_P(policy, M_BUFFER_DEFERRED_POP)) \ - atomic_store_explicit(&dest->number[1], v->number[1], memory_order_relaxed); \ + atomic_store_explicit(&dest->number[1], atomic_load_explicit(&v->number[1], memory_order_relaxed), memory_order_relaxed); \ \ m_cond_broadcast(v->there_is_room_for_data); \ m_cond_broadcast(v->there_is_data); \ From 98b3bbd7a15d7623f786d673437ec8c62695debf Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 6 Apr 2025 01:00:16 +0200 Subject: [PATCH 42/91] Fix for MACOS --- tests/test-mqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-mqueue.c b/tests/test-mqueue.c index 8e3c75ba..9e702863 100644 --- a/tests/test-mqueue.c +++ b/tests/test-mqueue.c @@ -29,7 +29,7 @@ STACK_DEF(stack_obj, testobj_t, 0, TESTOBJ_OPLIST) END_COVERAGE M_QUEUE_DEF(queue_obj, testobj_t, 10, TESTOBJ_OPLIST) -M_STACK_DEF(stack, int, 15) +M_STACK_DEF(stack_int, int, 15) QUEUE_DEF(buffer_llong, long long, 0) static void test_obj(void) From daadf693f78d48b0ec55e848a0e2428cddb347e7 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 6 Apr 2025 12:23:16 +0200 Subject: [PATCH 43/91] Update doc --- README.md | 176 +++++++++++++++++++++++++++++++++++++++++++--------- doc/API.txt | 4 +- 2 files changed, 148 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index f3ed1cdf..f362b178 100644 --- a/README.md +++ b/README.md @@ -14,27 +14,27 @@ M\*LIB: Generic type-safe Container Library for C language 11. [API Documentation](#api-documentation) 1. [Generic methods](#generic-methods) 2. [List](#m-list) - 3. [Array](#m-array) - 4. [Deque](#m-deque) + 3. [Intrusive list](#m-i-list) + 4. [Array](#m-array) 5. [Dictionary](#m-dict) - 6. [Tuple](#m-tuple) - 7. [Variant](#m-variant) - 8. [Red/Black Tree](#m-rbtree) - 9. [B+ Tree](#m-bptree) - 10. [Generic Tree](#m-tree) - 11. [Priority queue](#m-prioqueue) - 12. [Fixed buffer queue](#m-buffer) - 13. [Atomic Shared Register](#m-snapshot) - 14. [Shared pointers](#m-shared-ptr) - 15. [Intrusive Shared Pointers](#m-i-shared) - 16. [Intrusive list](#m-i-list) - 17. [Concurrent adapter](#m-concurrent) - 18. [Bitset](#m-bitset) - 19. [String](#m-string) - 20. [Core preprocessing](#m-core) - 21. [Thread](#m-thread) - 22. [Worker threads](#m-worker) - 23. [Atomic](#m-atomic) + 6. [Red/Black Tree](#m-rbtree) + 7. [B+ Tree](#m-bptree) + 8. [Generic Tree](#m-tree) + 9. [Tuple](#m-tuple) + 10. [Variant](#m-variant) + 11. [Double end queue](#m-deque) + 12. [Priority queue](#m-prioqueue) + 13. [Fixed size queue / stack](#m-queue) + 14. [Shared Fixed size queue](#m-buffer) + 15. [Atomic Shared Register](#m-snapshot) + 16. [Shared pointers](#m-shared-ptr) + 17. [Intrusive Shared Pointers](#m-i-shared) + 18. [Concurrent adapter](#m-concurrent) + 19. [Bitset](#m-bitset) + 20. [String](#m-string) + 21. [Byte String](#m-bstring) + 22. [Core preprocessing](#m-core) + 23. [Worker threads](#m-worker) 24. [Generic algorithms](#m-algo) 25. [Function objects](#m-funcobj) 26. [Exception handling](#m-try) @@ -42,7 +42,8 @@ M\*LIB: Generic type-safe Container Library for C language 28. [JSON Serialization](#m-serial-json) 29. [Binary Serialization](#m-serial-bin) 30. [Generic interface](#m-generic) - 31. [Byte String](#m-bstring) + 31. [Thread](#m-thread) + 32. [Atomic](#m-atomic) 12. [Global User Customization](#global-user-customization) 13. [License](#license) @@ -149,17 +150,18 @@ The following headers define containers that don't require the user structure to * [m-array.h](#m-array): header for creating dynamic array of generic type, * [m-list.h](#m-list): header for creating singly-linked list of generic type, * [m-deque.h](#m-deque): header for creating dynamic double-ended queue of generic type, +* [m-queue.h](#m-queue): header for creating static queue or stack of generic type, +* [m-prioqueue.h](#m-prioqueue): header for creating dynamic priority queue of generic type. * [m-dict.h](#m-dict): header for creating unordered associative array (through hashmap) or unordered set of generic type, * [m-rbtree.h](#m-rbtree): header for creating ordered set (through Red/Black binary sorted tree) of generic type, * [m-bptree.h](#m-bptree): header for creating ordered map/set/multimap/multiset (through sorted B+TREE) of generic type, * [m-tree.h](#m-tree): header for creating arbitrary tree of generic type, * [m-tuple.h](#m-tuple): header for creating arbitrary tuple of generic types, * [m-variant.h](#m-variant): header for creating arbitrary variant of generic type, -* [m-prioqueue.h](#m-prioqueue): header for creating dynamic priority queue of generic type. The available containers of M\*LIB for thread synchronization are in the following headers: -* [m-buffer.h](#m-buffer): header for creating fixed-size queue (or stack) of generic type (multiple producer / multiple consumer), +* [m-buffer.h](#m-buffer): header for creating fixed-size queue (or stack) of generic type (multiple producer / multiple consumer) used for transferring data from a thread to another, * [m-snapshot](#m-snapshot): header for creating 'atomic buffer' (through triple buffer) for sharing synchronously big data (thread safe), * [m-shared-ptr.h](#m-shared-ptr): header for creating shared pointer of generic type, @@ -3791,11 +3793,124 @@ to `new_val` (increase or decrease priority). This method has a complexity of `O(n)` (due to linear search of the data). This method is defined only if the `EQUAL` method is defined. +_________________ + +### M-QUEUE + +This header implements a fixed circular queue or stack. + +A [circular buffer](https://en.wikipedia.org/wiki/Circular_buffer) +(or ring buffer or circular queue) is a data structure using a single, bounded buffer +as if its head was connected to its tail. + +#### QUEUE_DEF(name, type, size, [, oplist]) +#### QUEUE_DEF_AS(name, name_t, type, size, [, oplist]) + +Define the circular queue `name_t` and its associated methods as `static inline` functions. +This queue is not thread-safe (See m-buffer header for a thread safe variant). +The order of the elements in the container is FIFO (First In, First Out). + +`name` shall be a C identifier that will be used to identify the queue. +It will be used to create all the types (including the iterator) +and functions to handle the container. +This definition shall be done once per name and per compilation unit. + +The `size` parameter defined the fixed size of the queue. +It can be 0. In this case, the fixed size is defined at initialization time only +and the needed objects to handle the queue are allocated at initialization time too. +Otherwise the needed objects are embedded within the structure, preventing +any other allocations. + +The size of the queue shall be lower or equal than the maximum of the type `unsigned int`. + +The oplist shall have at least the following operators (`INIT_SET`, `SET` and `CLEAR`), +otherwise it won't generate compilable code. + +`QUEUE_DEF_AS` is the same as `QUEUE_DEF` except the name of the type `name_t` is provided. + +Example: + +```C +QUEUE_DEF(queue_uint, unsigned int, 10) + +queue_uint_t g_buff; + +void f(unsigned int i) { + queue_uint_init(g_buff, 10); + queue_uint_push(g_buff, i); + queue_uint_pop(&i, g_buff); + queue_uint_clear(g_buff); +} +``` + +#### STACK_DEF(name, type, size, [, oplist]) +#### STACK_DEF_AS(name, name_t, type, size, [, oplist]) + +Define the fixed size stack `name_t` and its associated methods as `static inline` functions. +This stack is not thread-safe (See m-buffer header for a thread safe variant). +The order of the elements in the container is FILO (First In, Last Out). + +`name` shall be a C identifier that will be used to identify the stack. +It will be used to create all the types (including the iterator) +and functions to handle the container. +This definition shall be done once per name and per compilation unit. + +The `size` parameter defined the fixed size of the stack. +It can be 0. In this case, the fixed size is defined at initialization time only +and the needed objects to handle the stack are allocated at initialization time too. +Otherwise the needed objects are embedded within the structure, preventing +any other allocations. + +The size of the stack shall be lower or equal than the maximum of the type `unsigned int`. + +The oplist shall have at least the following operators (`INIT_SET`, `SET` and `CLEAR`), +otherwise it won't generate compilable code. + +`STACK_DEF_AS` is the same as `STACK_DEF` except the name of the type `name_t` is provided. + + +#### Created types + +The following types are automatically defined by the previous definition macro if not provided by the user: + +##### `name_t` + +Type of the circular queue (or stack). + +#### Generic methods + +The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): + +```C +void name_clear(queue_t queue) +void name_reset(queue_t queue) +bool name_empty_p(const queue_t queue) +size_t name_size(const queue_t queue) +size_t name_capacity(const queue_t queue) +void name_push(queue_t queue, const type data) +void name_pop(type *data, queue_t queue) +``` + +#### Specialized methods + +The following specialized methods are automatically created by the previous definition macro: + +##### `void name_init(queue_t queue, size_t size)` + +Initialize the queue (or stack) `queue` for `size` elements. +The `size` argument shall be the same as the one used to create the container, or the size used to create it was `0` (ie. runtime fixed size). +The size of the queue shall be lower or equal than `UINT_MAX`. + +##### `bool name_full_p(const queue_t queue)` + +Return true if the queue (or stack) is full, false otherwise. + + _________________ ### M-BUFFER -This header implements different kind of fixed circular buffer. +This header implements different kind of fixed circular buffer used for threading purpose. A [circular buffer](https://en.wikipedia.org/wiki/Circular_buffer) (or ring buffer or circular queue) is a data structure using a single, bounded buffer @@ -3808,7 +3923,7 @@ Define the buffer `name_t` and its associated methods as `static inline` functio A buffer is a fixed circular queue implementing a queue (or stack) interface. It can be used to transfer message from multiple producer threads to multiple consumer threads. This is done internally using a mutex and conditional waits -(if it is built with the `BUFFER_THREAD_SAFE` option — default) +See m-queue for a non thread safe variant. `name` shall be a C identifier that will be used to identify the buffer. It will be used to create all the types (including the iterator) @@ -3821,21 +3936,18 @@ and the needed objects to handle the buffer are allocated at initialization time Otherwise the needed objects are embedded within the structure, preventing any other allocations. -The size of the buffer shall be lower or equal than the maximum of the type `int`. +The size of the buffer shall be lower or equal than the maximum of the type `unsigned int`. Multiple additional policy can be applied to the buffer by performing a logical or of the following properties: * `BUFFER_QUEUE` — define a FIFO queue (default), * `BUFFER_STACK` — define a stack (exclusive with `BUFFER_QUEUE`), -* `BUFFER_THREAD_SAFE` — define thread safe functions (default), -* `BUFFER_THREAD_UNSAFE` — define thread unsafe functions (exclusive with `BUFFER_THREAD_SAFE`), * `BUFFER_PUSH_INIT_POP_MOVE` — change the behavior of `PUSH` to push a new initialized object, and `POP` as moving this new object into the new emplacement (this is mostly used for performance reasons or to handle properly a shared_ptr semantic). In practice, it works as if `POP` performs the initialization of the object. * `BUFFER_PUSH_OVERWRITE` — `PUSH` overwrites the last entry if the queue is full instead of blocking, * `BUFFER_DEFERRED_POP` — do not consider the object to be fully popped from the buffer by calling the pop method until the call to `pop_deferred` ; this enables to handle object that are in-progress of being consumed by the thread. This container is designed to be used for synchronization inter-threads of data -(and the buffer variable should be a global shared one). A function tagged "thread safe" -is thread safe only if the container has been generated with the `THREAD_SAFE` option. +(and the buffer variable should be a global shared one). The oplist shall have at least the following operators (`INIT_SET`, `SET` and `CLEAR`), otherwise it won't generate compilable code. @@ -3942,6 +4054,7 @@ the object being popped is considered fully release (freeing a space in the queue). Otherwise it does nothing. + #### `QUEUE_MPMC_DEF(name, type, policy[, oplist])` #### `QUEUE_MPMC_DEF_AS(name, name_t, type, policy[, oplist])` @@ -9057,6 +9170,9 @@ _________________ ### M-MEMPOOL +> [!NOTE] +> This header is obsolete: `M_USE_POOL` should be used instead to pass custom memory context to containers. + This header is for generating specialized and optimized memory pools: it will generate specialized functions to allocate and free only one kind of an object. The mempool functions are not specially thread safe for a given mempool, diff --git a/doc/API.txt b/doc/API.txt index 5cea1ec0..8b061196 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -94,6 +94,6 @@ V0.8.0 : * REALLOC / FREE operators are incompatible: This allows more and efficient integration into custom allocators. * M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated. - * m-buffer: non-thread safe queue & stack are moved into their dedicated header (m-queue) + * m-buffer: non-thread safe queue & stack are moved into their dedicated header (m-queue) BUFFER_THREAD_UNSAFE is no longer supported. * m-buffer: Remove buffer blocking policy and thread safe (_push / _pop returns now void) - + * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_POOL interface to pass local pool context. From 505e2c4a62de9a5d2873ee0a8c754462c78b9d4c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 6 Apr 2025 23:01:49 +0200 Subject: [PATCH 44/91] Fix spelling --- m-atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m-atomic.h b/m-atomic.h index eb66c777..332dc3a7 100644 --- a/m-atomic.h +++ b/m-atomic.h @@ -146,7 +146,7 @@ using std::memory_order_seq_cst; #endif /* Non working C++ atomic header, nor working stdatomic.h found. - Write a compatible layer using mutex as slin as possible. + Write a compatible layer using mutex as slim as possible. Supports only up to 64-bits atomic (sizeof long long to be more precise). The locks are never properly cleared and remain active until the end of the program. From 03cceafd736584b5b954bd5a969acfb4bf460fb6 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 6 Apr 2025 23:04:33 +0200 Subject: [PATCH 45/91] Update --- doc/API.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/API.txt b/doc/API.txt index 8b061196..58cd24d7 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -86,14 +86,16 @@ V0.7.2: * Rename m-mutex.h header in m-thread.h V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated. Use DICT_DEF2 / DICT_DEF2_AS -V0.8.0 : * REALLOC / FREE operators are incompatible: +V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible: Add the old number of elements of the array as argument of REALLOC Add the number of elements of the array and its base type as arguments of FREE. - You need to ignore the new arguments. + (You can ignore the new arguments which are only hints provided to memory functions). Also impact M_MEMORY_REALLOC & M_MEMORY_FREE This allows more and efficient integration into custom allocators. * M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated. * m-buffer: non-thread safe queue & stack are moved into their dedicated header (m-queue) BUFFER_THREAD_UNSAFE is no longer supported. * m-buffer: Remove buffer blocking policy and thread safe (_push / _pop returns now void) + * m-buffer push / pop no longer return a bool (it was undocumented) + * Remove MEMPOOL support from list & R/B tree * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_POOL interface to pass local pool context. From c2cfb2f0a095b960739570ecec04ba1c9155fbaa Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 6 Apr 2025 23:11:28 +0200 Subject: [PATCH 46/91] Cleanup & support of M_USE_GLOBAL_POOL --- m-core.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/m-core.h b/m-core.h index 51eba8bf..83ad9f8e 100644 --- a/m-core.h +++ b/m-core.h @@ -412,19 +412,22 @@ M_BEGIN_PROTECTED_CODE #endif -// FIXME: Rename to M_USE_MEMORY_CONTEXT? /* In order to support context for memory functions, the prototypes and usages of some functions are modified - * so that they accept a first argument 'm_pool' which is the memory context parameter. + * so that they can accept a first argument 'm_pool' which is the memory context parameter. * For some functions, there is no meaning of a local memory context parameter: for all data shared between threads, * only a global memory context has any meaning. For such cases, the memory context parameter is not requested to * the used but set to 0. - * several macros are defined **globally**. Theses macros expand to nothing if memory context is not requested. + * This is controlled through M_USE_POOL parameter that define the type of the memory context parameter. + * + * Several macros are defined **globally** to support such features. + * They expand to nothing if the memory context parameter is not requested. * * M_P_EXPAND: expand to the first parameter 'm_pool' of type M_USE_POOL for a function that may use memory context. - * * M_P_EXPAND_void: same but assume that there is no argument - * * M_R_EXPAND: expand to the first parameter 'm_pool' + * * M_P_EXPAND_void: same but assume that there is no argument in the initial funciton. + * * M_R_EXPAND: expand to the first parameter 'm_pool' (followed by a comma) * * M_R_EXPAND_void: same but assume that there is no argument * * M_R: add the parameter m_pool to the function call if needed, * * M_P: define the prototype of a function that may have the parameter m_pool. + * * M_N: define the prototype of a function that don't need the parameter m_pool. * * M_ASSERT_POOL: avoid warning of unused m_pool argument * * M_GLOBAL_POOL: define m_pool to zero, meaning it is a global memory context. */ @@ -438,6 +441,10 @@ M_BEGIN_PROTECTED_CODE # define M_ASSERT_POOL() # define M_GLOBAL_POOL() #else +// Default global value is to set to 0 the global pool. +#ifndef M_USE_GLOBAL_POOL +#define M_USE_GLOBAL_POOL(x) M_USE_POOL x = { 0 } +#endif // Memory pool parameter is used for function using memory. (local definition to the function). // Expand to a prototype to a function that may not trigger exception # define M_P_EXPAND M_USE_POOL m_pool, @@ -446,7 +453,7 @@ M_BEGIN_PROTECTED_CODE # define M_R_EXPAND_void m_pool # define M_R(...) (m_pool, __VA_ARGS__) # define M_ASSERT_POOL() (void) m_pool -# define M_GLOBAL_POOL() M_USE_POOL m_pool = { 0 }; (void) m_pool +# define M_GLOBAL_POOL() M_USE_GLOBAL_POOL(m_pool); (void) m_pool #endif // M_P: Expand to a prototype of a function that may trigger exception / accept memory context @@ -462,7 +469,7 @@ M_BEGIN_PROTECTED_CODE #endif // TODO: 'pool' seems not the right term. Rename 'pool' into 'localmem' ? 'arena'? memcontext? context? -// TODO: M_USE_GLOBAL_POOL , value for setting the global pool. +// Rename to M_USE_MEMORY_CONTEXT? M_USE_MEMCONTEXT /************************************************************/ /********************* ERROR handling **********************/ From 77195fb1d09712792b0ba16b6e9e037014861c81 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 13 Apr 2025 15:45:47 +0200 Subject: [PATCH 47/91] Remove m-mutex header --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fe1ab31a..4232cdfa 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ PACKAGE=m_lib-$(VERSION) VERSION=0.8.0 # Define the contain of the distribution tarball -HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-mutex.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h m-queue.h +HEADER=m-algo.h m-array.h m-atomic.h m-bitset.h m-bptree.h m-buffer.h m-c-mempool.h m-concurrent.h m-core.h m-deque.h m-dict.h m-funcobj.h m-generic.h m-genint.h m-i-list.h m-i-shared.h m-list.h m-mempool.h m-thread.h m-prioqueue.h m-rbtree.h m-serial-bin.h m-serial-json.h m-shared.h m-snapshot.h m-string.h m-tree.h m-try.h m-tuple.h m-variant.h m-worker.h m-bstring.h m-shared-ptr.h m-queue.h DOC1=LICENSE README.md DOC2=doc/API.txt doc/Container.html doc/Container.ods doc/depend.png doc/DEV.md doc/ISSUES.org doc/oplist.odp doc/oplist.png doc/bench-array-log.png doc/bench-array.png doc/bench-list-log.png doc/bench-list.png doc/bench-oset-log.png doc/bench-oset.png doc/bench-umap-log.png doc/bench-umap.png doc/cc.sh EXAMPLE=example/ex11-algo01.c example/ex11-algo02.c example/ex11-json01.c example/ex11-section.c example/ex-algo02.c example/ex-algo03.c example/ex-algo04.c example/ex-array00.c example/ex-array01.c example/ex-array02.c example/ex-array03.c example/ex-array04.c example/ex-array05.c example/ex-bptree01.c example/ex-buffer01.c example/ex-dict01.c example/ex-dict02.c example/ex-dict03.c example/ex-dict04.c example/ex-grep01.c example/ex-list01.c example/ex-mph.c example/ex-multi01.c example/ex11-multi02.c example/ex-multi03.c example/ex-multi04.c example/ex-multi05.c example/ex-rbtree01.c example/ex11-algo02.json example/ex11-json01.json example/Makefile example/ex-defer01.c example/ex-string01.c example/ex-string02.c example/ex-astar.c example/ex-string03.c example/ex11-tstc.c example/ex-no-stdio.c example/ex11-count-lines.c example/ex11-json-net.c example/ex11-rbtree02.c example/ex-curl.c example/ex-dict05.c example/ex-dict06.c example/exm-lib.c example/exm-main.c example/exn-lib.c example/exn-main.c example/exm-header.h example/exn-header.h example/ex-alloc1.c example/ex-alloc2.c example/ex-try01.c example/ex11-generic01.c example/ex-bptree02.c example/ex-i-list.c example/ex11-generic02.c example/ex11-small-name.c example/ex11-variant01.c From 256ff916a2987a8d27c85ed07bfbe98393b04412 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 13 Apr 2025 15:46:14 +0200 Subject: [PATCH 48/91] Port serial to new memory format --- example/ex11-use-pool.c | 3 + m-array.h | 9 +-- m-bptree.h | 17 ++--- m-bstring.h | 13 ++-- m-core.h | 93 ++++++++++++----------- m-deque.h | 9 +-- m-dict.h | 17 ++--- m-list.h | 11 ++- m-prioqueue.h | 5 +- m-rbtree.h | 9 +-- m-serial-bin.h | 58 +++++++-------- m-serial-json.h | 159 ++++++++++++++++++---------------------- m-shared-ptr.h | 11 +-- m-string.h | 26 +++---- m-tuple.h | 9 +-- m-variant.h | 9 +-- 16 files changed, 218 insertions(+), 240 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 785ad189..023ebdd4 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -155,6 +155,9 @@ M_SHARED_PTR_DEF(shared_str, string_t) M_QUEUE_DEF(queue_10, int, 10 ) M_STACK_DEF(stack_20, string_t, 20) +#include "m-serial-json.h" + +#include "m-serial-bin.h" int main(void) { diff --git a/m-array.h b/m-array.h index 1c057382..5a89fd7a 100644 --- a/m-array.h +++ b/m-array.h @@ -1050,22 +1050,21 @@ , /* no IN_STR & INIT */ ) \ \ M_IF_METHOD(OUT_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, const array_t array) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const array_t array) \ { \ M_ARRA4_CONTRACT(array); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_return_code_t ret; \ m_serial_local_t local; \ - ret = f->m_interface->write_array_start(local, f, array->size); \ + ret = f->m_interface->write_array_start M_R(local, f, array->size); \ for (size_t i = 0; i < array->size; i++) { \ type const *item = M_F(name, _cget)(array, i); \ if (i != 0) { \ - ret |= f->m_interface->write_array_next(local, f); \ + ret |= f->m_interface->write_array_next M_R(local, f); \ } \ ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ } \ - ret |= f->m_interface->write_array_end(local, f); \ + ret |= f->m_interface->write_array_end M_R(local, f); \ return ret & M_SERIAL_FAIL; \ } \ , /* no OUT_SERIAL */ ) \ diff --git a/m-bptree.h b/m-bptree.h index 68c6449f..b1dcf01b 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -1383,8 +1383,7 @@ , /* no in_str */ ) \ \ M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, tree_t const t1) \ { \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ @@ -1396,31 +1395,31 @@ /* Format is different between associative container \ & set container */ \ M_IF(isMap)( \ - ret = f->m_interface->write_map_start(local, f, t1->size); \ + ret = f->m_interface->write_map_start M_R(local, f, t1->size); \ for (M_F(name, _it)(it, t1) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_map_next(local, f); \ + ret |= f->m_interface->write_map_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item->key_ptr); \ - ret |= f->m_interface->write_map_value(local, f); \ + ret |= f->m_interface->write_map_value M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(value_oplist, f, *item->value_ptr); \ first_done = true; \ } \ - ret |= f->m_interface->write_map_end(local, f); \ + ret |= f->m_interface->write_map_end M_R(local, f); \ , \ - ret = f->m_interface->write_array_start(local, f, t1->size); \ + ret = f->m_interface->write_array_start M_R(local, f, t1->size); \ for (M_F(name, _it)(it, t1) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ + ret |= f->m_interface->write_array_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \ first_done = true; \ } \ - ret |= f->m_interface->write_array_end(local, f); \ + ret |= f->m_interface->write_array_end M_R(local, f); \ ) \ return ret & M_SERIAL_FAIL; \ } \ diff --git a/m-bstring.h b/m-bstring.h index fe984b06..85ff86b0 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -480,8 +480,7 @@ M_P(bool, m_bstring, _fread, m_bstring_t v, FILE *f, size_t num) and output it in the given serializer See serialization for return code. */ -M_INLINE m_serial_return_code_t -m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v) +M_P(m_serial_return_code_t, m_bstring, _out_serial, m_serial_write_t serial, const m_bstring_t v) { M_ASSERT (serial != NULL && serial->m_interface != NULL); M_BSTRING_CONTRACT (v); @@ -489,15 +488,15 @@ m_bstring_out_serial(m_serial_write_t serial, const m_bstring_t v) m_serial_return_code_t ret; size_t size = m_bstring_size(v); uint8_t *ptr = m_bstr1ng_cstr(v); - ret = serial->m_interface->write_array_start(local, serial, size); + ret = serial->m_interface->write_array_start M_R(local, serial, size); if (size > 0) { - ret |= serial->m_interface->write_integer(serial, ptr[0], 1); + ret |= serial->m_interface->write_integer M_R(serial, ptr[0], 1); for(size_t i = 1; i < size; i++) { - ret |= serial->m_interface->write_array_next(local, serial); - ret |= serial->m_interface->write_integer(serial, ptr[i], 1); + ret |= serial->m_interface->write_array_next M_R(local, serial); + ret |= serial->m_interface->write_integer M_R(serial, ptr[i], 1); } } - ret |= serial->m_interface->write_array_end(local, serial); + ret |= serial->m_interface->write_array_end M_R(local, serial); return ret; } diff --git a/m-core.h b/m-core.h index 83ad9f8e..625af87f 100644 --- a/m-core.h +++ b/m-core.h @@ -412,17 +412,20 @@ M_BEGIN_PROTECTED_CODE #endif -/* In order to support context for memory functions, the prototypes and usages of some functions are modified +/* In order to support local context for memory functions, the prototypes and usages of some functions are modified * so that they can accept a first argument 'm_pool' which is the memory context parameter. - * For some functions, there is no meaning of a local memory context parameter: for all data shared between threads, - * only a global memory context has any meaning. For such cases, the memory context parameter is not requested to - * the used but set to 0. - * This is controlled through M_USE_POOL parameter that define the type of the memory context parameter. * - * Several macros are defined **globally** to support such features. - * They expand to nothing if the memory context parameter is not requested. + * For some functions, there is no meaning of a local memory context parameter: + * for all data shared between threads, only a global memory context has any meaning. + * For such cases, the memory context parameter is globally requested to the user through M_USE_GLOBAL_POOL or set to 0. + * + * This is controlled through M_USE_POOL parameter that define the type of the memory context parameter + * to be used globally for all M*LIB. There is no possibility to support only some containers and not others. + * + * Several macros are defined **globally** to support such features and being internally used by M*LIB containers. + * They expand to nothing if the memory context parameter is not requested: * * M_P_EXPAND: expand to the first parameter 'm_pool' of type M_USE_POOL for a function that may use memory context. - * * M_P_EXPAND_void: same but assume that there is no argument in the initial funciton. + * * M_P_EXPAND_void: same but assume that there is no argument in the initial function. * * M_R_EXPAND: expand to the first parameter 'm_pool' (followed by a comma) * * M_R_EXPAND_void: same but assume that there is no argument * * M_R: add the parameter m_pool to the function call if needed, @@ -458,7 +461,8 @@ M_BEGIN_PROTECTED_CODE // M_P: Expand to a prototype of a function that may trigger exception / accept memory context // M_N: Expand to a prototype of a function that may not trigger exception or accept memory context -// If not M_F, no overloaded M_INLINE and no M_P_EXPAND, simplify M_P +// If not user M_F, no overloaded M_INLINE and no M_P_EXPAND, +// simplify definition of M_P/M_N to provide faster compile time. // (faster build: 0.54s instead of 0.80s in extreme expanding) #if !defined(M_USE_POOL) && !defined(M_F) && !defined(M_USE_FINE_GRAINED_LINKAGE) && !defined(M_USE_DEF) && !defined(M_USE_DECL) # define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) @@ -5201,6 +5205,7 @@ m_core_parse2_enum (const char str[], const char **endptr) * each time it is called with a pseudo random wait. * It is used to avoid too many threads trying to grab some atomic * variables at the same times (it makes the threads waits randomly). + * Initialization is cheap. */ typedef struct m_core_backoff_s { unsigned int count; // Number of times it has been run @@ -5274,7 +5279,7 @@ struct m_string_s; * - OK & done (object is fully parsed), * - OK & continue parsing (object is partially parsed) * - Fail parsing - * - Fail parsing with given arguments (give explicit size) + * - Fail parsing with given arguments (give explicit size) but a retry will succeed. */ typedef enum m_serial_return_code_e { M_SERIAL_OK_DONE = 0, M_SERIAL_OK_CONTINUE = 1, M_SERIAL_FAIL = 2, M_SERIAL_FAIL_RETRY = 4 @@ -5354,7 +5359,7 @@ typedef struct m_serial_read_interface_s { m_serial_return_code_t (*read_boolean)(m_serial_read_t,bool *); m_serial_return_code_t (*read_integer)(m_serial_read_t, long long *, const size_t size_of_type); m_serial_return_code_t (*read_float)(m_serial_read_t, long double *, const size_t size_of_type); - m_serial_return_code_t (*read_string)(m_serial_read_t, struct m_string_s *); + m_serial_return_code_t (*read_string)(M_P_EXPAND m_serial_read_t, struct m_string_s *); m_serial_return_code_t (*read_array_start)(m_serial_local_t, m_serial_read_t, size_t *); m_serial_return_code_t (*read_array_next)(m_serial_local_t, m_serial_read_t); m_serial_return_code_t (*read_map_start)(m_serial_local_t, m_serial_read_t, size_t *); @@ -5384,22 +5389,22 @@ typedef struct m_serial_write_s { * All function pointers shall be not null. */ typedef struct m_serial_write_interface_s { - m_serial_return_code_t (*write_boolean)(m_serial_write_t,const bool data); - m_serial_return_code_t (*write_integer)(m_serial_write_t,const long long data, const size_t size_of_type); - m_serial_return_code_t (*write_float)(m_serial_write_t, const long double data, const size_t size_of_type); - m_serial_return_code_t (*write_string)(m_serial_write_t,const char data[], size_t len); - m_serial_return_code_t (*write_array_start)(m_serial_local_t, m_serial_write_t, const size_t number_of_elements); - m_serial_return_code_t (*write_array_next)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_array_end)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_map_start)(m_serial_local_t, m_serial_write_t, const size_t number_of_elements); - m_serial_return_code_t (*write_map_value)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_map_next)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_map_end)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_tuple_start)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_tuple_id)(m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index); - m_serial_return_code_t (*write_tuple_end)(m_serial_local_t, m_serial_write_t); - m_serial_return_code_t (*write_variant_start)(m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index); - m_serial_return_code_t (*write_variant_end)(m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_boolean)(M_P_EXPAND m_serial_write_t,const bool data); + m_serial_return_code_t (*write_integer)(M_P_EXPAND m_serial_write_t,const long long data, const size_t size_of_type); + m_serial_return_code_t (*write_float)(M_P_EXPAND m_serial_write_t, const long double data, const size_t size_of_type); + m_serial_return_code_t (*write_string)(M_P_EXPAND m_serial_write_t,const char data[], size_t len); + m_serial_return_code_t (*write_array_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const size_t number_of_elements); + m_serial_return_code_t (*write_array_next)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_array_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_map_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const size_t number_of_elements); + m_serial_return_code_t (*write_map_value)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_map_next)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_map_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_tuple_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_tuple_id)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index); + m_serial_return_code_t (*write_tuple_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t); + m_serial_return_code_t (*write_variant_start)(M_P_EXPAND m_serial_local_t, m_serial_write_t, const char * const field_name[], const int max, const int index); + m_serial_return_code_t (*write_variant_end)(M_P_EXPAND m_serial_local_t, m_serial_write_t); } m_serial_write_interface_t; @@ -5409,23 +5414,23 @@ typedef struct m_serial_write_interface_s { */ #define M_OUT_SERIAL_DEFAULT_ARG(serial, x) \ _Generic(((void)0,(x)), \ - bool: (serial)->m_interface->write_boolean(serial, M_AS_TYPE(bool, (x))), \ - char: (serial)->m_interface->write_integer(serial, M_AS_TYPE(char,(x)), sizeof (x)), \ - signed char: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed char,(x)), sizeof (x)), \ - unsigned char: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned char,(x)), sizeof (x)), \ - signed short: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed short,(x)), sizeof (x)), \ - unsigned short: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned short,(x)), sizeof (x)), \ - signed int: (serial)->m_interface->write_integer(serial, M_AS_TYPE(signed int,(x)), sizeof (x)), \ - unsigned int: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned int,(x)), sizeof (x)), \ - long int: (serial)->m_interface->write_integer(serial, M_AS_TYPE(long,(x)), sizeof (x)), \ - unsigned long int: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned long,(x)), sizeof (x)), \ - long long int: (serial)->m_interface->write_integer(serial, M_AS_TYPE(long long,(x)), sizeof (x)), \ - unsigned long long int: (serial)->m_interface->write_integer(serial, (long long) M_AS_TYPE(unsigned long long,(x)), sizeof (x)), \ - float: (serial)->m_interface->write_float(serial, M_AS_TYPE(float,(x)), sizeof (x)), \ - double: (serial)->m_interface->write_float(serial, M_AS_TYPE(double,(x)), sizeof (x)), \ - long double: (serial)->m_interface->write_float(serial, M_AS_TYPE(long double,(x)), sizeof (x)), \ - const char *: (serial)->m_interface->write_string(serial, M_AS_TYPE(const char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \ - char *: (serial)->m_interface->write_string(serial, M_AS_TYPE(char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \ + bool: (serial)->m_interface->write_boolean M_R(serial, M_AS_TYPE(bool, (x))), \ + char: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(char,(x)), sizeof (x)), \ + signed char: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(signed char,(x)), sizeof (x)), \ + unsigned char: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned char,(x)), sizeof (x)), \ + signed short: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(signed short,(x)), sizeof (x)), \ + unsigned short: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned short,(x)), sizeof (x)), \ + signed int: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(signed int,(x)), sizeof (x)), \ + unsigned int: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned int,(x)), sizeof (x)), \ + long int: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(long,(x)), sizeof (x)), \ + unsigned long int: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned long,(x)), sizeof (x)), \ + long long int: (serial)->m_interface->write_integer M_R(serial, M_AS_TYPE(long long,(x)), sizeof (x)), \ + unsigned long long int: (serial)->m_interface->write_integer M_R(serial, (long long) M_AS_TYPE(unsigned long long,(x)), sizeof (x)), \ + float: (serial)->m_interface->write_float M_R(serial, M_AS_TYPE(float,(x)), sizeof (x)), \ + double: (serial)->m_interface->write_float M_R(serial, M_AS_TYPE(double,(x)), sizeof (x)), \ + long double: (serial)->m_interface->write_float M_R(serial, M_AS_TYPE(long double,(x)), sizeof (x)), \ + const char *: (serial)->m_interface->write_string M_R(serial, M_AS_TYPE(const char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \ + char *: (serial)->m_interface->write_string M_R(serial, M_AS_TYPE(char *,(x)), m_core_out_serial_strlen(M_AS_TYPE(const char *,(x))) ), \ const void *: M_SERIAL_FAIL /* unsupported */, \ void *: M_SERIAL_FAIL /* unsupported */) diff --git a/m-deque.h b/m-deque.h index c33dd12f..f45cb254 100644 --- a/m-deque.h +++ b/m-deque.h @@ -974,26 +974,25 @@ , /* no IN_STR */ ) \ \ M_IF_METHOD(OUT_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, const deque_t deque) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const deque_t deque) \ { \ M_D3QU3_CONTRACT(deque); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ m_serial_return_code_t ret; \ bool first_done = false; \ - ret = f->m_interface->write_array_start(local, f, deque->count); \ + ret = f->m_interface->write_array_start M_R(local, f, deque->count); \ M_F(name, _it_ct) it; \ for (M_F(name, _it)(it, deque) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ type const *item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ + ret |= f->m_interface->write_array_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ first_done = true; \ } \ - ret |= f->m_interface->write_array_end(local, f); \ + ret |= f->m_interface->write_array_end M_R(local, f); \ return ret & M_SERIAL_FAIL; \ } \ , /* no OUT_SERIAL */ ) \ diff --git a/m-dict.h b/m-dict.h index 93db9be8..811690d7 100644 --- a/m-dict.h +++ b/m-dict.h @@ -1119,8 +1119,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) , /* no IN_STR */ ) \ \ M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, dict_t const t1) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, dict_t const t1) \ { \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_local_t local; \ @@ -1131,31 +1130,31 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* Format is different between associative container \ & set container */ \ M_IF(isSet)( \ - ret = f->m_interface->write_array_start(local, f, M_F(name, _size)(t1)); \ + ret = f->m_interface->write_array_start M_R(local, f, M_F(name, _size)(t1)); \ for (M_F(name, _it)(it, t1) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ + ret |= f->m_interface->write_array_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(key_oplist, f, *item); \ first_done = true; \ } \ - ret |= f->m_interface->write_array_end(local, f); \ + ret |= f->m_interface->write_array_end M_R(local, f); \ , \ - ret = f->m_interface->write_map_start(local, f, M_F(name, _size)(t1)); \ + ret = f->m_interface->write_map_start M_R(local, f, M_F(name, _size)(t1)); \ for (M_F(name, _it)(it, t1) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_map_next(local, f); \ + ret |= f->m_interface->write_map_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(key_oplist, f, item->key); \ - ret |= f->m_interface->write_map_value(local, f); \ + ret |= f->m_interface->write_map_value M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(value_oplist, f, item->value); \ first_done = true; \ } \ - ret |= f->m_interface->write_map_end(local, f); \ + ret |= f->m_interface->write_map_end M_R(local, f); \ ) \ return ret & M_SERIAL_FAIL; \ } \ diff --git a/m-list.h b/m-list.h index d082905d..1542d141 100644 --- a/m-list.h +++ b/m-list.h @@ -748,18 +748,17 @@ , /* no IN_STR & INIT */ ) \ \ M_IF_METHOD(OUT_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, const list_t list) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const list_t list) \ { \ M_ASSERT (list != NULL); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ m_serial_return_code_t ret; \ m_serial_local_t local; \ bool first_done = false; \ - ret = f->m_interface->write_array_start(local, f, (size_t)-1); \ + ret = f->m_interface->write_array_start M_R(local, f, (size_t)-1); \ if (ret == M_SERIAL_FAIL_RETRY) { \ size_t n = M_F(name, _size)(list); \ - ret = f->m_interface->write_array_start(local, f, n); \ + ret = f->m_interface->write_array_start M_R(local, f, n); \ } \ it_t it; \ for (M_F(name, _it)(it, list) ; \ @@ -767,11 +766,11 @@ M_F(name, _next)(it)){ \ type const *item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ + ret |= f->m_interface->write_array_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ first_done = true; \ } \ - ret |= f->m_interface->write_array_end(local, f); \ + ret |= f->m_interface->write_array_end M_R(local, f); \ return ret & M_SERIAL_FAIL; \ } \ , /* no OUT_SERIAL */ ) \ diff --git a/m-prioqueue.h b/m-prioqueue.h index 6366e185..a238ec44 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -478,10 +478,9 @@ ,/* No PARSE_STR */) \ \ M_IF_METHOD(OUT_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, const prioqueue_t p) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, const prioqueue_t p) \ { \ - return M_F(name, _array_out_serial)(f, p->array); \ + return M_F(name, _array_out_serial) M_R(f, p->array); \ } \ ,/* No OUT_SERIAL */) \ \ diff --git a/m-rbtree.h b/m-rbtree.h index aca9f769..57459a33 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -1075,8 +1075,7 @@ typedef enum { , /* no in_str */ ) \ \ M_IF_METHOD(OUT_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, tree_t const t1) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, tree_t const t1) \ { \ M_RBTR33_CONTRACT(t1); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ @@ -1085,17 +1084,17 @@ typedef enum { M_F(name, _subtype_ct) const *item; \ bool first_done = false; \ it_t it; \ - ret = f->m_interface->write_array_start(local, f, t1->size); \ + ret = f->m_interface->write_array_start M_R(local, f, t1->size); \ for (M_F(name, _it)(it, t1) ; \ !M_F(name, _end_p)(it); \ M_F(name, _next)(it)){ \ item = M_F(name, _cref)(it); \ if (first_done) \ - ret |= f->m_interface->write_array_next(local, f); \ + ret |= f->m_interface->write_array_next M_R(local, f); \ ret |= M_CALL_OUT_SERIAL(oplist, f, *item); \ first_done = true; \ } \ - ret |= f->m_interface->write_array_end(local, f); \ + ret |= f->m_interface->write_array_end M_R(local, f); \ return ret & M_SERIAL_FAIL; \ } \ , /* no OUT_SERIAL */ ) \ diff --git a/m-serial-bin.h b/m-serial-bin.h index a61c3a18..ad8b242d 100644 --- a/m-serial-bin.h +++ b/m-serial-bin.h @@ -111,9 +111,9 @@ m_ser1al_bin_read_size(FILE *f, size_t *size) /* Write the boolean 'data' into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_boolean, m_serial_write_t serial, const bool data) { + M_ASSERT_POOL(); FILE *f = (FILE *)serial->data[0].p; size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f); return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail(); @@ -121,9 +121,9 @@ m_ser1al_bin_write_boolean(m_serial_write_t serial, const bool data) /* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_integer, m_serial_write_t serial,const long long data, const size_t size_of_type) { + M_ASSERT_POOL(); size_t n; FILE *f = (FILE *)serial->data[0].p; @@ -146,9 +146,9 @@ m_ser1al_bin_write_integer(m_serial_write_t serial,const long long data, const s /* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type) { + M_ASSERT_POOL(); size_t n; FILE *f = (FILE *)serial->data[0].p; @@ -168,9 +168,9 @@ m_ser1al_bin_write_float(m_serial_write_t serial, const long double data, const /* Write the null-terminated string 'data'into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t length) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_string, m_serial_write_t serial, const char data[], size_t length) { + M_ASSERT_POOL(); M_ASSERT_SLOW(length == strlen(data) ); FILE *f = (FILE *)serial->data[0].p; M_ASSERT(f != NULL && data != NULL); @@ -188,9 +188,9 @@ m_ser1al_bin_write_string(m_serial_write_t serial, const char data[], size_t len Initialize 'local' so that it can be used to serialize the array (local is an unique serialization object of the array). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { + M_ASSERT_POOL(); (void) local; //Unused if (number_of_elements == (size_t)-1) return M_SERIAL_FAIL_RETRY; FILE *f = (FILE *)serial->data[0].p; @@ -200,9 +200,9 @@ m_ser1al_bin_write_array_start(m_serial_local_t local, m_serial_write_t serial, /* Write an array separator between elements of an array into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_next, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // Unused (void) serial; // Unused return M_SERIAL_OK_CONTINUE; @@ -210,9 +210,9 @@ m_ser1al_bin_write_array_next(m_serial_local_t local, m_serial_write_t serial) /* End the writing of an array into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // Unused (void) serial; // Unused return M_SERIAL_OK_CONTINUE; @@ -220,9 +220,9 @@ m_ser1al_bin_write_array_end(m_serial_local_t local, m_serial_write_t serial) /* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_map_value, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_CONTINUE; @@ -232,9 +232,9 @@ m_ser1al_bin_write_map_value(m_serial_local_t local, m_serial_write_t serial) Initialize 'local' so that it can serial the tuple (local is an unique serialization object of the tuple). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_CONTINUE; @@ -242,9 +242,9 @@ m_ser1al_bin_write_tuple_start(m_serial_local_t local, m_serial_write_t serial) /* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { + M_ASSERT_POOL(); (void) local; // argument not used (void) serial; (void) field_name; @@ -255,9 +255,9 @@ m_ser1al_bin_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, con /* End the write of a tuple into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_DONE; @@ -268,9 +268,9 @@ m_ser1al_bin_write_tuple_end(m_serial_local_t local, m_serial_write_t serial) Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise Otherwise, the field 'field_name[index]' will be filled. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { + M_ASSERT_POOL(); (void) field_name; (void) max; (void) local; @@ -281,9 +281,9 @@ m_ser1al_bin_write_variant_start(m_serial_local_t local, m_serial_write_t serial /* End Writing a variant into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_write_variant_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_DONE; @@ -399,15 +399,15 @@ m_ser1al_bin_read_float(m_serial_read_t serial, long double *r, const size_t siz /* Read from the stream 'serial' a string. Set 's' with the string if succeeds Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_bin_read_string(m_serial_read_t serial, struct m_string_s *s){ +M_P(m_serial_return_code_t, m_ser1al_bin, _read_string, m_serial_read_t serial, struct m_string_s *s) +{ FILE *f = (FILE*) serial->data[0].p; M_ASSERT(f != NULL && s != NULL); // First read the number of non null characters size_t length; if (m_ser1al_bin_read_size(f, &length) != true) return m_core_serial_fail(); // Use of internal string interface to dimension the string - char *p = m_str1ng_fit2size(s, length + 1); + char *p = m_str1ng_fit2size M_R(s, length + 1); m_str1ng_set_size(s, length); // Read the characters excluding the final null one. // NOTE: fread supports length == 0. diff --git a/m-serial-json.h b/m-serial-json.h index dc15ea38..557b9e82 100644 --- a/m-serial-json.h +++ b/m-serial-json.h @@ -36,9 +36,9 @@ M_BEGIN_PROTECTED_CODE /* Write the boolean 'data' into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_boolean(m_serial_write_t serial, const bool data) +M_P(m_serial_return_code_t, m_ser1al_json, _write_boolean, m_serial_write_t serial, const bool data) { + M_ASSERT_POOL(); FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "%s", data ? "true" : "false"); return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail(); @@ -46,9 +46,9 @@ m_ser1al_json_write_boolean(m_serial_write_t serial, const bool data) /* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type) +M_P(m_serial_return_code_t, m_ser1al_json, _write_integer, m_serial_write_t serial,const long long data, const size_t size_of_type) { + M_ASSERT_POOL(); (void) size_of_type; // Ignored FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "%lld", data); @@ -57,9 +57,9 @@ m_ser1al_json_write_integer(m_serial_write_t serial,const long long data, const /* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type) +M_P(m_serial_return_code_t, m_ser1al_json, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type) { + M_ASSERT_POOL(); (void) size_of_type; // Ignored FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "%Lf", data); @@ -68,9 +68,9 @@ m_ser1al_json_write_float(m_serial_write_t serial, const long double data, const /* Write the null-terminated string 'data'into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t length) +M_P(m_serial_return_code_t, m_ser1al_json, _write_string, m_serial_write_t serial, const char data[], size_t length) { + M_ASSERT_POOL(); M_ASSERT(length == (m_str1ng_size_t) length); M_ASSERT_SLOW(length == strlen(data) ); FILE *f = (FILE *)serial->data[0].p; @@ -92,9 +92,9 @@ m_ser1al_json_write_string(m_serial_write_t serial, const char data[], size_t le Initialize 'local' so that it can be used to serialize the array (local is an unique serialization object of the array). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) +M_P(m_serial_return_code_t, m_ser1al_json, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { + M_ASSERT_POOL(); (void) local; // argument not used (void) number_of_elements; // Ignored FILE *f = (FILE *)serial->data[0].p; @@ -104,9 +104,9 @@ m_ser1al_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, /* Write an array separator between elements of an array into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_array_next(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_array_next, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, ","); @@ -115,9 +115,9 @@ m_ser1al_json_write_array_next(m_serial_local_t local, m_serial_write_t serial) /* End the writing of an array into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_array_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_array_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "]"); @@ -130,9 +130,9 @@ m_ser1al_json_write_array_end(m_serial_local_t local, m_serial_write_t serial) Initialize 'local' so that it can be used to serialize the map (local is an unique serialization object of the map). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) +M_P(m_serial_return_code_t, m_ser1al_json, _write_map_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { + M_ASSERT_POOL(); (void) local; // argument not used (void) number_of_elements; // Ignored FILE *f = (FILE *)serial->data[0].p; @@ -142,9 +142,9 @@ m_ser1al_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, c /* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_map_value(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_map_value, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, ":"); @@ -153,9 +153,9 @@ m_ser1al_json_write_map_value(m_serial_local_t local, m_serial_write_t serial) /* Write a map separator between elements of a map into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_map_next(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_map_next, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, ","); @@ -164,9 +164,9 @@ m_ser1al_json_write_map_next(m_serial_local_t local, m_serial_write_t serial) /* End the writing of a map into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_map_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_map_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "}"); @@ -177,9 +177,9 @@ m_ser1al_json_write_map_end(m_serial_local_t local, m_serial_write_t serial) Initialize 'local' so that it can serial the tuple (local is an unique serialization object of the tuple). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "{"); @@ -188,9 +188,9 @@ m_ser1al_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial) /* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) +M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { + M_ASSERT_POOL(); (void) local; // argument not used (void) max; // Ignored FILE *f = (FILE *)serial->data[0].p; @@ -200,9 +200,9 @@ m_ser1al_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, co /* End the write of a tuple into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "}"); @@ -214,9 +214,9 @@ m_ser1al_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial) Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise Otherwise, the field 'field_name[index]' will be filled. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) +M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { + M_ASSERT_POOL(); (void) local; // argument not used (void) max; // argument not used FILE *f = (FILE *)serial->data[0].p; @@ -233,9 +233,9 @@ m_ser1al_json_write_variant_start(m_serial_local_t local, m_serial_write_t seria /* End Writing a variant into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_end, m_serial_local_t local, m_serial_write_t serial) { + M_ASSERT_POOL(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "}"); @@ -344,12 +344,12 @@ m_ser1al_json_read_float(m_serial_read_t serial, long double *r, const size_t si /* Read from the stream 'serial' a string. Set 's' with the string if succeeds Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_json_read_string(m_serial_read_t serial, struct m_string_s *s){ +M_P(m_serial_return_code_t, m_ser1al_json, _read_string, m_serial_read_t serial, struct m_string_s *s) +{ FILE *f = (FILE*) serial->data[0].p; int n = m_core_fscanf(f, " "); // Skip any leading spaces. (void) n; // Unused return value. - return m_string_in_str(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail(); + return m_string_in_str M_R(s, f) ? M_SERIAL_OK_DONE : m_core_serial_fail(); } /* Start reading from the stream 'serial' an array. @@ -587,40 +587,37 @@ typedef m_serial_read_t m_serial_json_read_t; /* Write the boolean 'data' into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_boolean(m_serial_write_t serial, const bool data) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_boolean, m_serial_write_t serial, const bool data) { struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - int n = m_string_cat_printf(f, "%s", data ? "true" : "false"); +//TODO: Simplify code. + int n = m_string_cat_printf M_R(f, "%s", data ? "true" : "false"); return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail(); } /* Write the integer 'data' of 'size_of_type' bytes into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_integer(m_serial_write_t serial,const long long data, const size_t size_of_type) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_integer, m_serial_write_t serial, const long long data, const size_t size_of_type) { (void) size_of_type; // Ignored struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - int n = m_string_cat_printf(f, "%lld", data); + int n = m_string_cat_printf M_R(f, "%lld", data); return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail(); } /* Write the float 'data' of 'size_of_type' bytes into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_float(m_serial_write_t serial, const long double data, const size_t size_of_type) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type) { (void) size_of_type; // Ignored struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - int n = m_string_cat_printf(f, "%Lf", data); + int n = m_string_cat_printf M_R(f, "%Lf", data); return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail(); } /* Write the null-terminated string 'data'into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_t length) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_string, m_serial_write_t serial, const char data[], size_t length) { M_ASSERT(length == (m_str1ng_size_t) length); M_ASSERT_SLOW(length == strlen(data) ); @@ -633,7 +630,7 @@ m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_ v2->u.heap.alloc[sizeof(m_str1ng_size_t)-2] = 1; v2->u.heap.alloc[sizeof(m_str1ng_size_t)-1] = 31; v2->u.heap.ptr = (char*)ptr; - m_string_get_str(f, v2, true); + m_string_get_str M_R(f, v2, true); return M_SERIAL_OK_DONE; } @@ -643,35 +640,32 @@ m_ser1al_str_json_write_string(m_serial_write_t serial, const char data[], size_ Initialize 'local' so that it can be used to serialize the array (local is an unique serialization object of the array). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_array_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { (void) local; // argument not used (void) number_of_elements; // Ignored struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, '['); + m_string_push_back M_R(f, '['); return M_SERIAL_OK_CONTINUE; } /* Write an array separator between elements of an array into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_array_next(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_array_next, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, ','); + m_string_push_back M_R(f, ','); return M_SERIAL_OK_CONTINUE; } /* End the writing of an array into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_array_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_array_end, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, ']'); + m_string_push_back M_R(f, ']'); return M_SERIAL_OK_CONTINUE; } @@ -681,46 +675,42 @@ m_ser1al_str_json_write_array_end(m_serial_local_t local, m_serial_write_t seria Initialize 'local' so that it can be used to serialize the map (local is an unique serialization object of the map). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_map_start(m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { (void) local; // argument not used (void) number_of_elements; // Ignored struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, '{'); + m_string_push_back M_R(f, '{'); return M_SERIAL_OK_CONTINUE; } /* Write a value separator between element of the same pair of a map into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_map_value(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_value, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, ':'); + m_string_push_back M_R(f, ':'); return M_SERIAL_OK_CONTINUE; } /* Write a map separator between elements of a map into the serial stream 'serial' if needed. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_map_next(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_next, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, ','); + m_string_push_back M_R(f, ','); return M_SERIAL_OK_CONTINUE; } /* End the writing of a map into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_map_end, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, '}'); + m_string_push_back M_R(f, '}'); return M_SERIAL_OK_CONTINUE; } @@ -728,35 +718,32 @@ m_ser1al_str_json_write_map_end(m_serial_local_t local, m_serial_write_t serial) Initialize 'local' so that it can serial the tuple (local is an unique serialization object of the tuple). Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_tuple_start(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, '{'); + m_string_push_back M_R(f, '{'); return M_SERIAL_OK_CONTINUE; } /* Start writing the field named field_name[index] of a tuple into the serial stream 'serial'. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_tuple_id(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { (void) local; // argument not used (void) max; // Ignored struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - int n = m_string_cat_printf(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]); + int n = m_string_cat_printf M_R(f, "%c\"%s\":", index == 0 ? ' ' : ',', field_name[index]); return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail(); } /* End the write of a tuple into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, '}'); + m_string_push_back M_R(f, '}'); return M_SERIAL_OK_CONTINUE; } @@ -765,8 +752,7 @@ m_ser1al_str_json_write_tuple_end(m_serial_local_t local, m_serial_write_t seria Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise Otherwise, the field 'field_name[index]' will be filled. Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { (void) local; // argument not used (void) max; // argument not used @@ -774,22 +760,21 @@ m_ser1al_str_json_write_variant_start(m_serial_local_t local, m_serial_write_t s int n; if (index >= 0) { M_ASSERT (index < max); - n = m_string_cat_printf(f, "{\"%s\":", field_name[index]); + n = m_string_cat_printf M_R(f, "{\"%s\":", field_name[index]); return n > 0 ? M_SERIAL_OK_CONTINUE : m_core_serial_fail(); } else { - n = m_string_cat_printf(f, "{}"); + n = m_string_cat_printf M_R(f, "{}"); return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail(); } } /* End Writing a variant into the serial stream 'serial'. Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_write_variant_end(m_serial_local_t local, m_serial_write_t serial) +M_P(m_serial_return_code_t, m_ser1al_str_json, _write_variant_end, m_serial_local_t local, m_serial_write_t serial) { (void) local; // argument not used struct m_string_s *f = (struct m_string_s *)serial->data[0].p; - m_string_push_back(f, '}'); + m_string_push_back M_R(f, '}'); return M_SERIAL_OK_CONTINUE; } @@ -933,12 +918,12 @@ m_ser1al_str_json_read_float(m_serial_read_t serial, long double *r, const size_ /* Read from the stream 'serial' a string. Set 's' with the string if succeeds Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ -M_INLINE m_serial_return_code_t -m_ser1al_str_json_read_string(m_serial_read_t serial, struct m_string_s *s){ +M_P(m_serial_return_code_t, m_ser1al_str_json, _read_string, m_serial_read_t serial, struct m_string_s *s) +{ const char **f = &serial->data[0].cstr; m_ser1al_str_json_skip(f); const char *e; - bool b = m_string_parse_str(s, *f, &e); + bool b = m_string_parse_str M_R(s, *f, &e); serial->data[0].cstr = e; return b ? M_SERIAL_OK_DONE : m_core_serial_fail(); } diff --git a/m-shared-ptr.h b/m-shared-ptr.h index 064e1e23..ff80a35c 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -1308,8 +1308,8 @@ M_IF_METHOD(OUT_STR, oplist)( extern void M_F(name, _out_str)(FILE *, const shar M_IF_METHOD(IN_STR, oplist)( extern bool M_F(name, _in_str)(shared_t *, FILE *); , ) \ M_IF_METHOD(GET_STR, oplist)( extern void M_F(name, _get_str)(m_string_t, const shared_t *, bool); , ) \ M_IF_METHOD(PARSE_STR, oplist)( extern bool M_F(name, _parse_str)(shared_t *, const char *, const char **); , ) \ -M_IF_METHOD(OUT_SERIAL, oplist)( extern m_serial_return_code_t M_F(name, _out_serial)(m_serial_write_t, const shared_t *); , ) \ -M_IF_METHOD(IN_SERIAL, oplist)( extern m_serial_return_code_t M_F(name, _in_serial)(shared_t *, m_serial_read_t); , ) \ +M_IF_METHOD(OUT_SERIAL, oplist)( extern m_serial_return_code_t M_F(M_P_EXPAND name, _out_serial)(m_serial_write_t, const shared_t *); , ) \ +M_IF_METHOD(IN_SERIAL, oplist)( extern m_serial_return_code_t M_F(M_P_EXPAND name, _in_serial)(shared_t *, m_serial_read_t); , ) \ #define M_SHAR3D_PTR_DEF_IO(name, shared_t, type, oplist, fattr) \ M_IF_METHOD(OUT_STR, oplist)( \ @@ -1364,12 +1364,13 @@ M_IF_METHOD(PARSE_STR, oplist)( \ } \ , ) \ M_IF_METHOD(OUT_SERIAL, oplist)( \ - fattr m_serial_return_code_t M_F(name, _out_serial)(m_serial_write_t serial, const shared_t *out) \ + fattr m_serial_return_code_t M_F(name, _out_serial)(M_P_EXPAND m_serial_write_t serial, const shared_t *out) \ { \ M_ASSERT (out != NULL); \ M_F(name, _read_lock)(out); \ - /* FIXME: No exception. Really? */ \ - m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, serial, out->data); \ + m_volatile m_serial_return_code_t r = M_SERIAL_FAIL; \ + M_ON_EXCEPTION( M_F(name, _read_unlock)(out) ) \ + r = M_CALL_OUT_SERIAL(oplist, serial, out->data); \ M_F(name, _read_unlock)(out); \ return r; \ } \ diff --git a/m-string.h b/m-string.h index fefef8b7..7ff065d8 100644 --- a/m-string.h +++ b/m-string.h @@ -1187,7 +1187,6 @@ M_P(int, m_string, _cat_vprintf, m_string_t v, const char format[], va_list args } /* Append to the string the formatted string of the given printf format */ -//FIXME: M_P(int, m_string, _cat_printf, m_string_t v, const char format[], ...) { M_STR1NG_CONTRACT (v); @@ -1633,23 +1632,20 @@ M_P(bool, m_string, _parse_str, m_string_t v, const char str[], const char **end and output it in the given serializer See serialization for return code. */ -M_INLINE m_serial_return_code_t -m_string_out_serial(m_serial_write_t serial, const m_string_t v) +M_P(m_serial_return_code_t, m_string, _out_serial, m_serial_write_t serial, const m_string_t v) { - //FIXME: What to do for memory context? Can be passed through serial M_ASSERT (serial != NULL && serial->m_interface != NULL); - return serial->m_interface->write_string(serial, m_string_get_cstr(v), m_string_size(v) ); + return serial->m_interface->write_string M_R(serial, m_string_get_cstr(v), m_string_size(v) ); } /* Read the formatted string from the serializer and set the converted value in the string 'v'. See serialization for return code. */ -M_INLINE m_serial_return_code_t -m_string_in_serial(m_string_t v, m_serial_read_t serial) +M_P(m_serial_return_code_t, m_string, _in_serial, m_string_t v, m_serial_read_t serial) { M_ASSERT (serial != NULL && serial->m_interface != NULL); - return serial->m_interface->read_string(serial, v); + return serial->m_interface->read_string M_R(serial, v); } /* UTF8 character classification: @@ -2178,7 +2174,7 @@ namespace m_lib { CMP(m_string_cmp), TYPE(m_string_t), GENTYPE(struct m_string_s*), \ PARSE_STR(API_0P(m_string_parse_str)), GET_STR(API_0P(m_string_get_str)), \ OUT_STR(m_string_out_str), IN_STR(API_0P(m_string_in_str)), \ - OUT_SERIAL(m_string_out_serial), IN_SERIAL(m_string_in_serial), \ + OUT_SERIAL(API_0P(m_string_out_serial)), IN_SERIAL(API_0P(m_string_in_serial)), \ EXT_ALGO(M_STR1NG_SPLIT), \ OOR_EQUAL(m_string_oor_equal_p), OOR_SET(m_string_oor_set) \ ,SUBTYPE(m_string_unicode_t) \ @@ -2695,25 +2691,23 @@ namespace m_lib { return ret; \ } \ \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t serial, const bounded_t v) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t serial, const bounded_t v) \ { \ M_BOUNDED_STR1NG_CONTRACT(v, max_size); \ M_ASSERT (serial != NULL && serial->m_interface != NULL); \ - return serial->m_interface->write_string(serial, v->s, strlen(v->s) ); \ + return serial->m_interface->write_string M_R(serial, v->s, strlen(v->s) ); \ } \ \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(bounded_t v, m_serial_read_t serial) \ + M_P(m_serial_return_code_t, name, _in_serial, bounded_t v, m_serial_read_t serial) \ { \ M_BOUNDED_STR1NG_CONTRACT(v, max_size); \ M_ASSERT (serial != NULL && serial->m_interface != NULL); \ m_string_t tmp; \ /* TODO: Not optimum */ \ m_string_init(tmp); \ - m_serial_return_code_t r = serial->m_interface->read_string(serial, tmp); \ + m_serial_return_code_t r = serial->m_interface->read_string M_R(serial, tmp); \ m_core_strncpy(v->s, max_size+1, m_string_get_cstr(tmp), max_size); \ - m_string_clear(tmp); \ + m_string_clear M_R(tmp); \ M_BOUNDED_STR1NG_CONTRACT(v, max_size); \ return r; \ } diff --git a/m-tuple.h b/m-tuple.h index f7402ae8..692df1b1 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -563,8 +563,7 @@ namespace m_lib { /* Define a OUT_SERIAL method by calling the OUT_SERIAL methods for all params */ #define M_TUPL3_DEFINE_OUT_SERIAL(name, ...) \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, M_F(name,_ct) const el) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, M_F(name,_ct) const el) \ { \ M_TUPL3_CONTRACT(el); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ @@ -575,15 +574,15 @@ namespace m_lib { int index = 0; \ m_serial_local_t local; \ m_serial_return_code_t ret; \ - ret = f->m_interface->write_tuple_start(local, f); \ + ret = f->m_interface->write_tuple_start M_R(local, f); \ M_MAP(M_TUPL3_DEFINE_OUT_SERIAL_FUNC , __VA_ARGS__) \ M_ASSERT( index == field_max); \ - ret |= f->m_interface->write_tuple_end(local, f); \ + ret |= f->m_interface->write_tuple_end M_R(local, f); \ return ret & M_SERIAL_FAIL; \ } #define M_TUPL3_DEFINE_OUT_SERIAL_FUNC(a) \ - f->m_interface->write_tuple_id(local, f, field_name, field_max, index); \ + f->m_interface->write_tuple_id M_R(local, f, field_name, field_max, index); \ M_TUPL3_CALL_OUT_SERIAL(a, f, el -> M_TUPL3_GET_FIELD a); \ index++; \ diff --git a/m-variant.h b/m-variant.h index 0c08e598..37c20bce 100644 --- a/m-variant.h +++ b/m-variant.h @@ -690,8 +690,7 @@ M_INLINE void \ /* Define the OUT_SERIAL function */ #define M_VAR1ANT_DEFINE_OUT_SERIAL(name, ...) \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, M_F(name,_ct) const el) \ + M_P(m_serial_return_code_t, name, _out_serial, m_serial_write_t f, M_F(name,_ct) const el) \ { \ M_VAR1ANT_CONTRACT(name, el); \ const int field_max = M_NARGS(__VA_ARGS__); \ @@ -702,18 +701,18 @@ M_INLINE void \ m_serial_return_code_t ret; \ switch (el->type) { \ case M_F(name, _EMPTY): \ - return f->m_interface->write_variant_start(local, f, field_name, field_max, -1); \ + return f->m_interface->write_variant_start M_R(local, f, field_name, field_max, -1); \ break; \ M_MAP2(M_VAR1ANT_DEFINE_OUT_SERIAL_FUNC , name, __VA_ARGS__) \ default: M_ASSUME(false); break; \ } \ - ret |= f->m_interface->write_variant_end(local, f); \ + ret |= f->m_interface->write_variant_end M_R(local, f); \ return ret & M_SERIAL_FAIL; \ } #define M_VAR1ANT_DEFINE_OUT_SERIAL_FUNC(name, a) \ case M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value): \ - ret = f->m_interface->write_variant_start(local, f, field_name, field_max, \ + ret = f->m_interface->write_variant_start M_R(local, f, field_name, field_max, \ M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value) -1); \ M_VAR1ANT_CALL_OUT_SERIAL(a, f, el -> value . M_VAR1ANT_GET_FIELD a); \ break; From b275859a3736e1ca0e088ae04db992200218d832 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 13 Apr 2025 16:08:38 +0200 Subject: [PATCH 49/91] Fix issue if BString is empty --- m-bstring.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/m-bstring.h b/m-bstring.h index 85ff86b0..913a30b4 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -453,6 +453,10 @@ m_bstring_fwrite(FILE *f, const m_bstring_t v) { M_BSTRING_CONTRACT (v); M_ASSERT (f != NULL); + if (M_UNLIKELY(m_bstring_size(v) == 0)) { + return 0; + } + M_ASSERT(m_bstr1ng_cstr(v) != NULL); return fwrite(m_bstr1ng_cstr(v), 1, m_bstring_size(v), f); } From cc97aa887f7d8f458b179b7cd07bc85f73bb5a39 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 13 Apr 2025 16:11:46 +0200 Subject: [PATCH 50/91] Fix reference --- tests/test-mgeneric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-mgeneric.c b/tests/test-mgeneric.c index 79abb7bd..ed0e8807 100644 --- a/tests/test-mgeneric.c +++ b/tests/test-mgeneric.c @@ -30,7 +30,7 @@ // Generic is not supported if not C11 // TCC has some issues in the preprocessing. -// See https://lists.nongnu.org/archive/html/tinycc-devel/2025-12/msg00004.html +// See https://lists.nongnu.org/archive/html/tinycc-devel/2023-12/msg00004.html #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__TINYC__) ARRAY_DEF(array_int, int) From ab75397e2124ef01e75f9fa6f7e9c962abebfbd2 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 13 Apr 2025 16:14:55 +0200 Subject: [PATCH 51/91] TCC now supports m-generic --- README.md | 3 --- tests/test-mgeneric.c | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index f362b178..595880d1 100644 --- a/README.md +++ b/README.md @@ -9407,9 +9407,6 @@ If no type is associated to this variable, an error is reported by the compiler. This header needs a C23 compliant compiler or a C11 compiler providing the typeof extension (like GCC, CLANG, MSVC). -> [!NOTE] -> TCC is not supported yet due to some bugs in the compiler. - This provides the same level of flexibility of the C++. However, there is some drawbacks of using this generic interface: * Error messages can be more complex, diff --git a/tests/test-mgeneric.c b/tests/test-mgeneric.c index ed0e8807..3c98aca5 100644 --- a/tests/test-mgeneric.c +++ b/tests/test-mgeneric.c @@ -29,9 +29,7 @@ #include "coverage.h" // Generic is not supported if not C11 -// TCC has some issues in the preprocessing. -// See https://lists.nongnu.org/archive/html/tinycc-devel/2023-12/msg00004.html -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__TINYC__) +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L ARRAY_DEF(array_int, int) #define M_OPL_array_int_t() ARRAY_OPLIST(array_int, M_BASIC_OPLIST) From 0d0747dea9caac7393a4bb173f1bfd5daf8cdd44 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 14 Apr 2025 00:13:40 +0200 Subject: [PATCH 52/91] Update oplists --- m-bitset.h | 7 ++++--- m-bstring.h | 17 +++++++++-------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/m-bitset.h b/m-bitset.h index f9a41e3d..af0c7b3f 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -834,6 +834,7 @@ m_bitset_popcount(const m_bitset_t set) } /* Oplist for a bitset */ +#ifndef M_USE_POOL #define M_BITSET_OPLIST \ (INIT(m_bitset_init) \ ,INIT_SET(m_bitset_init_set) \ @@ -868,9 +869,8 @@ m_bitset_popcount(const m_bitset_t set) ,IN_STR(m_bitset_in_str) \ ,EQUAL(m_bitset_equal_p) \ ) - -/* Oplist for a bitset */ -#define M_BITSET_POOL_OPLIST \ +#else +#define M_BITSET_OPLIST \ (INIT(m_bitset_init) \ ,INIT_SET(API_0P(m_bitset_init_set)) \ ,INIT_WITH(API_1(M_INIT_VAI)) \ @@ -904,6 +904,7 @@ m_bitset_popcount(const m_bitset_t set) ,IN_STR(API_0P(m_bitset_in_str)) \ ,EQUAL(m_bitset_equal_p) \ ) +#endif /* Register the OPLIST as a global one */ #ifdef M_USE_POOL diff --git a/m-bstring.h b/m-bstring.h index 913a30b4..db0f1cf3 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -534,26 +534,27 @@ M_P(m_serial_return_code_t, m_bstring, _in_serial, m_bstring_t v, m_serial_read_ } /* Define the OPLIST of a BYTE STRING */ +#ifndef M_USE_POOL #define M_BSTRING_OPLIST \ (INIT(m_bstring_init),INIT_SET(m_bstring_init_set), SET(m_bstring_set), \ INIT_MOVE(m_bstring_init_move), MOVE(m_bstring_move), \ - SWAP(m_bstring_swap), RESET(m_bstring_reset), \ - EMPTY_P(m_bstring_empty_p), \ + SWAP(m_bstring_swap), RESET(m_bstring_reset), EMPTY_P(m_bstring_empty_p), \ + SUBTYPE(uint8_t), PUSH(m_bstring_push), \ CLEAR(m_bstring_clear), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \ CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \ OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(m_bstring_in_serial), \ ) - -/* Define the OPLIST of a BYTE STRING using POOL */ -#define M_BSTRING_POOL_OPLIST \ +#else +#define M_BSTRING_OPLIST \ (INIT(m_bstring_init),INIT_SET(API_0P(m_bstring_init_set)), SET(API_0P(m_bstring_set)), \ INIT_MOVE(m_bstring_init_move), MOVE(API_0P(m_bstring_move)), \ - SWAP(m_bstring_swap), RESET(m_bstring_reset), \ - EMPTY_P(m_bstring_empty_p), \ + SWAP(m_bstring_swap), RESET(m_bstring_reset), EMPTY_P(m_bstring_empty_p), \ + SUBTYPE(uint8_t), PUSH(API_0P(m_bstring_push)), \ CLEAR(API_0P(m_bstring_clear)), HASH(m_bstring_hash), EQUAL(m_bstring_equal_p), \ CMP(m_bstring_cmp), TYPE(m_bstring_t), GENTYPE(struct m_bstring_s*), \ - OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(API_0P(m_bstring_in_serial=) \ + OUT_SERIAL(API_0P(m_bstring_out_serial)), IN_SERIAL(API_0P(m_bstring_in_serial=) \ ) +#endif /********************************************************************************/ /* */ From fa41f3affd9ed269ddd3954757b4352129470c1d Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 14 Apr 2025 00:17:10 +0200 Subject: [PATCH 53/91] M_INIT_VAI supports API --- m-core.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/m-core.h b/m-core.h index 625af87f..64e8bb76 100644 --- a/m-core.h +++ b/m-core.h @@ -4756,12 +4756,12 @@ m_core_parse2_enum (const char str[], const char **endptr) so it reverses the final order. */ #define M_INIT_VAI(oplist, dest, ...) \ - (void)(M_GET_INIT oplist (dest) , \ - M_MAP2_C(M_INIT_VAI_FUNC, (dest, M_GET_PUSH oplist) , __VA_ARGS__) \ - M_IF_METHOD(REVERSE, oplist)(M_DEFERRED_COMMA M_GET_REVERSE oplist (dest), ) \ + (void)(M_CALL_INIT(oplist, dest) , \ + M_MAP2_C(M_INIT_VAI_FUNC, (dest, oplist) , __VA_ARGS__) \ + M_IF_METHOD(REVERSE, oplist)(M_DEFERRED_COMMA M_CALL_REVERSE(oplist, dest), ) \ ) #define M_INIT_VAI_FUNC(d, a) \ - M_PAIR_2 d (M_PAIR_1 d, a) + M_CALL_PUSH(M_PAIR_2 d, M_PAIR_1 d, a) /* Initialize the container 'dest' as per 'oplist' INIT operator From 3a39ce5a4a389cac9d0dc71ea8079c1c271179d1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Tue, 15 Apr 2025 22:04:42 +0200 Subject: [PATCH 54/91] Reformat --- m-bitset.h | 2 +- m-bstring.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/m-bitset.h b/m-bitset.h index af0c7b3f..dd81ea97 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -870,7 +870,7 @@ m_bitset_popcount(const m_bitset_t set) ,EQUAL(m_bitset_equal_p) \ ) #else -#define M_BITSET_OPLIST \ +#define M_BITSET_OPLIST \ (INIT(m_bitset_init) \ ,INIT_SET(API_0P(m_bitset_init_set)) \ ,INIT_WITH(API_1(M_INIT_VAI)) \ diff --git a/m-bstring.h b/m-bstring.h index db0f1cf3..0e13630a 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -545,7 +545,7 @@ M_P(m_serial_return_code_t, m_bstring, _in_serial, m_bstring_t v, m_serial_read_ OUT_SERIAL(m_bstring_out_serial), IN_SERIAL(m_bstring_in_serial), \ ) #else -#define M_BSTRING_OPLIST \ +#define M_BSTRING_OPLIST \ (INIT(m_bstring_init),INIT_SET(API_0P(m_bstring_init_set)), SET(API_0P(m_bstring_set)), \ INIT_MOVE(m_bstring_init_move), MOVE(API_0P(m_bstring_move)), \ SWAP(m_bstring_swap), RESET(m_bstring_reset), EMPTY_P(m_bstring_empty_p), \ From d5481175382c495aa469f2da37b583fed9b4f9e1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 16 Apr 2025 00:19:05 +0200 Subject: [PATCH 55/91] Make M*LIB stricter for INIT_MOVE operator: * either the default INIT_MOVE operator works ('=') * either an INIT_MOVE method is defined * or it is disabled. As a consequence, fix usage of testobj_t and mpz_t in the repository The emulation layer of INIT_MOVE using INIT_SET+CLEAR is removed: it wasn't working correctly with the local memory context (INIT_MOVE doesn't need any local memory context to work, whereas INIT_SET/CLEAR does) Remove macro M_DO_INIT_MOVE as it is now useless and uses M_CALL_INIT_MOVE. The INIT_MOVE default method no longer sets the old 'src' to '0': it was useless (it doesn't catch any error) and complicates compiler parsing. Fix POD & A1 & CSTR & classic oplists definition (missing INIT_MOVE operators). --- README.md | 25 +++++++---- doc/API.txt | 2 + doc/ISSUES.org | 6 +-- example/ex11-multi02.c | 4 +- m-array.h | 29 +++--------- m-buffer.h | 12 ++--- m-core.h | 99 ++++++++++++++++++----------------------- m-deque.h | 4 +- m-dict.h | 24 +++++----- m-list.h | 10 ++--- m-string.h | 1 + m-tree.h | 10 ++--- tests/test-marray.c | 6 +-- tests/test-mcore.c | 33 +++++--------- tests/test-mdeque.c | 2 +- tests/test-mlist.c | 4 +- tests/test-mtree.c | 5 --- tests/test-obj-except.h | 1 + tests/test-obj.h | 6 ++- 19 files changed, 126 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 595880d1..165aefc3 100644 --- a/README.md +++ b/README.md @@ -356,7 +356,7 @@ Here is another example with a complete type (with proper initialization & clear #include #include #include "m-array.h" -ARRAY_DEF(array_mpz, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear)) ) +ARRAY_DEF(array_mpz, mpz_t, (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT)) ) int main(void) { array_mpz_t array ; /* array_mpz_t has been define above */ array_mpz_init(array); /* All type needs to be initialized */ @@ -401,7 +401,7 @@ We can also write the same example shorter: // Register the oplist of a mpz_t. #define M_OPL_mpz_t() (INIT(mpz_init), INIT_SET(mpz_init_set), \ - SET(mpz_set), CLEAR(mpz_clear)) + SET(mpz_set), CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT)) // Define an instance of an array of mpz_t (both type and function) ARRAY_DEF(array_mpz, mpz_t) // Register the oplist of the created instance of array of mpz_t @@ -786,7 +786,7 @@ void mpz_clear(mpz_t z); // Destructor of the object z A basic oplist will be: ```C -(INIT(mpz_init),SET(mpz_set),INIT_SET(mpz_init_set),CLEAR(mpz_clear),TYPE(mpz_t)) +(INIT(mpz_init),SET(mpz_set),INIT_SET(mpz_init_set),CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT),TYPE(mpz_t)) ``` Much more complete oplist can be built for this type however, enabling much more powerful generation: @@ -803,7 +803,7 @@ Example: ```C #define M_OPL_mpz_t() (INIT(mpz_init),SET(mpz_set), \ - INIT_SET(mpz_init_set),CLEAR(mpz_clear),TYPE(mpz_t)) + INIT_SET(mpz_init_set),CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT),TYPE(mpz_t)) ``` This can simplify a lot `OPLIST` usage and it is recommended. @@ -841,7 +841,7 @@ The API Adaptation to use shall be embedded in the `OPLIST` definition. For example: ```C -(INIT(API_0(mpz_init)), SET(API_0(mpz_set)), INIT_SET(API_0(mpz_init_set)), CLEAR(API_0(mpz_clear))) +(INIT(API_0(mpz_init)), SET(API_0(mpz_set)), INIT_SET(API_0(mpz_init_set)), CLEAR(API_0(mpz_clear)), INIT_MOVE(M_COPY_A1_DEFAULT)) ``` The default adaptation is API_0 (i.e. no adaptation between operator interface and method interface). @@ -1174,6 +1174,11 @@ perl -i -e 's/;/;\n/g' test-file.i cc -std=c99 -c -Wall test-file.i ``` +If you get the error "assignment to expression with array type", it means that the library +tries using the default '=' operator to set an object which is not compatible: +give the right method to the needed operator (usually `INIT_MOVE` or `INIT_SET`) in its oplist +or use the proper oplist of the type. + If there is a warning reported by the compiler in the generated code, then there is definitely an **error** you should fix (except if it reports shadowed variables), in particular cast evolving pointers. @@ -1311,6 +1316,8 @@ and you shall use a typedef as an intermediary named type for such types. The output parameters are listed fist, then the input/output parameters and finally the input parameters. +The oplist shall also provide the `INIT_MOVE` operator if the default instance (aka '=' operator) is not working for this type (for example for array of size 1, in which case the method `M_COPY_A1_DEFAULT` is likely to work), or disable the operator. + This generic interface is specified as follow: ##### `void name_init(name_t container)` @@ -1773,7 +1780,7 @@ Example: #define MPZ_OUT_STR(stream, x) mpz_out_str(stream, 0, x) LIST_DEF(list_mpz, mpz_t, \ (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), \ - CLEAR(mpz_clear), OUT_STR(MPZ_OUT_STR))) + CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT), OUT_STR(MPZ_OUT_STR))) int main(void) { list_mpz_t a; @@ -1973,7 +1980,7 @@ Example: #define MPZ_OUT_STR(stream, x) mpz_out_str(stream, 0, x) LIST_DUAL_PUSH_DEF(list_mpz, mpz_t, \ (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), \ - CLEAR(mpz_clear), OUT_STR(MPZ_OUT_STR))) + CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT), OUT_STR(MPZ_OUT_STR))) int main(void) { list_mpz_t a; @@ -2132,7 +2139,7 @@ Example: #define MPZ_OUT_STR(stream, x) mpz_out_str(stream, 0, x) ARRAY_DEF(array_mpz, mpz_t, \ (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), \ - CLEAR(mpz_clear), OUT_STR(MPZ_OUT_STR))) + CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT), OUT_STR(MPZ_OUT_STR))) int main(void) { array_mpz_t a; @@ -2339,7 +2346,7 @@ Example: #include "m-deque.h" DEQUE_DEF(deque_mpz, mpz_t, \ - (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear))) + (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), INIT_MOVE(M_COPY_A1_DEFAULT))) int main(void) { deque_mpz_t a; diff --git a/doc/API.txt b/doc/API.txt index 58cd24d7..21104174 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -99,3 +99,5 @@ V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible: * m-buffer push / pop no longer return a bool (it was undocumented) * Remove MEMPOOL support from list & R/B tree * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_POOL interface to pass local pool context. + * M*LIB becomes stricter for INIT_MOVE: Emulation layer using CLEAR+INIT_SET when missing INIT_MOVE operator has been removed: either default INIT_MOVE operator (operator '=') is working, or a methode is provided for INIT_MOVE or it is disabled. + (It's because supporting emulation layer with new memory context parameter was complicated) diff --git a/doc/ISSUES.org b/doc/ISSUES.org index 41d12d90..a3c814f9 100644 --- a/doc/ISSUES.org +++ b/doc/ISSUES.org @@ -1,7 +1,7 @@ *Long term issues* ========================================================== -* TODO #34 : Pass old size arguments to memory allocator :ENHANCEMENT: +* DONE #34 : Pass old size arguments to memory allocator :ENHANCEMENT: ** State @@ -53,7 +53,7 @@ function due to the copy of the object one per one. Each copied sub object may throw an exception, so we always need to have the container in a correct state so that it can be cleanup. -* TODO #32 : User specialization fields in the container :ENHANCEMENT: +* DONE #32 : User specialization fields in the container :ENHANCEMENT: ** State Some methods of a contained object may need to have some options that @@ -452,7 +452,7 @@ as DPRIORITY_QUEUE_DEF ? NOTE: Needs for such container? On hold until a user needs it. -* TODO #23 : Strict MOVE semantic to clarify :ENHANCEMENT: +* DONE #23 : Strict MOVE semantic to clarify :ENHANCEMENT: ** State diff --git a/example/ex11-multi02.c b/example/ex11-multi02.c index 07b379cf..a4a1f3a5 100644 --- a/example/ex11-multi02.c +++ b/example/ex11-multi02.c @@ -35,6 +35,7 @@ mpz_fast_hash(const mpz_t z) #define M_OPL_mpz_t() \ (INIT(mpz_init), INIT_SET(mpz_init_set), SET(mpz_set), CLEAR(mpz_clear), \ INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \ + INIT_MOVE(M_COPY_A1_DEFAULT) \ EQUAL( API( mpz_cmp, EQ(0), ARG1, ARG2)), \ CMP(mpz_cmp), \ HASH(mpz_fast_hash), \ @@ -77,7 +78,8 @@ mpfr_fast_hash (const mpfr_t f) /* Define the OPLIST of a mpfr_t and register it globally */ #define M_OPL_mpfr_t() \ (INIT(mpfr_init), INIT_SET(API(mpfr_init_set, VOID, ARG1, ARG2, MPFR_RNDN)), SET(API(mpfr_set, VOID, ARG1, ARG2, MPFR_RNDN)), CLEAR(mpfr_clear), \ - INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \ + INIT_WITH(API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)), \ + INIT_MOVE(M_COPY_A1_DEFAULT) \ EQUAL( API( mpfr_cmp, EQ(0), ARG1, ARG2)), \ CMP(mpfr_cmp), \ HASH(mpfr_fast_hash), \ diff --git a/m-array.h b/m-array.h index 5a89fd7a..671ba378 100644 --- a/m-array.h +++ b/m-array.h @@ -173,7 +173,6 @@ #define M_ARRA4_DEF_P3(name, type, oplist, array_t, it_t) \ M_ARRA4_DEF_TYPE(name, type, oplist, array_t, it_t) \ M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - /* TODO: Check if type has not disabled INIT_MOVE */ \ M_ARRA4_DEF_CORE(name, type, oplist, array_t, it_t) \ M_ARRA4_DEF_IO(name, type, oplist, array_t, it_t) \ M_EMPLACE_QUEUE_DEF(name, array_t, _emplace_back, oplist, M_ARRA4_EMPLACE_DEF) @@ -365,16 +364,14 @@ } \ , /* No INIT */ ) \ \ - M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ M_P(void, name, _push_move, array_t v, type *x) \ { \ M_ASSERT (x != NULL); \ type *data = M_F(name, _push_raw) M_R(v); \ if (M_UNLIKELY (data == NULL) ) \ return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ + M_CALL_INIT_MOVE (oplist, *data, *x); \ } \ - , /* INIT_SET | INIT_MOVE */ ) \ \ M_IF_METHOD(INIT_SET, oplist)( \ M_P(void, name, _push_at, array_t v, size_t key, type const x) \ @@ -490,7 +487,6 @@ } \ , /* No INIT */) \ \ - M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ M_P(void, name, _pop_back, type *dest, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ @@ -505,11 +501,7 @@ } \ M_ARRA4_CONTRACT(v); \ } \ - , /* SET | INIT_MOVE */ ) \ \ - M_IF_AT_LEAST_METHOD(INIT_SET, INIT_MOVE, oplist)( \ - /* FIXME: type has to be trivially movable (imposed by array) ! */ \ - /* FIXME: Really allocation or allocation free? */ \ M_INLINE void \ M_F(name, _pop_move)(type *dest, array_t v) \ { \ @@ -518,11 +510,9 @@ M_ASSERT_INDEX(0, v->size); \ M_ASSERT (dest != NULL); \ v->size--; \ - /* FIXME: M_DO_INIT_MOVE may use INIT_SET so allocator !*/ \ - M_DO_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \ + M_CALL_INIT_MOVE (oplist, *dest, v->ptr[v->size]); \ M_ARRA4_CONTRACT(v); \ } \ - , /* INIT_SET | INIT_MOVE */ ) \ \ /* TODO: Factorize all INIT dependent methods within the same IF*/ \ M_IF_METHOD(INIT, oplist)( \ @@ -556,14 +546,12 @@ return v->alloc; \ } \ \ - M_IF_AT_LEAST_METHOD(SET, INIT_MOVE, oplist)( \ M_P(void, name, _pop_at, type *dest, array_t v, size_t i) \ { \ M_ARRA4_CONTRACT(v); \ M_ASSERT_POOL(); \ M_ASSERT (v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ - /* FIXME: type is trivially movable */ \ if (dest) \ M_DO_MOVE (oplist, *dest, v->ptr[i]); \ else \ @@ -580,7 +568,6 @@ M_F(name, _pop_at) M_R(NULL, a, i); \ return true; \ } \ - , /* SET | INIT_MOVE */ ) \ \ M_IF_METHOD(INIT, oplist)( \ M_P(void, name, _insert_v, array_t v, size_t i, size_t num) \ @@ -644,7 +631,6 @@ M_ARRA4_CONTRACT(v2); \ } \ \ - M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist) ( \ M_INLINE void \ M_F(name, _swap_at)(array_t v, size_t i, size_t j) \ { \ @@ -653,12 +639,11 @@ M_ASSERT_INDEX(i, v->size); \ M_ASSERT_INDEX(j, v->size); \ type tmp; \ - M_DO_INIT_MOVE(oplist, tmp, v->ptr[i]); \ - M_DO_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \ - M_DO_INIT_MOVE(oplist, v->ptr[j], tmp); \ + M_CALL_INIT_MOVE(oplist, tmp, v->ptr[i]); \ + M_CALL_INIT_MOVE(oplist, v->ptr[i], v->ptr[j]); \ + M_CALL_INIT_MOVE(oplist, v->ptr[j], tmp); \ M_ARRA4_CONTRACT(v); \ } \ - , /* INIT_SET | INIT_MOVE */ ) \ \ M_INLINE type * \ M_F(name, _get)(const array_t v, size_t i) \ @@ -849,7 +834,7 @@ k += n1+n2; \ for (;;) { \ if (M_CALL_CMP(oplist, *el1, *el2) <= 0) { \ - M_DO_INIT_MOVE(oplist, *dest, *el1); \ + M_CALL_INIT_MOVE(oplist, *dest, *el1); \ dest++; \ el1++; \ if (M_UNLIKELY(-- n1 == 0)) { \ @@ -860,7 +845,7 @@ break; \ } \ } else { \ - M_DO_INIT_MOVE(oplist, *dest, *el2); \ + M_CALL_INIT_MOVE(oplist, *dest, *el2); \ dest++; \ el2++; \ if (M_UNLIKELY(-- n2 == 0)) { \ diff --git a/m-buffer.h b/m-buffer.h index 9bbebde7..7486286a 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -541,7 +541,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ M_CALL_SET(oplist, *data, v->data[v->idx_cons].x); \ } else { \ - M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_cons].x); \ + M_CALL_INIT_MOVE (oplist, *data, v->data[v->idx_cons].x); \ } \ v->idx_cons = (v->idx_cons == M_BUFF3R_SIZE(m_size)-1) ? 0 : (v->idx_cons + 1); \ } else { \ @@ -550,7 +550,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ M_CALL_SET(oplist, *data, v->data[v->idx_prod].x); \ } else { \ - M_DO_INIT_MOVE (oplist, *data, v->data[v->idx_prod].x); \ + M_CALL_INIT_MOVE (oplist, *data, v->data[v->idx_prod].x); \ } \ } \ \ @@ -767,7 +767,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ M_CALL_SET(oplist, *ptr, table->Tab[i].x); \ } else { \ - M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ + M_CALL_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ } \ atomic_store_explicit(&table->Tab[i].seq, 2*iC + 1, memory_order_release); \ M_QU3UE_MPMC_CONTRACT(table); \ @@ -971,7 +971,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ M_DO_MOVE(oplist, table->Tab[i].x, *x); \ } else { \ - M_DO_INIT_MOVE(oplist, table->Tab[i].x, *x); \ + M_CALL_INIT_MOVE(oplist, table->Tab[i].x, *x); \ } \ atomic_store_explicit(&table->prodIdx, w+1, memory_order_release); \ M_QU3UE_SPSC_CONTRACT(table); \ @@ -993,7 +993,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ M_CALL_SET(oplist, *ptr , table->Tab[i].x); \ } else { \ - M_DO_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ + M_CALL_INIT_MOVE (oplist, *ptr, table->Tab[i].x); \ } \ atomic_store_explicit(&table->consoIdx, r+1, memory_order_release); \ M_QU3UE_SPSC_CONTRACT(table); \ @@ -1044,7 +1044,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ M_CALL_SET(oplist, ptr[k], table->Tab[i].x); \ } else { \ - M_DO_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \ + M_CALL_INIT_MOVE (oplist, ptr[k], table->Tab[i].x); \ } \ } \ atomic_store_explicit(&table->consoIdx, r+max, memory_order_release); \ diff --git a/m-core.h b/m-core.h index 64e8bb76..5000112c 100644 --- a/m-core.h +++ b/m-core.h @@ -3545,7 +3545,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) /* Get the given method */ #define M_GET_INIT(...) M_GET_METHOD(INIT, M_INIT_DEFAULT, __VA_ARGS__) #define M_GET_INIT_SET(...) M_GET_METHOD(INIT_SET, M_SET_DEFAULT, __VA_ARGS__) -#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_NO_DEF_INIT_MOVE, __VA_ARGS__) +#define M_GET_INIT_MOVE(...) M_GET_METHOD(INIT_MOVE, M_SET_DEFAULT, __VA_ARGS__) #define M_GET_INIT_WITH(...) M_GET_METHOD(INIT_WITH, M_NO_DEF_INIT_WITH, __VA_ARGS__) #define M_GET_SET(...) M_GET_METHOD(SET, M_SET_DEFAULT, __VA_ARGS__) #define M_GET_MOVE(...) M_GET_METHOD(MOVE, M_NO_DEF_MOVE, __VA_ARGS__) @@ -3869,12 +3869,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) "The " #operator " operator has no method associated in the given OPLIST."),\ (return_type) 0) -// TODO: Use default INIT_MOVE which assume trivially movable type -// by getting throught API_2 the oplist and the size of the type -// If no type defined and no INIT_MOVE defined, just use sizeof (dst) -// Most types are trivially movable. Can remove macro M_DO_INIT_MOVE to use M_CALL_INIT_MOVE -// If disabled in oplist, M_CALL_INIT_MOVE will generate an error. -#define M_NO_DEF_INIT_MOVE(...) M_NO_DEFAULT(INIT_MOVE, void) #define M_NO_DEF_INIT_WITH(...) M_NO_DEFAULT(INIT_WITH, void) #define M_NO_DEF_MOVE(...) M_NO_DEFAULT(MOVE, void) #define M_NO_DEF_SWAP(...) M_NO_DEFAULT(SWAP, void) @@ -4063,9 +4057,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) /* NOTE: Theses operators are NOT compatible with the '[1]' tricks if the variable is defined as a parameter of a function (sizeof (a) is not portable). */ -#define M_MOVE_DEFAULT(a,b) (M_CHECK_SAME(a, b), M_MEMCPY_DEFAULT(a, b), memset(&(b), 0, sizeof (a))) -#define M_MEMCPY_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcpy(&(a), &(b), sizeof (a))) -#define M_MEMSET_DEFAULT(a) (memset(&(a), 0, sizeof (a))) +#define M_RESET_DEFAULT(a) (memset(&(a), 0, sizeof (a))) #define M_MEMCMP1_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a)) == 0) #define M_MEMCMP2_DEFAULT(a,b) (M_CHECK_SAME(a, b), memcmp(&(a), &(b), sizeof (a))) #define M_SWAP_DEFAULT(el1, el2) do { \ @@ -4076,28 +4068,35 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) memcpy(&(el2), &_tmp, sizeof (el1)); \ } while (0) +/* Default oplist for plain structure */ +#define M_POD_OPLIST \ + (INIT(M_RESET_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ + INIT_MOVE(M_SET_DEFAULT) ) + + /* NOTE: Theses operators are to be used with the '[1]' tricks if the variable is defined as a parameter of a function (sizeof (a) is not portable). */ -#define M_MOVE_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), M_MEMCPY_A1_DEFAULT(a, b), M_MEMSET_A1_DEFAULT(b)) -#define M_MEMCPY_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcpy(&(a[0]), &(b[0]), sizeof (a[0]))) -#define M_MEMSET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0]))) +#define M_COPY_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcpy(&(a[0]), &(b[0]), sizeof (a[0]))) +#define M_RESET_A1_DEFAULT(a) (memset(&(a[0]), 0, sizeof (a[0]))) #define M_MEMCMP1_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0],b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0])) == 0) #define M_MEMCMP2_A1_DEFAULT(a,b) (M_CHECK_SAME(a[0], b[0]), memcmp(&(a[0]), &(b[0]), sizeof (a[0]))) #define M_HASH_A1_DEFAULT(a) (m_core_hash((const void*) &(a[0]), sizeof (a[0])) ) +#define M_SWAP_A1_DEFAULT(a, b) do { \ + char _tmp[sizeof (a[0])]; \ + M_CHECK_SAME(a[0], b[0]); \ + memcpy(&_tmp, &(a[0]), sizeof (a[0])); \ + memcpy(&(a[0]), &(b[0]), sizeof (a[0])); \ + memcpy(&(b[0]), &_tmp, sizeof (a[0])); \ +} while (0) -/* Default oplist for plain structure */ -#define M_POD_OPLIST \ - (INIT(M_MEMSET_DEFAULT), INIT_SET(M_MEMCPY_DEFAULT), SET(M_MEMCPY_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_DEFAULT), CMP(M_MEMCMP2_DEFAULT), \ - HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT)) - - -/* Default oplist for a structure defined with an array of size 1 */ +/* Default oplist for a structure defined with an array of size 1. + MOVE operator is not defined since the object may need to release some data */ #define M_A1_OPLIST \ - (INIT(M_MEMSET_A1_DEFAULT), INIT_SET(M_MEMCPY_A1_DEFAULT), SET(M_MEMCPY_A1_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_MEMCMP1_A1_DEFAULT), CMP(M_MEMCMP2_A1_DEFAULT), \ - HASH(M_HASH_A1_DEFAULT)) + (INIT(M_RESET_A1_DEFAULT), INIT_SET(M_COPY_A1_DEFAULT), SET(M_COPY_A1_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + EQUAL(M_MEMCMP1_A1_DEFAULT), CMP(M_MEMCMP2_A1_DEFAULT), HASH(M_HASH_A1_DEFAULT), SWAP(M_SWAP_A1_DEFAULT), \ + INIT_MOVE(M_COPY_A1_DEFAULT) ) /* Oplist for a type that does nothing and shall not be instanciated */ @@ -4122,7 +4121,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) # define M_BASIC_OPLIST \ (INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \ CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_BASIC), CMP(M_CMP_BASIC), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \ RESET(M_INIT_BASIC), PROPERTIES( (NOCLEAR(1)) ), \ ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ @@ -4135,7 +4134,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) # define M_BASIC_OPLIST \ (INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \ CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_BASIC), CMP(M_CMP_BASIC), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \ RESET(M_INIT_BASIC), PROPERTIES( (NOCLEAR(1)) ), \ ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ @@ -4148,7 +4147,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) # define M_BASIC_OPLIST \ (INIT(M_INIT_BASIC), INIT_SET(M_SET_BASIC), SET(M_SET_BASIC), \ CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_BASIC), CMP(M_CMP_BASIC), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \ RESET(M_INIT_BASIC), PROPERTIES( (NOCLEAR(1)) ), \ ADD(M_ADD_DEFAULT), SUB(M_SUB_DEFAULT), \ MUL(M_MUL_DEFAULT), DIV(M_DIV_DEFAULT), \ @@ -4179,7 +4178,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) (INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \ SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \ HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ TYPE(type), OPLIST(init), \ IN_STR(API_1(M_ENUM_FSCAN)), OUT_STR(M_ENUM_FPRINT), \ @@ -4192,7 +4191,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) (INIT(API_1(M_ENUM_INIT)), INIT_SET(M_SET_DEFAULT), \ SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ EQUAL(M_EQUAL_DEFAULT), CMP(M_CMP_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) , \ HASH(M_HASH_POD_DEFAULT), SWAP(M_SWAP_DEFAULT), \ TYPE(type), OPLIST(init), \ IN_SERIAL(API_1(M_ENUM_IN_SERIAL)), OUT_SERIAL(M_ENUM_OUT_SERIAL), \ @@ -4255,32 +4254,29 @@ m_core_parse2_enum (const char str[], const char **endptr) /* Default oplist for standard types of pointers. */ #define M_PTR_OPLIST \ - (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), \ - CLEAR(M_NOTHING_DEFAULT), EQUAL(M_EQUAL_DEFAULT), \ - INIT_MOVE(M_MOVE_DEFAULT), MOVE(M_MOVE_DEFAULT) , \ - SWAP(M_SWAP_DEFAULT) ) + (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + EQUAL(M_EQUAL_DEFAULT), SWAP(M_SWAP_DEFAULT) \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT) ) -/* Default oplist for complex objects with "classic" names for methods. +/* Default oplist for complex objects (using [1] trick) with "classic" names for methods. */ #define M_CLASSIC_OPLIST(name) ( \ - INIT(M_F(name, _init)), \ - INIT_SET(M_F(name, _init_set)), \ - SET(M_F(name, _set)), \ - CLEAR(M_F(name, _clear)), \ - TYPE(M_F(name, _t)) ) + INIT(M_F(name, _init)), INIT_SET(M_F(name, _init_set)), SET(M_F(name, _set)), CLEAR(M_F(name, _clear)), \ + INIT_MOVE(M_COPY_A1_DEFAULT), TYPE(M_F(name, _t)) ) -/* OPLIST for 'const char *' string (with NO memory allocation). +/* Default oplist for 'const char *' string (with NO memory allocation). */ #define M_CSTR_EQUAL(a,b) (strcmp((a),(b)) == 0) #define M_CSTR_OUT_STR(file, str) fprintf(file, "%s", str) -#define M_CSTR_OPLIST (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), \ - SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ - HASH(m_core_cstr_hash), EQUAL(M_CSTR_EQUAL), \ - CMP(strcmp), TYPE(const char *), \ - OUT_STR(M_CSTR_OUT_STR) ) +#define M_CSTR_OPLIST \ + (INIT(M_INIT_DEFAULT), INIT_SET(M_SET_DEFAULT), SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT), \ + HASH(m_core_cstr_hash), EQUAL(M_CSTR_EQUAL), CMP(strcmp), SWAP(M_SWAP_DEFAULT), \ + INIT_MOVE(M_SET_DEFAULT), MOVE(M_SET_DEFAULT), TYPE(const char *), \ + OUT_STR(M_CSTR_OUT_STR) ) +/****************************************************************************/ /* From an oplist (...) return ... (Like M_ID but for OPLIST) */ #define M_OPFLAT(...) __VA_ARGS__ @@ -4365,15 +4361,6 @@ m_core_parse2_enum (const char str[], const char **endptr) so that the first argument becomes a pointer to the destination (OBSOLETE MACRO) */ #define M_IPTR(...) ( & __VA_ARGS__ ) -/* Perform an INIT_MOVE if present, or emulate it using INIT_SET/CLEAR */ -/* FIXME: Use INIT_MOVE if present or assume trivially movable otherwise? */ -/* A non trivially movable type shall provide an INIT_MOVE method or disable it */ -#define M_DO_INIT_MOVE(oplist, dest, src) do { \ - M_IF_METHOD(INIT_MOVE, oplist)(M_CALL_INIT_MOVE(oplist, (dest), (src)), \ - M_CALL_INIT_SET(oplist, (dest), (src)) ; \ - M_CALL_CLEAR(oplist, (src) )); \ - } while (0) - /* Perform a MOVE if present, or emulate it using CLEAR/INIT_MOVE if possible, or with SET/CLEAR otherwise */ #define M_DO_MOVE(oplist, dest, src) do { \ @@ -4756,8 +4743,8 @@ m_core_parse2_enum (const char str[], const char **endptr) so it reverses the final order. */ #define M_INIT_VAI(oplist, dest, ...) \ - (void)(M_CALL_INIT(oplist, dest) , \ - M_MAP2_C(M_INIT_VAI_FUNC, (dest, oplist) , __VA_ARGS__) \ + (void)(M_CALL_INIT(oplist, dest) , \ + M_MAP2_C(M_INIT_VAI_FUNC, (dest, oplist) , __VA_ARGS__) \ M_IF_METHOD(REVERSE, oplist)(M_DEFERRED_COMMA M_CALL_REVERSE(oplist, dest), ) \ ) #define M_INIT_VAI_FUNC(d, a) \ diff --git a/m-deque.h b/m-deque.h index f45cb254..062e3703 100644 --- a/m-deque.h +++ b/m-deque.h @@ -309,7 +309,7 @@ { \ M_ASSERT (x != NULL); \ type *p = M_F(name, _push_back_raw)M_R(d); \ - M_DO_INIT_MOVE (oplist, *p, *x); \ + M_CALL_INIT_MOVE (oplist, *p, *x); \ } \ \ M_P(type *, name, _push_front_raw, deque_t d) \ @@ -358,7 +358,7 @@ { \ M_ASSERT (x != NULL); \ type *p = M_F(name, _push_front_raw)M_R(d); \ - M_DO_INIT_MOVE (oplist, *p, *x); \ + M_CALL_INIT_MOVE (oplist, *p, *x); \ } \ \ M_P(void, name, _pop_back, type *ptr, deque_t d) \ diff --git a/m-dict.h b/m-dict.h index 811690d7..642aaf17 100644 --- a/m-dict.h +++ b/m-dict.h @@ -1421,8 +1421,8 @@ enum m_d1ct_oa_element_e { \ /* NOTE: We don't want a real oplist for this sub type */ \ M_ARRAY_DEF(M_F(name, _array_pair), M_F(name, _pair_ct), \ - (INIT(M_NOTHING_DEFAULT), SET(M_MEMCPY_DEFAULT), \ - INIT_SET(M_MEMCPY_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \ + (INIT(M_NOTHING_DEFAULT), SET(M_SET_DEFAULT), \ + INIT_SET(M_SET_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) \ \ typedef struct M_F(name,_s) { \ size_t mask, count, count_delete; \ @@ -1576,12 +1576,12 @@ enum m_d1ct_oa_element_e { if (p != i) { \ if (M_LIKELY (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \ || M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED))) { \ - M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ + M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ + M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ } else { \ M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \ - M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ + M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ + M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ } \ M_CALL_OOR_SET(key_oplist, data[i].key, M_D1CT_OA_EMPTY); \ } \ @@ -1750,12 +1750,12 @@ enum m_d1ct_oa_element_e { if (p != i) { \ if (M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) \ || M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_DELETED)) { \ - M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ + M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ + M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ } else { \ M_F(name, _pair_ct) *ptr = M_F(name, _array_pair_push_raw)M_R(tmp); \ - M_DO_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ + M_CALL_INIT_MOVE(key_oplist, ptr->key, data[i].key); \ + M_CALL_INIT_MOVE(value_oplist, ptr->value, data[i].value); \ } \ M_CALL_OOR_SET(key_oplist, data[i].key, M_D1CT_OA_EMPTY); \ } \ @@ -1773,8 +1773,8 @@ enum m_d1ct_oa_element_e { M_ASSERT (s <= h->mask); \ } while (!M_CALL_OOR_EQUAL(key_oplist, data[p].key, M_D1CT_OA_EMPTY) ); \ } \ - M_DO_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ - M_DO_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ + M_CALL_INIT_MOVE(key_oplist, data[p].key, data[i].key); \ + M_CALL_INIT_MOVE(value_oplist, data[p].value, data[i].value); \ } \ } \ /* Pass 3: scan moved entries and move them back */ \ diff --git a/m-list.h b/m-list.h index 1542d141..1a5b01ec 100644 --- a/m-list.h +++ b/m-list.h @@ -307,14 +307,14 @@ type *data = M_F(name, _push_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ + M_CALL_INIT_MOVE (oplist, *data, *x); \ } \ \ M_P(void, name, _pop_move, type *data, list_t v) \ { \ M_L1ST_CONTRACT(v); \ M_ASSERT(*v != NULL && data != NULL); \ - M_DO_INIT_MOVE (oplist, *data, (*v)->data); \ + M_CALL_INIT_MOVE (oplist, *data, (*v)->data); \ struct M_F(name, _s) *tofree = *v; \ *v = (*v)->next; \ M_CALL_DEL(oplist, tofree); \ @@ -1057,7 +1057,7 @@ type *data = M_F(name, _push_back_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ + M_CALL_INIT_MOVE (oplist, *data, *x); \ } \ \ M_P(void, name, _push_move, list_t v, type *x) \ @@ -1091,7 +1091,7 @@ M_ASSERT (v->back != NULL); \ M_ASSERT (data != NULL); \ struct M_F(name, _s) *tofree = v->back; \ - M_DO_INIT_MOVE (oplist, *data, tofree->data); \ + M_CALL_INIT_MOVE (oplist, *data, tofree->data); \ v->back = tofree->next; \ M_CALL_DEL(oplist, tofree); \ /* Update front too if the list became empty */ \ @@ -1149,7 +1149,7 @@ type *data = M_F(name, _push_front_raw)(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ - M_DO_INIT_MOVE (oplist, *data, *x); \ + M_CALL_INIT_MOVE (oplist, *data, *x); \ } \ \ M_IF_METHOD(INIT, oplist)( \ diff --git a/m-string.h b/m-string.h index 7ff065d8..036fa803 100644 --- a/m-string.h +++ b/m-string.h @@ -2357,6 +2357,7 @@ namespace m_lib { INIT_SET(M_F(name,_init_set)), \ SET(M_F(name,_set)), \ CLEAR(M_F(name,_clear)), \ + INIT_MOVE(M_COPY_A1_DEFAULT), \ NAME(name), \ INIT_WITH( API_1(M_BOUNDED_STR1NG_INIT_WITH)), \ HASH(M_F(name,_hash)), \ diff --git a/m-tree.h b/m-tree.h index c1e76f58..0ed0f757 100644 --- a/m-tree.h +++ b/m-tree.h @@ -476,7 +476,7 @@ typedef int32_t m_tr33_index_t; \ M_P(it_t, name, _move_up, it_t pos, type *data) { \ it_t it = M_F(name, _insert_up_raw)M_R(pos); \ - M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ + M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ @@ -510,7 +510,7 @@ typedef int32_t m_tr33_index_t; \ M_P(it_t, name, _move_down, it_t pos, type *data) { \ it_t it = M_F(name, _insert_down_raw)M_R(pos); \ - M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ + M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ @@ -544,7 +544,7 @@ typedef int32_t m_tr33_index_t; \ M_P(it_t, name, _move_child, it_t pos, type *data) { \ it_t it = M_F(name, _insert_child_raw)M_R(pos); \ - M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ + M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ @@ -581,7 +581,7 @@ typedef int32_t m_tr33_index_t; \ M_P(it_t, name, _move_left, it_t pos, type *data) { \ it_t it = M_F(name, _insert_left_raw)M_R(pos); \ - M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ + M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ @@ -612,7 +612,7 @@ typedef int32_t m_tr33_index_t; \ M_P(it_t, name, _move_right, it_t pos, type *data) { \ it_t it = M_F(name, _insert_right_raw)M_R(pos); \ - M_DO_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ + M_CALL_INIT_MOVE(oplist, it.tree->tab[it.index].data, *data); \ M_TR33_IT_CONTRACT(it, true); \ return it; \ } \ diff --git a/tests/test-marray.c b/tests/test-marray.c index e3a37e81..194eba97 100644 --- a/tests/test-marray.c +++ b/tests/test-marray.c @@ -33,9 +33,9 @@ END_COVERAGE #define ARRAY_UINT_OPLIST ARRAY_OPLIST(array_uint) // Array with the minimum number of methods. -ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear))) -ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear))) -ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear))) +ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) )) +ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) ) ) +ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT))) ARRAY_DEF(array_ulong, uint64_t) ARRAY_DEF(array_string, string_t) diff --git a/tests/test-mcore.c b/tests/test-mcore.c index 54419440..b19eab44 100644 --- a/tests/test-mcore.c +++ b/tests/test-mcore.c @@ -746,65 +746,54 @@ typedef struct { int b,c; } ts; static void f_ti(ti x) { ti y; - M_MOVE_A1_DEFAULT(y,x); + M_COPY_A1_DEFAULT(y,x); assert(y[0] == 9); - assert(x[0] == 0); } static void f_ts(ts x) { ts y; - M_MOVE_DEFAULT(y,x); + M_SET_DEFAULT(y,x); assert(y.b == 2); assert(y.c == 3); - assert(x.b == 0); - assert(x.c == 0); } static void f_ts2(ts *x) { ts y; - M_MOVE_DEFAULT(y,*x); + M_SET_DEFAULT(y,*x); assert(y.b == 2); assert(y.c == 3); - assert(x->b == 0); - assert(x->c == 0); } static void test_move_default(void) { int o, p; o = 9; - M_MOVE_DEFAULT(p, o); + M_SET_DEFAULT(p, o); assert(p == 9); - assert(o == 0); double u, k; k = -1.0; u = 9.5; - M_MOVE_DEFAULT(k, u); + M_SET_DEFAULT(k, u); assert(k == 9.5); - assert(u == 0.0); // NOTE: memset(0) sets an IEEE-754 number to 0.0 int *ptr = &o, *m; - M_MOVE_DEFAULT(m, ptr); - assert( ptr == NULL); - assert( m == &o); - + M_SET_DEFAULT(m, ptr); + (void)m; + ti x, y; x[0] = 9; - M_MOVE_A1_DEFAULT(y, x); + M_COPY_A1_DEFAULT(y, x); assert(y[0] == 9); - assert(x[0] == 0); x[0] = 9; f_ti(x); - assert(x[0] == 0); ts y2, x2 = { 2, 3}; - M_MOVE_DEFAULT(y2, x2); + M_SET_DEFAULT(y2, x2); assert(y2.b == 2 && y2.c == 3); - assert(x2.b == 0 && x2.c == 0); x2.b = 2; x2.c = 3; f_ts(x2); @@ -812,8 +801,6 @@ static void test_move_default(void) assert(x2.c == 3); f_ts2(&x2); - assert(x2.b == 0); - assert(x2.c == 0); } static void test_builtin(void) diff --git a/tests/test-mdeque.c b/tests/test-mdeque.c index a6f55d55..f87f5174 100644 --- a/tests/test-mdeque.c +++ b/tests/test-mdeque.c @@ -35,7 +35,7 @@ END_COVERAGE DEQUE_DEF(deque_mpz, testobj_t, TESTOBJ_OPLIST) // Deque with the minimum number of methods. -DEQUE_DEF(deque_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear))) +DEQUE_DEF(deque_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) )) // Dequeue of an enumerate typedef enum { diff --git a/tests/test-mlist.c b/tests/test-mlist.c index 599c1dd1..0a2dbded 100644 --- a/tests/test-mlist.c +++ b/tests/test-mlist.c @@ -35,8 +35,8 @@ LIST_DUAL_PUSH_DEF(list2_mpz, testobj_t, TESTOBJ_OPLIST) #define LIST2_DOUBLE_OPLIST LIST_OPLIST(list2_double) // Array with the minimum number of methods. -LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear))) -LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear))) +LIST_DEF(list_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) )) +LIST_DUAL_PUSH_DEF(list2_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT))) LIST_DEF(list_string, string_t) #define M_OPL_list_string_t() LIST_OPLIST(list_string, STRING_OPLIST) diff --git a/tests/test-mtree.c b/tests/test-mtree.c index 6017b112..9144823b 100644 --- a/tests/test-mtree.c +++ b/tests/test-mtree.c @@ -295,31 +295,26 @@ static void test_basic(void) tree_move_up(it2, &data); tree_get_str(s, t, false); assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{2,[{1,[{5}]}]}]}]}]")); - assert(data == 0); data = 11; tree_move_left(it2, &data); tree_get_str(s, t, false); assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{1,[{5}]}]}]}]}]")); - assert(data == 0); data = 12; tree_move_right(it2, &data); tree_get_str(s, t, false); assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{1,[{5}]}]},{12}]}]}]")); - assert(data == 0); data = 13; tree_move_child(it2, &data); tree_get_str(s, t, false); assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{13},{1,[{5}]}]},{12}]}]}]")); - assert(data == 0); data = 14; tree_move_down(it2, &data); tree_get_str(s, t, false); assert(string_equal_str_p(s, "[{0,[{-1,[{3}]},{10,[{11},{2,[{14,[{13},{1,[{5}]}]}]},{12}]}]}]")); - assert(data == 0); tree_it_set(&it, root); assert(tree_it_equal_p(it, root)); diff --git a/tests/test-obj-except.h b/tests/test-obj-except.h index b09457d5..e4aaa0db 100644 --- a/tests/test-obj-except.h +++ b/tests/test-obj-except.h @@ -236,6 +236,7 @@ static inline size_t test_obj_except__hash(const test_obj_except__t z) INIT_SET(test_obj_except__init_set), \ SET(test_obj_except__set), \ CLEAR(test_obj_except__clear), \ + INIT_MOVE(M_COPY_A1_DEFAULT), \ TYPE(test_obj_except__t), \ ADD(test_obj_except__add), \ OUT_STR(test_obj_except__out_str), \ diff --git a/tests/test-obj.h b/tests/test-obj.h index 933499c0..660e2d4b 100644 --- a/tests/test-obj.h +++ b/tests/test-obj.h @@ -227,11 +227,12 @@ static inline void testobj_str(string_t str, const testobj_t z, bool append) // This enables testing good macro expansion in OPLIST usage #define testobj_clear_indirect(op, x) testobj_clear(x) -#define TESTOBJ_OPLIST \ +#define TESTOBJ_OPLIST \ (INIT(testobj_init), \ INIT_SET(testobj_init_set), \ SET(testobj_set), \ CLEAR(API_1(testobj_clear_indirect)), \ + INIT_MOVE(M_COPY_A1_DEFAULT), \ TYPE(testobj_t), \ OUT_STR(testobj_out_str), \ IN_STR(testobj_in_str), \ @@ -242,11 +243,12 @@ static inline void testobj_str(string_t str, const testobj_t z, bool append) EMPLACE_TYPE( LIST( (_ui, testobj_init_set_ui, unsigned int), (_str, testobj_init_set_str, const char *), ( /*empty*/, testobj_init_set, testobj_t) ) ) \ ) -#define TESTOBJ_CMP_OPLIST \ +#define TESTOBJ_CMP_OPLIST \ (INIT(testobj_init), \ INIT_SET(testobj_init_set), \ SET(testobj_set), \ CLEAR(testobj_clear), \ + INIT_MOVE(M_COPY_A1_DEFAULT), \ TYPE(testobj_t), \ OUT_STR(testobj_out_str), \ IN_STR(testobj_in_str), \ From 8e3a06b852d42b4471336a49d273ae44f392e5ae Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 16 Apr 2025 23:21:36 +0200 Subject: [PATCH 56/91] Simplify OPLIST definition as INIT_MOVE is mandatory for arrays --- m-array.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/m-array.h b/m-array.h index 671ba378..8c7e83bc 100644 --- a/m-array.h +++ b/m-array.h @@ -107,7 +107,7 @@ ,IT_REF(M_F(name,_ref)) \ ,IT_CREF(M_F(name,_cref)) \ ,M_IF_METHOD(INIT_SET, oplist)(IT_INSERT(M_F(name,_insert)) ,) \ - ,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(IT_REMOVE(M_F(name,_remove)),) \ + ,IT_REMOVE(M_F(name,_remove)) \ ,RESET(M_F(name,_reset)) \ ,KEY_TYPE(size_t) \ ,VALUE_TYPE(M_F(name, _subtype_ct)) \ @@ -116,12 +116,12 @@ ,M_IF_METHOD(SET, oplist)(SET_KEY(M_F(name, _set_at)) ,) \ ,GET_KEY(M_F(name, _get)) \ ,M_IF_METHOD(INIT, oplist)(SAFE_GET_KEY(M_F(name, _safe_get)) ,) \ - ,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(ERASE_KEY(M_F(name, _erase)),) \ + ,ERASE_KEY(M_F(name, _erase)) \ ,GET_SIZE(M_F(name, _size)) \ ,M_IF_METHOD(INIT_SET, oplist)(PUSH(M_F(name,_push_back)) ,) \ - ,M_IF_AT_LEAST_METHOD(SET,INIT_MOVE,oplist)(POP(M_F(name,_pop_back)) ,) \ - ,M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist)(PUSH_MOVE(M_F(name,_push_move)) ,) \ - ,M_IF_AT_LEAST_METHOD(INIT_SET,INIT_MOVE,oplist)(POP_MOVE(M_F(name,_pop_move)) ,) \ + ,POP(M_F(name,_pop_back)) \ + ,PUSH_MOVE(M_F(name,_push_move)) \ + ,POP_MOVE(M_F(name,_pop_move)) \ ,OPLIST(oplist) \ ,M_IF_METHOD(CMP, oplist)(SORT(M_F(name, _special_sort)),) \ ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \ From c7bad98a7e90f706c8b68e7c00a692e52c91bdae Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 16 Apr 2025 23:35:55 +0200 Subject: [PATCH 57/91] Port ARRAY oplist to support local memcontext --- m-array.h | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/m-array.h b/m-array.h index 8c7e83bc..7e2326d0 100644 --- a/m-array.h +++ b/m-array.h @@ -80,7 +80,7 @@ /* OPLIST definition of a dynamic array */ /* FIXME: Do we want to export some methods as they are slow and are not fit to be used for building other methods (like _it_remove)? */ -//TODO: ARRAY_POOL_OPLIST +#ifndef M_USE_POOL #define M_ARRA4_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_F(name, _init_set)),) \ @@ -133,7 +133,60 @@ ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ ) - +#else +#define M_ARRA4_OPLIST_P3(name, oplist) \ + (INIT(M_F(name, _init)) \ + ,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(API_0P(M_F(name, _init_set))),) \ + ,M_IF_METHOD(INIT_SET, oplist)(INIT_WITH(API_1(M_INIT_WITH_VAI)),) \ + ,M_IF_METHOD2(INIT_SET,SET, oplist)(SET(API_0P(M_F(name, _set))), ) \ + ,CLEAR(API_0P(M_F(name, _clear))) \ + ,INIT_MOVE(M_F(name, _init_move)) \ + ,MOVE(API_0P(M_F(name, _move))) \ + ,SWAP(M_F(name, _swap)) \ + ,TYPE(M_F(name,_ct)) , GENTYPE(struct M_F(name,_s)*) \ + ,NAME(name) \ + ,SUBTYPE(M_F(name, _subtype_ct)) \ + ,EMPTY_P(M_F(name,_empty_p)) \ + ,IT_TYPE(M_F(name,_it_ct)), \ + ,IT_FIRST(M_F(name,_it)) \ + ,IT_LAST(M_F(name,_it_last)) \ + ,IT_END(M_F(name,_it_end)) \ + ,IT_SET(M_F(name,_it_set)) \ + ,IT_END_P(M_F(name,_end_p)) \ + ,IT_LAST_P(M_F(name,_last_p)) \ + ,IT_EQUAL_P(M_F(name,_it_equal_p)) \ + ,IT_NEXT(M_F(name,_next)) \ + ,IT_PREVIOUS(M_F(name,_previous)) \ + ,IT_REF(M_F(name,_ref)) \ + ,IT_CREF(M_F(name,_cref)) \ + ,M_IF_METHOD(INIT_SET, oplist)(IT_INSERT(API_0P(M_F(name,_insert))) ,) \ + ,IT_REMOVE(API_0P(M_F(name,_remove))) \ + ,RESET(API_0P(M_F(name,_reset))) \ + ,KEY_TYPE(size_t) \ + ,VALUE_TYPE(M_F(name, _subtype_ct)) \ + ,KEY_OPLIST(M_BASIC_OPLIST) \ + ,VALUE_OPLIST(oplist) \ + ,M_IF_METHOD(SET, oplist)(SET_KEY(API_0P(M_F(name, _set_at))) ,) \ + ,GET_KEY(M_F(name, _get)) \ + ,M_IF_METHOD(INIT, oplist)(SAFE_GET_KEY(API_0P(M_F(name, _safe_get))) ,) \ + ,ERASE_KEY(API_0P(M_F(name, _erase))) \ + ,GET_SIZE(M_F(name, _size)) \ + ,M_IF_METHOD(INIT_SET, oplist)(PUSH(API_0P(M_F(name,_push_back))) ,) \ + ,POP(API_0P(M_F(name,_pop_back))) \ + ,PUSH_MOVE(API_0P(M_F(name,_push_move))) \ + ,POP_MOVE(M_F(name,_pop_move)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(CMP, oplist)(SORT(M_F(name, _special_sort)),) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \ + ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ + ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ + ) +#endif /********************************** INTERNAL *********************************/ From 586d0ae13a1cdcbe2cad4c883df331c8d3dc698f Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 16 Apr 2025 23:47:41 +0200 Subject: [PATCH 58/91] Update documentation --- doc/API.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/API.txt b/doc/API.txt index 21104174..b7dc9a3e 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -95,9 +95,10 @@ V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible: * M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated. * m-buffer: non-thread safe queue & stack are moved into their dedicated header (m-queue) BUFFER_THREAD_UNSAFE is no longer supported. - * m-buffer: Remove buffer blocking policy and thread safe (_push / _pop returns now void) + * m-buffer: Remove buffer blocking policy BUFFER_BLOCKING (default policy is now forced) and thread safe (_push / _pop returns now void) * m-buffer push / pop no longer return a bool (it was undocumented) * Remove MEMPOOL support from list & R/B tree * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_POOL interface to pass local pool context. - * M*LIB becomes stricter for INIT_MOVE: Emulation layer using CLEAR+INIT_SET when missing INIT_MOVE operator has been removed: either default INIT_MOVE operator (operator '=') is working, or a methode is provided for INIT_MOVE or it is disabled. + * M*LIB becomes stricter for INIT_MOVE: Emulation layer using CLEAR+INIT_SET when missing INIT_MOVE operator has been removed: either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled. + If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method. (It's because supporting emulation layer with new memory context parameter was complicated) From 22ccae74c34fd3ae482c230091aab7d5318a520e Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 16 Apr 2025 23:47:52 +0200 Subject: [PATCH 59/91] Minor optimization of stable_sort --- m-array.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/m-array.h b/m-array.h index 7e2326d0..e723add9 100644 --- a/m-array.h +++ b/m-array.h @@ -891,10 +891,9 @@ dest++; \ el1++; \ if (M_UNLIKELY(-- n1 == 0)) { \ - if (n2 > 0) { \ - memcpy (dest, el2, n2 * sizeof (type)); \ - dest += n2; \ - } \ + M_ASSERT (n2 > 0); \ + memcpy (dest, el2, n2 * sizeof (type)); \ + dest += n2; \ break; \ } \ } else { \ @@ -902,10 +901,9 @@ dest++; \ el2++; \ if (M_UNLIKELY(-- n2 == 0)) { \ - if (n1 > 0) { \ - memcpy (dest, el1, n1 * sizeof (type)); \ - dest += n1; \ - } \ + M_ASSERT (n1 > 0); \ + memcpy (dest, el1, n1 * sizeof (type)); \ + dest += n1; \ break; \ } \ } \ From 692c0487af0eb656a113085bca010266e6fd4913 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 17 Apr 2025 23:20:48 +0200 Subject: [PATCH 60/91] Update oplist for new memory model --- m-bptree.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++-- m-deque.h | 44 ++++++++++++++++++++++++++- m-dict.h | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ m-list.h | 46 ++++++++++++++++++++++++++++ m-prioqueue.h | 38 ++++++++++++++++++++++- m-queue.h | 14 ++++----- m-rbtree.h | 42 +++++++++++++++++++++++++- m-tuple.h | 26 ++++++++++++++++ m-variant.h | 26 ++++++++++++++++ 9 files changed, 387 insertions(+), 13 deletions(-) diff --git a/m-bptree.h b/m-bptree.h index b1dcf01b..93ea8fb7 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -156,6 +156,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a b+tree (global tree) */ +#ifndef M_USE_POOL #define M_BPTR33_KEY_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -189,7 +190,40 @@ M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \ M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ ) - +#else +#define M_BPTR33_KEY_OPLIST_P3(name, oplist) \ + (INIT(API_0P(M_F(name, _init))), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_INIT_VAI)), \ + SET(API_0P(M_F(name, _set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + INIT_MOVE(M_F(name, _init_move)), \ + MOVE(API_0P(M_F(name, _move))), \ + SWAP(M_F(name, _swap)), \ + NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \ + SUBTYPE(M_F(name, _subtype_ct)), \ + IT_TYPE(M_F(name, _it_ct)), \ + IT_FIRST(M_F(name,_it)), \ + IT_SET(M_F(name,_it_set)), \ + IT_END(M_F(name,_it_end)), \ + IT_END_P(M_F(name,_end_p)), \ + IT_EQUAL_P(M_F(name,_it_equal_p)), \ + IT_NEXT(M_F(name,_next)), \ + IT_CREF(M_F(name,_cref)), \ + RESET(API_0P(M_F(name,_reset))), \ + PUSH(API_0P(M_F(name,_push))), \ + GET_MIN(M_F(name,_min)), \ + GET_MAX(M_F(name,_max)), \ + M_IF_METHOD(GET_STR, oplist)(API_0P(GET_STR(M_F(name, _get_str))),), \ + M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \ + M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),), \ + M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),), \ + M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \ + M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \ + M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \ + M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ + ) +#endif /* Deferred evaluation */ #define M_BPTR33_OPLIST2_P1(arg) M_BPTR33_OPLIST2_P2 arg @@ -205,6 +239,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist))) /* Final definition of the oplist (associative array) */ +#ifndef M_USE_POOL #define M_BPTR33_OPLIST2_P4(name, key_oplist, value_oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -233,7 +268,7 @@ VALUE_TYPE(M_F(name, _value_ct)), \ SET_KEY(M_F(name, _set_at)), \ GET_KEY(M_F(name, _get)), \ - SAFE_GET_KEY(M_F(name, _safe_get)) \ + SAFE_GET_KEY(M_F(name, _safe_get)), \ ERASE_KEY(M_F(name, _erase)), \ KEY_OPLIST(key_oplist), \ VALUE_OPLIST(value_oplist), \ @@ -245,7 +280,47 @@ M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_F(name, _equal_p)),), \ M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_F(name, _hash)),) \ ) - +#else +#define M_BPTR33_OPLIST2_P4(name, key_oplist, value_oplist) \ + (INIT(API_0P(M_F(name, _init))), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_INIT_KEY_VAI)), \ + SET(API_0P(M_F(name, _set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + INIT_MOVE(M_F(name, _init_move)), \ + MOVE(API_0P(M_F(name, _move))), \ + SWAP(M_F(name, _swap)), \ + NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \ + SUBTYPE(M_F(name, _subtype_ct)), \ + EMPTY_P(M_F(name,_empty_p)), \ + IT_TYPE(M_F(name, _it_ct)), \ + IT_FIRST(M_F(name,_it)), \ + IT_SET(M_F(name,_it_set)), \ + IT_END(M_F(name,_it_end)), \ + IT_END_P(M_F(name,_end_p)), \ + IT_EQUAL_P(M_F(name,_it_equal_p)), \ + IT_NEXT(M_F(name,_next)), \ + IT_CREF(M_F(name,_cref)), \ + RESET(API_0P(M_F(name,_reset))), \ + GET_MIN(M_F(name,_min)), \ + GET_MAX(M_F(name,_max)), \ + KEY_TYPE(M_F(name, _key_ct)), \ + VALUE_TYPE(M_F(name, _value_ct)), \ + SET_KEY(API_0P(M_F(name, _set_at))), \ + GET_KEY(M_F(name, _get)), \ + SAFE_GET_KEY(API_0P(M_F(name, _safe_get))), \ + ERASE_KEY(API_0P(M_F(name, _erase))), \ + KEY_OPLIST(key_oplist), \ + VALUE_OPLIST(value_oplist), \ + M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \ + M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_F(name, _out_str)),), \ + M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(API_0P(M_F(name, _in_str))),), \ + M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \ + M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \ + M_IF_METHOD_BOTH(EQUAL, key_oplist, value_oplist)(EQUAL(M_F(name, _equal_p)),), \ + M_IF_METHOD_BOTH(HASH, key_oplist, value_oplist)(HASH(M_F(name, _hash)),) \ + ) +#endif /******************************** INTERNAL ***********************************/ diff --git a/m-deque.h b/m-deque.h index 062e3703..b1d41390 100644 --- a/m-deque.h +++ b/m-deque.h @@ -1057,6 +1057,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a deque */ +#ifndef M_USE_POOL #define M_D3QU3_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,INIT_SET(M_F(name, _init_set)) \ @@ -1097,7 +1098,48 @@ ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ ) - +#else +#define M_D3QU3_OPLIST_P3(name, oplist) \ + (INIT(API_0P(M_F(name, _init))) \ + ,INIT_SET(API_0P(M_F(name, _init_set))) \ + ,INIT_WITH(API_1(M_INIT_WITH_VAI)) \ + ,SET(API_0P(M_F(name, _set))) \ + ,CLEAR(API_0P(M_F(name, _clear))) \ + ,INIT_MOVE(M_F(name, _init_move)) \ + ,MOVE(API_0P(M_F(name, _move))) \ + ,SWAP(M_F(name, _swap)) \ + ,NAME(name) \ + ,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \ + ,SUBTYPE(M_F(name, _subtype_ct)) \ + ,EMPTY_P(M_F(name,_empty_p)) \ + ,IT_TYPE(M_F(name,_it_ct)) \ + ,IT_FIRST(M_F(name,_it)) \ + ,IT_LAST(M_F(name,_it_last)) \ + ,IT_END(M_F(name,_it_end)) \ + ,IT_SET(M_F(name,_it_set)) \ + ,IT_END_P(M_F(name,_end_p)) \ + ,IT_LAST_P(M_F(name,_last_p)) \ + ,IT_EQUAL_P(M_F(name,_it_equal_p)) \ + ,IT_NEXT(M_F(name,_next)) \ + ,IT_PREVIOUS(M_F(name,_previous)) \ + ,IT_REF(M_F(name,_ref)) \ + ,IT_CREF(M_F(name,_cref)) \ + ,IT_REMOVE(API_0P(M_F(name,_remove))) \ + ,RESET(API_0P(M_F(name,_reset))) \ + ,GET_SIZE(M_F(name, _size)) \ + ,PUSH(API_0P(M_F(name,_push_back))) \ + ,POP(API_0P(M_F(name,_pop_front))) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(GET_STR, oplist)(API_0P(GET_STR(M_F(name, _get_str))),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(API_0P(PARSE_STR(M_F(name, _parse_str))),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \ + ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ + ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ + ) +#endif /********************************* INTERNAL **********************************/ diff --git a/m-dict.h b/m-dict.h index 642aaf17..f946991d 100644 --- a/m-dict.h +++ b/m-dict.h @@ -1253,6 +1253,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* Define the oplist of a dictionary NOTE: IT_REF is not exported so that the contained appears as not modifiable by algorithm.*/ +#ifndef M_USE_POOL #define M_D1CT_OPLIST_P4(name, key_oplist, value_oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -1292,6 +1293,46 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) ,M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(M_F(name, _in_serial)),) \ ,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_F(name, _equal_p)),) \ ) +#else +#define M_D1CT_OPLIST_P4(name, key_oplist, value_oplist) \ + (INIT(API_0P(M_F(name, _init))), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_INIT_KEY_VAI)), \ + SET(API_0P(M_F(name, _set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + INIT_MOVE(M_F(name, _init_move)), \ + MOVE(API_0P(M_F(name, _move))), \ + SWAP(M_F(name, _swap)), \ + RESET(API_0P(M_F(name, _reset))), \ + NAME(name), TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \ + SUBTYPE(M_F(name, _subtype_ct)), \ + EMPTY_P(M_F(name,_empty_p)), \ + IT_TYPE(M_F(name, _it_ct)), \ + IT_FIRST(M_F(name,_it)), \ + IT_SET(M_F(name, _it_set)), \ + IT_END(M_F(name,_it_end)), \ + IT_END_P(M_F(name,_end_p)), \ + IT_LAST_P(M_F(name,_last_p)), \ + IT_NEXT(M_F(name,_next)), \ + IT_CREF(M_F(name,_cref)) \ + ,KEY_TYPE(M_F(name, _key_ct)) \ + ,VALUE_TYPE(M_F(name, _value_ct)) \ + ,SET_KEY(API_0P(M_F(name, _set_at))) \ + ,GET_KEY(M_F(name, _get)) \ + ,SAFE_GET_KEY(API_0P(M_F(name, _safe_get))) \ + ,ERASE_KEY(API_0P(M_F(name, _erase))) \ + ,KEY_OPLIST(key_oplist) \ + ,VALUE_OPLIST(value_oplist) \ + ,GET_SIZE(M_F(name, _size)) \ + ,M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)(API_0P(GET_STR(M_F(name, _get_str))),) \ + ,M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)(API_0P(PARSE_STR(M_F(name, _parse_str))),) \ + ,M_IF_METHOD_BOTH(OUT_STR, key_oplist, value_oplist)(OUT_STR(M_F(name, _out_str)),) \ + ,M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \ + ,M_IF_METHOD_BOTH(OUT_SERIAL, key_oplist, value_oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \ + ,M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \ + ,M_IF_METHOD(EQUAL, value_oplist)(EQUAL(M_F(name, _equal_p)),) \ + ) +#endif /* Deferred evaluation for the definition, so that all arguments are evaluated before further expansion */ @@ -1308,6 +1349,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* Define the oplist of a set Note: IT_REF is not exported so that the contained appears as not modifiable */ +#ifndef M_USE_POOL #define M_D1CT_SET_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -1348,6 +1390,47 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \ ,EQUAL(M_F(name, _equal_p)), \ ) +#else +#define M_D1CT_SET_OPLIST_P3(name, oplist) \ + (INIT(API_0P(M_F(name, _init))), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_INIT_VAI)), \ + SET(API_0P(M_F(name, _set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + INIT_MOVE(M_F(name, _init_move)), \ + MOVE(API_0P(M_F(name, _move))), \ + SWAP(M_F(name, _swap)), \ + RESET(API_0P(M_F(name, _reset))), \ + NAME(name), TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \ + SUBTYPE(M_F(name, _subtype_ct)), \ + EMPTY_P(M_F(name,_empty_p)), \ + PUSH(API_0P(M_F(name,_push))), \ + KEY_TYPE(M_F(name, _key_ct)), \ + VALUE_TYPE(M_F(name, _key_ct)), \ + GET_KEY(M_F(name, _get)), \ + SAFE_GET_KEY(API_0P(M_F(name, _safe_get))), \ + ERASE_KEY(API_0P(M_F(name, _erase))), \ + KEY_OPLIST(oplist), \ + VALUE_OPLIST(oplist), \ + GET_SIZE(M_F(name, _size)), \ + IT_TYPE(M_F(name, _it_ct)), \ + IT_FIRST(M_F(name,_it)), \ + IT_SET(M_F(name, _it_set)), \ + IT_END(M_F(name,_it_end)), \ + IT_END_P(M_F(name,_end_p)), \ + IT_LAST_P(M_F(name,_last_p)), \ + IT_NEXT(M_F(name,_next)), \ + IT_CREF(M_F(name,_cref)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \ + ,EQUAL(M_F(name, _equal_p)), \ + ) +#endif /******************************** INTERNAL ***********************************/ diff --git a/m-list.h b/m-list.h index 1a5b01ec..11c8e818 100644 --- a/m-list.h +++ b/m-list.h @@ -101,6 +101,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a list and list_dual_push */ +#ifndef M_USE_POOL #define M_L1ST_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -144,6 +145,51 @@ ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ ) +#else +#define M_L1ST_OPLIST_P3(name, oplist) \ + (INIT(M_F(name, _init)), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_INIT_WITH_VAI)), \ + SET(API_0P(M_F(name, _set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + MOVE(API_0P(M_F(name, _move))), \ + INIT_MOVE(M_F(name, _init_move)), \ + SWAP(M_F(name, _swap)), \ + NAME(name), \ + TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)**), \ + SUBTYPE(M_F(name,_subtype_ct)), \ + EMPTY_P(M_F(name,_empty_p)), \ + IT_TYPE(M_F(name, _it_ct)), \ + IT_FIRST(M_F(name,_it)), \ + IT_END(M_F(name,_it_end)), \ + IT_SET(M_F(name,_it_set)), \ + IT_END_P(M_F(name,_end_p)), \ + IT_EQUAL_P(M_F(name,_it_equal_p)), \ + IT_LAST_P(M_F(name,_last_p)), \ + IT_NEXT(M_F(name,_next)), \ + IT_REF(M_F(name,_ref)), \ + IT_CREF(M_F(name,_cref)), \ + IT_INSERT(API_0P(M_F(name, _insert))), \ + IT_REMOVE(API_0P(M_F(name,_remove))), \ + RESET(API_0P(M_F(name,_reset))), \ + PUSH(API_0P(M_F(name,_push_back))), \ + POP(API_0P(M_F(name,_pop_back))), \ + PUSH_MOVE(API_0P(M_F(name,_push_move))), \ + POP_MOVE(API_0P(M_F(name,_pop_move))) \ + ,SPLICE_BACK(M_F(name,_splice_back)) \ + ,SPLICE_AT(M_F(name,_splice_at)) \ + ,REVERSE(M_F(name,_reverse)) \ + ,OPLIST(oplist) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \ + ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ + ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ + ) +#endif /* Deferred evaluation for the list definition, so that all arguments are evaluated before further expansion */ diff --git a/m-prioqueue.h b/m-prioqueue.h index a238ec44..77979745 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -71,6 +71,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* Define oplist of a priority queue */ +#ifndef M_USE_POOL #define M_PR1OQUEUE_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,INIT_SET(M_F(name, _init_set)) \ @@ -105,7 +106,42 @@ ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \ ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \ ) - +#else +#define M_PR1OQUEUE_OPLIST_P3(name, oplist) \ + (INIT(M_F(name, _init)) \ + ,INIT_SET(API_0P(M_F(name, _init_set))) \ + ,INIT_WITH(API_1(M_INIT_VAI)) \ + ,SET(API_0P(M_F(name, _set))) \ + ,CLEAR(API_0P(M_F(name, _clear))) \ + ,INIT_MOVE(M_F(name, _init_move)) \ + ,MOVE(API_0P(M_F(name, _move))) \ + ,SWAP(M_F(name, _swap)) \ + ,NAME(name) \ + ,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \ + ,SUBTYPE(M_F(name, _subtype_ct)) \ + ,RESET(API_0P(M_F(name,_reset))) \ + ,PUSH(API_0P(M_F(name,_push))) \ + ,POP(API_0P(M_F(name,_pop))) \ + ,OPLIST(oplist) \ + ,EMPTY_P(M_F(name, _empty_p)) \ + ,GET_SIZE(M_F(name, _size)) \ + ,IT_TYPE(M_F(name, _it_ct)) \ + ,IT_FIRST(M_F(name,_it)) \ + ,IT_END(M_F(name,_it_end)) \ + ,IT_SET(M_F(name,_it_set)) \ + ,IT_END_P(M_F(name,_end_p)) \ + ,IT_EQUAL_P(M_F(name,_it_equal_p)) \ + ,IT_LAST_P(M_F(name,_last_p)) \ + ,IT_NEXT(M_F(name,_next)) \ + ,IT_CREF(M_F(name,_cref)) \ + ,M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),) \ + ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),) \ + ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \ + ,M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),) \ + ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),) \ + ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),) \ + ) +#endif /********************************** INTERNAL *********************************/ diff --git a/m-queue.h b/m-queue.h index c1bc3c71..182a2f81 100644 --- a/m-queue.h +++ b/m-queue.h @@ -87,16 +87,16 @@ /* OPLIST definition of a buffer */ #define M_QUEU3_OPLIST_P3(name, oplist) \ - (INIT(M_F(name, _i_init)) \ - ,INIT_SET(M_F(name, _init_set)) \ - ,SET(M_F(name, _set)) \ - ,CLEAR(M_F(name, _clear)) \ + (INIT(API_0P(M_F(name, _i_init))) \ + ,INIT_SET(API_0P(M_F(name, _init_set))) \ + ,SET(API_0P(M_F(name, _set))) \ + ,CLEAR(API_0P(M_F(name, _clear))) \ ,NAME(name) \ ,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \ ,SUBTYPE(M_F(name, _subtype_ct)) \ - ,RESET(M_F(name,_reset)) \ - ,PUSH(M_F(name,_push)) \ - ,POP(M_F(name,_pop)) \ + ,RESET(API_0P(M_F(name,_reset))) \ + ,PUSH(API_0P(M_F(name,_push))) \ + ,POP(API_0P(M_F(name,_pop))) \ ,OPLIST(oplist) \ ,EMPTY_P(M_F(name, _empty_p)), \ ,FULL_P(M_F(name, _full_p)), \ diff --git a/m-rbtree.h b/m-rbtree.h index 57459a33..e8b6edef 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -71,6 +71,7 @@ /* OPLIST definition of a rbtree NOTE: IT_REF is not exported so that the container appears as not modifiable by algorithm.*/ +#ifndef M_USE_POOL #define M_RBTR33_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -110,7 +111,46 @@ M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \ M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ ) - +#else +#define M_RBTR33_OPLIST_P3(name, oplist) \ + (INIT(M_F(name, _init)), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_INIT_EMPLACE_VAI)), \ + SET(API_0P(M_F(name, _set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + INIT_MOVE(M_F(name, _init_move)), \ + MOVE(API_0P(M_F(name, _move))), \ + SWAP(M_F(name, _swap)), \ + NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \ + SUBTYPE(M_F(name, _subtype_ct)), \ + EMPTY_P(M_F(name,_empty_p)), \ + GET_SIZE(M_F(name, _size)), \ + IT_TYPE(M_F(name, _it_ct)), \ + IT_FIRST(M_F(name,_it)), \ + IT_SET(M_F(name,_it_set)), \ + IT_LAST(M_F(name,_it_last)), \ + IT_END(M_F(name,_it_end)), \ + IT_END_P(M_F(name,_end_p)), \ + IT_LAST_P(M_F(name,_last_p)), \ + IT_EQUAL_P(M_F(name,_it_equal_p)), \ + IT_NEXT(M_F(name,_next)), \ + IT_PREVIOUS(M_F(name,_previous)), \ + IT_CREF(M_F(name,_cref)), \ + IT_REMOVE(M_F(name,_remove)), \ + RESET(API_0P(M_F(name,_reset))), \ + PUSH(API_0P(M_F(name,_push))), \ + GET_MIN(M_F(name,_min)), \ + GET_MAX(M_F(name,_max)), \ + M_IF_METHOD(GET_STR, oplist)(GET_STR(API_0P(M_F(name, _get_str))),), \ + M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \ + M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),), \ + M_IF_METHOD(IN_STR, oplist)(IN_STR(API_0P(M_F(name, _in_str))),), \ + M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \ + M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \ + M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),), \ + M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ + ) +#endif /********************************** INTERNAL *********************************/ diff --git a/m-tuple.h b/m-tuple.h index 692df1b1..d9b97b51 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -746,6 +746,7 @@ namespace m_lib { ((M_LIB_ERROR(ONE_ARGUMENT_OF_M_TUPL3_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__))) /* Define the TUPLE oplist */ +#ifndef M_USE_POOL #define M_TUPL3_OPLIST_P3(name, ...) \ (M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_F(name,_init)),), \ INIT_SET(M_F(name, _init_set)), \ @@ -770,6 +771,31 @@ namespace m_lib { M_IF_METHOD_ALL(RESET, __VA_ARGS__)(RESET(M_F(name, _reset)),), \ EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \ ) +#else +#define M_TUPL3_OPLIST_P3(name, ...) \ + (M_IF_METHOD_ALL(INIT, __VA_ARGS__)(API_0P(INIT(M_F(name,_init))),), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + INIT_WITH(API_1(M_TUPL3_INIT_WITH)), \ + SET(API_0P(M_F(name,_set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \ + OPLIST( (__VA_ARGS__) ), \ + M_IF_METHOD_ALL(CMP, __VA_ARGS__)(CMP(M_F(name, _cmp)),), \ + M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_F(name, _hash)),), \ + M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_F(name, _equal_p)),), \ + M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(API_0P(M_F(name, _get_str))),), \ + M_IF_METHOD_ALL(PARSE_STR, __VA_ARGS__)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \ + M_IF_METHOD_ALL(IN_STR, __VA_ARGS__)(IN_STR(API_0P(M_F(name, _in_str))),), \ + M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_F(name, _out_str)),), \ + M_IF_METHOD_ALL(IN_SERIAL, __VA_ARGS__)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \ + M_IF_METHOD_ALL(OUT_SERIAL, __VA_ARGS__)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \ + M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_F(name, _init_move)),), \ + M_IF_METHOD_ALL(MOVE, __VA_ARGS__)(MOVE(API_0P(M_F(name, _move))),), \ + M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \ + M_IF_METHOD_ALL(RESET, __VA_ARGS__)(RESET(API_0P(M_F(name, _reset))),), \ + EMPLACE_TYPE( ( M_REDUCE2(M_TUPL3_OPLIST_SUBTYPE, M_ID, name, M_SEQ(1, M_NARGS(__VA_ARGS__))) ) ) \ + ) +#endif /* Support for EMPLACE_TYPE in OPLIST. It refers the created internal type alias */ #define M_TUPL3_OPLIST_SUBTYPE(name, num) \ diff --git a/m-variant.h b/m-variant.h index 37c20bce..506a6046 100644 --- a/m-variant.h +++ b/m-variant.h @@ -775,6 +775,7 @@ M_INLINE void \ ((M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__))) /* Define the oplist */ +#ifndef M_USE_POOL #define M_VAR1ANT_OPLIST_P3(name, ...) \ (INIT(M_F(name,_init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -799,6 +800,31 @@ M_INLINE void \ M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \ M_IF_METHOD_ALL(FIELD, __VA_ARGS__)(M_VAR1ANT_OPLIST_EMPLACE_TYPE,M_EAT)(name, __VA_ARGS__), \ ) +#else +#define M_VAR1ANT_OPLIST_P3(name, ...) \ + (INIT(M_F(name,_init)), \ + INIT_SET(API_0P(M_F(name, _init_set))), \ + SET(API_0P(M_F(name,_set))), \ + CLEAR(API_0P(M_F(name, _clear))), \ + RESET(API_0P(M_F(name, _reset))), \ + NAME(name), TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*), \ + EMPTY_P(M_F(name,_empty_p)), \ + SIZE( M_NARGS(__VA_ARGS__) ), \ + INIT_WITH( API_1(M_VAR1ANT_INIT_WITH) ), \ + M_IF_METHOD_ALL(HASH, __VA_ARGS__)(HASH(M_F(name, _hash)),), \ + M_IF_METHOD_ALL(EQUAL, __VA_ARGS__)(EQUAL(M_F(name, _equal_p)),), \ + M_IF_METHOD_ALL(GET_STR, __VA_ARGS__)(GET_STR(API_0P(M_F(name, _get_str))),), \ + M_IF_METHOD2_ALL(PARSE_STR, INIT, __VA_ARGS__)(PARSE_STR(API_0P(M_F(name, _parse_str))),), \ + M_IF_METHOD2_ALL(IN_STR, INIT, __VA_ARGS__)(IN_STR(API_0P(M_F(name, _in_str))),), \ + M_IF_METHOD_ALL(OUT_STR, __VA_ARGS__)(OUT_STR(M_F(name, _out_str)),), \ + M_IF_METHOD2_ALL(IN_SERIAL, INIT, __VA_ARGS__)(IN_SERIAL(API_0P(M_F(name, _in_serial))),), \ + M_IF_METHOD_ALL(OUT_SERIAL, __VA_ARGS__)(OUT_SERIAL(API_0P(M_F(name, _out_serial))),), \ + M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(INIT_MOVE(M_F(name, _init_move)),), \ + M_IF_METHOD_ALL(INIT_MOVE, __VA_ARGS__)(MOVE(API_0P(M_F(name, _move))),), \ + M_IF_METHOD_ALL(SWAP, __VA_ARGS__)(SWAP(M_F(name, _swap)),), \ + M_IF_METHOD_ALL(FIELD, __VA_ARGS__)(M_VAR1ANT_OPLIST_EMPLACE_TYPE,M_EAT)(name, __VA_ARGS__), \ + ) +#endif /* Expand to an EMPLACE_TYPE compatible with OPLIST definition (Use M_REDUCE2 which is already used by M_IF_METHOD_ALL) From 93a1be616d42720b486f31ee6023ad44176fab91 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 09:58:44 +0200 Subject: [PATCH 61/91] Rename parameter pool to context --- README.md | 2 +- doc/API.txt | 2 +- example/ex11-use-pool.c | 17 ++++++--- m-array.h | 12 +++---- m-bitset.h | 4 +-- m-bptree.h | 14 ++++---- m-bstring.h | 2 +- m-buffer.h | 44 +++++++++++------------ m-core.h | 77 ++++++++++++++++++++--------------------- m-deque.h | 12 +++---- m-dict.h | 6 ++-- m-list.h | 2 +- m-prioqueue.h | 2 +- m-queue.h | 10 +++--- m-rbtree.h | 2 +- m-serial-bin.h | 26 +++++++------- m-serial-json.h | 32 ++++++++--------- m-shared-ptr.h | 60 ++++++++++++++++---------------- m-snapshot.h | 10 +++--- m-string.h | 8 ++--- m-tree.h | 4 +-- m-tuple.h | 28 +++++++-------- m-variant.h | 12 +++---- m-worker.h | 18 +++++----- 24 files changed, 206 insertions(+), 200 deletions(-) diff --git a/README.md b/README.md index 165aefc3..c3db0303 100644 --- a/README.md +++ b/README.md @@ -9178,7 +9178,7 @@ _________________ ### M-MEMPOOL > [!NOTE] -> This header is obsolete: `M_USE_POOL` should be used instead to pass custom memory context to containers. +> This header is obsolete: `M_USE_CONTEXT` should be used instead to pass custom memory context to containers. This header is for generating specialized and optimized memory pools: it will generate specialized functions to allocate and free only one kind of an object. diff --git a/doc/API.txt b/doc/API.txt index b7dc9a3e..4fe94bd1 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -98,7 +98,7 @@ V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible: * m-buffer: Remove buffer blocking policy BUFFER_BLOCKING (default policy is now forced) and thread safe (_push / _pop returns now void) * m-buffer push / pop no longer return a bool (it was undocumented) * Remove MEMPOOL support from list & R/B tree - * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_POOL interface to pass local pool context. + * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_CONTEXT interface to pass local pool context. * M*LIB becomes stricter for INIT_MOVE: Emulation layer using CLEAR+INIT_SET when missing INIT_MOVE operator has been removed: either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled. If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method. (It's because supporting emulation layer with new memory context parameter was complicated) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 023ebdd4..3fa52735 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -1,7 +1,9 @@ #include +// Define the memory context. typedef int *context_t; +// Define the realloc / free that accepts the memory context. static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context) { (void) context; @@ -17,13 +19,18 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context) free(ptr); } -# define M_USE_POOL context_t -# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_pool) -# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (*ptr), m_pool) +// Request M*LIB to generate functions accepting a memory context parameter that will be passed to the memory functions +# define M_USE_CONTEXT context_t -# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_pool) -# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_pool) +// Overloaded memory functions to use the custom ones. +// m_context is the name of the memory context parameter +# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context) +# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (*ptr), m_context) +# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context) +# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context) + +// Now we can include M*LIB functions. #include "m-string.h" #include "m-bitset.h" #include "m-bstring.h" diff --git a/m-array.h b/m-array.h index e723add9..4c2bd6e6 100644 --- a/m-array.h +++ b/m-array.h @@ -80,7 +80,7 @@ /* OPLIST definition of a dynamic array */ /* FIXME: Do we want to export some methods as they are slow and are not fit to be used for building other methods (like _it_remove)? */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_ARRA4_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,M_IF_METHOD2(INIT_SET,SET, oplist)(INIT_SET(M_F(name, _init_set)),) \ @@ -270,7 +270,7 @@ M_P(void, name, _reset, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ for(size_t i = 0; i < v->size; i++) \ M_CALL_CLEAR(oplist, v->ptr[i]); \ v->size = 0; \ @@ -351,7 +351,7 @@ M_P(void, name, _set_at, array_t v, size_t i, type const x) \ { \ M_ARRA4_CONTRACT(v); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ M_CALL_SET(oplist, v->ptr[i], x); \ @@ -543,7 +543,7 @@ M_P(void, name, _pop_back, type *dest, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (v->ptr != NULL); \ M_ASSERT_INDEX(0, v->size); \ v->size--; \ @@ -602,7 +602,7 @@ M_P(void, name, _pop_at, type *dest, array_t v, size_t i) \ { \ M_ARRA4_CONTRACT(v); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ if (dest) \ @@ -661,7 +661,7 @@ M_P(void, name, _remove_v, array_t v, size_t i, size_t j) \ { \ M_ARRA4_CONTRACT(v); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(i < j && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ M_ASSERT_INDEX(j, v->size+1); \ diff --git a/m-bitset.h b/m-bitset.h index dd81ea97..482d67d7 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -834,7 +834,7 @@ m_bitset_popcount(const m_bitset_t set) } /* Oplist for a bitset */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_BITSET_OPLIST \ (INIT(m_bitset_init) \ ,INIT_SET(m_bitset_init_set) \ @@ -907,7 +907,7 @@ m_bitset_popcount(const m_bitset_t set) #endif /* Register the OPLIST as a global one */ -#ifdef M_USE_POOL +#ifdef M_USE_CONTEXT #define M_OPL_m_bitset_t() M_BITSET_POOL_OPLIST #else #define M_OPL_m_bitset_t() M_BITSET_OPLIST diff --git a/m-bptree.h b/m-bptree.h index 93ea8fb7..8bf07115 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -156,7 +156,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a b+tree (global tree) */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_BPTR33_KEY_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -239,7 +239,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_BPTREE_OPLIST_IS_NOT_AN_OPLIST, name, key_oplist, value_oplist))) /* Final definition of the oplist (associative array) */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_BPTR33_OPLIST2_P4(name, key_oplist, value_oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -706,7 +706,7 @@ M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \ { \ M_ASSERT (M_F(name, _is_leaf)(n)); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ int i, num = M_F(name, _get_num)(n); \ M_ASSERT (num <= N); \ /* Search for the key in the node n (a leaf) for insertion */ \ @@ -737,7 +737,7 @@ M_P(int, name, _i_search_and_insert_in_node, node_t n, node_t l, key_t key) \ { \ M_ASSERT (!M_F(name, _is_leaf)(n)); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ int i, num = M_F(name, _get_num)(n); \ M_ASSERT (num <= N); \ /* Search for the key in the node n (not a leaf) for insertion */ \ @@ -869,7 +869,7 @@ M_P(int, name, _i_search_and_remove_in_leaf, node_t n, key_t const key) \ { \ M_ASSERT(M_F(name, _is_leaf)(n)); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ const int num = M_F(name, _get_num)(n); \ for(int i = 0; i < num; i++) { \ const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ @@ -890,7 +890,7 @@ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ node_t left = parent->kind.node[k]; \ node_t right = parent->kind.node[k+1]; \ M_ASSERT (left != NULL && right != NULL); \ @@ -926,7 +926,7 @@ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ node_t left = parent->kind.node[k]; \ node_t right = parent->kind.node[k+1]; \ M_ASSERT (left != NULL && right != NULL); \ diff --git a/m-bstring.h b/m-bstring.h index 0e13630a..60f30059 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -534,7 +534,7 @@ M_P(m_serial_return_code_t, m_bstring, _in_serial, m_bstring_t v, m_serial_read_ } /* Define the OPLIST of a BYTE STRING */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_BSTRING_OPLIST \ (INIT(m_bstring_init),INIT_SET(m_bstring_init_set), SET(m_bstring_set), \ INIT_MOVE(m_bstring_init_move), MOVE(m_bstring_move), \ diff --git a/m-buffer.h b/m-buffer.h index 7486286a..7398fec8 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -221,7 +221,7 @@ typedef enum { M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_ASSERT(size <= UINT_MAX); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_BUFF3R_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = size); \ v->idx_prod = v->idx_cons = v->overwrite = 0; \ atomic_init (&v->number[0], 0U); \ @@ -256,7 +256,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _i_clear_obj, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \ M_CALL_CLEAR(oplist, v->data[i].x); \ @@ -280,7 +280,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _clear, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name,_i_clear_obj)(v); \ M_BUFF3R_IF_CTE_SIZE(m_size)( , \ M_CALL_FREE(oplist, M_F(name, _el_ct), v->data, M_BUFF3R_SIZE(m_size)); \ @@ -296,7 +296,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _reset, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ m_mutex_lock(v->mutexPush); \ m_mutex_lock(v->mutexPop); \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ @@ -314,7 +314,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ \ M_N(void, name, _init_set, buffer_t dest, const buffer_t src) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ vu.cptr = src; \ @@ -354,7 +354,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ \ M_N(void, name, _set, buffer_t dest, const buffer_t src) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ vu.cptr = src; \ @@ -449,7 +449,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push_blocking, buffer_t v, type const data, bool blocking) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ /* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \ m_mutex_lock(v->mutexPush); \ while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \ @@ -523,7 +523,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ M_ASSERT (data != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ /* consumer lock (mutex lock performs an acquire memory barrier) */ \ m_mutex_lock(v->mutexPop); \ while (M_F(name, _empty_p)(v)) { \ @@ -714,7 +714,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int idx = atomic_load_explicit(&table->ProdIdx, \ memory_order_relaxed); \ const unsigned int i = idx & (table->size -1); \ @@ -749,7 +749,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \ memory_order_relaxed); \ const unsigned int i = (iC & (table->size -1)); \ @@ -779,7 +779,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_ASSERT (buffer != NULL); \ M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \ M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ atomic_init(&buffer->ProdIdx, (unsigned int) size); \ atomic_init(&buffer->ConsoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ @@ -799,7 +799,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_MPMC_CONTRACT(buffer); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < buffer->size; j++) { \ M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ @@ -939,7 +939,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -960,7 +960,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push_move, buffer_t table, type *x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -982,7 +982,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1005,7 +1005,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (x != NULL); \ M_ASSERT (n <= table->size); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1031,7 +1031,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ M_ASSERT (n <= table->size); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1055,7 +1055,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _push_force, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1119,7 +1119,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_ASSERT (buffer != NULL); \ M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \ M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ atomic_init(&buffer->prodIdx, (unsigned int) size); \ atomic_init(&buffer->consoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ @@ -1138,7 +1138,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_SPSC_CONTRACT(buffer); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < buffer->size; j++) { \ M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ @@ -1193,12 +1193,12 @@ M_N(void, name, _init, buffer_t v, size_t size) \ ,GET_SIZE(M_F(name, _size)) \ ) -/* Same as M_EMPLACE_QUEUE_GENE but use M_GLOBAL_POOL */ +/* Same as M_EMPLACE_QUEUE_GENE but use M_GLOBAL_CONTEXT */ #define M_BUFF3R_EMPLACE_QUEUE_GENE(name, name_t, function_name, oplist, init_func, exp_emplace_type) \ M_N(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_GET_TYPE oplist data; \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \ M_F(name, _push)(v, data); \ M_CALL_CLEAR(oplist, data); \ diff --git a/m-core.h b/m-core.h index 5000112c..b07757b1 100644 --- a/m-core.h +++ b/m-core.h @@ -385,7 +385,7 @@ M_BEGIN_PROTECTED_CODE * It returns NULL in case of memory allocation failure. * void M_MEMORY_FREE(type, ptr, o): Free the object associated to the array of type 'type' at base 'ptr' of size 'o'. * By default, old size do nothing. - * Can use local optional named parameter "m_pool" which is defined by the called of the macro if M_USE_POOL is defined. + * Can use local optional named parameter "m_context" which is defined by the called of the macro if M_USE_CONTEXT is defined. */ #ifndef M_MEMORY_REALLOC #ifdef __cplusplus @@ -412,59 +412,60 @@ M_BEGIN_PROTECTED_CODE #endif +// Default global memory context is to consider the global context as '0' if it is not defined. +#ifndef M_USE_GLOBAL_CONTEXT +#define M_USE_GLOBAL_CONTEXT(varname) M_USE_CONTEXT varname = { 0 } +#endif + /* In order to support local context for memory functions, the prototypes and usages of some functions are modified - * so that they can accept a first argument 'm_pool' which is the memory context parameter. + * so that they can accept a first argument 'm_context' which is the memory context parameter. * * For some functions, there is no meaning of a local memory context parameter: * for all data shared between threads, only a global memory context has any meaning. * For such cases, the memory context parameter is globally requested to the user through M_USE_GLOBAL_POOL or set to 0. * - * This is controlled through M_USE_POOL parameter that define the type of the memory context parameter + * This is controlled through M_USE_CONTEXT parameter that define the type of the memory context parameter * to be used globally for all M*LIB. There is no possibility to support only some containers and not others. * * Several macros are defined **globally** to support such features and being internally used by M*LIB containers. * They expand to nothing if the memory context parameter is not requested: - * * M_P_EXPAND: expand to the first parameter 'm_pool' of type M_USE_POOL for a function that may use memory context. + * * M_P_EXPAND: expand to the first parameter 'm_context' of type M_USE_CONTEXT for a function that may use memory context. * * M_P_EXPAND_void: same but assume that there is no argument in the initial function. - * * M_R_EXPAND: expand to the first parameter 'm_pool' (followed by a comma) + * * M_R_EXPAND: expand to the first parameter 'm_context' (followed by a comma) * * M_R_EXPAND_void: same but assume that there is no argument - * * M_R: add the parameter m_pool to the function call if needed, - * * M_P: define the prototype of a function that may have the parameter m_pool. - * * M_N: define the prototype of a function that don't need the parameter m_pool. - * * M_ASSERT_POOL: avoid warning of unused m_pool argument - * * M_GLOBAL_POOL: define m_pool to zero, meaning it is a global memory context. + * * M_R: add the parameter m_context to the function call if needed, + * * M_P: define the prototype of a function that may have the parameter m_context. + * * M_N: define the prototype of a function that don't need the parameter m_context. + * * M_UNUSED_CONTEXT: avoid warning of unused m_context argument + * * M_GLOBAL_CONTEXT: define m_context to zero, meaning it is a global memory context. */ -#ifndef M_USE_POOL -// Memory pool parameter not used for memory function. Stub it with 0 as it won't be used (global definition). +#ifndef M_USE_CONTEXT +// Memory context parameter not used for memory function. # define M_P_EXPAND # define M_P_EXPAND_void void # define M_R_EXPAND # define M_R_EXPAND_void # define M_R -# define M_ASSERT_POOL() -# define M_GLOBAL_POOL() +# define M_UNUSED_CONTEXT() +# define M_GLOBAL_CONTEXT() #else -// Default global value is to set to 0 the global pool. -#ifndef M_USE_GLOBAL_POOL -#define M_USE_GLOBAL_POOL(x) M_USE_POOL x = { 0 } -#endif -// Memory pool parameter is used for function using memory. (local definition to the function). +// Memory context parameter is used for function using memory. (local definition to the function). // Expand to a prototype to a function that may not trigger exception -# define M_P_EXPAND M_USE_POOL m_pool, -# define M_P_EXPAND_void M_USE_POOL m_pool -# define M_R_EXPAND m_pool , -# define M_R_EXPAND_void m_pool -# define M_R(...) (m_pool, __VA_ARGS__) -# define M_ASSERT_POOL() (void) m_pool -# define M_GLOBAL_POOL() M_USE_GLOBAL_POOL(m_pool); (void) m_pool +# define M_P_EXPAND M_USE_CONTEXT m_context, +# define M_P_EXPAND_void M_USE_CONTEXT m_context +# define M_R_EXPAND m_context , +# define M_R_EXPAND_void m_context +# define M_R(...) (m_context, __VA_ARGS__) +# define M_UNUSED_CONTEXT() (void) m_context +# define M_GLOBAL_CONTEXT() M_USE_GLOBAL_CONTEXT(m_context); (void) m_context #endif // M_P: Expand to a prototype of a function that may trigger exception / accept memory context // M_N: Expand to a prototype of a function that may not trigger exception or accept memory context -// If not user M_F, no overloaded M_INLINE and no M_P_EXPAND, -// simplify definition of M_P/M_N to provide faster compile time. +// If not user defined M_F or memory context, no overloaded M_INLINE, +// simplify the definition of M_P/M_N to provide faster compile time. // (faster build: 0.54s instead of 0.80s in extreme expanding) -#if !defined(M_USE_POOL) && !defined(M_F) && !defined(M_USE_FINE_GRAINED_LINKAGE) && !defined(M_USE_DEF) && !defined(M_USE_DECL) +#if !defined(M_USE_CONTEXT) && !defined(M_F) && !defined(M_USE_FINE_GRAINED_LINKAGE) && !defined(M_USE_DEF) && !defined(M_USE_DECL) # define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) # define M_N(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__) #else @@ -472,8 +473,6 @@ M_BEGIN_PROTECTED_CODE # define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__) #endif -// TODO: 'pool' seems not the right term. Rename 'pool' into 'localmem' ? 'arena'? memcontext? context? -// Rename to M_USE_MEMORY_CONTEXT? M_USE_MEMCONTEXT /************************************************************/ /********************* ERROR handling **********************/ @@ -3730,14 +3729,14 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_OPLAPI_5(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, __VA_ARGS__) #define M_OPLAPI_6(method, oplist, x, ...) , M_DELAY3(method)(&x, &__VA_ARGS__) #define M_OPLAPI_7(method, oplist, x, ...) , M_DELAY3(method)(oplist, &x, &__VA_ARGS__) -#define M_OPLAPI_0P(method, oplist, ...) , M_DELAY3(method)(m_pool, __VA_ARGS__) -#define M_OPLAPI_1P(method, oplist, ...) , M_DELAY3(method)(oplist, m_pool, __VA_ARGS__) -#define M_OPLAPI_2P(method, oplist, ...) , M_DELAY3(method)(m_pool, & __VA_ARGS__) -#define M_OPLAPI_3P(method, oplist, ...) , M_DELAY3(method)(oplist, m_pool, &__VA_ARGS__) -#define M_OPLAPI_4P(method, oplist, x, ...) , x = M_DELAY3(method)(m_pool, __VA_ARGS__) -#define M_OPLAPI_5P(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, m_pool, __VA_ARGS__) -#define M_OPLAPI_6P(method, oplist, x, ...) , M_DELAY3(method)(m_pool, &x, &__VA_ARGS__) -#define M_OPLAPI_7P(method, oplist, x, ...) , M_DELAY3(method)(oplist, m_pool, &x, &__VA_ARGS__) +#define M_OPLAPI_0P(method, oplist, ...) , M_DELAY3(method)(m_context, __VA_ARGS__) +#define M_OPLAPI_1P(method, oplist, ...) , M_DELAY3(method)(oplist, m_context, __VA_ARGS__) +#define M_OPLAPI_2P(method, oplist, ...) , M_DELAY3(method)(m_context, & __VA_ARGS__) +#define M_OPLAPI_3P(method, oplist, ...) , M_DELAY3(method)(oplist, m_context, &__VA_ARGS__) +#define M_OPLAPI_4P(method, oplist, x, ...) , x = M_DELAY3(method)(m_context, __VA_ARGS__) +#define M_OPLAPI_5P(method, oplist, x, ...) , x = M_DELAY3(method)(oplist, m_context, __VA_ARGS__) +#define M_OPLAPI_6P(method, oplist, x, ...) , M_DELAY3(method)(m_context, &x, &__VA_ARGS__) +#define M_OPLAPI_7P(method, oplist, x, ...) , M_DELAY3(method)(oplist, m_context, &x, &__VA_ARGS__) /* API transformation support for indirection */ #define M_OPLAPI_INDIRECT_0 M_OPLAPI_ERROR #define M_OPLAPI_INDIRECT_API_0(...) M_OPLAPI_0 diff --git a/m-deque.h b/m-deque.h index b1d41390..9cbf9ad0 100644 --- a/m-deque.h +++ b/m-deque.h @@ -103,7 +103,7 @@ M_EMPLACE_QUEUE_DEF(name, deque_t, _emplace_front, oplist, M_D3QUE_EMPLACE_FRONT_DEF) // OPLIST for the node deletion -#ifdef M_USE_POOL +#ifdef M_USE_CONTEXT #define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API_0P(M_F(name, _node_list_i_del)))) #else #define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(M_F(name, _node_list_i_del))) @@ -222,7 +222,7 @@ M_P(void, name, _reset, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ node_t *min_node = NULL; \ for(node_t *n = d->front->node; \ n != NULL ; \ @@ -365,7 +365,7 @@ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT(d->count > 0); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ node_t *n = d->back->node; \ size_t index = d->back->index; \ index --; \ @@ -407,7 +407,7 @@ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT(d->count > 0); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ node_t *n = d->front->node; \ size_t index = d->front->index; \ if (ptr != NULL) \ @@ -825,7 +825,7 @@ M_P(void, name, _set_at, deque_t d, size_t key, type const x) \ { \ M_D3QU3_CONTRACT(d); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT_INDEX (key, d->count); \ type *p = M_F(name, _get)(d, key); \ M_CALL_SET(oplist, *p, x); \ @@ -1057,7 +1057,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_DEQUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a deque */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_D3QU3_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,INIT_SET(M_F(name, _init_set)) \ diff --git a/m-dict.h b/m-dict.h index f946991d..50ecae78 100644 --- a/m-dict.h +++ b/m-dict.h @@ -1253,7 +1253,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* Define the oplist of a dictionary NOTE: IT_REF is not exported so that the contained appears as not modifiable by algorithm.*/ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_D1CT_OPLIST_P4(name, key_oplist, value_oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -1349,7 +1349,7 @@ M_ARRAY_DEF(m_array_index, m_indexhash_t, M_POD_OPLIST) /* Define the oplist of a set Note: IT_REF is not exported so that the contained appears as not modifiable */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_D1CT_SET_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ @@ -2078,7 +2078,7 @@ enum m_d1ct_oa_element_e { M_P(void, name, _bulk_get, unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type const key[M_VLA(n)], value_type def) \ { \ M_D1CT_OA_CONTRACT (dict); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ size_t h[M_USE_MAX_PREFETCH]; \ M_F(name, _pair_ct) *data = dict->data; \ const size_t mask = dict->mask; \ diff --git a/m-list.h b/m-list.h index 11c8e818..250c1d66 100644 --- a/m-list.h +++ b/m-list.h @@ -101,7 +101,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_LIST_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* OPLIST definition of a list and list_dual_push */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_L1ST_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ diff --git a/m-prioqueue.h b/m-prioqueue.h index 77979745..75b635a1 100644 --- a/m-prioqueue.h +++ b/m-prioqueue.h @@ -71,7 +71,7 @@ ((M_LIB_ERROR(ARGUMENT_OF_PRIOQUEUE_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) /* Define oplist of a priority queue */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_PR1OQUEUE_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)) \ ,INIT_SET(M_F(name, _init_set)) \ diff --git a/m-queue.h b/m-queue.h index 182a2f81..1353b285 100644 --- a/m-queue.h +++ b/m-queue.h @@ -168,7 +168,7 @@ M_P(void, name, _init, queue_t v, size_t size) \ { \ M_ASSERT(size <= UINT_MAX); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_QUEU3_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = (unsigned) size); \ v->idx_prod = v->idx_cons = v->number = 0; \ \ @@ -194,7 +194,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ M_P(void, name, _i_clear_obj, queue_t v) \ { \ M_QUEU3_CONTRACT(v,m_size); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ for(size_t i = 0; i < M_QUEU3_SIZE(v, m_size); i++) { \ M_CALL_CLEAR(oplist, v->data[i]); \ } \ @@ -205,7 +205,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ M_P(void, name, _clear, queue_t v) \ { \ M_QUEU3_CONTRACT(v,m_size); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_F(name,_i_clear_obj)M_R(v); \ M_QUEU3_IF_CTE_SIZE(m_size)( , \ M_CALL_FREE(oplist, type, v->data, M_QUEU3_SIZE(v, m_size)); \ @@ -264,7 +264,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ M_P(bool, name, _push, queue_t v, type const data) \ { \ M_QUEU3_CONTRACT(v,m_size); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ if (M_F(name, _full_p)(v)) \ return false; \ \ @@ -284,7 +284,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ { \ M_QUEU3_CONTRACT(v,m_size); \ M_ASSERT (data != NULL); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ if (M_F(name, _empty_p)(v)) \ return false; \ \ diff --git a/m-rbtree.h b/m-rbtree.h index e8b6edef..99299972 100644 --- a/m-rbtree.h +++ b/m-rbtree.h @@ -71,7 +71,7 @@ /* OPLIST definition of a rbtree NOTE: IT_REF is not exported so that the container appears as not modifiable by algorithm.*/ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_RBTR33_OPLIST_P3(name, oplist) \ (INIT(M_F(name, _init)), \ INIT_SET(M_F(name, _init_set)), \ diff --git a/m-serial-bin.h b/m-serial-bin.h index ad8b242d..fb6ef26c 100644 --- a/m-serial-bin.h +++ b/m-serial-bin.h @@ -113,7 +113,7 @@ m_ser1al_bin_read_size(FILE *f, size_t *size) Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_boolean, m_serial_write_t serial, const bool data) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); FILE *f = (FILE *)serial->data[0].p; size_t n = fwrite (M_ASSIGN_CAST(const void*, &data), sizeof (bool), 1, f); return n == 1 ? M_SERIAL_OK_DONE : m_core_serial_fail(); @@ -123,7 +123,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_boolean, m_serial_write_t seria Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_integer, m_serial_write_t serial,const long long data, const size_t size_of_type) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); size_t n; FILE *f = (FILE *)serial->data[0].p; @@ -148,7 +148,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_integer, m_serial_write_t seria Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); size_t n; FILE *f = (FILE *)serial->data[0].p; @@ -170,7 +170,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_float, m_serial_write_t serial, Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_string, m_serial_write_t serial, const char data[], size_t length) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); M_ASSERT_SLOW(length == strlen(data) ); FILE *f = (FILE *)serial->data[0].p; M_ASSERT(f != NULL && data != NULL); @@ -190,7 +190,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_string, m_serial_write_t serial Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; //Unused if (number_of_elements == (size_t)-1) return M_SERIAL_FAIL_RETRY; FILE *f = (FILE *)serial->data[0].p; @@ -202,7 +202,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_start, m_serial_local_t l Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_next, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // Unused (void) serial; // Unused return M_SERIAL_OK_CONTINUE; @@ -212,7 +212,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_next, m_serial_local_t lo Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // Unused (void) serial; // Unused return M_SERIAL_OK_CONTINUE; @@ -222,7 +222,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_array_end, m_serial_local_t loc Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_map_value, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_CONTINUE; @@ -234,7 +234,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_map_value, m_serial_local_t loc Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_CONTINUE; @@ -244,7 +244,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_start, m_serial_local_t l Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) serial; (void) field_name; @@ -257,7 +257,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_id, m_serial_local_t loca Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_DONE; @@ -270,7 +270,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_tuple_end, m_serial_local_t loc Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) field_name; (void) max; (void) local; @@ -283,7 +283,7 @@ M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_start, m_serial_local_t Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_bin, _write_variant_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) serial; return M_SERIAL_OK_DONE; diff --git a/m-serial-json.h b/m-serial-json.h index 557b9e82..f773ba21 100644 --- a/m-serial-json.h +++ b/m-serial-json.h @@ -38,7 +38,7 @@ M_BEGIN_PROTECTED_CODE Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_boolean, m_serial_write_t serial, const bool data) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "%s", data ? "true" : "false"); return n > 0 ? M_SERIAL_OK_DONE : m_core_serial_fail(); @@ -48,7 +48,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_boolean, m_serial_write_t seri Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_integer, m_serial_write_t serial,const long long data, const size_t size_of_type) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) size_of_type; // Ignored FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "%lld", data); @@ -59,7 +59,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_integer, m_serial_write_t seri Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_float, m_serial_write_t serial, const long double data, const size_t size_of_type) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) size_of_type; // Ignored FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "%Lf", data); @@ -70,7 +70,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_float, m_serial_write_t serial Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_string, m_serial_write_t serial, const char data[], size_t length) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); M_ASSERT(length == (m_str1ng_size_t) length); M_ASSERT_SLOW(length == strlen(data) ); FILE *f = (FILE *)serial->data[0].p; @@ -94,7 +94,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_string, m_serial_write_t seria Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_array_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) number_of_elements; // Ignored FILE *f = (FILE *)serial->data[0].p; @@ -106,7 +106,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_array_start, m_serial_local_t Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_array_next, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, ","); @@ -117,7 +117,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_array_next, m_serial_local_t l Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_array_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "]"); @@ -132,7 +132,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_array_end, m_serial_local_t lo Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_start, m_serial_local_t local, m_serial_write_t serial, const size_t number_of_elements) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) number_of_elements; // Ignored FILE *f = (FILE *)serial->data[0].p; @@ -144,7 +144,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_start, m_serial_local_t lo Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_value, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, ":"); @@ -155,7 +155,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_value, m_serial_local_t lo Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_next, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, ","); @@ -166,7 +166,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_next, m_serial_local_t loc Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "}"); @@ -179,7 +179,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_map_end, m_serial_local_t loca Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_start, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "{"); @@ -190,7 +190,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_start, m_serial_local_t Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_id, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) max; // Ignored FILE *f = (FILE *)serial->data[0].p; @@ -202,7 +202,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_id, m_serial_local_t loc Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "}"); @@ -216,7 +216,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_tuple_end, m_serial_local_t lo Return M_SERIAL_OK_CONTINUE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_start, m_serial_local_t local, m_serial_write_t serial, const char *const field_name[], const int max, const int index) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used (void) max; // argument not used FILE *f = (FILE *)serial->data[0].p; @@ -235,7 +235,7 @@ M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_start, m_serial_local_ Return M_SERIAL_OK_DONE if it succeeds, M_SERIAL_FAIL otherwise */ M_P(m_serial_return_code_t, m_ser1al_json, _write_variant_end, m_serial_local_t local, m_serial_write_t serial) { - M_ASSERT_POOL(); + M_UNUSED_CONTEXT(); (void) local; // argument not used FILE *f = (FILE *)serial->data[0].p; int n = fprintf(f, "}"); diff --git a/m-shared-ptr.h b/m-shared-ptr.h index ff80a35c..562d60ea 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -613,7 +613,7 @@ extern shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type M_IF_METHOD(INIT, oplist)( \ fattr shared_t *M_F(name, _new)(void) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -629,7 +629,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ fattr shared_t *M_F(name, _clone)(const shared_t *src) \ { \ M_ASSERT(src != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -646,7 +646,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ fattr shared_t *M_F(name, _new_from)(type const src); ) \ fattr shared_t *M_F(name, _new_from)(type const src) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -663,7 +663,7 @@ M_IF_METHOD(SET, oplist)( \ { \ M_ASSERT(out != NULL); \ M_ASSERT(src != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (M_UNLIKELY (out == src)) return; \ M_F(name, _write_read_lock)(out, src); \ M_ON_EXCEPTION( M_F(name, _write_read_unlock)(out, src) ) \ @@ -682,7 +682,7 @@ fattr shared_t *M_F(name, _acquire)(shared_t *out) \ \ fattr void M_F(name, _release)(shared_t *out) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (out != NULL && M_C3(m_shar3d_, name, _dec_owner)(out)) { \ M_CALL_CLEAR(oplist, out->data); \ M_F(name, _clear_lock)(out); \ @@ -706,7 +706,7 @@ M_EMPLACE_QUEUE_DEF( (name, fattr), shared_t, M_F(name, _make), oplist, M_SHAR3D #define M_SHAR3D_PTR_DEF_BASIC_MAKE(name_attr, shared_t, function_name, oplist, init_func, exp_emplace_type) \ M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type)) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -753,7 +753,7 @@ M_IF_METHOD(RESET, oplist)( \ fattr void M_F(name, _reset)(shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ /* RESET cannot throw exception */ \ M_CALL_RESET(oplist, out->data); \ @@ -866,7 +866,7 @@ M_IF_METHOD(ADD, oplist)( \ fattr void M_F(name, _add)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_ADD(oplist, out->data, src1->data, src2->data); \ @@ -878,7 +878,7 @@ M_IF_METHOD(SUB, oplist)( \ fattr void M_F(name, _sub)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_SUB(oplist, out->data, src1->data, src2->data); \ @@ -890,7 +890,7 @@ M_IF_METHOD(MUL, oplist)( \ fattr void M_F(name, _mul)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_MUL(oplist, out->data, src1->data, src2->data); \ @@ -902,7 +902,7 @@ M_IF_METHOD(DIV, oplist)( \ fattr void M_F(name, _div)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_DIV(oplist, out->data, src1->data, src2->data); \ @@ -914,7 +914,7 @@ M_IF_METHOD(SPLICE, oplist)( \ fattr void M_F(name, _splice)(shared_t *out, shared_t *src) \ { \ M_ASSERT(out != NULL && src != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (out < src) { \ M_F(name, _write_lock)(out); \ M_F(name, _write_lock)(src); \ @@ -944,7 +944,7 @@ M_IF_METHOD(GET_KEY, oplist)( \ { \ M_ASSERT (out != NULL); \ M_ASSERT (value != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _read_lock)(out); \ /* No exception */ \ value_type *p = M_CALL_GET_KEY(oplist, out->data, key); \ @@ -961,7 +961,7 @@ M_IF_METHOD(SAFE_GET_KEY, oplist)( \ { \ M_ASSERT (out != NULL); \ M_ASSERT (value != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) { \ value_type *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \ @@ -977,7 +977,7 @@ M_IF_METHOD(SET_KEY, oplist)( \ fattr void M_F(name, _set_at)(shared_t *out, key_type const key, value_type const value) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ M_CALL_SET_KEY(oplist, out->data, key, value); \ @@ -990,7 +990,7 @@ M_IF_METHOD(ERASE_KEY, oplist)( \ fattr bool M_F(name, _erase)(shared_t *out, key_type const key) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ /* No exception */ \ bool r = M_CALL_ERASE_KEY(oplist, out->data, key); \ @@ -1021,7 +1021,7 @@ M_IF_METHOD(PUSH, oplist)( \ fattr void M_F(name, _push)(shared_t *out, sub_type const value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1038,7 +1038,7 @@ M_IF_METHOD(PUSH, oplist)( \ fattr bool M_F(name, _try_push)(shared_t *out, sub_type const value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1055,7 +1055,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr void M_F(name, _push_move)(shared_t *out, sub_type *value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1072,7 +1072,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr bool M_F(name, _try_push_move)(shared_t *out, sub_type *value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1094,7 +1094,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1117,7 +1117,7 @@ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_ty fattr bool function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1146,7 +1146,7 @@ M_IF_METHOD(POP, oplist)( \ fattr void M_F(name, _pop)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1163,7 +1163,7 @@ M_IF_METHOD(POP, oplist)( \ fattr bool M_F(name, _try_pop)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1180,7 +1180,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \ fattr void M_F(name, _pop_move)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1197,7 +1197,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \ fattr bool M_F(name, _try_pop_move)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1326,7 +1326,7 @@ M_IF_METHOD(IN_STR, oplist)( \ fattr bool M_F(name, _in_str)(shared_t *out, FILE *file) \ { \ M_ASSERT (out != NULL && file != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ m_volatile bool r = false; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ @@ -1341,7 +1341,7 @@ M_IF_METHOD(GET_STR, oplist)( \ fattr void M_F(name, _get_str)(m_string_t str, const shared_t *out, bool append) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _read_lock)(out); \ M_ON_EXCEPTION( M_F(name, _read_unlock)(out) ) \ M_CALL_GET_STR(oplist, str, out->data, append); \ @@ -1352,7 +1352,7 @@ M_IF_METHOD(PARSE_STR, oplist)( \ fattr bool M_F(name, _parse_str)(shared_t *out, const char str[], const char **endp) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ m_volatile bool r = false; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ @@ -1379,7 +1379,7 @@ M_IF_METHOD(IN_SERIAL, oplist)( \ fattr m_serial_return_code_t M_F(name, _in_serial)(shared_t *out, m_serial_read_t serial) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ m_volatile m_serial_return_code_t r = M_SERIAL_FAIL; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ diff --git a/m-snapshot.h b/m-snapshot.h index 4b82afe3..37d834d9 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -201,7 +201,7 @@ M_BEGIN_PROTECTED_CODE M_P(void, name, _init, snapshot_t snap) \ { \ M_ASSERT(snap != NULL); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_INIT(oplist, snap->data[i].x); \ } \ @@ -212,7 +212,7 @@ M_BEGIN_PROTECTED_CODE M_P(void, name, _clear, snapshot_t snap) \ { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_CLEAR(oplist, snap->data[i].x); \ } \ @@ -222,7 +222,7 @@ M_BEGIN_PROTECTED_CODE M_P(void, name, _init_set, snapshot_t snap, snapshot_t org) \ { \ M_SNAPSH0T_SPSC_CONTRACT(org); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(snap != NULL && snap != org); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \ @@ -236,7 +236,7 @@ M_BEGIN_PROTECTED_CODE { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ M_SNAPSH0T_SPSC_CONTRACT(org); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \ } \ @@ -264,7 +264,7 @@ M_BEGIN_PROTECTED_CODE { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ M_SNAPSH0T_SPSC_CONTRACT(org); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(snap != org); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \ diff --git a/m-string.h b/m-string.h index 036fa803..8139550f 100644 --- a/m-string.h +++ b/m-string.h @@ -2106,7 +2106,7 @@ namespace m_lib { m_lib::m_aligned_string(s).string #endif -#ifdef M_USE_POOL +#ifdef M_USE_CONTEXT /* Initialize and set a string to the given formatted value. */ #define m_string_init_printf(pool, v, ...) \ (m_string_printf ( pool, m_str1ng_init_ref(v), __VA_ARGS__) ) @@ -2138,7 +2138,7 @@ namespace m_lib { #endif /* Define the OPLIST of a STRING */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_STRING_OPLIST \ (INIT(m_string_init),INIT_SET(m_string_init_set), SET(m_string_set), \ INIT_WITH(M_STR1NG_INIT_WITH), \ @@ -2263,7 +2263,7 @@ namespace m_lib { )(a,b,c) /* Init & Set the string a to the string (or C string) b (constructor) */ -#ifdef M_USE_POOL +#ifdef M_USE_CONTEXT #define m_string_init_set(p, a,b) \ _Generic((b)+0, \ char*: m_string_init_set_cstr, \ @@ -2275,7 +2275,7 @@ namespace m_lib { #endif /* Set the string a to the string (or C string) b */ -#ifdef M_USE_POOL +#ifdef M_USE_CONTEXT #define m_string_set(p, a,b) \ _Generic((b)+0, \ char*: m_string_set_cstr, \ diff --git a/m-tree.h b/m-tree.h index 0ed0f757..92b4e11c 100644 --- a/m-tree.h +++ b/m-tree.h @@ -217,7 +217,7 @@ typedef int32_t m_tr33_index_t; \ M_P(void, name, _reset, tree_t tree) { \ M_TR33_CONTRACT(tree); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ if (tree->size > 0) { \ /* We don't scan recursively the node tree, but sequentially */ \ m_tr33_index_t free_index = tree->free_index; \ @@ -863,7 +863,7 @@ typedef int32_t m_tr33_index_t; \ M_P(bool, name, _remove, it_t it) { \ M_TR33_IT_CONTRACT(it, false); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ if (M_UNLIKELY(it.index < 0)) { return false; } \ type *ptr = M_F(name, _unlink)(it); \ M_CALL_CLEAR(oplist, *ptr); \ diff --git a/m-tuple.h b/m-tuple.h index d9b97b51..a83df23d 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -244,7 +244,7 @@ namespace m_lib { /* Define the INIT method calling the INIT method for all params */ #define M_TUPL3_DEFINE_INIT(name, ...) \ M_P(void, name, _init, M_F(name,_ct) my) { \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_INIT_FUNC , __VA_ARGS__) {} \ } @@ -255,7 +255,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_INIT_SET(name, ...) \ M_P(void, name, _init_set, M_F(name,_ct) my , M_F(name,_ct) const org) { \ M_TUPL3_CONTRACT(org); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_INIT_SET_FUNC , __VA_ARGS__) {} \ } #define M_TUPL3_DEFINE_INIT_SET_FUNC(a) \ @@ -265,7 +265,7 @@ namespace m_lib { /* Define the INIT_WITH method calling the INIT_SET method for all params. */ #define M_TUPL3_DEFINE_INIT_SET2(name, ...) \ M_P(void, name, _init_emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) {} \ } @@ -279,7 +279,7 @@ namespace m_lib { M_P(void, name, _set, M_F(name,_ct) my, M_F(name,_ct) const org) { \ M_TUPL3_CONTRACT(my); \ M_TUPL3_CONTRACT(org); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_SET_FUNC , __VA_ARGS__) \ } @@ -291,7 +291,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_SET2(name, ...) \ M_P(void, name, _emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \ M_TUPL3_CONTRACT(my); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_SET2_FUNC , __VA_ARGS__) \ } #define M_TUPL3_DEFINE_SET2_PROTO(a) \ @@ -305,7 +305,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_CLEAR(name, ...) \ M_P(void, name, _clear, M_F(name,_ct) my) { \ M_TUPL3_CONTRACT(my); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_CLEAR_FUNC , __VA_ARGS__) \ } @@ -343,7 +343,7 @@ namespace m_lib { M_INLINE void M_C3(name, _set_, M_TUPL3_GET_FIELD a) \ (M_P_EXPAND M_F(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \ M_TUPL3_CONTRACT(my); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_TUPL3_CALL_SET(a, my ->M_TUPL3_GET_FIELD a, M_TUPL3_GET_FIELD a); \ } @@ -362,7 +362,7 @@ namespace m_lib { function_name(M_P_EXPAND name_t v \ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_CALL_CLEAR(oplist, v->name); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->name, exp_emplace_type); \ } @@ -508,7 +508,7 @@ namespace m_lib { { \ bool comma = false; \ M_TUPL3_CONTRACT(el); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (f != NULL); \ int c = fgetc(f); \ if (c != '(') return false; \ @@ -533,7 +533,7 @@ namespace m_lib { { \ M_TUPL3_CONTRACT(el); \ M_ASSERT (str != NULL); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ bool success = false; \ bool comma = false; \ int c = *str++; \ @@ -592,7 +592,7 @@ namespace m_lib { M_P(m_serial_return_code_t, name, _in_serial, M_F(name,_ct) el, m_serial_read_t f) \ { \ M_TUPL3_CONTRACT(el); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ int index = -1; \ const int field_max = M_NARGS(__VA_ARGS__); \ @@ -637,7 +637,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_MOVE(name, ...) \ M_P(void, name, _move, M_F(name,_ct) el, M_F(name,_ct) org) { \ M_TUPL3_CONTRACT(el); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_MOVE_FUNC , __VA_ARGS__) \ } @@ -661,7 +661,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_RESET(name, ...) \ M_P(void, name, _reset, M_F(name,_ct) el1) { \ M_TUPL3_CONTRACT(el1); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \ } \ @@ -746,7 +746,7 @@ namespace m_lib { ((M_LIB_ERROR(ONE_ARGUMENT_OF_M_TUPL3_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__))) /* Define the TUPLE oplist */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_TUPL3_OPLIST_P3(name, ...) \ (M_IF_METHOD_ALL(INIT, __VA_ARGS__)(INIT(M_F(name,_init)),), \ INIT_SET(M_F(name, _init_set)), \ diff --git a/m-variant.h b/m-variant.h index 506a6046..2349f18a 100644 --- a/m-variant.h +++ b/m-variant.h @@ -227,7 +227,7 @@ M_P(void, name, _init_set, M_F(name,_ct) my, M_F(name,_ct) const org) \ { \ M_VAR1ANT_CONTRACT(name, org); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ my->type = org->type; \ switch (org->type) { \ M_MAP2(M_VAR1ANT_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \ @@ -278,7 +278,7 @@ M_P(void, name, _clear, M_F(name,_ct) my) \ { \ M_VAR1ANT_CONTRACT(name, my); \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ switch (my->type) { \ M_MAP2(M_VAR1ANT_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \ case M_F(name, _EMPTY): /* fallthrough */ \ @@ -322,7 +322,7 @@ M_INLINE void \ M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my) \ { \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ /* Reinit variable with the given value */ \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT(a, my -> value. M_VAR1ANT_GET_FIELD a); \ @@ -337,7 +337,7 @@ M_INLINE void \ M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \ { \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ @@ -345,7 +345,7 @@ M_INLINE void \ M_C4(m_var1ant_, name, _init_set_, num)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \ { \ - M_ASSERT_POOL(); \ + M_UNUSED_CONTEXT(); \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ @@ -775,7 +775,7 @@ M_INLINE void \ ((M_LIB_ERROR(ONE_ARGUMENT_OF_VARIANT_OPLIST_IS_NOT_AN_OPLIST, name, __VA_ARGS__))) /* Define the oplist */ -#ifndef M_USE_POOL +#ifndef M_USE_CONTEXT #define M_VAR1ANT_OPLIST_P3(name, ...) \ (INIT(M_F(name,_init)), \ INIT_SET(M_F(name, _init_set)), \ diff --git a/m-worker.h b/m-worker.h index 50ca1bc3..436ee715 100644 --- a/m-worker.h +++ b/m-worker.h @@ -234,7 +234,7 @@ typedef struct m_worker_sync_s { M_INLINE void \ M_C3(m_work3r_, name, _clear)(struct M_C3(m_worker_, name, _s) *p) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_CALLBACK_CLEAR, data, __VA_ARGS__) \ /* TODO: Overload */ \ M_MEMORY_DEL(p); \ @@ -263,7 +263,7 @@ typedef struct m_worker_sync_s { M_MAP3_C(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD, data, __VA_ARGS__) \ ) \ { \ - M_GLOBAL_POOL(); \ + M_GLOBAL_CONTEXT(); \ if (!m_work3r_queue_full_p(block->worker->queue_g)) { \ struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \ if (M_UNLIKELY_NOMEM(p == NULL)) { \ @@ -362,7 +362,7 @@ m_work3r_thread(void *arg) { // Get back the given argument struct m_worker_s *g = M_ASSIGN_CAST(struct m_worker_s *, arg); - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); while (true) { m_work3r_order_ct w; // If needed, reset the global state of the worker @@ -411,7 +411,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset // numWorker can still be 0 if it is a single core cpu (no worker available) M_ASSERT(numWorker >= 0); size_t numWorker_st = (size_t) numWorker; - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st); if (M_UNLIKELY_NOMEM (g->worker == NULL)) { M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st); @@ -443,7 +443,7 @@ M_INLINE void m_worker_clear(m_worker_t g) { M_ASSERT (m_work3r_queue_empty_p (g->queue_g)); - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); // Push the terminate order on the queue for(unsigned int i = 0; i < g->numWorker_g; i++) { m_work3r_order_ct w = M_WORK3R_EMPTY_ORDER; @@ -482,7 +482,7 @@ M_INLINE void m_worker_spawn(m_worker_sync_t block, void (*func)(void *data), void *data) { const m_work3r_order_ct w = { block, data, func M_WORK3R_EXTRA_ORDER }; - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) && m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { M_WORK3R_DEBUG ("Sending data to thread: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); @@ -501,7 +501,7 @@ M_INLINE void m_work3r_spawn_block(m_worker_sync_t block, void (^func)(void *data), void *data) { const m_work3r_order_ct w = { block, data, NULL, func }; - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) && m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); @@ -521,7 +521,7 @@ M_INLINE void m_work3r_spawn_function(m_worker_sync_t block, std::function func, void *data) { const m_work3r_order_ct w = { block, data, NULL, func }; - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); if (M_UNLIKELY (!m_work3r_queue_full_p(block->worker->queue_g)) && m_work3r_queue_push_blocking (block->worker->queue_g, w, false) == true) { M_WORK3R_DEBUG ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn); @@ -564,7 +564,7 @@ M_INLINE void m_worker_flush(m_worker_t g) { m_work3r_order_ct w; - M_GLOBAL_POOL(); + M_GLOBAL_CONTEXT(); while (m_work3r_queue_pop_blocking (&w, g->queue_g, false) == true) { m_work3r_exec(&w); m_work3r_queue_pop_release(g->queue_g); From 0de3c622e316bc793a6978c6ccb98ed718566741 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 10:42:35 +0200 Subject: [PATCH 62/91] Port algo to new memory format --- example/ex11-use-pool.c | 4 ++- m-algo.h | 41 ++++++++++++---------------- m-array.h | 10 +++---- m-bptree.h | 10 +++---- m-buffer.h | 42 ++++++++++++++--------------- m-deque.h | 8 +++--- m-dict.h | 2 +- m-queue.h | 10 +++---- m-shared-ptr.h | 60 ++++++++++++++++++++--------------------- m-snapshot.h | 10 +++---- m-string.h | 25 ++++++++++------- m-tree.h | 4 +-- m-tuple.h | 26 +++++++++--------- m-variant.h | 10 +++---- m-worker.h | 4 +-- 15 files changed, 134 insertions(+), 132 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 3fa52735..6611ad55 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -35,7 +35,7 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context) #include "m-bitset.h" #include "m-bstring.h" #include "m-genint.h" - +#include "m-algo.h" context_t my_pool = NULL; extern int f(string_t, bitset_t b, bstring_t y); @@ -59,7 +59,9 @@ int f(string_t x, bitset_t b, bstring_t y) #include "m-array.h" ARRAY_DEF(array, int) +ALGO_DEF(array, ARRAY_OPLIST(array, M_BASIC_OPLIST)) ARRAY_DEF(array_str, string_t) +ALGO_DEF(array_str, ARRAY_OPLIST(array_str, STRING_OPLIST)) #include "m-prioqueue.h" diff --git a/m-algo.h b/m-algo.h index a4b865e0..d1890de1 100644 --- a/m-algo.h +++ b/m-algo.h @@ -434,7 +434,7 @@ /* Compute the union of two ***sorted*** containers */ \ M_IF_METHOD(IT_INSERT, cont_oplist)( \ M_INLINE void \ - M_C3(name,sort_name,_union)(container_t dst, const container_t src cmp_param(name)) \ + M_C3(name,sort_name,_union)(M_P_EXPAND container_t dst, const container_t src cmp_param(name)) \ { \ it_t itSrc; \ it_t itDst; \ @@ -479,7 +479,7 @@ /* Compute the intersection of two ***sorted*** containers */ \ M_IF_METHOD(IT_REMOVE, cont_oplist)( \ M_INLINE void \ - M_C3(name,sort_name,_intersect)(container_t dst, const container_t src cmp_param(name)) \ + M_C3(name,sort_name,_intersect)(M_P_EXPAND container_t dst, const container_t src cmp_param(name)) \ { \ it_t itSrc; \ it_t itDst; \ @@ -688,9 +688,9 @@ #define M_ALG0_DEF_FILL(name, container_t, cont_oplist, type_t, type_oplist, it_t) \ \ /* Fill all the container with value (overwritten) */ \ - M_INLINE void \ - M_F(name, _fill) (container_t l, type_t const value) \ + M_P(void, name, _fill, container_t l, type_t const value) \ { \ + M_UNUSED_CONTEXT(); \ for M_EACH(item, l, cont_oplist) { \ M_CALL_SET(type_oplist, *item, value); \ } \ @@ -698,8 +698,7 @@ \ /* Fill the container with exactly 'n' occurrence of 'value' */ \ M_IF_METHOD(PUSH, cont_oplist)( \ - M_INLINE void \ - M_F(name, _fill_n) (container_t l, size_t n, type_t const value) \ + M_P(void, name, _fill_n, container_t l, size_t n, type_t const value) \ { \ M_CALL_RESET(cont_oplist, l); \ for(size_t i = 0; i < n; i++) { \ @@ -710,9 +709,9 @@ \ /* Fill the container with FOR('value'; 'value'+'inc') */ \ M_IF_METHOD(ADD, type_oplist)( \ - M_INLINE void \ - M_F(name, _fill_a) (container_t l, type_t const value, type_t const inc) \ + M_P(void, name, _fill_a, container_t l, type_t const value, type_t const inc) \ { \ + M_UNUSED_CONTEXT(); \ type_t tmp; \ M_CALL_INIT_SET(type_oplist, tmp, value); \ for M_EACH(item, l, cont_oplist) { \ @@ -724,9 +723,9 @@ \ /* Fill the container with n occurences of FOR('value'; 'value'+'inc') */ \ M_IF_METHOD(PUSH, cont_oplist)( \ - M_INLINE void \ - M_F(name, _fill_an) (container_t l, size_t n, type_t const value, type_t const inc) \ + M_P(void, name, _fill_an, container_t l, size_t n, type_t const value, type_t const inc) \ { \ + M_UNUSED_CONTEXT(); \ type_t tmp; \ M_CALL_INIT_SET(type_oplist, tmp, value); \ M_CALL_RESET(cont_oplist, l); \ @@ -756,10 +755,7 @@ M_IF_METHOD(PUSH_MOVE, cont_oplist)( \ \ /* Apply func for all elements of the container src and push the result in dst */ \ - M_INLINE void \ - M_F(name, _transform) (container_t dst, \ - container_t src, \ - M_F(name, _transform_cb_ct) func) \ + M_P(void, name, _transform, container_t dst, container_t src, M_F(name, _transform_cb_ct) func) \ { \ M_ASSERT(dst != src); \ M_CALL_RESET(cont_oplist, dst); \ @@ -775,10 +771,10 @@ \ /* Reduce all elements of the container in dst in function of func */ \ M_IF_METHOD(SET, type_oplist)( \ - M_INLINE void \ - M_F(name, _reduce) (type_t *dest, container_t const l, \ + M_P(void, name, _reduce, type_t *dest, container_t const l, \ M_F(name, _transform_cb_ct) func) \ { \ + M_UNUSED_CONTEXT(); \ bool initDone = false; \ for M_EACH(item, l, cont_oplist) { \ if (initDone) { \ @@ -793,12 +789,12 @@ \ /* Reduce all transformed elements of the container in dst in function of func */ \ M_IF_METHOD(INIT, type_oplist)( \ - M_INLINE \ - void M_F(name, _map_reduce) (type_t *dest, \ + M_P(void, name, _map_reduce, type_t *dest, \ const container_t l, \ M_F(name, _transform_cb_ct) redFunc, \ M_F(name, _transform_cb_ct) mapFunc) \ { \ + M_UNUSED_CONTEXT(); \ bool initDone = false; \ type_t tmp; \ M_CALL_INIT(type_oplist, tmp); \ @@ -905,8 +901,7 @@ /* Define functions based on remove method */ #define M_ALG0_DEF_REMOVE(name, container_t, cont_oplist, type_t, type_oplist, it_t) \ \ - M_INLINE void \ - M_F(name, _uniq)(container_t l) \ + M_P(void, name, _uniq, container_t l) \ { \ it_t it1; \ it_t it2; \ @@ -927,8 +922,7 @@ } \ } \ \ - M_INLINE void \ - M_F(name, _remove_val)(container_t l, type_t const val) \ + M_P(void, name, _remove_val, container_t l, type_t const val) \ { \ it_t it1; \ M_CALL_IT_FIRST(cont_oplist, it1, l); \ @@ -942,8 +936,7 @@ } \ } \ \ - M_INLINE void \ - M_F(name, _remove_if)(container_t l, M_F(name, _test_cb_ct) func) \ + M_P(void, name, _remove_if, container_t l, M_F(name, _test_cb_ct) func) \ { \ it_t it1; \ M_CALL_IT_FIRST(cont_oplist, it1, l); \ diff --git a/m-array.h b/m-array.h index 4c2bd6e6..01d42235 100644 --- a/m-array.h +++ b/m-array.h @@ -270,7 +270,7 @@ M_P(void, name, _reset, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ for(size_t i = 0; i < v->size; i++) \ M_CALL_CLEAR(oplist, v->ptr[i]); \ v->size = 0; \ @@ -351,7 +351,7 @@ M_P(void, name, _set_at, array_t v, size_t i, type const x) \ { \ M_ARRA4_CONTRACT(v); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ M_CALL_SET(oplist, v->ptr[i], x); \ @@ -543,7 +543,7 @@ M_P(void, name, _pop_back, type *dest, array_t v) \ { \ M_ARRA4_CONTRACT(v); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (v->ptr != NULL); \ M_ASSERT_INDEX(0, v->size); \ v->size--; \ @@ -602,7 +602,7 @@ M_P(void, name, _pop_at, type *dest, array_t v, size_t i) \ { \ M_ARRA4_CONTRACT(v); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (v->size > 0 && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ if (dest) \ @@ -661,7 +661,7 @@ M_P(void, name, _remove_v, array_t v, size_t i, size_t j) \ { \ M_ARRA4_CONTRACT(v); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(i < j && v->ptr != NULL); \ M_ASSERT_INDEX(i, v->size); \ M_ASSERT_INDEX(j, v->size+1); \ diff --git a/m-bptree.h b/m-bptree.h index 8bf07115..8f198f65 100644 --- a/m-bptree.h +++ b/m-bptree.h @@ -706,7 +706,7 @@ M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \ { \ M_ASSERT (M_F(name, _is_leaf)(n)); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ int i, num = M_F(name, _get_num)(n); \ M_ASSERT (num <= N); \ /* Search for the key in the node n (a leaf) for insertion */ \ @@ -737,7 +737,7 @@ M_P(int, name, _i_search_and_insert_in_node, node_t n, node_t l, key_t key) \ { \ M_ASSERT (!M_F(name, _is_leaf)(n)); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ int i, num = M_F(name, _get_num)(n); \ M_ASSERT (num <= N); \ /* Search for the key in the node n (not a leaf) for insertion */ \ @@ -869,7 +869,7 @@ M_P(int, name, _i_search_and_remove_in_leaf, node_t n, key_t const key) \ { \ M_ASSERT(M_F(name, _is_leaf)(n)); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ const int num = M_F(name, _get_num)(n); \ for(int i = 0; i < num; i++) { \ const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ @@ -890,7 +890,7 @@ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ node_t left = parent->kind.node[k]; \ node_t right = parent->kind.node[k+1]; \ M_ASSERT (left != NULL && right != NULL); \ @@ -926,7 +926,7 @@ { \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ node_t left = parent->kind.node[k]; \ node_t right = parent->kind.node[k+1]; \ M_ASSERT (left != NULL && right != NULL); \ diff --git a/m-buffer.h b/m-buffer.h index 7398fec8..36112868 100644 --- a/m-buffer.h +++ b/m-buffer.h @@ -221,7 +221,7 @@ typedef enum { M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_ASSERT(size <= UINT_MAX); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_BUFF3R_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = size); \ v->idx_prod = v->idx_cons = v->overwrite = 0; \ atomic_init (&v->number[0], 0U); \ @@ -256,7 +256,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _i_clear_obj, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(size_t i = 0; i < M_BUFF3R_SIZE(m_size); i++) { \ M_CALL_CLEAR(oplist, v->data[i].x); \ @@ -280,7 +280,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _clear, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name,_i_clear_obj)(v); \ M_BUFF3R_IF_CTE_SIZE(m_size)( , \ M_CALL_FREE(oplist, M_F(name, _el_ct), v->data, M_BUFF3R_SIZE(m_size)); \ @@ -296,7 +296,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _reset, buffer_t v) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ m_mutex_lock(v->mutexPush); \ m_mutex_lock(v->mutexPop); \ M_BUFF3R_PROTECTED_CONTRACT(policy, v, m_size); \ @@ -314,7 +314,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ \ M_N(void, name, _init_set, buffer_t dest, const buffer_t src) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ vu.cptr = src; \ @@ -354,7 +354,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ \ M_N(void, name, _set, buffer_t dest, const buffer_t src) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ /* un-const 'src', so that we can lock it (semantically it is const) */ \ M_F(name, _uptr_ct) vu; \ vu.cptr = src; \ @@ -449,7 +449,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push_blocking, buffer_t v, type const data, bool blocking) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ /* Producer Mutex lock (mutex lock performs an acquire memory barrier) */ \ m_mutex_lock(v->mutexPush); \ while (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_OVERWRITE) \ @@ -523,7 +523,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_BUFF3R_CONTRACT(v,m_size); \ M_ASSERT (data != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ /* consumer lock (mutex lock performs an acquire memory barrier) */ \ m_mutex_lock(v->mutexPop); \ while (M_F(name, _empty_p)(v)) { \ @@ -714,7 +714,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int idx = atomic_load_explicit(&table->ProdIdx, \ memory_order_relaxed); \ const unsigned int i = idx & (table->size -1); \ @@ -749,7 +749,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_QU3UE_MPMC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int iC = atomic_load_explicit(&table->ConsoIdx, \ memory_order_relaxed); \ const unsigned int i = (iC & (table->size -1)); \ @@ -779,7 +779,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_ASSERT (buffer != NULL); \ M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \ M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ atomic_init(&buffer->ProdIdx, (unsigned int) size); \ atomic_init(&buffer->ConsoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ @@ -799,7 +799,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_MPMC_CONTRACT(buffer); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < buffer->size; j++) { \ M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ @@ -939,7 +939,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -960,7 +960,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(bool, name, _push_move, buffer_t table, type *x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -982,7 +982,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1005,7 +1005,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (x != NULL); \ M_ASSERT (n <= table->size); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1031,7 +1031,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_QU3UE_SPSC_CONTRACT(table); \ M_ASSERT (ptr != NULL); \ M_ASSERT (n <= table->size); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ memory_order_relaxed); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ @@ -1055,7 +1055,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _push_force, buffer_t table, type const x) \ { \ M_QU3UE_SPSC_CONTRACT(table); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ unsigned int r = atomic_load_explicit(&table->consoIdx, \ memory_order_relaxed); \ unsigned int w = atomic_load_explicit(&table->prodIdx, \ @@ -1119,7 +1119,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_ASSERT (buffer != NULL); \ M_ASSERT( M_POWEROF2_P(size) && 0 < size && size <= UINT_MAX); \ M_ASSERT(((policy) & (M_BUFFER_STACK|M_BUFFER_PUSH_OVERWRITE)) == 0); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ atomic_init(&buffer->prodIdx, (unsigned int) size); \ atomic_init(&buffer->consoIdx, (unsigned int) size); \ buffer->size = (unsigned int) size; \ @@ -1138,7 +1138,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, _clear, buffer_t buffer) \ { \ M_QU3UE_SPSC_CONTRACT(buffer); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (!M_BUFF3R_POLICY_P((policy), M_BUFFER_PUSH_INIT_POP_MOVE)) { \ for(unsigned int j = 0; j < buffer->size; j++) { \ M_CALL_CLEAR(oplist, buffer->Tab[j].x); \ @@ -1198,7 +1198,7 @@ M_N(void, name, _init, buffer_t v, size_t size) \ M_N(void, name, function_name, name_t v M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ M_GET_TYPE oplist data; \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, data, exp_emplace_type); \ M_F(name, _push)(v, data); \ M_CALL_CLEAR(oplist, data); \ diff --git a/m-deque.h b/m-deque.h index 9cbf9ad0..01c9b119 100644 --- a/m-deque.h +++ b/m-deque.h @@ -222,7 +222,7 @@ M_P(void, name, _reset, deque_t d) \ { \ M_D3QU3_CONTRACT(d); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ node_t *min_node = NULL; \ for(node_t *n = d->front->node; \ n != NULL ; \ @@ -365,7 +365,7 @@ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT(d->count > 0); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ node_t *n = d->back->node; \ size_t index = d->back->index; \ index --; \ @@ -407,7 +407,7 @@ { \ M_D3QU3_CONTRACT(d); \ M_ASSERT(d->count > 0); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ node_t *n = d->front->node; \ size_t index = d->front->index; \ if (ptr != NULL) \ @@ -825,7 +825,7 @@ M_P(void, name, _set_at, deque_t d, size_t key, type const x) \ { \ M_D3QU3_CONTRACT(d); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT_INDEX (key, d->count); \ type *p = M_F(name, _get)(d, key); \ M_CALL_SET(oplist, *p, x); \ diff --git a/m-dict.h b/m-dict.h index 50ecae78..89d3369a 100644 --- a/m-dict.h +++ b/m-dict.h @@ -2078,7 +2078,7 @@ enum m_d1ct_oa_element_e { M_P(void, name, _bulk_get, unsigned n, value_type val[M_VLA(n)], dict_t dict, key_type const key[M_VLA(n)], value_type def) \ { \ M_D1CT_OA_CONTRACT (dict); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ size_t h[M_USE_MAX_PREFETCH]; \ M_F(name, _pair_ct) *data = dict->data; \ const size_t mask = dict->mask; \ diff --git a/m-queue.h b/m-queue.h index 1353b285..749f88f6 100644 --- a/m-queue.h +++ b/m-queue.h @@ -168,7 +168,7 @@ M_P(void, name, _init, queue_t v, size_t size) \ { \ M_ASSERT(size <= UINT_MAX); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_QUEU3_IF_CTE_SIZE(m_size)(M_ASSERT(size == m_size), v->capacity = (unsigned) size); \ v->idx_prod = v->idx_cons = v->number = 0; \ \ @@ -194,7 +194,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ M_P(void, name, _i_clear_obj, queue_t v) \ { \ M_QUEU3_CONTRACT(v,m_size); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ for(size_t i = 0; i < M_QUEU3_SIZE(v, m_size); i++) { \ M_CALL_CLEAR(oplist, v->data[i]); \ } \ @@ -205,7 +205,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ M_P(void, name, _clear, queue_t v) \ { \ M_QUEU3_CONTRACT(v,m_size); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_F(name,_i_clear_obj)M_R(v); \ M_QUEU3_IF_CTE_SIZE(m_size)( , \ M_CALL_FREE(oplist, type, v->data, M_QUEU3_SIZE(v, m_size)); \ @@ -264,7 +264,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ M_P(bool, name, _push, queue_t v, type const data) \ { \ M_QUEU3_CONTRACT(v,m_size); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ if (M_F(name, _full_p)(v)) \ return false; \ \ @@ -284,7 +284,7 @@ M_QUEU3_IF_CTE_SIZE(m_size)( \ { \ M_QUEU3_CONTRACT(v,m_size); \ M_ASSERT (data != NULL); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ if (M_F(name, _empty_p)(v)) \ return false; \ \ diff --git a/m-shared-ptr.h b/m-shared-ptr.h index 562d60ea..2caf0e05 100644 --- a/m-shared-ptr.h +++ b/m-shared-ptr.h @@ -613,7 +613,7 @@ extern shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type M_IF_METHOD(INIT, oplist)( \ fattr shared_t *M_F(name, _new)(void) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -629,7 +629,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ fattr shared_t *M_F(name, _clone)(const shared_t *src) \ { \ M_ASSERT(src != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -646,7 +646,7 @@ M_IF_METHOD(INIT_SET, oplist)( \ fattr shared_t *M_F(name, _new_from)(type const src); ) \ fattr shared_t *M_F(name, _new_from)(type const src) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -663,7 +663,7 @@ M_IF_METHOD(SET, oplist)( \ { \ M_ASSERT(out != NULL); \ M_ASSERT(src != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (M_UNLIKELY (out == src)) return; \ M_F(name, _write_read_lock)(out, src); \ M_ON_EXCEPTION( M_F(name, _write_read_unlock)(out, src) ) \ @@ -682,7 +682,7 @@ fattr shared_t *M_F(name, _acquire)(shared_t *out) \ \ fattr void M_F(name, _release)(shared_t *out) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (out != NULL && M_C3(m_shar3d_, name, _dec_owner)(out)) { \ M_CALL_CLEAR(oplist, out->data); \ M_F(name, _clear_lock)(out); \ @@ -706,7 +706,7 @@ M_EMPLACE_QUEUE_DEF( (name, fattr), shared_t, M_F(name, _make), oplist, M_SHAR3D #define M_SHAR3D_PTR_DEF_BASIC_MAKE(name_attr, shared_t, function_name, oplist, init_func, exp_emplace_type) \ M_PAIR_2 name_attr shared_t *function_name(M_EMPLACE_LIST_TYPE_VAR_ALTER(a, exp_emplace_type)) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ shared_t *out = M_CALL_NEW(oplist, shared_t); \ if (M_UNLIKELY_NOMEM( out == NULL)) { \ M_MEMORY_FULL(shared_t, 1); \ @@ -753,7 +753,7 @@ M_IF_METHOD(RESET, oplist)( \ fattr void M_F(name, _reset)(shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ /* RESET cannot throw exception */ \ M_CALL_RESET(oplist, out->data); \ @@ -866,7 +866,7 @@ M_IF_METHOD(ADD, oplist)( \ fattr void M_F(name, _add)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_ADD(oplist, out->data, src1->data, src2->data); \ @@ -878,7 +878,7 @@ M_IF_METHOD(SUB, oplist)( \ fattr void M_F(name, _sub)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_SUB(oplist, out->data, src1->data, src2->data); \ @@ -890,7 +890,7 @@ M_IF_METHOD(MUL, oplist)( \ fattr void M_F(name, _mul)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_MUL(oplist, out->data, src1->data, src2->data); \ @@ -902,7 +902,7 @@ M_IF_METHOD(DIV, oplist)( \ fattr void M_F(name, _div)(shared_t *out, const shared_t *src1, const shared_t *src2) \ { \ M_ASSERT(out != NULL && src1 != NULL && src2 != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_read2_lock)(out, src1, src2); \ M_ON_EXCEPTION( M_F(name, _write_read2_unlock)(out, src1, src2) ) \ M_CALL_DIV(oplist, out->data, src1->data, src2->data); \ @@ -914,7 +914,7 @@ M_IF_METHOD(SPLICE, oplist)( \ fattr void M_F(name, _splice)(shared_t *out, shared_t *src) \ { \ M_ASSERT(out != NULL && src != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (out < src) { \ M_F(name, _write_lock)(out); \ M_F(name, _write_lock)(src); \ @@ -944,7 +944,7 @@ M_IF_METHOD(GET_KEY, oplist)( \ { \ M_ASSERT (out != NULL); \ M_ASSERT (value != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _read_lock)(out); \ /* No exception */ \ value_type *p = M_CALL_GET_KEY(oplist, out->data, key); \ @@ -961,7 +961,7 @@ M_IF_METHOD(SAFE_GET_KEY, oplist)( \ { \ M_ASSERT (out != NULL); \ M_ASSERT (value != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) { \ value_type *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \ @@ -977,7 +977,7 @@ M_IF_METHOD(SET_KEY, oplist)( \ fattr void M_F(name, _set_at)(shared_t *out, key_type const key, value_type const value) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ M_CALL_SET_KEY(oplist, out->data, key, value); \ @@ -990,7 +990,7 @@ M_IF_METHOD(ERASE_KEY, oplist)( \ fattr bool M_F(name, _erase)(shared_t *out, key_type const key) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ /* No exception */ \ bool r = M_CALL_ERASE_KEY(oplist, out->data, key); \ @@ -1021,7 +1021,7 @@ M_IF_METHOD(PUSH, oplist)( \ fattr void M_F(name, _push)(shared_t *out, sub_type const value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1038,7 +1038,7 @@ M_IF_METHOD(PUSH, oplist)( \ fattr bool M_F(name, _try_push)(shared_t *out, sub_type const value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1055,7 +1055,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr void M_F(name, _push_move)(shared_t *out, sub_type *value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1072,7 +1072,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr bool M_F(name, _try_push_move)(shared_t *out, sub_type *value) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1094,7 +1094,7 @@ M_IF_METHOD(PUSH_MOVE, oplist)( \ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1117,7 +1117,7 @@ fattr void function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_ty fattr bool function_name(shared_t *out M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type)) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_FULL_P(oplist, out->data) == false) { \ @@ -1146,7 +1146,7 @@ M_IF_METHOD(POP, oplist)( \ fattr void M_F(name, _pop)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1163,7 +1163,7 @@ M_IF_METHOD(POP, oplist)( \ fattr bool M_F(name, _try_pop)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1180,7 +1180,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \ fattr void M_F(name, _pop_move)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ while (true) { \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1197,7 +1197,7 @@ M_IF_METHOD(POP_MOVE, oplist)( \ fattr bool M_F(name, _try_pop_move)(sub_type *value, shared_t *out) \ { \ M_ASSERT(out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ bool ret = false; \ M_F(name, _write_lock)(out); \ if (M_CALL_EMPTY_P(oplist, out->data) == false) { \ @@ -1326,7 +1326,7 @@ M_IF_METHOD(IN_STR, oplist)( \ fattr bool M_F(name, _in_str)(shared_t *out, FILE *file) \ { \ M_ASSERT (out != NULL && file != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ m_volatile bool r = false; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ @@ -1341,7 +1341,7 @@ M_IF_METHOD(GET_STR, oplist)( \ fattr void M_F(name, _get_str)(m_string_t str, const shared_t *out, bool append) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _read_lock)(out); \ M_ON_EXCEPTION( M_F(name, _read_unlock)(out) ) \ M_CALL_GET_STR(oplist, str, out->data, append); \ @@ -1352,7 +1352,7 @@ M_IF_METHOD(PARSE_STR, oplist)( \ fattr bool M_F(name, _parse_str)(shared_t *out, const char str[], const char **endp) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ m_volatile bool r = false; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ @@ -1379,7 +1379,7 @@ M_IF_METHOD(IN_SERIAL, oplist)( \ fattr m_serial_return_code_t M_F(name, _in_serial)(shared_t *out, m_serial_read_t serial) \ { \ M_ASSERT (out != NULL); \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_F(name, _write_lock)(out); \ m_volatile m_serial_return_code_t r = M_SERIAL_FAIL; \ M_ON_EXCEPTION( M_F(name, _write_unlock)(out) ) \ diff --git a/m-snapshot.h b/m-snapshot.h index 37d834d9..7e307811 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -201,7 +201,7 @@ M_BEGIN_PROTECTED_CODE M_P(void, name, _init, snapshot_t snap) \ { \ M_ASSERT(snap != NULL); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_INIT(oplist, snap->data[i].x); \ } \ @@ -212,7 +212,7 @@ M_BEGIN_PROTECTED_CODE M_P(void, name, _clear, snapshot_t snap) \ { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_CLEAR(oplist, snap->data[i].x); \ } \ @@ -222,7 +222,7 @@ M_BEGIN_PROTECTED_CODE M_P(void, name, _init_set, snapshot_t snap, snapshot_t org) \ { \ M_SNAPSH0T_SPSC_CONTRACT(org); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(snap != NULL && snap != org); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_INIT_SET(oplist, snap->data[i].x, org->data[i].x); \ @@ -236,7 +236,7 @@ M_BEGIN_PROTECTED_CODE { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ M_SNAPSH0T_SPSC_CONTRACT(org); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_SET(oplist, snap->data[i].x, org->data[i].x); \ } \ @@ -264,7 +264,7 @@ M_BEGIN_PROTECTED_CODE { \ M_SNAPSH0T_SPSC_CONTRACT(snap); \ M_SNAPSH0T_SPSC_CONTRACT(org); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT(snap != org); \ for(int i = 0; i < M_SNAPSH0T_SPSC_MAX_BUFFER; i++) { \ M_CALL_MOVE(oplist, snap->data[i].x, org->data[i].x); \ diff --git a/m-string.h b/m-string.h index 8139550f..9d588a83 100644 --- a/m-string.h +++ b/m-string.h @@ -2018,8 +2018,7 @@ m_string_utf8_p(const m_string_t str) /* Define the split & the join functions in case of usage with the algorithm module */ #define M_STR1NG_SPLIT(name, oplist, type_oplist) \ - M_INLINE void M_F(name, _split)(M_GET_TYPE oplist cont, \ - const m_string_t str, const char sep) \ + M_P(void, name, _split, M_GET_TYPE oplist cont, const m_string_t str, const char sep) \ { \ size_t begin = 0; \ m_string_t tmp; \ @@ -2029,7 +2028,7 @@ m_string_utf8_p(const m_string_t str) for(size_t i = 0 ; i < size; i++) { \ char c = m_string_get_char(str, i); \ if (c == sep) { \ - m_string_set_cstrn(tmp, &m_string_get_cstr(str)[begin], i - begin); \ + m_string_set_cstrn M_R(tmp, &m_string_get_cstr(str)[begin], i - begin); \ /* If push move method is available, use it */ \ M_IF_METHOD(PUSH_MOVE,oplist)( \ M_CALL_PUSH_MOVE(oplist, cont, &tmp); \ @@ -2040,24 +2039,23 @@ m_string_utf8_p(const m_string_t str) begin = i + 1; \ } \ } \ - m_string_set_cstrn(tmp, &m_string_get_cstr(str)[begin], size - begin); \ + m_string_set_cstrn M_R(tmp, &m_string_get_cstr(str)[begin], size - begin); \ M_CALL_PUSH(oplist, cont, tmp); \ /* HACK: if method reverse is defined, it is likely that we have */ \ /* inserted the items in the wrong order (aka for a list) */ \ M_IF_METHOD(REVERSE, oplist) (M_CALL_REVERSE(oplist, cont);, ) \ - m_string_clear(tmp); \ + m_string_clear M_R(tmp); \ } \ \ - M_INLINE void M_F(name, _join)(m_string_t dst, M_GET_TYPE oplist cont, \ - const m_string_t str) \ + M_P(void, name, _join, m_string_t dst, M_GET_TYPE oplist cont, const m_string_t str) \ { \ bool init_done = false; \ m_string_reset (dst); \ for M_EACH(item, cont, oplist) { \ if (init_done) { \ - m_string_cat(dst, str); \ + m_string_cat M_R(dst, str); \ } \ - m_string_cat (dst, *item); \ + m_string_cat M_R(dst, *item); \ init_done = true; \ } \ } \ @@ -2287,7 +2285,16 @@ namespace m_lib { #endif /* Concatenate the string (or C string) b to the string a */ +#ifdef M_USE_CONTEXT +#define m_string_cat(p, a,b) \ + _Generic((b)+0, \ + char*: m_string_cat_cstr, \ + const char *: m_string_cat_cstr, \ + default : m_string_cat \ + )(p,a,b) +#else #define m_string_cat(a,b) M_STR1NG_SELECT2(m_string_cat, m_string_cat_cstr, a, b) +#endif /* Compare the string a to the string (or C string) b and return the sort order */ #define m_string_cmp(a,b) M_STR1NG_SELECT2(m_string_cmp, m_string_cmp_cstr, a, b) diff --git a/m-tree.h b/m-tree.h index 92b4e11c..6bd480c8 100644 --- a/m-tree.h +++ b/m-tree.h @@ -217,7 +217,7 @@ typedef int32_t m_tr33_index_t; \ M_P(void, name, _reset, tree_t tree) { \ M_TR33_CONTRACT(tree); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ if (tree->size > 0) { \ /* We don't scan recursively the node tree, but sequentially */ \ m_tr33_index_t free_index = tree->free_index; \ @@ -863,7 +863,7 @@ typedef int32_t m_tr33_index_t; \ M_P(bool, name, _remove, it_t it) { \ M_TR33_IT_CONTRACT(it, false); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ if (M_UNLIKELY(it.index < 0)) { return false; } \ type *ptr = M_F(name, _unlink)(it); \ M_CALL_CLEAR(oplist, *ptr); \ diff --git a/m-tuple.h b/m-tuple.h index a83df23d..6ba2d8cf 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -244,7 +244,7 @@ namespace m_lib { /* Define the INIT method calling the INIT method for all params */ #define M_TUPL3_DEFINE_INIT(name, ...) \ M_P(void, name, _init, M_F(name,_ct) my) { \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_INIT_FUNC , __VA_ARGS__) {} \ } @@ -255,7 +255,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_INIT_SET(name, ...) \ M_P(void, name, _init_set, M_F(name,_ct) my , M_F(name,_ct) const org) { \ M_TUPL3_CONTRACT(org); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_INIT_SET_FUNC , __VA_ARGS__) {} \ } #define M_TUPL3_DEFINE_INIT_SET_FUNC(a) \ @@ -265,7 +265,7 @@ namespace m_lib { /* Define the INIT_WITH method calling the INIT_SET method for all params. */ #define M_TUPL3_DEFINE_INIT_SET2(name, ...) \ M_P(void, name, _init_emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_INIT_SET2_FUNC , __VA_ARGS__) {} \ } @@ -279,7 +279,7 @@ namespace m_lib { M_P(void, name, _set, M_F(name,_ct) my, M_F(name,_ct) const org) { \ M_TUPL3_CONTRACT(my); \ M_TUPL3_CONTRACT(org); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_SET_FUNC , __VA_ARGS__) \ } @@ -291,7 +291,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_SET2(name, ...) \ M_P(void, name, _emplace, M_F(name,_ct) my M_MAP(M_TUPL3_DEFINE_SET2_PROTO, __VA_ARGS__) ) { \ M_TUPL3_CONTRACT(my); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_SET2_FUNC , __VA_ARGS__) \ } #define M_TUPL3_DEFINE_SET2_PROTO(a) \ @@ -305,7 +305,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_CLEAR(name, ...) \ M_P(void, name, _clear, M_F(name,_ct) my) { \ M_TUPL3_CONTRACT(my); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_CLEAR_FUNC , __VA_ARGS__) \ } @@ -343,7 +343,7 @@ namespace m_lib { M_INLINE void M_C3(name, _set_, M_TUPL3_GET_FIELD a) \ (M_P_EXPAND M_F(name,_ct) my, M_TUPL3_GET_TYPE a const M_TUPL3_GET_FIELD a) { \ M_TUPL3_CONTRACT(my); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_TUPL3_CALL_SET(a, my ->M_TUPL3_GET_FIELD a, M_TUPL3_GET_FIELD a); \ } @@ -362,7 +362,7 @@ namespace m_lib { function_name(M_P_EXPAND name_t v \ M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ { \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_CALL_CLEAR(oplist, v->name); \ M_EMPLACE_CALL_FUNC(a, init_func, oplist, v->name, exp_emplace_type); \ } @@ -508,7 +508,7 @@ namespace m_lib { { \ bool comma = false; \ M_TUPL3_CONTRACT(el); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (f != NULL); \ int c = fgetc(f); \ if (c != '(') return false; \ @@ -533,7 +533,7 @@ namespace m_lib { { \ M_TUPL3_CONTRACT(el); \ M_ASSERT (str != NULL); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ bool success = false; \ bool comma = false; \ int c = *str++; \ @@ -592,7 +592,7 @@ namespace m_lib { M_P(m_serial_return_code_t, name, _in_serial, M_F(name,_ct) el, m_serial_read_t f) \ { \ M_TUPL3_CONTRACT(el); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_ASSERT (f != NULL && f->m_interface != NULL); \ int index = -1; \ const int field_max = M_NARGS(__VA_ARGS__); \ @@ -637,7 +637,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_MOVE(name, ...) \ M_P(void, name, _move, M_F(name,_ct) el, M_F(name,_ct) org) { \ M_TUPL3_CONTRACT(el); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_MOVE_FUNC , __VA_ARGS__) \ } @@ -661,7 +661,7 @@ namespace m_lib { #define M_TUPL3_DEFINE_RESET(name, ...) \ M_P(void, name, _reset, M_F(name,_ct) el1) { \ M_TUPL3_CONTRACT(el1); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ M_MAP(M_TUPL3_DEFINE_RESET_FUNC , __VA_ARGS__) \ } \ diff --git a/m-variant.h b/m-variant.h index 2349f18a..64cd1674 100644 --- a/m-variant.h +++ b/m-variant.h @@ -227,7 +227,7 @@ M_P(void, name, _init_set, M_F(name,_ct) my, M_F(name,_ct) const org) \ { \ M_VAR1ANT_CONTRACT(name, org); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ my->type = org->type; \ switch (org->type) { \ M_MAP2(M_VAR1ANT_DEFINE_INIT_SET_FUNC, name, __VA_ARGS__) \ @@ -278,7 +278,7 @@ M_P(void, name, _clear, M_F(name,_ct) my) \ { \ M_VAR1ANT_CONTRACT(name, my); \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ switch (my->type) { \ M_MAP2(M_VAR1ANT_DEFINE_CLEAR_FUNC, name, __VA_ARGS__) \ case M_F(name, _EMPTY): /* fallthrough */ \ @@ -322,7 +322,7 @@ M_INLINE void \ M_C3(name, _init_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my) \ { \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ /* Reinit variable with the given value */ \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT(a, my -> value. M_VAR1ANT_GET_FIELD a); \ @@ -337,7 +337,7 @@ M_INLINE void \ M_C3(name, _init_set_, M_VAR1ANT_GET_FIELD a)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \ { \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ @@ -345,7 +345,7 @@ M_INLINE void \ M_C4(m_var1ant_, name, _init_set_, num)(M_P_EXPAND M_F(name,_ct) my, M_VAR1ANT_GET_TYPE a const M_VAR1ANT_GET_FIELD a) \ { \ - M_UNUSED_CONTEXT(); \ + M_UNUSED_CONTEXT(); \ my->type = M_C4(name, _, M_VAR1ANT_GET_FIELD a, _value); \ M_VAR1ANT_CALL_INIT_SET(a, my -> value. M_VAR1ANT_GET_FIELD a, \ M_VAR1ANT_GET_FIELD a); \ diff --git a/m-worker.h b/m-worker.h index 436ee715..2bf0244f 100644 --- a/m-worker.h +++ b/m-worker.h @@ -234,7 +234,7 @@ typedef struct m_worker_sync_s { M_INLINE void \ M_C3(m_work3r_, name, _clear)(struct M_C3(m_worker_, name, _s) *p) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_CALLBACK_CLEAR, data, __VA_ARGS__) \ /* TODO: Overload */ \ M_MEMORY_DEL(p); \ @@ -263,7 +263,7 @@ typedef struct m_worker_sync_s { M_MAP3_C(M_WORK3R_SPAWN_EXTEND_DEF_EMPLACE_FIELD, data, __VA_ARGS__) \ ) \ { \ - M_GLOBAL_CONTEXT(); \ + M_GLOBAL_CONTEXT(); \ if (!m_work3r_queue_full_p(block->worker->queue_g)) { \ struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \ if (M_UNLIKELY_NOMEM(p == NULL)) { \ From bd9485a3fefd3d16664273ddffd56f82077ed827 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 10:55:55 +0200 Subject: [PATCH 63/91] Port algo to new memory format --- example/ex11-use-pool.c | 2 ++ m-algo.h | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 6611ad55..9b432daa 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -76,7 +76,9 @@ RBTREE_DEF(rbtree_str, string_t) #include "m-list.h" LIST_DEF(list, int) +ALGO_DEF(list, LIST_OPLIST(list, M_BASIC_OPLIST)) LIST_DEF(list_str, string_t) +ALGO_DEF(list_str, LIST_OPLIST(list_str, M_STRING_OPLIST)) #include "m-bptree.h" diff --git a/m-algo.h b/m-algo.h index d1890de1..955bcb65 100644 --- a/m-algo.h +++ b/m-algo.h @@ -276,14 +276,14 @@ M_CALL_SPLICE_BACK(cont_oplist, (b ? l1 : l2), l, it); \ b = !b; \ } \ - /* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \ + M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); \ } \ \ /* Merge in empty 'l' the sorted container 'l1' and 'l2' */ \ M_INLINE void \ M_C3(name,sort_name,_merge)(container_t l, container_t l1, container_t l2 cmp_param(name)) \ { \ - /* M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); */ \ + M_ASSERT(M_CALL_EMPTY_P (cont_oplist, l)); \ it_t it; \ it_t it1; \ it_t it2; \ @@ -350,6 +350,7 @@ return; \ } \ /* Container length is greater than 2: split, sort & merge */ \ + M_GLOBAL_CONTEXT(); \ M_CALL_INIT(cont_oplist, l1); \ M_CALL_INIT(cont_oplist, l2); \ M_C3(name,sort_name,_split)(l1, l2, l); \ @@ -357,6 +358,9 @@ M_F(name,sort_name)(l2 cmp_arg); \ M_C3(name,sort_name,_merge)(l, l1, l2 cmp_arg); \ /* l1 & l2 shall be empty now */ \ + M_ASSERT( M_CALL_EMPTY_P(cont_oplist, l1)); \ + M_ASSERT( M_CALL_EMPTY_P(cont_oplist, l2)); \ + /* Normally nothing is done here */ \ M_CALL_CLEAR(cont_oplist, l2); \ M_CALL_CLEAR(cont_oplist, l1); \ } \ From 33aa102b7c7b8830e89d09457243d9397db886fd Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 10:59:22 +0200 Subject: [PATCH 64/91] Port DualPush list to new format --- example/ex11-use-pool.c | 3 +++ m-list.h | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 9b432daa..0c28e50c 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -80,6 +80,9 @@ ALGO_DEF(list, LIST_OPLIST(list, M_BASIC_OPLIST)) LIST_DEF(list_str, string_t) ALGO_DEF(list_str, LIST_OPLIST(list_str, M_STRING_OPLIST)) +LIST_DUAL_PUSH_DEF(list2, int) +LIST_DUAL_PUSH_DEF(list2_str, string_t) + #include "m-bptree.h" BPTREE_DEF2(bptree, 5, int, int) diff --git a/m-list.h b/m-list.h index 250c1d66..0d02fd58 100644 --- a/m-list.h +++ b/m-list.h @@ -1192,7 +1192,7 @@ M_P(void, name, _push_front_move, list_t v, type *x) \ { \ M_ASSERT (x != NULL); \ - type *data = M_F(name, _push_front_raw)(v); \ + type *data = M_F(name, _push_front_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return; \ M_CALL_INIT_MOVE (oplist, *data, *x); \ @@ -1202,7 +1202,7 @@ M_P(type *, name, _push_front_new, list_t v) \ { \ M_IF_EXCEPTION(struct M_F(name, _s) *front = v->front, *back = v->back); \ - type *data = M_F(name, _push_front_raw)(v); \ + type *data = M_F(name, _push_front_raw)M_R(v); \ if (M_UNLIKELY (data == NULL)) \ return NULL; \ M_IF_EXCEPTION(struct M_F(name, _s) *m_volatile tofree = v->front); \ @@ -1397,7 +1397,7 @@ M_ASSERT (list != org); \ M_ON_EXCEPTION( M_F(name, _clear)(list)) { \ M_F(name, _init)(list); \ - M_F(name, _set)(list, org); \ + M_F(name, _set) M_R(list, org); \ } \ } \ \ From 147bc0a36362ee9db8790975f7ba5093a5e111c3 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 13:30:59 +0200 Subject: [PATCH 65/91] Fix ALGO and oplist doesn't providing IT_REF --- m-algo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m-algo.h b/m-algo.h index 955bcb65..1b0dc7dd 100644 --- a/m-algo.h +++ b/m-algo.h @@ -171,7 +171,7 @@ typedef bool (*M_F(name, _eq_cb_ct))(type_t const, type_t const); \ typedef int (*M_F(name, _cmp_cb_ct))(type_t const, type_t const); \ typedef void (*M_F(name, _transform_cb_ct))(type_t *, type_t const); \ - typedef void (*M_F(name, _apply_cb_ct))(type_t); \ + typedef void (*M_F(name, _apply_cb_ct))(type_t M_IF_METHOD(IT_REF, cont_oplist)( , const) ); /* Define the function objects associated to the algorithms. From a1a5ae749db5ce603262ddb0448dca50edfb7e2c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 13:31:11 +0200 Subject: [PATCH 66/91] Fix oplist of bitset --- m-bitset.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/m-bitset.h b/m-bitset.h index 482d67d7..fdeb0ace 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -907,11 +907,7 @@ m_bitset_popcount(const m_bitset_t set) #endif /* Register the OPLIST as a global one */ -#ifdef M_USE_CONTEXT -#define M_OPL_m_bitset_t() M_BITSET_POOL_OPLIST -#else #define M_OPL_m_bitset_t() M_BITSET_OPLIST -#endif // TODO: set_at2, insert_v, remove_v From 8f47fb35aedcefb2cc47d37395a57e796daf59eb Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 13:31:35 +0200 Subject: [PATCH 67/91] Use of context for nearly all M*LIB --- example/ex11-use-pool.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 0c28e50c..00c76544 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -67,11 +67,13 @@ ALGO_DEF(array_str, ARRAY_OPLIST(array_str, STRING_OPLIST)) PRIOQUEUE_DEF(prio, int) PRIOQUEUE_DEF(prio_str, string_t) +ALGO_DEF(prio_str, PRIOQUEUE_OPLIST(prio_str, STRING_OPLIST)) #include "m-rbtree.h" RBTREE_DEF(rbtree, int) RBTREE_DEF(rbtree_str, string_t) +ALGO_DEF(rbtree_str, RBTREE_OPLIST(rbtree_str, STRING_OPLIST)) #include "m-list.h" @@ -82,18 +84,23 @@ ALGO_DEF(list_str, LIST_OPLIST(list_str, M_STRING_OPLIST)) LIST_DUAL_PUSH_DEF(list2, int) LIST_DUAL_PUSH_DEF(list2_str, string_t) +ALGO_DEF(list2_str, LIST_OPLIST(list2_str, M_STRING_OPLIST)) #include "m-bptree.h" BPTREE_DEF2(bptree, 5, int, int) +BPTREE_DEF2(bptree_str, 8, string_t, string_t) +ALGO_DEF(bptree_str, M_BPTREE_OPLIST2(bptree_str, M_STRING_OPLIST, M_STRING_OPLIST)) #include "m-dict.h" DICT_DEF2(dict, int, int) DICT_DEF2(dict_str, string_t, string_t) +ALGO_DEF(dict_str, DICT_OPLIST(dict_str, M_STRING_OPLIST, M_STRING_OPLIST)) DICT_SET_DEF(set, int) DICT_SET_DEF(set_str, string_t) +ALGO_DEF(set_str, DICT_SET_OPLIST(set_str, M_STRING_OPLIST)) static inline bool oor_equal_p(int k, char n) { @@ -109,10 +116,12 @@ DICT_OA_DEF2(dict_oa, int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))), int, M_BASIC_OPLIST) DICT_OA_DEF2(dict2_str, string_t, string_t) +ALGO_DEF(dict2_str, DICT_OPLIST(dict2_str, M_STRING_OPLIST, M_STRING_OPLIST)) DICT_OASET_DEF(set_oa, int, M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(oor_equal_p), OOR_SET(API_4(oor_set))) ) DICT_OASET_DEF(set2_str, string_t) +ALGO_DEF(set2_str, DICT_SET_OPLIST(set2_str, M_STRING_OPLIST)) #include "m-buffer.h" @@ -132,12 +141,13 @@ M_QUEUE_SPSC_DEF(queue22, string_t, M_BUFFER_STACK) M_DEQUE_DEF(deque, int) M_DEQUE_DEF(deque_str, string_t) +M_ALGO_DEF(deque_str, M_DEQUE_OPLIST(deque_str, M_STRING_OPLIST)) #include "m-snapshot.h" M_SNAPSHOT_SPSC_DEF(snap1, int) M_SNAPSHOT_SPMC_DEF(snap2, int) -M_SNAPSHOT_MPMC_DEF(snap3, int) +M_SNAPSHOT_MPMC_DEF(snap3, string_t) #include "m-tree.h" From 2ad8d4240179e218fe14e4d9ba8d2c3508a355f9 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 16:01:04 +0200 Subject: [PATCH 68/91] Update summary --- README.md | 69 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index c3db0303..a84df798 100644 --- a/README.md +++ b/README.md @@ -12,39 +12,44 @@ M\*LIB: Generic type-safe Container Library for C language 9. [Errors & compilers](#errors--compilers) 10. [External Reference](#external-reference) 11. [API Documentation](#api-documentation) - 1. [Generic methods](#generic-methods) - 2. [List](#m-list) - 3. [Intrusive list](#m-i-list) - 4. [Array](#m-array) - 5. [Dictionary](#m-dict) - 6. [Red/Black Tree](#m-rbtree) - 7. [B+ Tree](#m-bptree) - 8. [Generic Tree](#m-tree) - 9. [Tuple](#m-tuple) - 10. [Variant](#m-variant) - 11. [Double end queue](#m-deque) - 12. [Priority queue](#m-prioqueue) - 13. [Fixed size queue / stack](#m-queue) - 14. [Shared Fixed size queue](#m-buffer) - 15. [Atomic Shared Register](#m-snapshot) - 16. [Shared pointers](#m-shared-ptr) - 17. [Intrusive Shared Pointers](#m-i-shared) - 18. [Concurrent adapter](#m-concurrent) - 19. [Bitset](#m-bitset) - 20. [String](#m-string) - 21. [Byte String](#m-bstring) - 22. [Core preprocessing](#m-core) - 23. [Worker threads](#m-worker) - 24. [Generic algorithms](#m-algo) - 25. [Function objects](#m-funcobj) - 26. [Exception handling](#m-try) - 27. [Memory pool](#m-mempool) - 28. [JSON Serialization](#m-serial-json) - 29. [Binary Serialization](#m-serial-bin) - 30. [Generic interface](#m-generic) - 31. [Thread](#m-thread) - 32. [Atomic](#m-atomic) + 1. [Generic method interface](#generic-methods) + 2. Sequence containers + 1. [List](#m-list) + 2. [Intrusive list](#m-i-list) + 3. [Array](#m-array) + 4. [Double end queue](#m-deque) + 6. [Fixed size queue / stack](#m-queue) + 3. Associative containers + 1. [Dictionary](#m-dict) + 2. [Red/Black Tree](#m-rbtree) + 3. [B+ Tree](#m-bptree) + 4. Misc containers + 1. [Priority queue](#m-prioqueue) + 2. [Generic Tree](#m-tree) + 3. [Tuple](#m-tuple) + 4. [Variant](#m-variant) + 5. Thread containers + 1. [Shared Fixed size queue](#m-buffer) + 2. [Atomic Shared Register](#m-snapshot) + 3. [Shared pointers](#m-shared-ptr) + 4. [Worker threads](#m-worker) + 6.Dataset + 1. [String](#m-string) + 2. [Byte String](#m-bstring) + 3. [Bitset](#m-bitset) + 7.Algorithms + 1. [Generic algorithms](#m-algo) + 2. [Function objects](#m-funcobj) + 8.Serialization + 1. [JSON Serialization](#m-serial-json) + 2. [Binary Serialization](#m-serial-bin) + 9. [Uniform interface](#m-generic) + 10. [Core preprocessing](#m-core) + 11. C11 compatibility headers + 1. [Thread](#m-thread) + 2. [Atomic](#m-atomic) 12. [Global User Customization](#global-user-customization) + 1. [Exception handling](#m-try) 13. [License](#license) ## Overview From df37a5d8f16f089f1a048ad0bf7b41c93e3b82bc Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 21 Apr 2025 16:02:19 +0200 Subject: [PATCH 69/91] Fix --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a84df798..2ebb6cf2 100644 --- a/README.md +++ b/README.md @@ -33,14 +33,14 @@ M\*LIB: Generic type-safe Container Library for C language 2. [Atomic Shared Register](#m-snapshot) 3. [Shared pointers](#m-shared-ptr) 4. [Worker threads](#m-worker) - 6.Dataset + 6. Dataset 1. [String](#m-string) 2. [Byte String](#m-bstring) 3. [Bitset](#m-bitset) - 7.Algorithms + 7. Algorithms 1. [Generic algorithms](#m-algo) 2. [Function objects](#m-funcobj) - 8.Serialization + 8. Serialization 1. [JSON Serialization](#m-serial-json) 2. [Binary Serialization](#m-serial-bin) 9. [Uniform interface](#m-generic) From 6e8aa58bd6278b00edd9ba8f71274a78eab36ecf Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 23 Apr 2025 21:16:08 +0200 Subject: [PATCH 70/91] Update doc --- README.md | 105 +++++++++++++++++++++++++++--------------------------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 2ebb6cf2..b0ba319d 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ M\*LIB: Generic type-safe Container Library for C language 9. [Errors & compilers](#errors--compilers) 10. [External Reference](#external-reference) 11. [API Documentation](#api-documentation) - 1. [Generic method interface](#generic-methods) + 1. [Common Interface](#Common-Interface) 2. Sequence containers - 1. [List](#m-list) - 2. [Intrusive list](#m-i-list) - 3. [Array](#m-array) + 1. [Array](#m-array) + 2. [List](#m-list) + 3. [Intrusive list](#m-i-list) 4. [Double end queue](#m-deque) 6. [Fixed size queue / stack](#m-queue) 3. Associative containers @@ -1284,11 +1284,11 @@ _________________ The M\*LIB reference card is available [here](http://htmlpreview.github.io/?https://github.com/P-p-H-d/mlib/blob/master/doc/Container.html). -### Generic methods +### Common Interface The generated containers tries to generate and provide a consistent interface: their methods would behave the same for all generated containers. -This chapter will explain the generic interface. +This chapter will explain the common generated interface. In case of difference, it will be explained in the specific container. In the following description: @@ -1323,7 +1323,7 @@ The output parameters are listed fist, then the input/output parameters and fina The oplist shall also provide the `INIT_MOVE` operator if the default instance (aka '=' operator) is not working for this type (for example for array of size 1, in which case the method `M_COPY_A1_DEFAULT` is likely to work), or disable the operator. -This generic interface is specified as follow: +This common interface is specified as follow: ##### `void name_init(name_t container)` @@ -1873,9 +1873,9 @@ Type of the list of `type` objects. Type of an iterator over this list. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t list) @@ -2035,9 +2035,9 @@ Type of the list of `type`. Type of an iterator over this list. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t list) @@ -2197,9 +2197,9 @@ Type of the array of `type`. Type of an iterator over this array. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t array) @@ -2392,9 +2392,9 @@ Type of the deque of `type`. Type of an iterator over this deque. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t deque) @@ -2671,9 +2671,9 @@ Type of one item referenced in the dictionary for associative array. It is a structure composed of the key (field `key`) and the value (field `value`). This type is created only for associative arrays (`_DEF2` suffix) and not for sets. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t dict) @@ -2740,7 +2740,7 @@ Each element is defined by three parameters within parenthesis: * the element name (the field name of the structure) * the element type (the associated type) -* and the optional element oplist associated to this type (see [generic interface](#Generic-API-Interface-Adaptation) for the behavior if it is absent) +* and the optional element oplist associated to this type. `name` and `element` shall be C identifiers that will be used to identify the container and the fields. @@ -2809,9 +2809,9 @@ The following type is automatically defined by the previous definition macro if Type of the defined tuple. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t tuple) @@ -2953,9 +2953,9 @@ The following type is automatically defined by the previous definition macro if Type of the defined variant. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t variant) @@ -3083,9 +3083,9 @@ Type of the Red Black Tree. Type of an iterator over this Red Black Tree. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t rbtree) @@ -3307,9 +3307,9 @@ Type of one item referenced in the B+Tree. It is either: * a structure composed of a pointer to the key (field `key_ptr`) and a pointer to the value (field `value_ptr`) if the B+Tree is an associative array, * or the basic type of the container if the B+Tree is a set. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t tree) @@ -3452,9 +3452,9 @@ Type of the generic tree of `type`. Type of an iterator over this generic tree. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t tree) @@ -3755,9 +3755,9 @@ Type of the priority queue of `type`. Type of an iterator over this priority queue. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t queue) @@ -3889,9 +3889,9 @@ The following types are automatically defined by the previous definition macro i Type of the circular queue (or stack). -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_clear(queue_t queue) @@ -3992,9 +3992,9 @@ The following types are automatically defined by the previous definition macro i Type of the buffer. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_clear(buffer_t buffer) /* Not thread safe */ @@ -4111,9 +4111,9 @@ The following types are automatically defined by the previous definition macro i Type of the circular queue. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_clear(buffer_t buffer) @@ -4196,9 +4196,9 @@ The following types are automatically defined by the previous definition macro i Type of the circular queue. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_clear(buffer_t buffer) @@ -4353,9 +4353,9 @@ The following types are automatically defined by the previous definition macro i Type of the circular queue. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details) +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): but none is thread safe: ```C @@ -4435,9 +4435,9 @@ The following types are automatically defined by the previous definition macro i Type of the circular queue. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_clear(snapshot_t snapshot) @@ -4518,9 +4518,9 @@ The following types are automatically defined by the previous definition macro i Type of the circular queue. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_clear(snapshot_t snapshot) @@ -5509,9 +5509,9 @@ Type of the list of `type`. Type of an iterator over this list. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t list) @@ -5672,9 +5672,9 @@ The following types are automatically defined by the previous definition macro i Type of the concurrent container of `type`. -#### Generic methods +#### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t concurrent) @@ -6538,9 +6538,9 @@ The following types are automatically defined by the previous definition macro i Type of the concurrent container of `type`. -###### Generic methods +###### Common methods -The following methods of the generic interface are defined (See [generic interface](#Generic-API-Interface-Adaptation) for details): +The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): ```C void name_init(name_t bounded_string) @@ -9090,7 +9090,8 @@ _________________ ### M-TRY -This header is for [exception handling](https://en.wikipedia.org/wiki/Exception_handling). +This header is for enabling [exception handling](https://en.wikipedia.org/wiki/Exception_handling) for M\*LIB. +It shall be included first, before any other headers, to enable globally the use of exceptions. It provides basic functionality for throwing exception and catching then. The `setjmp` and `longjmp` standard library functions (or some variants) are used to implement the try / catch / throw macro keywords. It doesn't support the `finally` keyword. @@ -9413,7 +9414,7 @@ _________________ ### M-GENERIC -This header is for registering and using a generic interface, regardless of the real type. +This header is for registering type to use them within a generic interface, regardless of the real type. More precisely it provides way of registering the oplist of a type. Then a variable of this type can be used in macro-like functions (`init`, `clear`, `push`, ...) and the associated method of this oplist will be used to handle the variable. If no type is associated to this variable, an error is reported by the compiler. From 3ddf9438da405b64d71b919c0dd4296605627adf Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 23 Apr 2025 21:24:56 +0200 Subject: [PATCH 71/91] Update --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b0ba319d..81f46cb7 100644 --- a/README.md +++ b/README.md @@ -9683,12 +9683,6 @@ Define the size of the private data (reserved to the serial implementation) in a Default value: `4` -#### `M_USE_MEMPOOL_MAX_PER_SEGMENT(type)` - -Define the number of elements to allocate in a segment per object of type `type`. - -Default value: number of elements that fits in a `16KB` page. - #### `M_USE_DEQUE_DEFAULT_SIZE` Define the default size of a segment for a deque structure. @@ -9707,16 +9701,17 @@ Use fast integer conversion algorithms instead of using the LIBC. Default value: `1` (because it also generates smaller code). -#### `M_USE_DECL` +#### `M_USE_DECL` and `M_USE_DEF` If `M_USE_FINE_GRAINED_LINKAGE` is not defined, -it will request M\*LIB to change the linkage of its symbols globally: -instead of inlining the functions, it will emit weak symbols -for the functions that are not inlined. +`M_USE_DECL` will request M\*LIB to globally change the linkage of the functions: +instead of being inline, the functions will be emitted as `weak` symbols, +ensuring that only one definition of the function remains at the end +of the link. -And in exactly one translation unit, the macro `M_USE_DEF` +In exactly one translation unit, the macro `M_USE_DEF` should also be defined so that it emits the normal definition -of the functions. In which case, it should contain all symbols +of the functions (non `weak`). In which case, it should contain all symbols used by all other translation units. You should compile your program with: @@ -9727,11 +9722,13 @@ and link with ```shell -Wl,--gc-sections ``` -in order to remove unused code and to merge identical code -otherwise it is likely to generate even bigger code than using the inlining linkage. +in order to remove unused code +otherwise it is possible to generate even bigger code than using the inlining linkage. This works for GCC / CLANG in C mode. +Default value: undefined (inline definition) + #### `M_USE_FINE_GRAINED_LINKAGE` It will request M\*LIB to change the linkage of its symbols dynamically at compile time: @@ -9749,10 +9746,14 @@ This enables to inline some functions and not others. See `M_USE_DECL` for more details. +Default value: undefined (inline definition) + #### `M_USE_PRINT_OPLIST` If defined, it displays the oplist associated to the static assert. +Default value: undefined (oplist not printed) + #### `M_MEMORY_ALLOC` See [m-core.h](#m-core) From 431e3a12283021c4ff85218ed90bb15997415d03 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Fri, 25 Apr 2025 22:21:57 +0200 Subject: [PATCH 72/91] Update doc (WIP) --- README.md | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/README.md b/README.md index 81f46cb7..fdee532c 100644 --- a/README.md +++ b/README.md @@ -9583,6 +9583,144 @@ The following macro is defined and enabled to iterate over a container (See exam _________________ +## Memory context Customization + +It is possible to give a custom memory context parameter to the memory methods `REALLOC`, `FREE`, `NEW`and `DEL`. + +For this, you need to define `M_USE_CONTEXT` to the type of the custom memory context parameter. +The definition of this global parameter modifies the generation of **all** functions +so that the functions that may allocate or free something will add a new argument, +the memory context parameter `m_context` of type `M_USE_CONTEXT`, +as their first arguement. +It will also modifies the `OPLIST` definition so that they request the parameter named `m_context` +for such methods. + +The memory context can be an [arena allocator](https://www.rfleury.com/p/untangling-lifetimes-the-arena-allocator) + +> [!Note] +> The memory context parameter is not stored in the container +> because it is not efficient in memory usage and is redundant when you +> create container of other containers (example `array` of `string_t)` +> The user shall ensure of the coherence of the memory context for a given container +> so that it is the same memory context since its construction to its destruction. + +If you master your own memory, you may want to control when performing the Garbage Collecting. +This Garbage Collecting may be quite efficient in reclaiming allocated memory in a single and efficient pass: +in such a case, you may not want calling the destructors of the containers as their operation of freeing the memory +back to the memory allocator will be redundant and inefficient. +As a consequence, the following guarantee is ensured: +The destructors of all containers except the thread safe ones only free back memory. +As such, it is safe not to call the destructors of these containers if you have another way to reclaim your memory. +If the destructor of a mutex is also a no-op on your system, this guarantee is extended to the thread safe containers too. + +In order to use such feature, you need to: + +* define globally `M_USE_CONTEXT` with your type. +* define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE`. + +You will realize that the expected definitions of these macros don't expect the memory context parameter. +Instead, the macros themselves shall directly use the named argument `m_context` for this purpose. +This argument is ensure to be defined by the function when using this macro. + +FIXME: Seems bad design when written... + +Example + +```C +// Define a memory context type +typedef int *context_t; + +// Define the realloc / free that accepts the memory context. +static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context) +{ + (void) context; // TODO + (void) old; // TODO + return realloc(ptr, new*base); +} + +static void my_free(void *ptr, size_t old, size_t base, context_t context) +{ + (void) context; // TODO + (void) old; // TODO + (void) base; // TODO + free(ptr); +} + +// Request M*LIB to generate functions accepting a memory context parameter that will be passed to the memory functions +# define M_USE_CONTEXT context_t + +// Overloaded memory functions to use the custom ones. +// m_context is the name of the memory context parameter +# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context) +# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (type), m_context) + +# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context) +# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context) + +// Now you may include M*LIB headers. +``` + +This works great for local allocators for a thread. However some containers are designed to handle +objects accross several threads: shared pointer, communication queue, ... + +For such containers, a local allocator has no meaning: it will be very hard to ensure the same allocator +is used for both the producor thread and the user threads. + +As a concequence, shared pointer, communication queue container and all thread containers +will use a global memory context: +M\*LIB won't add a new argument `m_context` to the functions of such containers. Instead it will generate +a local parameter initialize to the global memory context. +The global memory context is defined by the macro `M_USE_GLOBAL_CONTEXT` which shall define and initialize +the named argument to the global memory context. In the absence of definition of such macro, the default is +to initialize the context to '0'. The memory functions shall recognize such context as the global one. + +FIXME: if it is expensive, it is useless to initialize a local variable rather than using the global variable directly... + +The following methods are modified to support the memory context parameter: + +* m-string: +** _clear +** _clear_get_cstr +** _reserve +** _set_cstr +** _set_cstrn +** _set +** _set_n +** _init_set +** _init_set_cstr +** _move +** _push_back +** _cat_cstr +** _cat +** _replace_cstr +** _replace +** _replace_at +** _replace_all_cstr +** _replace_all +** _set_ui +** _set_si +** _vprintf +** _printf +** _cat_vprintf +** _cat_printf +** _set_ui +** _set_si +** _fgets +** _fget_word +** _get_str +** _in_str +** _parse_str +** _out_serial +** _in_serial +** _it_set_ref +** _push_u +** _split +** _join +** _out_serial +** _in_serial + +_________________ + ## Global User Customization The behavior of M\*LIB can be customized globally by defining the following macros From fb3140e64504ede62c8ed081da06979a449e7e82 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 26 Apr 2025 00:10:01 +0200 Subject: [PATCH 73/91] Fix warning of unused variable. --- m-string.h | 1 + 1 file changed, 1 insertion(+) diff --git a/m-string.h b/m-string.h index 9d588a83..8f5259bf 100644 --- a/m-string.h +++ b/m-string.h @@ -1984,6 +1984,7 @@ m_string_pop_u(m_string_unicode_t *u, m_string_t str) // Support of NULL pointer m_string_unicode_t u_tmp; m_string_unicode_t *u_ptr = u == NULL ? &u_tmp : u; + *u_ptr = 0; do { m_str1ng_utf8_decode(*tmp++, &state, u_ptr); } while (state != M_STR1NG_UTF8_STARTING && state != M_STR1NG_UTF8_ERROR); From 174c62015b9337de72de7dae51f9763770423cde Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 26 Apr 2025 00:10:58 +0200 Subject: [PATCH 74/91] Workaround wrong analyze by GCC analyzer --- tests/test-obj.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test-obj.h b/tests/test-obj.h index 660e2d4b..42f73df1 100644 --- a/tests/test-obj.h +++ b/tests/test-obj.h @@ -46,8 +46,9 @@ static inline void *overloaded_realloc(size_t st, void *ptr, size_t o, size_t n) assert(p[1] == o); amount_allocated -= st * o; } - p = (size_t *) realloc(p, 2*sizeof(size_t) + st * n); - assert(p != NULL); + ptr = realloc((void*)p, 2*sizeof(size_t) + st * n); + assert(ptr != NULL); + p = (size_t*) ptr; p[0] = st; p[1] = n; amount_allocated += st * n; From 196db1cf62847461acab3c5a8df3aeaa0469fd47 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 26 Apr 2025 00:29:16 +0200 Subject: [PATCH 75/91] Improve test suite --- tests/test-mbuffer.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test-mbuffer.c b/tests/test-mbuffer.c index 435dd771..80b14a6f 100644 --- a/tests/test-mbuffer.c +++ b/tests/test-mbuffer.c @@ -564,9 +564,11 @@ static void test_double2(void) BufferDouble2_push(buffer, 0.0); BufferDouble2_push(buffer, 1.0); double d; - BufferDouble2_pop(&d, buffer); + bool b = BufferDouble2_pop(&d, buffer); + assert(b); assert(d == 0.0); - BufferDouble2_pop(&d, buffer); + b = BufferDouble2_pop(&d, buffer); + assert(b); assert(d == 1.0); BufferDouble2_clear(buffer); } @@ -578,9 +580,11 @@ static void test_double3(void) BufferDouble3_push(buffer, 0.0); BufferDouble3_push(buffer, 1.0); double d; - BufferDouble3_pop(&d, buffer); + bool b = BufferDouble3_pop(&d, buffer); + assert(b); assert(d == 0.0); - BufferDouble3_pop(&d, buffer); + b = BufferDouble3_pop(&d, buffer); + assert(b); assert(d == 1.0); BufferDouble3_clear(buffer); } From 6d5d34fb7220a5e457e286c7415d5544c3d8dda8 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 30 Apr 2025 00:12:35 +0200 Subject: [PATCH 76/91] Update --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fdee532c..14c0be93 100644 --- a/README.md +++ b/README.md @@ -516,15 +516,16 @@ of the library. The final goal of the library is to be able to write code like this in pure C while keeping type safety and compile time name resolution: ```C -M_LET(list, list_uint_t) { +let(list, list_uint_t) { push(list, 42); push(list, 17); for each (item, list) { - M_PRINT(*item, "\n"); + print(*item, "\n"); } } ``` +And it works! See the [example](https://github.com/P-p-H-d/mlib/blob/master/example/ex11-generic01.c) and [M-GENERIC](#M-GENERIC) header for details. @@ -9675,6 +9676,7 @@ the named argument to the global memory context. In the absence of definition of to initialize the context to '0'. The memory functions shall recognize such context as the global one. FIXME: if it is expensive, it is useless to initialize a local variable rather than using the global variable directly... +Seems difficult to fix without. The following methods are modified to support the memory context parameter: From f585167fa8501f78676dcbdde5a16b07bd4bcb55 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 30 Apr 2025 00:13:41 +0200 Subject: [PATCH 77/91] Simplify code (remove redundant intermediary macro) --- m-core.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/m-core.h b/m-core.h index b07757b1..8228bace 100644 --- a/m-core.h +++ b/m-core.h @@ -3612,10 +3612,10 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_GET_PROPERTIES(...) M_GET_METHOD(PROPERTIES, (), __VA_ARGS__) #define M_GET_EMPLACE_TYPE(...) M_GET_METHOD(EMPLACE_TYPE, , __VA_ARGS__) // As attribute customization -#define M_GET_NEW(...) M_GET_METHOD(NEW, M_NEW_DEFAULT, __VA_ARGS__) -#define M_GET_DEL(...) M_GET_METHOD(DEL, M_DEL_DEFAULT, __VA_ARGS__) -#define M_GET_REALLOC(...) M_GET_METHOD(REALLOC, M_REALLOC_DEFAULT, __VA_ARGS__) -#define M_GET_FREE(...) M_GET_METHOD(FREE, M_FREE_DEFAULT, __VA_ARGS__) +#define M_GET_NEW(...) M_GET_METHOD(NEW, M_MEMORY_ALLOC, __VA_ARGS__) +#define M_GET_DEL(...) M_GET_METHOD(DEL, M_MEMORY_DEL, __VA_ARGS__) +#define M_GET_REALLOC(...) M_GET_METHOD(REALLOC, M_MEMORY_REALLOC, __VA_ARGS__) +#define M_GET_FREE(...) M_GET_METHOD(FREE, M_MEMORY_FREE, __VA_ARGS__) #define M_GET_MEMPOOL(...) M_GET_METHOD(MEMPOOL, M_NO_DEF_MEMPOOL, __VA_ARGS__) #define M_GET_MEMPOOL_LINKAGE(...) M_GET_METHOD(MEMPOOL_LINKAGE, , __VA_ARGS__) #define M_GET_SIZE(...) M_GET_METHOD(SIZE, 0, __VA_ARGS__) @@ -4031,10 +4031,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_EMPTY_DEFAULT(...) ((void)1) #define M_TRUE_DEFAULT(...) true #define M_FALSE_DEFAULT(...) false -#define M_NEW_DEFAULT(a) M_MEMORY_ALLOC(a) -#define M_DEL_DEFAULT(a) M_MEMORY_DEL(a) -#define M_REALLOC_DEFAULT(t,p,o,s) M_MEMORY_REALLOC(t,p,o,s) -#define M_FREE_DEFAULT(t,a,o) M_MEMORY_FREE(t,a,o) #define M_EQUAL_DEFAULT(a,b) ((a) == (b)) #define M_CMP_DEFAULT(a,b) ((a) < (b) ? -1 : (a) > (b)) #define M_ADD_DEFAULT(a,b,c) ((a) = (b) + (c)) From 3721129da11ea6db12fa1015187b27e44354a5fc Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 1 May 2025 23:04:25 +0200 Subject: [PATCH 78/91] Update prototype of memory functions to always get the memory context parameter (even if it is not needed) to provide a cleaner and simpler user interface (instead of requesting the user to use directly m_context). --- README.md | 99 ++++++++++++++++++++++++++--------------- doc/API.txt | 1 + example/ex-alloc1.c | 8 ++-- example/ex-alloc2.c | 8 ++-- example/ex11-use-pool.c | 9 ++-- m-bitset.h | 12 ++--- m-bstring.h | 8 ++-- m-c-mempool.h | 24 +++++----- m-core.h | 44 ++++++++++-------- m-deque.h | 4 +- m-genint.h | 4 +- m-mempool.h | 6 +-- m-snapshot.h | 4 +- m-string.h | 10 ++--- m-worker.h | 8 ++-- tests/test-mbuffer.c | 2 +- tests/test-milist.c | 2 +- tests/test-obj-except.h | 16 +++---- tests/test-obj.h | 4 +- 19 files changed, 155 insertions(+), 118 deletions(-) diff --git a/README.md b/README.md index 14c0be93..7fd56d22 100644 --- a/README.md +++ b/README.md @@ -1041,18 +1041,37 @@ In which case, this enables you to close the file even if an exception is thrown Memory Allocation functions can be globally set by overriding the following macros before using the definition `_DEF` macros: -* `M_MEMORY_ALLOC (type)` --> `ptr`: return a pointer to a new object of type `type`. -* `M_MEMORY_DEL (ptr)`: free the single object pointed by `ptr`. -* `M_MEMORY_REALLOC (type, ptr, old_number, new_number)` --> `ptr`: return a pointer to an array of `new_number` objects of type `type`, reusing the old array pointed by `ptr` of `old_number` objects. `ptr` can be NULL, in which case the array will be created. -* `M_MEMORY_FREE (type, ptr, number)`: free the array of `number` objects of type `type` pointed by `ptr`. +* `M_MEMORY_ALLOC (context, type)` --> `ptr`: return a pointer to a new object of type `type`. +* `M_MEMORY_DEL (context, ptr)`: free the single object pointed by `ptr`. +* `M_MEMORY_REALLOC (context, type, ptr, old_number, new_number)` --> `ptr`: return a pointer to an array of `new_number` objects of type `type`, reusing the old array pointed by `ptr` of `old_number` objects. `ptr` can be NULL, in which case the array will be created. +* `M_MEMORY_FREE (context, type, ptr, number)`: free the array of `number` objects of type `type` pointed by `ptr`. -`ALLOC` and `DEL` operators are supposed to allocate fixed size single element object (no array). +> [!NOTE] +> You can use `sizeof (type)` and `alignof (type)` to get the size and the alignement of the object. + +> [!NOTE] +> For `M_MEMORY_DEL`, `sizeof *ptr` always identifies the size of the object. + +`ALLOC` and `DEL` operators are supposed to allocate **fixed** size single element object (no array). These objects are not expected to grow. `REALLOC` and `FREE` operators deal with allocated memory for growing objects. Do not mix pointers between both: a pointer allocated by `ALLOC` (resp. `REALLOC`) is supposed to be only freed by `DEL` (resp. `FREE`). There are separated 'free' operators to enable specialization in the allocator (a good allocator can take this hint into account). +`context` is a local user context used to identify the memory context to use for the allocation. +This parameter **only** exists if the library is compiled with the `M_USE_CONTEXT` customization parameter enabled globally. +Otherwise this parameter identifies a non existing symbol `m_context`. + +This parameter shall be discarded if `M_USE_CONTEXT` is not defined (it shall not exist anymore after preprocessing step). +For that, you can define the macros to ignore the first parameter +or you can use GAIA to adapt the call to what your function expects. + +> [!NOTE] +> If you get error on `m_context` being undefined +> it is likely because one of your memory is trying to evaluate the memory context +> without defining `M_USE_CONTEXT`. + `M_MEMORY_ALLOC` and `M_MEMORY_REALLOC` are supposed to return NULL in case of memory allocation failure. The defaults are `malloc`, `free`, `realloc` and `free`. @@ -4724,7 +4743,7 @@ void f(void) { shared_data_push(p, 23); shared_data_push(p, 32); // And send it through 2 channels of communication - comm_buffer_push(comm1, p); // shared_data_acquire is done by the buffer to acquite ownership of the data + comm_buffer_push(comm1, p); // shared_data_acquire is done by the buffer to acquit ownership of the data comm_buffer_push(comm2, p); // Release our ownership of the data shared_data_clear(p); @@ -4909,7 +4928,7 @@ This method is created only if the `PUSH` operator is defined. ##### `bool name_try_push_move(name_t *a, sub_type *el)` Try to push in `*a` the element `*el`,if the container is not full and clear `*el` (return true in this case). -Return false otherwise (cannot push element) and `*el` is still initializated. +Return false otherwise (cannot push element) and `*el` is still initialized. This method is created only if the `PUSH_MOVE` operator is defined. ##### `bool name_try_emplace(name_t *a[, args])` @@ -7967,22 +7986,28 @@ void struct_init_set(struct_t d, struct_t s) All these macro can be overridden before including the header [m-core.h](#m-core) so that they can be adapted to a particular memory pool. -##### `type *M_MEMORY_ALLOC (type)` +##### `type *M_MEMORY_ALLOC (context, type)` Return a pointer to a new allocated non-initialized object of type `type`. In case of allocation error, it returns NULL. +`context` parameter is the memory context parameter as provided by the user. +It only exists if the library is built with `M_USE_CONTEXT` + The default used function is the `malloc` function of the LIBC. -##### `void M_MEMORY_DEL (type *ptr)` +##### `void M_MEMORY_DEL (context, type *ptr)` Delete the cleared object pointed by the pointer `ptr` that was previously allocated by the macro `M_MEMORY_ALLOC`. `ptr` can not be NULL. +`context` parameter is the memory context parameter as provided by the user. +It only exists if the library is built with `M_USE_CONTEXT` + The default used function is the `free` function of the LIBC. -##### `type *M_MEMORY_REALLOC (type, ptr, old_number, new_number)` +##### `type *M_MEMORY_REALLOC (context, type, ptr, old_number, new_number)` Return a pointer to an array of `new_number` objects of type `type` `ptr` is either NULL (in which the array is allocated), @@ -7994,14 +8019,20 @@ The address of the previous objects may have moved and the `MOVE` operator is not used in this case. In case of allocation error, it returns NULL. +`context` parameter is the memory context parameter as provided by the user. +It only exists if the library is built with `M_USE_CONTEXT` + The default used function is the `realloc` function of the LIBC. -##### `void M_MEMORY_FREE (type, ptr, number)` +##### `void M_MEMORY_FREE (context, type, ptr, number)` Delete the cleared array of `number` objects of type `type pointed by the pointer `ptr`. The pointer was previously allocated by the macro `M_MEMORY_REALLOC`. If `ptr` is NULL, the function shall do nothing. +`context` parameter is the memory context parameter as provided by the user. +It only exists if the library is built with `M_USE_CONTEXT` + The default used function is the `free` function of the LIBC. ##### `void M_MEMORY_FULL (type, number)` @@ -9591,8 +9622,8 @@ It is possible to give a custom memory context parameter to the memory methods ` For this, you need to define `M_USE_CONTEXT` to the type of the custom memory context parameter. The definition of this global parameter modifies the generation of **all** functions so that the functions that may allocate or free something will add a new argument, -the memory context parameter `m_context` of type `M_USE_CONTEXT`, -as their first arguement. +the memory context parameter `m_context` of the user provided type `M_USE_CONTEXT`, +as their first argument. It will also modifies the `OPLIST` definition so that they request the parameter named `m_context` for such methods. @@ -9601,29 +9632,26 @@ The memory context can be an [arena allocator](https://www.rfleury.com/p/untangl > [!Note] > The memory context parameter is not stored in the container > because it is not efficient in memory usage and is redundant when you -> create container of other containers (example `array` of `string_t)` -> The user shall ensure of the coherence of the memory context for a given container -> so that it is the same memory context since its construction to its destruction. +> create container of other containers (example `array` of `string_t`). + +The user shall ensure of the coherence of the memory context for a given container +so that the same memory context is used from its construction to its destruction. If you master your own memory, you may want to control when performing the Garbage Collecting. This Garbage Collecting may be quite efficient in reclaiming allocated memory in a single and efficient pass: in such a case, you may not want calling the destructors of the containers as their operation of freeing the memory back to the memory allocator will be redundant and inefficient. As a consequence, the following guarantee is ensured: + The destructors of all containers except the thread safe ones only free back memory. As such, it is safe not to call the destructors of these containers if you have another way to reclaim your memory. -If the destructor of a mutex is also a no-op on your system, this guarantee is extended to the thread safe containers too. +If the destructor of a mutex is also a no-op on your system, this guarantee is extended to all containers +(including the thread safe containers too). In order to use such feature, you need to: * define globally `M_USE_CONTEXT` with your type. -* define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE`. - -You will realize that the expected definitions of these macros don't expect the memory context parameter. -Instead, the macros themselves shall directly use the named argument `m_context` for this purpose. -This argument is ensure to be defined by the function when using this macro. - -FIXME: Seems bad design when written... +* define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE` to use your context. Example @@ -9634,16 +9662,16 @@ typedef int *context_t; // Define the realloc / free that accepts the memory context. static void *my_realloc(void *ptr, size_t old, size_t new, size_t base, context_t context) { - (void) context; // TODO - (void) old; // TODO + (void) context; // TODO what you want with it. + (void) old; // TODO what you want with it. return realloc(ptr, new*base); } static void my_free(void *ptr, size_t old, size_t base, context_t context) { - (void) context; // TODO - (void) old; // TODO - (void) base; // TODO + (void) context; // TODO what you want with it. + (void) old; // TODO what you want with it. + (void) base; // TODO what you want with it. free(ptr); } @@ -9652,13 +9680,14 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context) // Overloaded memory functions to use the custom ones. // m_context is the name of the memory context parameter -# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context) -# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (type), m_context) +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), ctx) +# define M_MEMORY_FREE(ctx, type, ptr, o) my_free(ptr, o, sizeof (type), ctx) -# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context) -# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context) +# define M_MEMORY_ALLOC(ctx, type) my_realloc(NULL, 0, 1, sizeof (type), ctx) +# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, 1, sizeof (*ptr), ctx) // Now you may include M*LIB headers. +#include "m-array.h" ``` This works great for local allocators for a thread. However some containers are designed to handle @@ -9667,9 +9696,9 @@ objects accross several threads: shared pointer, communication queue, ... For such containers, a local allocator has no meaning: it will be very hard to ensure the same allocator is used for both the producor thread and the user threads. -As a concequence, shared pointer, communication queue container and all thread containers +As a consequence, shared pointer, communication queue container and all thread containers will use a global memory context: -M\*LIB won't add a new argument `m_context` to the functions of such containers. Instead it will generate +M\*LIB won't add a context argument to the functions of such containers. Instead it will generate a local parameter initialize to the global memory context. The global memory context is defined by the macro `M_USE_GLOBAL_CONTEXT` which shall define and initialize the named argument to the global memory context. In the absence of definition of such macro, the default is diff --git a/doc/API.txt b/doc/API.txt index 4fe94bd1..0c17fd07 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -90,6 +90,7 @@ V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible: Add the old number of elements of the array as argument of REALLOC Add the number of elements of the array and its base type as arguments of FREE. (You can ignore the new arguments which are only hints provided to memory functions). + Add the memory context argument. Also impact M_MEMORY_REALLOC & M_MEMORY_FREE This allows more and efficient integration into custom allocators. * M_MEMORY_FULL: replace the failed size allocation size argument diff --git a/example/ex-alloc1.c b/example/ex-alloc1.c index 49390dae..c20b361f 100644 --- a/example/ex-alloc1.c +++ b/example/ex-alloc1.c @@ -43,12 +43,12 @@ static void my_array_free(void *ptr) //////////////////////////////////////////////////////////// // Allocate for single object -# define M_MEMORY_ALLOC(type) my_alloc (sizeof (type)) -# define M_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr) +# define M_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type)) +# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr) // Allocate for array of objects -# define M_MEMORY_REALLOC(type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) -# define M_MEMORY_FREE(type, ptr, n) my_array_free(ptr) +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) +# define M_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr) #include "m-list.h" #include "m-array.h" diff --git a/example/ex-alloc2.c b/example/ex-alloc2.c index 48a441dd..996362ef 100644 --- a/example/ex-alloc2.c +++ b/example/ex-alloc2.c @@ -23,8 +23,8 @@ static void my_free(void *ptr, size_t s) } // Allocate for single object -# define MY_MEMORY_ALLOC(type) my_alloc (sizeof (type)) -# define MY_MEMORY_DEL(ptr) my_free(ptr, sizeof *ptr) +# define MY_MEMORY_ALLOC(ctx, type) my_alloc (sizeof (type)) +# define MY_MEMORY_DEL(ctx, ptr) my_free(ptr, sizeof *ptr) //////////////////////////////////////////////////////////// @@ -76,8 +76,8 @@ static void my_array_free(void *ptr) } // Allocate for array of objects -# define MY_MEMORY_REALLOC(type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) -# define MY_MEMORY_FREE(type, ptr, n) my_array_free(ptr) +# define MY_MEMORY_REALLOC(ctx, type, ptr, o, n) my_array_alloc (sizeof (type), ptr, n) +# define MY_MEMORY_FREE(ctx, type, ptr, n) my_array_free(ptr) //////////////////////////////////////////////////////////// diff --git a/example/ex11-use-pool.c b/example/ex11-use-pool.c index 00c76544..3e11f85e 100644 --- a/example/ex11-use-pool.c +++ b/example/ex11-use-pool.c @@ -23,12 +23,11 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context) # define M_USE_CONTEXT context_t // Overloaded memory functions to use the custom ones. -// m_context is the name of the memory context parameter -# define M_MEMORY_REALLOC(type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), m_context) -# define M_MEMORY_FREE(type, ptr, o) my_free(ptr, o, sizeof (*ptr), m_context) +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) my_realloc(ptr, o, n, sizeof (type), ctx) +# define M_MEMORY_FREE(ctx, type, ptr, o) my_free(ptr, o, sizeof (*ptr), ctx) -# define M_MEMORY_ALLOC(type) my_realloc(NULL, 0, 1, sizeof (type), m_context) -# define M_MEMORY_DEL(ptr) my_free(ptr, 1, sizeof (*ptr), m_context) +# define M_MEMORY_ALLOC(ctx, type) my_realloc(NULL, 0, 1, sizeof (type), ctx) +# define M_MEMORY_DEL(ctx, ptr) my_free(ptr, 1, sizeof (*ptr), ctx) // Now we can include M*LIB functions. #include "m-string.h" diff --git a/m-bitset.h b/m-bitset.h index fdeb0ace..4c346054 100644 --- a/m-bitset.h +++ b/m-bitset.h @@ -104,7 +104,7 @@ m_bitset_reset(m_bitset_t t) M_P(void, m_bitset, _clear, m_bitset_t t) { m_bitset_reset(t); - M_MEMORY_FREE(m_b1tset_limb_ct, t->ptr, t->alloc); + M_MEMORY_FREE(m_context, m_b1tset_limb_ct, t->ptr, t->alloc); // This is not really needed, but is safer // This representation is invalid and will be detected by the contract. // A C compiler should be able to optimize out theses initializations. @@ -122,7 +122,7 @@ M_P(void, m_bitset, _set, m_bitset_t d, const m_bitset_t s) if (M_LIKELY (s->size > 0)) { // Test if enough space in target if (s->size > M_B1TSET_FROM_ALLOC (d->alloc)) { - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, d->ptr, d->alloc, needAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); } @@ -209,7 +209,7 @@ M_P(void, m_bitset, _push_back, m_bitset_t v, bool x) M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); } // Alloc memory - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, needAlloc); // Check if success if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(m_b1tset_limb_ct, needAlloc); @@ -245,7 +245,7 @@ M_P(void, m_bitset, _resize, m_bitset_t v, size_t size) size_t newAlloc = M_B1TSET_TO_ALLOC (size); if (newAlloc > v->alloc) { // Allocate more limbs to store the bitset. - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc); } @@ -290,12 +290,12 @@ M_P(void, m_bitset, _reserve, m_bitset_t v, size_t alloc) } if (M_UNLIKELY (newAlloc == 0)) { // Free all memory used by the bitsets - M_MEMORY_FREE (m_b1tset_limb_ct, v->ptr, v->alloc); + M_MEMORY_FREE (m_context, m_b1tset_limb_ct, v->ptr, v->alloc); v->size = v->alloc = 0; v->ptr = NULL; } else { // Allocate more memory or reduce memory usage - m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); + m_b1tset_limb_ct *ptr = M_MEMORY_REALLOC (m_context, m_b1tset_limb_ct, v->ptr, v->alloc, newAlloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(m_b1tset_limb_ct, newAlloc); } diff --git a/m-bstring.h b/m-bstring.h index 60f30059..4d956f46 100644 --- a/m-bstring.h +++ b/m-bstring.h @@ -77,7 +77,7 @@ m_bstring_init(m_bstring_t s) M_P(void, m_bstring, _clear, m_bstring_t s) { M_BSTRING_CONTRACT(s); - M_MEMORY_FREE(uint8_t, s->ptr, s->alloc); + M_MEMORY_FREE(m_context, uint8_t, s->ptr, s->alloc); s->offset = (size_t) -1; } @@ -164,7 +164,7 @@ M_P(uint8_t *, m_bstr1ng, _fit2size, m_bstring_t v, size_t size_alloc, bool exac if (M_UNLIKELY_NOMEM (alloc < size_alloc)) { goto allocation_error; } - uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, alloc); + uint8_t *ptr = M_MEMORY_REALLOC (m_context, uint8_t, v->ptr, v->alloc, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { goto allocation_error; } @@ -396,13 +396,13 @@ M_P(void, m_bstring, _reserve, m_bstring_t v, size_t n) n = v->offset + size; } if (n == 0) { - M_MEMORY_FREE(uint8_t, v->ptr, v->alloc); + M_MEMORY_FREE(m_context, uint8_t, v->ptr, v->alloc); v->offset = 0; v->size = 0; v->alloc = 0; v->ptr = NULL; } else { - uint8_t *ptr = M_MEMORY_REALLOC (uint8_t, v->ptr, v->alloc, n); + uint8_t *ptr = M_MEMORY_REALLOC (m_context, uint8_t, v->ptr, v->alloc, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(uint8_t, n); } diff --git a/m-c-mempool.h b/m-c-mempool.h index d2059016..e144e496 100644 --- a/m-c-mempool.h +++ b/m-c-mempool.h @@ -97,7 +97,7 @@ M_BEGIN_PROTECTED_CODE M_F(name, _slist_node_ct) *it = *list, *next; \ while (it) { \ next = it->next; \ - M_MEMORY_DEL(it); \ + M_MEMORY_DEL(m_context, it); \ it = next; \ } \ *list = NULL; \ @@ -292,14 +292,14 @@ M_BEGIN_PROTECTED_CODE M_F(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \ memory_order_relaxed); \ M_F(name, _slist_clear)(node->list); \ - M_MEMORY_DEL(node); \ + M_MEMORY_DEL(m_context, node); \ node = next; \ } \ /* Dummy node to free too */ \ M_F(name, _lf_node_t) *dummy; \ dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \ M_F(name, _slist_clear)(dummy->list); \ - M_MEMORY_DEL(dummy); \ + M_MEMORY_DEL(m_context, dummy); \ } \ /* System node allocator: request memory to the system. @@ -310,7 +310,7 @@ M_BEGIN_PROTECTED_CODE M_F(name, _alloc_node)(unsigned int initial) \ { \ M_F(name, _lf_node_t) * node; \ - node = M_MEMORY_ALLOC(M_F(name, _lf_node_t)); \ + node = M_MEMORY_ALLOC(m_context, M_F(name, _lf_node_t)); \ if (M_UNLIKELY_NOMEM (node == NULL)) { \ M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ } \ @@ -319,7 +319,7 @@ M_BEGIN_PROTECTED_CODE M_F(name, _slist_init)(node->list); \ for(unsigned i = 0; i < initial; i++) { \ M_F(name, _slist_node_ct) *n; \ - n = M_MEMORY_ALLOC(M_F(name, _slist_node_ct)); \ + n = M_MEMORY_ALLOC(m_context, M_F(name, _slist_node_ct)); \ if (M_UNLIKELY_NOMEM (n == NULL)) { \ M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ } \ @@ -462,7 +462,7 @@ M_BEGIN_PROTECTED_CODE { \ const size_t max_thread = gc_mem->max_thread; \ /* Initialize the thread data of the mempool */ \ - mem->thread_data = M_MEMORY_REALLOC(M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \ + mem->thread_data = M_MEMORY_REALLOC(m_context, M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \ if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \ M_MEMORY_FULL(M_F(name, _lfmp_thread_ct), max_thread); \ } \ @@ -494,7 +494,7 @@ M_BEGIN_PROTECTED_CODE for(unsigned i = 0; i < max_thread;i++) { \ M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \ } \ - M_MEMORY_FREE(M_F(name, _lfmp_thread_ct), mem->thread_data, max_thread); \ + M_MEMORY_FREE(m_context, M_F(name, _lfmp_thread_ct), mem->thread_data, max_thread); \ mem->thread_data = NULL; \ M_F(name, _lflist_clear)(mem->empty); \ M_F(name, _lflist_clear)(mem->free); \ @@ -584,7 +584,7 @@ m_gc_init(m_gc_t gc_mem, size_t max_thread) atomic_init(&gc_mem->ticket, 0UL); m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread); - gc_mem->thread_data = M_MEMORY_REALLOC(m_gc_lfmp_thread_ct, NULL, 0, max_thread); + gc_mem->thread_data = M_MEMORY_REALLOC(m_context, m_gc_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) { M_MEMORY_FULL(m_gc_lfmp_thread_ct, max_thread); } @@ -604,7 +604,7 @@ m_gc_clear(m_gc_t gc_mem) for(m_gc_tid_t i = 0; i < gc_mem->max_thread;i++) { m_core_backoff_clear(gc_mem->thread_data[i].bkoff); } - M_MEMORY_FREE(m_gc_lfmp_thread_ct, gc_mem->thread_data, gc_mem->max_thread); + M_MEMORY_FREE(m_context, m_gc_lfmp_thread_ct, gc_mem->thread_data, gc_mem->max_thread); gc_mem->thread_data = NULL; m_genint_clear(gc_mem->thread_alloc); } @@ -753,7 +753,7 @@ m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem) const size_t max_thread = gc_mem->max_thread; /* Initialize the thread data of the vlapool */ - mem->thread_data = M_MEMORY_REALLOC(m_vlapool_lfmp_thread_ct, NULL, 0, max_thread); + mem->thread_data = M_MEMORY_REALLOC(m_context, m_vlapool_lfmp_thread_ct, NULL, 0, max_thread); if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { M_MEMORY_FULL(m_vlapool_lfmp_thread_ct, max_thread); } @@ -779,7 +779,7 @@ m_vlapool_clear(m_vlapool_t mem) for(unsigned i = 0; i < max_thread;i++) { m_vlapool_lfmp_thread_clear(&mem->thread_data[i]); } - M_MEMORY_FREE(m_vlapool_lfmp_thread_ct, mem->thread_data, max_thread); + M_MEMORY_FREE(m_context, m_vlapool_lfmp_thread_ct, mem->thread_data, max_thread); mem->thread_data = NULL; m_vlapool_lflist_clear(mem->empty); M_ASSERT(m_vlapool_lflist_empty_p(mem->to_be_reclaimed)); @@ -802,7 +802,7 @@ m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size) size += offsetof(struct m_vlapool_slist_node_s, data); // Simply wrap around a system call to get the memory - char *ptr = M_MEMORY_REALLOC(char, NULL, 0, size); + char *ptr = M_MEMORY_REALLOC(m_context, char, NULL, 0, size); // TODO: save the allocated size somewhere (create a new field in vla) // FIXME: Bug, we call DEL operator to free the node, but we have allocated it with the REALLOC one! // And they are not necessarily compatible as per the spec (even if they are if they both use 'free') diff --git a/m-core.h b/m-core.h index 8228bace..3a8eccb5 100644 --- a/m-core.h +++ b/m-core.h @@ -363,39 +363,47 @@ M_BEGIN_PROTECTED_CODE explicit cast) */ /* Define allocators for object: - * void *M_MEMORY_ALLOC(type): Return a pointer to a new object of type 'type' + * void *M_MEMORY_ALLOC(ctx, type): + * Return a pointer to a new object of type 'type' * It returns NULL in case of memory allocation failure. - * void M_MEMORY_DEL(ptr): Free the object associated to the pointer. + * void M_MEMORY_DEL(ctx, ptr): + * Free the object associated to the pointer. + * By default, 'context' does nothing. + * 'context' is the context parameter given to the memory functions to identify where to create the object. + * It exists only if M_USE_CONTEXT has been globally defined. */ #ifndef M_MEMORY_ALLOC #ifdef __cplusplus # include -# define M_MEMORY_ALLOC(type) ((type*)std::malloc (sizeof (type))) -# define M_MEMORY_DEL(ptr) std::free(ptr) +# define M_MEMORY_ALLOC(ctx, type) ((type*)std::malloc (sizeof (type))) +# define M_MEMORY_DEL(ctx, ptr) std::free(ptr) #else -# define M_MEMORY_ALLOC(type) malloc (sizeof (type)) -# define M_MEMORY_DEL(ptr) free(ptr) +# define M_MEMORY_ALLOC(ctx, type) malloc (sizeof (type)) +# define M_MEMORY_DEL(ctx, ptr) free(ptr) #endif #endif /* Define allocators for array - * void *M_MEMORY_REALLOC(type, ptr, o, n, perm): Return a pointer to a new array of 'n' object of type 'type'. + * void *M_MEMORY_REALLOC(context, type, ptr, o, n, perm): + * Return a pointer to a new array of 'n' object of type 'type'. * If ptr is NULL, it creates a new array of type 'type' and size 'n' * If ptr is not null, it reallocates the given array of type 'type' and size 'o' to the new size. * It returns NULL in case of memory allocation failure. - * void M_MEMORY_FREE(type, ptr, o): Free the object associated to the array of type 'type' at base 'ptr' of size 'o'. - * By default, old size do nothing. - * Can use local optional named parameter "m_context" which is defined by the called of the macro if M_USE_CONTEXT is defined. + * void M_MEMORY_FREE(type, ptr, o): + * Free the object associated to the array of type 'type' at base 'ptr' of size 'o'. + * By default, 'o' size and 'context' do nothing. + * 'context' is the context parameter given to the memory functions to identify where to create the object. + * It exists only if M_USE_CONTEXT has been globally defined. */ #ifndef M_MEMORY_REALLOC #ifdef __cplusplus # include -# define M_MEMORY_REALLOC(type, ptr, o, n) \ +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) \ ((type*) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : std::realloc ((ptr), (n)*sizeof (type)))) -# define M_MEMORY_FREE(type, ptr, o) std::free(ptr) +# define M_MEMORY_FREE(ctx, type, ptr, o) std::free(ptr) #else -# define M_MEMORY_REALLOC(type, ptr, o, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type))) -# define M_MEMORY_FREE(type, ptr, o) free(ptr) +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (M_UNLIKELY ((n) > SIZE_MAX / sizeof(type)) ? NULL : realloc ((ptr), (n)*sizeof (type))) +# define M_MEMORY_FREE(ctx, type, ptr, o) free(ptr) #endif #endif @@ -3632,7 +3640,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_CALL_MOVE(oplist, ...) M_APPLY_API(M_GET_MOVE oplist, oplist, __VA_ARGS__) #define M_CALL_SWAP(oplist, ...) M_APPLY_API(M_GET_SWAP oplist, oplist, __VA_ARGS__) #define M_CALL_CLEAR(oplist, ...) M_APPLY_API(M_GET_CLEAR oplist, oplist, __VA_ARGS__) -#define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, __VA_ARGS__) #define M_CALL_HASH(oplist, ...) M_APPLY_API(M_GET_HASH oplist, oplist, __VA_ARGS__) #define M_CALL_EQUAL(oplist, ...) M_APPLY_API(M_GET_EQUAL oplist, oplist, __VA_ARGS__) #define M_CALL_CMP(oplist, ...) M_APPLY_API(M_GET_CMP oplist, oplist, __VA_ARGS__) @@ -3691,9 +3698,10 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) //#define M_CALL_PROPERTIES(oplist, ...) M_APPLY_API(M_GET_PROPERTIES oplist, oplist, __VA_ARGS__) //#define M_CALL_EMPLACE_TYPE(oplist, ...) M_APPLY_API(M_GET_EMPLACE_TYPE oplist, oplist, __VA_ARGS__) // As attribute customization -#define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, __VA_ARGS__) -#define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, __VA_ARGS__) -#define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, __VA_ARGS__) +#define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, m_context, __VA_ARGS__) +#define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, m_context, __VA_ARGS__) +#define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, m_context, __VA_ARGS__) +#define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, m_context, __VA_ARGS__) #define M_CALL_MEMPOOL(oplist, ...) M_APPLY_API(M_GET_MEMPOOL oplist, oplist, __VA_ARGS__) #define M_CALL_MEMPOOL_LINKAGE(oplist, ...) M_APPLY_API(M_GET_MEMPOOL_LINKAGE oplist, oplist, __VA_ARGS__) //#define M_CALL_SIZE(oplist, ...) M_APPLY_API(M_GET_SIZE oplist, oplist, __VA_ARGS__) diff --git a/m-deque.h b/m-deque.h index 01c9b119..42cfec4c 100644 --- a/m-deque.h +++ b/m-deque.h @@ -104,9 +104,9 @@ // OPLIST for the node deletion #ifdef M_USE_CONTEXT -#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API_0P(M_F(name, _node_list_i_del)))) -#else #define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(M_F(name, _node_list_i_del))) +#else +#define M_D3QU3_NODE_DEL_OPLIST(name) (DEL(API(M_F(name, _node_list_i_del), NONE, ARG2))) #endif /* Define the types. diff --git a/m-genint.h b/m-genint.h index 49b6a8ae..d65eebb2 100644 --- a/m-genint.h +++ b/m-genint.h @@ -108,7 +108,7 @@ M_P(void, m_genint, _init, m_genint_t s, unsigned int n) M_ASSERT (s != NULL && n > 0 && n <= M_GENINT_MAX_ALLOC); const size_t alloc = (n + M_GEN1NT_LIMBSIZE - 1) / M_GEN1NT_LIMBSIZE; const unsigned int index = n % M_GEN1NT_LIMBSIZE; - atomic_ullong *ptr = M_MEMORY_REALLOC (atomic_ullong, NULL, 0, alloc); + atomic_ullong *ptr = M_MEMORY_REALLOC (m_context, atomic_ullong, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(atomic_ullong, alloc); } @@ -127,7 +127,7 @@ M_P(void, m_genint, _init, m_genint_t s, unsigned int n) M_P(void, m_genint, _clear, m_genint_t s) { M_GEN1NT_CONTRACT(s); - M_MEMORY_FREE(atomic_ullong, s->data, s->max+1); + M_MEMORY_FREE(m_context, atomic_ullong, s->data, s->max+1); s->data = NULL; } diff --git a/m-mempool.h b/m-mempool.h index c8d9b301..b7017a73 100644 --- a/m-mempool.h +++ b/m-mempool.h @@ -116,7 +116,7 @@ M_F(name,_init)(name_t mem) \ { \ mem->free_list = NULL; \ - mem->current_segment = M_MEMORY_ALLOC(M_F(name,_segment_ct)); \ + mem->current_segment = M_MEMORY_ALLOC(m_context, M_F(name,_segment_ct)); \ if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \ M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ } \ @@ -132,7 +132,7 @@ M_F(name,_segment_ct) *segment = mem->current_segment; \ while (segment != NULL) { \ M_F(name,_segment_ct) *next = segment->next; \ - M_MEMORY_DEL (segment); \ + M_MEMORY_DEL (m_context, segment); \ segment = next; \ } \ /* Clean pointers to be safer */ \ @@ -157,7 +157,7 @@ unsigned int count = segment->count; \ /* If segment is full, allocate a new one from the system */ \ if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \ - M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (M_F(name,_segment_ct)); \ + M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (m_context, M_F(name,_segment_ct)); \ if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \ M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ } \ diff --git a/m-snapshot.h b/m-snapshot.h index 7e307811..72e595f5 100644 --- a/m-snapshot.h +++ b/m-snapshot.h @@ -390,7 +390,7 @@ M_P(void, m_snapsh0t, _mrsw_init, m_snapsh0t_mrsw_ct s, size_t n) n += M_SNAPSH0T_SPMC_EXTRA_BUFFER; // Initialize the counters to zero (no reader use it) - atomic_uint *ptr = M_MEMORY_REALLOC (atomic_uint, NULL, 0, n); + atomic_uint *ptr = M_MEMORY_REALLOC (m_context, atomic_uint, NULL, 0, n); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(atomic_uint, n); } @@ -416,7 +416,7 @@ M_P(void, m_snapsh0t, _mrsw_init, m_snapsh0t_mrsw_ct s, size_t n) M_P(void, m_snapsh0t, _mrsw_clear, m_snapsh0t_mrsw_ct s) { M_SNAPSH0T_SPMC_INT_CONTRACT(s); - M_MEMORY_FREE (atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); + M_MEMORY_FREE (m_context, atomic_uint, s->cptTab, s->n_reader+M_SNAPSH0T_SPMC_EXTRA_BUFFER); m_genint_clear M_R(s->freeList); s->cptTab = NULL; s->n_reader = 0; diff --git a/m-string.h b/m-string.h index 8f5259bf..03e7efe0 100644 --- a/m-string.h +++ b/m-string.h @@ -285,7 +285,7 @@ M_P(void, m_string, _clear, m_string_t v) { M_STR1NG_CONTRACT(v); if (!m_str1ng_embedded_p(v)) { - M_MEMORY_FREE(char, v->u.heap.ptr, m_string_capacity(v)); + M_MEMORY_FREE(m_context, char, v->u.heap.ptr, m_string_capacity(v)); v->u.heap.ptr = NULL; } /* This is not needed but is safer to make @@ -309,7 +309,7 @@ M_P(char *, m_string, _clear_get_cstr, m_string_t v) p = &v->u.buffer[0]; // Need to allocate a heap string to return the copy. size_t alloc = m_string_size(v)+1; - char *ptr = M_MEMORY_REALLOC (char, NULL, 0, alloc); + char *ptr = M_MEMORY_REALLOC (m_context, char, NULL, 0, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(char, alloc); } @@ -386,7 +386,7 @@ M_P(char *, m_str1ng, _fit2size, m_string_t v, size_t size_alloc) } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; //FIXME: old_alloc may not be NULL if ptr is NULL. - ptr = M_MEMORY_REALLOC (char, ptr, old_alloc, alloc); + ptr = M_MEMORY_REALLOC (m_context, char, ptr, old_alloc, alloc); if (M_UNLIKELY_NOMEM (ptr == NULL)) { M_MEMORY_FULL(char, alloc); } @@ -429,7 +429,7 @@ M_P(void, m_string, _reserve, m_string_t v, size_t alloc) char *oldptr = v->u.heap.ptr; memcpy(ptr, oldptr, size+1); // Free the allocated memory on the heap - M_MEMORY_FREE(char, oldptr, m_string_capacity(v)); + M_MEMORY_FREE(m_context, char, oldptr, m_string_capacity(v)); v->u.buffer[sizeof(m_string_t)-2] = 0; v->u.buffer[sizeof(m_string_t)-1] = (char) size; } else { @@ -444,7 +444,7 @@ M_P(void, m_string, _reserve, m_string_t v, size_t alloc) M_MEMORY_FULL(char, alloc); } char *ptr = m_str1ng_embedded_p(v) ? NULL : v->u.heap.ptr; - ptr = M_MEMORY_REALLOC (char, ptr, m_string_capacity(v), r_alloc); + ptr = M_MEMORY_REALLOC (m_context, char, ptr, m_string_capacity(v), r_alloc); if (M_UNLIKELY_NOMEM (ptr == NULL) ) { M_MEMORY_FULL(char, alloc); } diff --git a/m-worker.h b/m-worker.h index 2bf0244f..4e533f92 100644 --- a/m-worker.h +++ b/m-worker.h @@ -237,7 +237,7 @@ typedef struct m_worker_sync_s { M_GLOBAL_CONTEXT(); \ M_MAP3(M_WORK3R_SPAWN_EXTEND_DEF_CALLBACK_CLEAR, data, __VA_ARGS__) \ /* TODO: Overload */ \ - M_MEMORY_DEL(p); \ + M_MEMORY_DEL(m_context, p); \ } \ \ M_INLINE void \ @@ -265,7 +265,7 @@ typedef struct m_worker_sync_s { { \ M_GLOBAL_CONTEXT(); \ if (!m_work3r_queue_full_p(block->worker->queue_g)) { \ - struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC ( struct M_C3(m_worker_, name, _s)); \ + struct M_C3(m_worker_, name, _s) *p = M_MEMORY_ALLOC (m_context, struct M_C3(m_worker_, name, _s)); \ if (M_UNLIKELY_NOMEM(p == NULL)) { \ M_MEMORY_FULL(struct M_C3(m_worker_, name, _s), 1); \ } \ @@ -412,7 +412,7 @@ m_worker_init(m_worker_t g, int numWorker, unsigned int extraQueue, void (*reset M_ASSERT(numWorker >= 0); size_t numWorker_st = (size_t) numWorker; M_GLOBAL_CONTEXT(); - g->worker = M_MEMORY_REALLOC(m_work3r_thread_ct, NULL, 0, numWorker_st); + g->worker = M_MEMORY_REALLOC(m_context, m_work3r_thread_ct, NULL, 0, numWorker_st); if (M_UNLIKELY_NOMEM (g->worker == NULL)) { M_MEMORY_FULL(m_work3r_thread_ct, numWorker_st); } @@ -457,7 +457,7 @@ m_worker_clear(m_worker_t g) m_thread_join(g->worker[i].id); } // Clear memory - M_MEMORY_FREE(m_work3r_thread_ct, g->worker, g->numWorker_g); + M_MEMORY_FREE(m_context, m_work3r_thread_ct, g->worker, g->numWorker_g); m_mutex_clear(g->lock); m_cond_clear(g->a_thread_ends); m_work3r_queue_clear (g->queue_g); diff --git a/tests/test-mbuffer.c b/tests/test-mbuffer.c index 80b14a6f..a9077c06 100644 --- a/tests/test-mbuffer.c +++ b/tests/test-mbuffer.c @@ -271,7 +271,7 @@ typedef struct test_s { static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); } static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); } ISHARED_PTR_DEF(ishared_itest, test_t, - (INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(free))) + (INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(API(free, NONE, ARG2)))) typedef struct test2_s { ISHARED_PTR_INTERFACE(ishared_itest2, struct test_s); diff --git a/tests/test-milist.c b/tests/test-milist.c index df3a3849..939ef36f 100644 --- a/tests/test-milist.c +++ b/tests/test-milist.c @@ -41,7 +41,7 @@ START_COVERAGE ILIST_DEF(ilist_tname, test_t, M_OPEXTEND(M_POD_OPLIST, EQUAL(API_6(test_equal_p)))) END_COVERAGE -ILIST_DEF(ilist_free, test_t, (DEL(free))) +ILIST_DEF(ilist_free, test_t, (DEL(API(free, NONE, ARG2)))) typedef struct testd_s { double n; diff --git a/tests/test-obj-except.h b/tests/test-obj-except.h index e4aaa0db..e3086607 100644 --- a/tests/test-obj-except.h +++ b/tests/test-obj-except.h @@ -37,16 +37,16 @@ static inline void test_obj_except_trigger(void); extern int test_obj_except__malloc_counter; #ifdef __cplusplus # include -# define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type))) -# define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) -# define M_MEMORY_REALLOC(type, ptr, o, n) \ +# define M_MEMORY_ALLOC(ctx, type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, (type*)std::malloc (sizeof (type))) +# define M_MEMORY_DEL(ctx, ptr) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) \ ((type*) (test_obj_except_trigger(), test_obj_except__malloc_counter+= (ptr == NULL), std::realloc ((ptr), (n)*sizeof (type)))) -# define M_MEMORY_FREE(type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) +# define M_MEMORY_FREE(ctx, type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), std::free(ptr)) #else -# define M_MEMORY_ALLOC(type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type))) -# define M_MEMORY_DEL(ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) -# define M_MEMORY_REALLOC(type, ptr, o, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type))) -# define M_MEMORY_FREE(type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) +# define M_MEMORY_ALLOC(ctx, type) (test_obj_except_trigger(), test_obj_except__malloc_counter++, malloc (sizeof (type))) +# define M_MEMORY_DEL(ctx, ptr) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) +# define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (test_obj_except_trigger(), test_obj_except__malloc_counter+=(ptr == NULL), realloc ((ptr), (n)*sizeof (type))) +# define M_MEMORY_FREE(ctx, type, ptr, o) (test_obj_except__malloc_counter-=(ptr != NULL), free(ptr)) #endif // Include M*LIB headers diff --git a/tests/test-obj.h b/tests/test-obj.h index 42f73df1..fc6a5944 100644 --- a/tests/test-obj.h +++ b/tests/test-obj.h @@ -68,8 +68,8 @@ static inline void overloaded_free(size_t st, void *ptr, size_t n) free(p); } -#define M_MEMORY_REALLOC(type, ptr, o, n) (type *) overloaded_realloc(sizeof(type), ptr, o, n) -#define M_MEMORY_FREE(type, ptr, o) overloaded_free(sizeof(type), ptr, o) +#define M_MEMORY_REALLOC(ctx, type, ptr, o, n) (type *) overloaded_realloc(sizeof(type), ptr, o, n) +#define M_MEMORY_FREE(ctx, type, ptr, o) overloaded_free(sizeof(type), ptr, o) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// From 1a62f5a4ed21452c2e16286571726c76ac812d15 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 1 May 2025 23:09:02 +0200 Subject: [PATCH 79/91] Update doc --- README.md | 88 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 7fd56d22..5579b82c 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ M\*LIB: Generic type-safe Container Library for C language 2. [Atomic](#m-atomic) 12. [Global User Customization](#global-user-customization) 1. [Exception handling](#m-try) + 2. [Memory context Customization](#memory-context-customization) 13. [License](#license) ## Overview @@ -7992,7 +7993,7 @@ Return a pointer to a new allocated non-initialized object of type `type`. In case of allocation error, it returns NULL. `context` parameter is the memory context parameter as provided by the user. -It only exists if the library is built with `M_USE_CONTEXT` +It only exists as a C symbol if the library is built with `M_USE_CONTEXT` The default used function is the `malloc` function of the LIBC. @@ -8003,7 +8004,7 @@ that was previously allocated by the macro `M_MEMORY_ALLOC`. `ptr` can not be NULL. `context` parameter is the memory context parameter as provided by the user. -It only exists if the library is built with `M_USE_CONTEXT` +It only exists as a C symbol if the library is built with `M_USE_CONTEXT` The default used function is the `free` function of the LIBC. @@ -8020,7 +8021,7 @@ is not used in this case. In case of allocation error, it returns NULL. `context` parameter is the memory context parameter as provided by the user. -It only exists if the library is built with `M_USE_CONTEXT` +It only exists as a C symbol if the library is built with `M_USE_CONTEXT` The default used function is the `realloc` function of the LIBC. @@ -8031,7 +8032,7 @@ The pointer was previously allocated by the macro `M_MEMORY_REALLOC`. If `ptr` is NULL, the function shall do nothing. `context` parameter is the memory context parameter as provided by the user. -It only exists if the library is built with `M_USE_CONTEXT` +It only exists as a C symbol if the library is built with `M_USE_CONTEXT` The default used function is the `free` function of the LIBC. @@ -9633,6 +9634,7 @@ The memory context can be an [arena allocator](https://www.rfleury.com/p/untangl > The memory context parameter is not stored in the container > because it is not efficient in memory usage and is redundant when you > create container of other containers (example `array` of `string_t`). +> It is always passed as argument of the functions. The user shall ensure of the coherence of the memory context for a given container so that the same memory context is used from its construction to its destruction. @@ -9710,45 +9712,45 @@ Seems difficult to fix without. The following methods are modified to support the memory context parameter: * m-string: -** _clear -** _clear_get_cstr -** _reserve -** _set_cstr -** _set_cstrn -** _set -** _set_n -** _init_set -** _init_set_cstr -** _move -** _push_back -** _cat_cstr -** _cat -** _replace_cstr -** _replace -** _replace_at -** _replace_all_cstr -** _replace_all -** _set_ui -** _set_si -** _vprintf -** _printf -** _cat_vprintf -** _cat_printf -** _set_ui -** _set_si -** _fgets -** _fget_word -** _get_str -** _in_str -** _parse_str -** _out_serial -** _in_serial -** _it_set_ref -** _push_u -** _split -** _join -** _out_serial -** _in_serial + * _clear + * _clear_get_cstr + * _reserve + * _set_cstr + * _set_cstrn + * _set + * _set_n + * _init_set + * _init_set_cstr + * _move + * _push_back + * _cat_cstr + * _cat + * _replace_cstr + * _replace + * _replace_at + * _replace_all_cstr + * _replace_all + * _set_ui + * _set_si + * _vprintf + * _printf + * _cat_vprintf + * _cat_printf + * _set_ui + * _set_si + * _fgets + * _fget_word + * _get_str + * _in_str + * _parse_str + * _out_serial + * _in_serial + * _it_set_ref + * _push_u + * _split + * _join + * _out_serial + * _in_serial _________________ From d9953daf59deae61080032f01222833e7067aba1 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Thu, 1 May 2025 23:25:24 +0200 Subject: [PATCH 80/91] Update doc --- README.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5579b82c..95d74ce4 100644 --- a/README.md +++ b/README.md @@ -4682,7 +4682,7 @@ except the type of the shared pointer `name_type` is given as parameter instead Define the shared pointer `name_t *` as a C pointer to an opaque structure that encapsulate the access to the C type `type` which oplist is `oplist` and the associated public and private methods as external linkage. -`oplist` parameter is optional. If not present, it will look for a globaly registered oplist. +`oplist` parameter is optional. If not present, it will look for a globally registered oplist. It shall match with the `oplist`argument given to the corresponding `_DECL`macro with the same `name`, meaning it shall provide at least all operators of the oplist provided to the corresponding `_DECL`macro and all operator types shall be the same. @@ -4701,7 +4701,7 @@ See `SHARED_PTR_DECL` for additional information. Define the shared pointer `name_t *` as a C pointer to an opaque structure that encapsulate the access to the C object (aka the shared object) of type `type` which oplist is `oplist` and the associated public and private methods as static inline. -`oplist` parameter is optional. If not present, it will look for a globaly registered oplist. +`oplist` parameter is optional. If not present, it will look for a globally registered oplist. This definition shall be done once per name and per compilation unit. @@ -5025,8 +5025,8 @@ This method is created only if the `IN_SERIAL` operator is defined. #### Private interface -The private interface is only availale for the implementation. -It is used by the implementator of the shared object to provide additional, more specialized, functions to its user for the shared object. +The private interface is only available for the implementation. +It is used by the implementor of the shared object to provide additional, more specialized, functions to its user for the shared object. ##### `void name_init_lock(name_t *out)` @@ -5976,12 +5976,12 @@ representation (if `append` is false) or append `str` with this representation This method is only defined if the header [m-string.h](#m-string) was included before including [m-bitset.h](#m-bitset) -##### `bool bitset_parse_str(bitset_t array, const char str[], const char **endp)` +##### `bool bitset_parse_str(bitset_t array, const char str[], const char **endptr)` Parse the formatted string `str` that is assumed to be a string representation of a bitset and set `array` to this representation. It returns true if success, false otherwise. -If `endp` is not NULL, it sets `*endp` to the pointer of the first character not +If `endptr` is not NULL, it sets `*endptr` to the pointer of the first character not decoded by the function. ##### `void bitset_out_str(FILE *file, const bitset_t array)` @@ -6913,7 +6913,7 @@ Return a symbol corresponding to the concatenation of the input arguments. ##### `M_F(base, suffix)` Return a function name corresponding to the concatenation of the input arguments. -In developer mode, it can be overrided before inclusion of any header to support user customization of suffix. +In developer mode, it can be overridden before inclusion of any header to support user customization of suffix. To do this you need to define `M_F` as `M_OVERRIDE_F`, then define as many suffix macros as needed. As suffix macro shall be named `M_OVERRIDE_ ## suffix ()` and each generated suffix shall start with a comma (preliminary interface). Example: @@ -7655,8 +7655,8 @@ Extend an `oplist` with the given list of operators. Theses new operators will have higher priority than the ones in the given oplist. -#####` M_TEST_METHOD_P(method, oplist)` -#####` M_TEST_METHOD_ALTER_P(method, oplist)` +##### `M_TEST_METHOD_P(method, oplist)` +##### `M_TEST_METHOD_ALTER_P(method, oplist)` Test if a method is present in an `oplist`. Return 0 or 1. `M_TEST_METHOD_P` does not work if the returned method is something within parenthesis (like `OPLIST*`) @@ -9752,6 +9752,9 @@ The following methods are modified to support the memory context parameter: * _out_serial * _in_serial +> [!Note] +> The API defined by `M_USE_CONTEXT` is experimental and may change incompatibily in the future. + _________________ ## Global User Customization From de6ccc293edfb0d63e527a1a61047a8087701db2 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 5 May 2025 21:35:06 +0200 Subject: [PATCH 81/91] Update doc Update M_USE_GLOBAL_CONTEXT definition to be simpler. --- README.md | 391 ++++++++++++++++++++++++++++++++++++++++++++++-------- m-core.h | 4 +- 2 files changed, 336 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 95d74ce4..112cafaf 100644 --- a/README.md +++ b/README.md @@ -9632,9 +9632,10 @@ The memory context can be an [arena allocator](https://www.rfleury.com/p/untangl > [!Note] > The memory context parameter is not stored in the container -> because it is not efficient in memory usage and is redundant when you -> create container of other containers (example `array` of `string_t`). -> It is always passed as argument of the functions. +> because it is not efficient in memory usage as it is redundant when you +> create container of other containers (example `array` of `string_t`): +> all `string_t` in the array would need to store the context which is duplicate information. +> Therefore it is always passed as argument of the functions. The user shall ensure of the coherence of the memory context for a given container so that the same memory context is used from its construction to its destruction. @@ -9650,12 +9651,12 @@ As such, it is safe not to call the destructors of these containers if you have If the destructor of a mutex is also a no-op on your system, this guarantee is extended to all containers (including the thread safe containers too). -In order to use such feature, you need to: +In order to use the local context feature, you need to: * define globally `M_USE_CONTEXT` with your type. * define globally an override of the memory functions `M_MEMORY_ALLOC`, `M_MEMORY_DEL`, `M_MEMORY_REALLOC` and `M_MEMORY_FREE` to use your context. -Example +Example: ```C // Define a memory context type @@ -9692,68 +9693,344 @@ static void my_free(void *ptr, size_t old, size_t base, context_t context) #include "m-array.h" ``` -This works great for local allocators for a thread. However some containers are designed to handle -objects accross several threads: shared pointer, communication queue, ... +This works great for local allocators for a thread. +However some containers are designed to handle +objects across several threads: shared pointer, communication queue, ... For such containers, a local allocator has no meaning: it will be very hard to ensure the same allocator -is used for both the producor thread and the user threads. +is used for both the producer thread and the user threads. As a consequence, shared pointer, communication queue container and all thread containers -will use a global memory context: -M\*LIB won't add a context argument to the functions of such containers. Instead it will generate -a local parameter initialize to the global memory context. -The global memory context is defined by the macro `M_USE_GLOBAL_CONTEXT` which shall define and initialize -the named argument to the global memory context. In the absence of definition of such macro, the default is -to initialize the context to '0'. The memory functions shall recognize such context as the global one. +use a global memory context instead: +M\*LIB doesn't add a context argument to the functions of such containers. Instead it uses +the global memory context and gives this one to the memory functions. -FIXME: if it is expensive, it is useless to initialize a local variable rather than using the global variable directly... -Seems difficult to fix without. +The exact value of the global memory context is defined by the macro `M_USE_GLOBAL_CONTEXT` which shall define its value. +In the absence of definition of such macro, the default is the value '0' +(The memory functions shall recognize such context as the global one). -The following methods are modified to support the memory context parameter: +context arguments shall be settable and trivially movable using the '=' C operator. + +The following methods are modified to support the memory context parameter (the first argument of theses functions is the memory context parameter): * m-string: - * _clear - * _clear_get_cstr - * _reserve - * _set_cstr - * _set_cstrn - * _set - * _set_n - * _init_set - * _init_set_cstr - * _move - * _push_back - * _cat_cstr - * _cat - * _replace_cstr - * _replace - * _replace_at - * _replace_all_cstr - * _replace_all - * _set_ui - * _set_si - * _vprintf - * _printf - * _cat_vprintf - * _cat_printf - * _set_ui - * _set_si - * _fgets - * _fget_word - * _get_str - * _in_str - * _parse_str - * _out_serial - * _in_serial - * _it_set_ref - * _push_u - * _split - * _join - * _out_serial - * _in_serial + * string_clear + * string_clear_get_str + * string_reserve + * string_set_str + * string_set_strn + * string_set + * string_set_n + * string_init_set + * string_init_set_str + * string_move + * string_push_back + * string_cat_str + * string_cat + * string_replace_str + * string_replace + * string_replace_at + * string_replace_all_str + * string_replace_all + * string_set_ui + * string_set_si + * string_vprintf + * string_printf + * string_cat_vprintf + * string_cat_printf + * string_set_ui + * string_set_si + * string_fgets + * string_fget_word + * string_get_str + * string_in_str + * string_parse_str + * string_out_serial + * string_in_serial + * string_it_set_ref + * string_push_u + * string_split + * string_join + * string_out_serial + * string_in_serial +* m-biset: + * bitset_clear + * bitset_set + * bitset_init_set + * bitset_move + * bitset_push_back + * bitset_resize + * bitset_reserve + * bitset_push_at + * bitset_in_str + * bitset_parse_str + * bitset_set_str + * bitset_get_str +* m-bstring: + * bstring_clear + * bstring_push_back + * bstring_push_back_bytes + * bstring_splice + * bstring_init_set + * bstring_set + * bstring_move + * bstring_push_bytes_at + * bstring_resize + * bstring_reserve + * bstring_fread + * bstring_out_serial + * bstring_in_serial +* m-algo: + * _fill + * _fill_n + * _fill_a + * _fill_an + * _transform + * _reduce + * _map_reduce + * _uniq + * _remove_val + * _remove_if +* m-array: + * _reset + * _clear + * _set + * _init_set + * _move + * _set_at + * _push_raw + * _push_back + * _push_new + * _push_move + * _push_at + * _resize + * _reserve + * _safe_get + * _pop_back + * _pop_until + * _pop_at + * _erase + * _insert_v + * _remove_v + * _insert + * _remove + * _special_stable_sort + * _splice + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial + * _ +* m-bptree: + * _init + * _reset + * _clear + * _copy_node + * _init_set + * _set + * _set_at + * _push + * _safe_get + * _erase + * _pop_at + * _move + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial +* m-deque: + * _init + * _reset + * _clear + * _push_back_raw + * _push_back + * _push_back_new + * _push_back_move + * _push_front_raw + * _push_front + * _push_front_new + * _push_front_move + * _pop_back + * _pop_back_move + * _pop_front + * _pop_front_move + * _remove + * _init_set + * _set + * _move + * _set_at + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial + * _ + * _ +* m-dict: + * _init + * _clear + * _push + * _set_at + * _safe_get + * _erase + * _init_set + * _set + * _move + * _reset + * _reserve + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial + * _splice + * _bulk_get + * _bulk_set + * _bulk_update +* m-i-list + * _reset + * _clear + * _move + * _remove +* m-list + * _reset + * _clear + * _push_raw + * _push_back + * _push_new + * _pop_back + * _push_move + * _pop_move + * _insert + * _remove + * _init_set + * _set + * _move + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial + * _ + * _ + * _ + * _push_back_raw + * _push_raw + * _push_back + * _push_back_new + * _push_back_move + * _push_move + * _push_front_raw + * _push_front + * _push_front_move + * _push_front_new +* m-prioqueue + * _init_set + * _set + * _clear + * _move + * _reset + * _push + * _pop + * _erase + * _update + * _in_str + * _get_str + * _parse_str + * _out_serial + * _in_serial +* m-queue: + * _init + * _clear + * _init_set + * _set + * _push + * _pop +* m-rbtree: + * _reset + * _clear + * _push + * _init_set + * _set + * _move + * _pop_at + * _remove + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial +* m-snapshot: + * _init + * _clear + * _init_set + * _set + * _move +* m-tree: + * _reset + * _clear + * _reserve + * _set_root + * _insert_up_raw + * _insert_up + * _move_up + * _insert_down_raw + * _insert_down + * _move_down + * _insert_child_raw + * _insert_child + * _move_child + * _insert_left_raw + * _insert_left + * _move_left + * _insert_right_raw + * _insert_right + * _move_right + * _remove + * _prune + * _init_set + * _set + * _move + * _get_str + * _parse_str + * _in_str + * name + * _ + * _ + * _ + * _ + * _ +* m-tuple: + * _init + * _init_set + * _init_emplace + * _set + * _emplace + * _clear + * _get_str + * _in_str + * _parse_str + * _out_serial + * _in_serial + * _move + * _reset +* m-variant: + * _init_set + * _set + * _clear + * _move + * _get_str + * _parse_str + * _in_str + * _out_serial + * _in_serial + * _reset + > [!Note] -> The API defined by `M_USE_CONTEXT` is experimental and may change incompatibily in the future. +> The API defined by `M_USE_CONTEXT` is experimental and may change incompatibly in the future. _________________ diff --git a/m-core.h b/m-core.h index 3a8eccb5..1ad5bb4e 100644 --- a/m-core.h +++ b/m-core.h @@ -422,7 +422,7 @@ M_BEGIN_PROTECTED_CODE // Default global memory context is to consider the global context as '0' if it is not defined. #ifndef M_USE_GLOBAL_CONTEXT -#define M_USE_GLOBAL_CONTEXT(varname) M_USE_CONTEXT varname = { 0 } +#define M_USE_GLOBAL_CONTEXT 0 #endif /* In order to support local context for memory functions, the prototypes and usages of some functions are modified @@ -465,7 +465,7 @@ M_BEGIN_PROTECTED_CODE # define M_R_EXPAND_void m_context # define M_R(...) (m_context, __VA_ARGS__) # define M_UNUSED_CONTEXT() (void) m_context -# define M_GLOBAL_CONTEXT() M_USE_GLOBAL_CONTEXT(m_context); (void) m_context +# define M_GLOBAL_CONTEXT() M_USE_CONTEXT m_context = { M_USE_GLOBAL_CONTEXT }; (void) m_context #endif // M_P: Expand to a prototype of a function that may trigger exception / accept memory context From bfcc4134d615e26653261faa2d6e4625188dad09 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 5 May 2025 21:47:18 +0200 Subject: [PATCH 82/91] Fix markdown --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 112cafaf..feb87b5b 100644 --- a/README.md +++ b/README.md @@ -9781,16 +9781,16 @@ The following methods are modified to support the memory context parameter (the * bstring_out_serial * bstring_in_serial * m-algo: - * _fill - * _fill_n - * _fill_a - * _fill_an - * _transform - * _reduce - * _map_reduce - * _uniq - * _remove_val - * _remove_if + * \_fill + * \_fill_n + * \_fill_a + * \_fill_an + * \_transform + * \_reduce + * \_map_reduce + * \_uniq + * \_remove_val + * \_remove_if * m-array: * _reset * _clear From 725f42852eab8cc8a3d1b4c7b35569af1058e8b5 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 5 May 2025 21:50:56 +0200 Subject: [PATCH 83/91] Update markdown --- README.md | 448 +++++++++++++++++++++++++++--------------------------- 1 file changed, 224 insertions(+), 224 deletions(-) diff --git a/README.md b/README.md index feb87b5b..569bdb7c 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,7 @@ This is equivalent to this C++ program using the STL: ```C #include -#include +#include \ typedef std::list list_uint_t; typedef std::list::iterator list_uint_it_t; @@ -9792,241 +9792,241 @@ The following methods are modified to support the memory context parameter (the * \_remove_val * \_remove_if * m-array: - * _reset - * _clear - * _set - * _init_set - * _move - * _set_at - * _push_raw - * _push_back - * _push_new - * _push_move - * _push_at - * _resize - * _reserve - * _safe_get - * _pop_back - * _pop_until - * _pop_at - * _erase - * _insert_v - * _remove_v - * _insert - * _remove - * _special_stable_sort - * _splice - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial - * _ + * \_reset + * \_clear + * \_set + * \_init_set + * \_move + * \_set_at + * \_push_raw + * \_push_back + * \_push_new + * \_push_move + * \_push_at + * \_resize + * \_reserve + * \_safe_get + * \_pop_back + * \_pop_until + * \_pop_at + * \_erase + * \_insert_v + * \_remove_v + * \_insert + * \_remove + * \_special_stable_sort + * \_splice + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial + * \_\ * m-bptree: - * _init - * _reset - * _clear - * _copy_node - * _init_set - * _set - * _set_at - * _push - * _safe_get - * _erase - * _pop_at - * _move - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial + * \_init + * \_reset + * \_clear + * \_copy_node + * \_init_set + * \_set + * \_set_at + * \_push + * \_safe_get + * \_erase + * \_pop_at + * \_move + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial * m-deque: - * _init - * _reset - * _clear - * _push_back_raw - * _push_back - * _push_back_new - * _push_back_move - * _push_front_raw - * _push_front - * _push_front_new - * _push_front_move - * _pop_back - * _pop_back_move - * _pop_front - * _pop_front_move - * _remove - * _init_set - * _set - * _move - * _set_at - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial - * _ - * _ + * \_init + * \_reset + * \_clear + * \_push_back_raw + * \_push_back + * \_push_back_new + * \_push_back_move + * \_push_front_raw + * \_push_front + * \_push_front_new + * \_push_front_move + * \_pop_back + * \_pop_back_move + * \_pop_front + * \_pop_front_move + * \_remove + * \_init_set + * \_set + * \_move + * \_set_at + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial + * \_\ + * \_\ * m-dict: - * _init - * _clear - * _push - * _set_at - * _safe_get - * _erase - * _init_set - * _set - * _move - * _reset - * _reserve - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial - * _splice - * _bulk_get - * _bulk_set - * _bulk_update + * \_init + * \_clear + * \_push + * \_set_at + * \_safe_get + * \_erase + * \_init_set + * \_set + * \_move + * \_reset + * \_reserve + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial + * \_splice + * \_bulk_get + * \_bulk_set + * \_bulk_update * m-i-list - * _reset - * _clear - * _move - * _remove + * \_reset + * \_clear + * \_move + * \_remove * m-list - * _reset - * _clear - * _push_raw - * _push_back - * _push_new - * _pop_back - * _push_move - * _pop_move - * _insert - * _remove - * _init_set - * _set - * _move - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial - * _ - * _ - * _ - * _push_back_raw - * _push_raw - * _push_back - * _push_back_new - * _push_back_move - * _push_move - * _push_front_raw - * _push_front - * _push_front_move - * _push_front_new + * \_reset + * \_clear + * \_push_raw + * \_push_back + * \_push_new + * \_pop_back + * \_push_move + * \_pop_move + * \_insert + * \_remove + * \_init_set + * \_set + * \_move + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial + * \_\ + * \_\ + * \_\ + * \_push_back_raw + * \_push_raw + * \_push_back + * \_push_back_new + * \_push_back_move + * \_push_move + * \_push_front_raw + * \_push_front + * \_push_front_move + * \_push_front_new * m-prioqueue - * _init_set - * _set - * _clear - * _move - * _reset - * _push - * _pop - * _erase - * _update - * _in_str - * _get_str - * _parse_str - * _out_serial - * _in_serial + * \_init_set + * \_set + * \_clear + * \_move + * \_reset + * \_push + * \_pop + * \_erase + * \_update + * \_in_str + * \_get_str + * \_parse_str + * \_out_serial + * \_in_serial * m-queue: - * _init - * _clear - * _init_set - * _set - * _push - * _pop + * \_init + * \_clear + * \_init_set + * \_set + * \_push + * \_pop * m-rbtree: - * _reset - * _clear - * _push - * _init_set - * _set - * _move - * _pop_at - * _remove - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial + * \_reset + * \_clear + * \_push + * \_init_set + * \_set + * \_move + * \_pop_at + * \_remove + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial * m-snapshot: - * _init - * _clear - * _init_set - * _set - * _move + * \_init + * \_clear + * \_init_set + * \_set + * \_move * m-tree: - * _reset - * _clear - * _reserve - * _set_root - * _insert_up_raw - * _insert_up - * _move_up - * _insert_down_raw - * _insert_down - * _move_down - * _insert_child_raw - * _insert_child - * _move_child - * _insert_left_raw - * _insert_left - * _move_left - * _insert_right_raw - * _insert_right - * _move_right - * _remove - * _prune - * _init_set - * _set - * _move - * _get_str - * _parse_str - * _in_str - * name - * _ - * _ - * _ - * _ - * _ + * \_reset + * \_clear + * \_reserve + * \_set_root + * \_insert_up_raw + * \_insert_up + * \_move_up + * \_insert_down_raw + * \_insert_down + * \_move_down + * \_insert_child_raw + * \_insert_child + * \_move_child + * \_insert_left_raw + * \_insert_left + * \_move_left + * \_insert_right_raw + * \_insert_right + * \_move_right + * \_remove + * \_prune + * \_init_set + * \_set + * \_move + * \_get_str + * \_parse_str + * \_in_str + * \name + * \_\ + * \_\ + * \_\ + * \_\ + * \_\ * m-tuple: - * _init - * _init_set - * _init_emplace - * _set - * _emplace - * _clear - * _get_str - * _in_str - * _parse_str - * _out_serial - * _in_serial - * _move - * _reset + * \_init + * \_init_set + * \_init_emplace + * \_set + * \_emplace + * \_clear + * \_get_str + * \_in_str + * \_parse_str + * \_out_serial + * \_in_serial + * \_move + * \_reset * m-variant: - * _init_set - * _set - * _clear - * _move - * _get_str - * _parse_str - * _in_str - * _out_serial - * _in_serial - * _reset + * \_init_set + * \_set + * \_clear + * \_move + * \_get_str + * \_parse_str + * \_in_str + * \_out_serial + * \_in_serial + * \_reset > [!Note] From 6a2bdc49fbae6de31ab04230a51afd1f5f2b19ae Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 14:17:28 +0200 Subject: [PATCH 84/91] Update API incompatibility & documentation --- README.md | 43 ++++++++++++++++++++++++++++--------------- doc/API.txt | 33 ++++++++++++++++++--------------- m-core.h | 2 +- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 569bdb7c..606b05de 100644 --- a/README.md +++ b/README.md @@ -649,10 +649,10 @@ Other documented operators are: * `VALUE_TYPE()` --> `value_t`: Return the value type for associative containers. * `KEY_OPLIST()` --> `oplist`: Return the oplist of the key type for associative containers. * `VALUE_OPLIST()` --> `oplist`: Return the oplist of the value type for associative containers. -* `NEW(type)` --> `type pointer`: allocate a new object (with suitable alignment and size) and return a pointer to it. The returned object is **not initialized** (a constructor operator shall be called afterward). The default method is `M_MEMORY_ALLOC` (that allocates from the heap). It returns NULL in case of failure. -* `DEL(&obj)`: free the allocated uninitialized object `obj`. The destructor of the pointed object shall be called before freeing the memory by calling this method. The object shall have been allocated by the associated NEW method. `sizeof obj` is the size of the allocated object. The default method is `M_MEMORY_DEL` (that frees to the heap). `obj` shall not be NULL and shall be of the proper type. -* `REALLOC(type, pointer, previous_number, new_number)` --> `pointer`: reallocate the given array of `previous_number` elements of type `type` referenced by `pointer` (either a NULL pointer or a pointer returned by a previous call to `REALLOC`) to an array of `new_number` objects of type `type` and return a pointer to this new array. Previously objects pointed by the pointer are kept up to the minimum of the new size and old one but may have moved from their original positions (if the array is reallocated otherwhere). New objects are not initialized (a constructor operator shall be called afterward). Freed objects are not cleared (A destructor operator shall be called before). The default is `M_MEMORY_REALLOC` (that allocates from the heap). It returns NULL in case of failure in which case the original array is not modified. If `pointer` is NULL, then `previous_number` should be 0. -* `FREE(type, pointer, number)`: free the allocated uninitialized array of `number` elements of type `type` referenced by `pointer`. The destructor of the pointed objects shall be called before freeing the memory. The memory of the objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap). If pointer is NULL, then the function shall do nothing. +* `NEW(context, type)` --> `type pointer`: allocate a new object (with suitable alignment and size) and return a pointer to it. The returned object is **not initialized** (a constructor operator shall be called afterward). The default method is `M_MEMORY_ALLOC` (that allocates from the heap). It returns NULL in case of failure. +* `DEL(context, &obj)`: free the allocated uninitialized object `obj`. The destructor of the pointed object shall be called before freeing the memory by calling this method. The object shall have been allocated by the associated NEW method. `sizeof obj` is the size of the allocated object. The default method is `M_MEMORY_DEL` (that frees to the heap). `obj` shall not be NULL and shall be of the proper type. +* `REALLOC(context, type, pointer, previous_number, new_number)` --> `pointer`: reallocate the given array of `previous_number` elements of type `type` referenced by `pointer` (either a NULL pointer or a pointer returned by a previous call to `REALLOC`) to an array of `new_number` objects of type `type` and return a pointer to this new array. Previously objects pointed by the pointer are kept up to the minimum of the new size and old one but may have moved from their original positions (if the array is reallocated otherwhere). New objects are not initialized (a constructor operator shall be called afterward). Freed objects are not cleared (A destructor operator shall be called before). The default is `M_MEMORY_REALLOC` (that allocates from the heap). It returns NULL in case of failure in which case the original array is not modified. If `pointer` is NULL, then `previous_number` should be 0. +* `FREE(context, type, pointer, number)`: free the allocated uninitialized array of `number` elements of type `type` referenced by `pointer`. The destructor of the pointed objects shall be called before freeing the memory. The memory of the objects shall have been allocated by the associated REALLOC method. The default is `M_MEMORY_FREE` (that frees to the heap). If pointer is NULL, then the function shall do nothing. * `INC_ALLOC(size_t s)` --> `size_t`: Define the growing policy of an array (or equivalent structure). It returns a new allocation size based on the old allocation size (`s`). Default policy is to get the maximum between `2*s` and 16. In case of overflow, it shall return a number less or equal than the original size. > [!NOTE] @@ -669,7 +669,7 @@ Other documented operators are: * `INIT_WITH(obj, ...)`: Initialize the object `obj` with the given variable set of arguments (constructor). The arguments are variable and can be of different types. It is up to the method of the object to decide how to initialize the object based on this initialization array. This operator is used by the `M_LET` macro to initialize objects with their given values and this operator defines what the `M_LET` macro supports. It may raise asynchronous error. > [!NOTE] ->In C11, you can use `API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)` as method to automatically use the different emplace functions defined in `EMPLACE_TYPE` through a _Generic switch case. The `EMPLACE_TYPE` shall use the LIST format. See [emplace chapter](#Emplace-construction). +>In C11, you can use `API_1(M_INIT_WITH_THROUGH_EMPLACE_TYPE)` as a method for `INIT_WITH` to automatically use the different emplace functions defined in `EMPLACE_TYPE` through a _Generic switch case. The provided `EMPLACE_TYPE` shall use the LIST format. See [emplace chapter](#Emplace-construction). > * `SWAP(objd, objc)`: Swap the states of the object `objc` and the object `objd`. @@ -746,7 +746,7 @@ The I/O operators are: * `OUT_STR(FILE* f, obj)`: Output `obj` as a custom formatted string into the `FILE*` stream `f`. Format is container dependent, but is human readable. * `IN_STR(obj, FILE* f)` --> `bool`: Set `obj` to the value associated to the formatted string representation of the object in the `FILE*` stream `f`. Return true in case of success (in that case the stream `f` has been advanced to the end of the parsing of the object), false otherwise (in that case, the stream `f` is in an undetermined position but is likely where the parsing fails). It ensures that an object which is output in a FILE through `OUT_STR`, and an object which is read from this FILE through `IN_STR` are considered as equal. It may raise asynchronous error. * `GET_STR(string_t str, obj, bool append)`: Set `str` to a formatted string representation of the object `obj`. Append to the string if `append` is true, set it otherwise. This operator requires the module [m-string](#m-string). It may raise asynchronous error. -* `PARSE_STR(obj, const char *str, const char **endp)` --> `bool`: Set `obj` to the value associated to the formatted string representation of the object in the char stream `str`. Return true in case of success (in that case if endp is not NULL, it points to the end of the parsing of the object), false otherwise (in that case, if endp is not NULL, it points to an undetermined position but likely to be where the parsing fails). It ensures that an object which is written in a string through GET_STR, and an object which is read from this string through `PARSE_STR` are considered as equal. It may raise asynchronous error. +* `PARSE_STR(obj, const char *str, const char **endp)` --> `bool`: Set `obj` to the value associated to the formatted string representation of the object in the char stream `str`. Return true in case of success (in that case if `endp` is not NULL, it points to the end of the parsing of the object), false otherwise (in that case, if `endp` is not NULL, it points to an undetermined position but likely to be where the parsing fails). It ensures that an object which is written in a string through GET_STR, and an object which is read from this string through `PARSE_STR` are considered as equal. It may raise asynchronous error. * `OUT_SERIAL(m_serial_write_t *serial, obj)` --> `m_serial_return_code_t`: Output `obj` into the configurable serialization stream `serial` (See [m-serial-json.h](#m-serial-json) for details and example) as per the serial object semantics. Return `M_SERIAL_OK_DONE` in case of success, or `M_SERIAL_FAIL` otherwise. It may raise asynchronous error. * `IN_SERIAL(obj, m_serial_read_t *serial)` --> `m_serial_return_code_t`: Set `obj` to its representation from the configurable serialization stream `serial` (See [m-serial-json.h](#m-serial-json) for details and example) as per the serial object semantics. `M_SERIAL_OK_DONE` in case of success (in that case the stream `serial` has been advanced up to the complete parsing of the object), or `M_SERIAL_FAIL` otherwise (in that case, the stream `serial` is in an undetermined position but usually around the next characters after the first failure). It may raise asynchronous error. @@ -1340,7 +1340,7 @@ in fact, the only constraint is that the preprocessing concatenation between `ty Therefore the `type` cannot be a C array or a function pointer and you shall use a typedef as an intermediary named type for such types. -The output parameters are listed fist, then the input/output parameters and finally the input parameters. +The output parameters are listed first, then the input/output parameters and finally the input parameters. The oplist shall also provide the `INIT_MOVE` operator if the default instance (aka '=' operator) is not working for this type (for example for array of size 1, in which case the method `M_COPY_A1_DEFAULT` is likely to work), or disable the operator. @@ -7543,8 +7543,7 @@ Count the number of leading zero and return it. ##### `size_t m_core_hash (const void *str, size_t length)` Compute the hash of the binary representation of the data pointer by `str` -of length `length`. `str` shall have the maximum alignment restriction -of all types that size is less or equal than `length`. +of length `length`. `str` shall be aligned to `min(length, 8)`. #### OPERATORS Functions @@ -9458,7 +9457,7 @@ This provides the same level of flexibility of the C++. However, there is some d * Error messages can be more complex, * Compilation time increase a lot (on pair with C++) -This header is still a WIP and is currently more a demo (Not ready for production). +This header is still a WIP. #### Example @@ -9469,25 +9468,27 @@ It reuses the basic example of the introduction of the library. #include "m-list.h" #include "m-generic.h" +// Define a list of unsigned int LIST_DEF(list_uint, unsigned int) -// Register oplist for M_LET & M_EACH : +// Register the oplist of this new list for usage in M_LET & M_EACH : #define M_OPL_list_uint_t() LIST_OPLIST(list_uint, M_BASIC_OPLIST) -// Register for Generic (Organization, Component & Oplist) +// Register the oplist of this new list for the Generic framework +// Organization=USER, Component=CORE & Oplist Number=1 #define M_GENERIC_ORG_1() (USER) #define M_GENERIC_ORG_USER_COMP_1() (CORE) #define M_GENERIC_ORG_USER_COMP_CORE_OPLIST_1() M_OPL_list_uint_t() int main(void) { - M_LET(list, list_uint_t) { + let(list, list_uint_t) { push(list, 42); push(list, 17); for each(item, list) { - M_PRINT("ITEM=", *item, "\n"); + print("ITEM=", *item, "\n"); } - M_PRINT("List = ", list, "\n"); + print("List = ", list, "\n"); } } ``` @@ -10237,6 +10238,18 @@ See [m-core.h](#m-core) See [m-core.h](#m-core) +#### `M_USE_CONTEXT` + +See [Memory context Customization](#memory-context-customization) + +Default value: undefined (No memory context) + +#### `M_USE_GLOBAL_CONTEXT` + +See [Memory context Customization](#memory-context-customization) + +Default value: 0 + _________________ ## License diff --git a/doc/API.txt b/doc/API.txt index 0c17fd07..0458e919 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -86,20 +86,23 @@ V0.7.2: * Rename m-mutex.h header in m-thread.h V0.7.3 : * DICT_STOREHASH_DEF2 / DICT_STOREHASH_DEF2_AS are deprecated. Use DICT_DEF2 / DICT_DEF2_AS -V0.8.0 : * The prototypes of REALLOC / FREE operators are incompatible: - Add the old number of elements of the array as argument of REALLOC - Add the number of elements of the array and its base type as arguments of FREE. +V0.8.0 : * Memory interface massive compatibility break to allow more efficient integration of custom allocators. + The prototypes of NEW / DEL REALLOC / FREE operators are incompatible: + * Add the old number of elements of the array as argument of REALLOC + * Add the number of elements of the array and its base type as arguments of FREE. + * Add the context argument (which shall be ignored in not specific build) (You can ignore the new arguments which are only hints provided to memory functions). - Add the memory context argument. - Also impact M_MEMORY_REALLOC & M_MEMORY_FREE - This allows more and efficient integration into custom allocators. - * M_MEMORY_FULL: replace the failed size allocation size argument - into the base type and the number of elements that failed to be allocated. - * m-buffer: non-thread safe queue & stack are moved into their dedicated header (m-queue) BUFFER_THREAD_UNSAFE is no longer supported. - * m-buffer: Remove buffer blocking policy BUFFER_BLOCKING (default policy is now forced) and thread safe (_push / _pop returns now void) - * m-buffer push / pop no longer return a bool (it was undocumented) + Also impact M_MEMORY_NEW / M_MEMORY_DEL / M_MEMORY_REALLOC & M_MEMORY_FREE + M_MEMORY_FULL: replace the failed size allocation size argument into the base type and the number of elements that failed to be allocated. + * m-buffer: + * non-thread safe queue & stack are moved into their dedicated header (m-queue) + * BUFFER_THREAD_UNSAFE policy is no longer supported. + * Disabling BUFFER_BLOCKING policy is no longer supported (default policy is now forced). + * _push / _pop now returns now void like other containers instead of a bool (it was undocumented) * Remove MEMPOOL support from list & R/B tree - * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove?). Use new M_USE_CONTEXT interface to pass local pool context. - * M*LIB becomes stricter for INIT_MOVE: Emulation layer using CLEAR+INIT_SET when missing INIT_MOVE operator has been removed: either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled. - If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method. - (It's because supporting emulation layer with new memory context parameter was complicated) + * m-mempool: Header is obsolete (and no longer useful at all as lists & RB Tree no longer can use it. To remove). Use new M_USE_CONTEXT interface to pass local pool context. + * M*LIB becomes stricter for the INIT_MOVE operator: + The Emulation layer using CLEAR+INIT_SET methods, when there is no INIT_MOVE operator, has been removed: + either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled. + If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method. + (It's because supporting emulation layer with new memory context parameter was complicated) diff --git a/m-core.h b/m-core.h index 1ad5bb4e..caf574d0 100644 --- a/m-core.h +++ b/m-core.h @@ -3697,7 +3697,7 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_CALL_OOR_EQUAL(oplist, ...) M_APPLY_API(M_GET_OOR_EQUAL oplist, oplist, __VA_ARGS__) //#define M_CALL_PROPERTIES(oplist, ...) M_APPLY_API(M_GET_PROPERTIES oplist, oplist, __VA_ARGS__) //#define M_CALL_EMPLACE_TYPE(oplist, ...) M_APPLY_API(M_GET_EMPLACE_TYPE oplist, oplist, __VA_ARGS__) -// As attribute customization +// m_context is always added here! #define M_CALL_NEW(oplist, ...) M_APPLY_API(M_GET_NEW oplist, oplist, m_context, __VA_ARGS__) #define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, m_context, __VA_ARGS__) #define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, m_context, __VA_ARGS__) From d795476157b7a9cb8c24e85f477e7f30c0919385 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 21:02:55 +0200 Subject: [PATCH 85/91] Update version --- m-core.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/m-core.h b/m-core.h index caf574d0..53b0fff5 100644 --- a/m-core.h +++ b/m-core.h @@ -70,8 +70,8 @@ /* Define M*LIB version */ #define M_CORE_VERSION_MAJOR 0 -#define M_CORE_VERSION_MINOR 7 -#define M_CORE_VERSION_PATCHLEVEL 4 +#define M_CORE_VERSION_MINOR 8 +#define M_CORE_VERSION_PATCHLEVEL 0 /* M_ASSUME is equivalent to M_ASSERT, but gives hints to compiler about how to optimize the code if NDEBUG is defined. From 790ae333344a6de4987a6c93bf857b0644e52035 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 21:28:13 +0200 Subject: [PATCH 86/91] Remove obsolete m-c-mempool.h header --- README.md | 1 - example/ex11-small-name.c | 3 +- m-c-mempool.h | 835 -------------------------------------- tests/test-mcmempool.c | 208 ---------- 4 files changed, 1 insertion(+), 1046 deletions(-) delete mode 100644 m-c-mempool.h delete mode 100644 tests/test-mcmempool.c diff --git a/README.md b/README.md index 606b05de..46fb7756 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,6 @@ The following headers are obsolete and will be removed in the next major release * [m-concurrent.h](#m-concurrent): header for transforming a container into a concurrent container (thread safe), * [m-i-shared.h](#m-i-shared): header for creating intrusive shared pointer of generic type (Thread Safe). * [m-mempool.h](#m-mempool): header for creating specialized & fast memory allocator, -* m-c-mempool.h: WIP header for creating fast concurrent memory allocation. Each containers define their iterators (if it is meaningful). diff --git a/example/ex11-small-name.c b/example/ex11-small-name.c index f16227cd..e05b2ea2 100644 --- a/example/ex11-small-name.c +++ b/example/ex11-small-name.c @@ -8,7 +8,6 @@ #include "m-bptree.h" #include "m-bstring.h" #include "m-buffer.h" -#include "m-c-mempool.h" #include "m-concurrent.h" #include "m-deque.h" #include "m-dict.h" @@ -70,4 +69,4 @@ M_WORKER_SPAWN_DEF2(worker, (filename, m_string_t) ) int main(void) { exit(0); -} \ No newline at end of file +} diff --git a/m-c-mempool.h b/m-c-mempool.h deleted file mode 100644 index e144e496..00000000 --- a/m-c-mempool.h +++ /dev/null @@ -1,835 +0,0 @@ -/* - * M*LIB - Concurrent memory pool allocator - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef MSTARLIB_CONCURRENT_MEMPOOL_H -#define MSTARLIB_CONCURRENT_MEMPOOL_H - -#include "m-core.h" -#include "m-atomic.h" -#include "m-genint.h" - -M_BEGIN_PROTECTED_CODE - -/* Minimum number of nodes per group of nodes */ -#define M_CMEMP00L_MIN_NODE_PER_GROUP 16 - -#define M_C_MEMPOOL_DEF(name, type_t) \ - M_BEGIN_PROTECTED_CODE \ - M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \ - M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \ - M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \ - M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \ - M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \ - M_END_PROTECTED_CODE - -/* Classic internal Singly List without allocation */ -#define M_CMEMP00L_DEF_SINGLY_LIST(name, type_t) \ - \ - typedef struct M_F(name, _slist_node_s) { \ - struct M_F(name, _slist_node_s) *next; \ - type_t data; \ - } M_F(name, _slist_node_ct); \ - \ - typedef struct M_F(name, _slist_node_s) *M_F(name, _slist_ct)[1]; \ - \ - M_INLINE void \ - M_F(name, _slist_init)(M_F(name, _slist_ct) list) \ - { \ - *list = NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _slist_push)(M_F(name, _slist_ct) list, \ - M_F(name, _slist_node_ct) *node) \ - { \ - node->next = *list; \ - *list = node; \ - } \ - \ - M_INLINE M_F(name, _slist_node_ct) * \ - M_F(name, _slist_pop)(M_F(name, _slist_ct) list) \ - { \ - M_ASSERT (*list != NULL); \ - M_F(name, _slist_node_ct) *node = *list; \ - *list = node->next; \ - M_IF_DEBUG(node->next = NULL;) \ - return node; \ - } \ - \ - M_INLINE bool \ - M_F(name, _slist_empty_p)(M_F(name, _slist_ct) list) \ - { \ - return *list == NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _slist_move)(M_F(name, _slist_ct) list, \ - M_F(name, _slist_ct) src) \ - { \ - *list = *src; \ - *src = NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _slist_clear)(M_F(name, _slist_ct) list) \ - { \ - M_F(name, _slist_node_ct) *it = *list, *next; \ - while (it) { \ - next = it->next; \ - M_MEMORY_DEL(m_context, it); \ - it = next; \ - } \ - *list = NULL; \ - } \ - - -/* Lock Free free queue list (not generic one) of lists without allocation - Based on Michael & Scott Lock Free Queue List algorithm. - Each list is considered empty if there is only one node within. - This LF Queue List doesn't try to prevent the ABA problem. It is up to the - caller to avoid recycling the nodes too fast. - Each list has its own unique NIL ptr in order to avoid issues when - migrating a node from a Q to another: in the following scenario, - - Thread 1 performs a PUSH of N in Q1 with Q1 empty (only node is NA) - NA.next is NIL. - - Thread 1 is interrupted just before the CAS on NA.next - - Thread 2 performs a successful push of NB in Q1. NA.next is set to NB. - - Thread 2 performs a successful pop of NA in Q1 - - Thread 2 performs a successful push of NA in Q2. NA.next is set to NIL. - - Thread 1 is restored and will succeed as NA.next is once again NIL. - In order to prevent the last CAS to succeed, each queue uses its own NIL pointer. - It is a derived problem of the ABA problem. - */ -/* TODO: Optimize alignment to reduce memory consumption. NIL object can use [] - to reduce memory consumption too (non compatible with C++ ...) */ -#define M_CMEMP00L_DEF_LF_QUEUE(name, type_t) \ - \ - typedef struct M_F(name, _lf_node_s) { \ - M_ATTR_EXTENSION _Atomic(struct M_F(name, _lf_node_s) *) next; \ - m_gc_atomic_ticket_ct cpt; \ - M_F(name, _slist_ct) list; \ - } M_F(name, _lf_node_t); \ - \ - typedef struct M_F(name, _lflist_s) { \ - M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) head; \ - char align1[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \ - M_ATTR_EXTENSION _Atomic(M_F(name, _lf_node_t) *) tail; \ - char align2[M_ALIGN_FOR_CACHELINE_EXCLUSION]; \ - M_F(name, _lf_node_t) nil; \ - } M_F(name, _lflist_ct)[1]; \ - \ - M_INLINE void \ - M_F(name, _lflist_init)(M_F(name, _lflist_ct) list, \ - M_F(name, _lf_node_t) *node) \ - { \ - atomic_init(&list->head, node); \ - atomic_init(&list->tail, node); \ - atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \ - } \ - \ - M_INLINE bool \ - M_F(name, _lflist_empty_p)(M_F(name, _lflist_ct) list) \ - { \ - return atomic_load(&list->tail) == atomic_load(&list->head); \ - } \ - \ - M_INLINE void \ - M_F(name, _lflist_push)(M_F(name, _lflist_ct) list, \ - M_F(name, _lf_node_t) *node, m_core_backoff_ct bkoff) \ - { \ - M_F(name, _lf_node_t) *tail; \ - M_F(name, _lf_node_t) *next; \ - \ - atomic_store_explicit(&node->next, &list->nil, memory_order_relaxed); \ - m_core_backoff_reset(bkoff); \ - while (true) { \ - tail = atomic_load(&list->tail); \ - next = atomic_load_explicit(&tail->next, memory_order_acquire); \ - if (M_UNLIKELY(next != &list->nil)) { \ - /* Tail was not pointing to the last node \ - Try to swing Tail to the next node */ \ - atomic_compare_exchange_weak_explicit(&list->tail, \ - &tail, next, \ - memory_order_release, \ - memory_order_relaxed); \ - } else { \ - /* Try to link node at the end of the linked list */ \ - if (atomic_compare_exchange_strong_explicit(&tail->next, \ - &next, node, \ - memory_order_release, \ - memory_order_relaxed)) \ - break; \ - m_core_backoff_wait(bkoff); \ - } \ - } \ - /* Enqueue is done. Try to swing Tail to the inserted node \ - If it fails, someone else will do it or has already did it. */ \ - atomic_compare_exchange_strong_explicit(&list->tail, &tail, node, \ - memory_order_acq_rel, \ - memory_order_relaxed); \ - } \ - \ - M_INLINE M_F(name, _lf_node_t) * \ - M_F(name, _lflist_pop)(M_F(name, _lflist_ct) list, m_core_backoff_ct bkoff) \ - { \ - M_F(name, _lf_node_t) *head; \ - M_F(name, _lf_node_t) *tail; \ - M_F(name, _lf_node_t) *next; \ - \ - /* Reinitialize backoff */ \ - m_core_backoff_reset(bkoff); \ - while (true) { \ - head = atomic_load(&list->head); \ - tail = atomic_load(&list->tail); \ - next = atomic_load(&head->next); \ - /* Are head, tail, and next consistent?*/ \ - if (M_LIKELY(head == \ - atomic_load_explicit(&list->head, memory_order_relaxed))) \ - { \ - /* Is queue empty or Tail falling behind? */ \ - if (head == tail) { \ - /* Is queue empty? */ \ - if (next == &list->nil) \ - return NULL; \ - /* Tail is falling behind. Try to advance it */ \ - atomic_compare_exchange_strong_explicit(&list->tail, &tail, \ - next, \ - memory_order_release, \ - memory_order_relaxed); \ - } else { \ - /* Try to swing Head to the next node */ \ - if (atomic_compare_exchange_strong_explicit(&list->head, \ - &head, next, \ - memory_order_release, \ - memory_order_relaxed)) { \ - break; \ - } \ - /* Failure: perform a random exponential backoff */ \ - m_core_backoff_wait(bkoff); \ - } \ - } \ - } \ - /* dequeue returns an element that becomes the new dummy element (the new head), \ - and the former dummy element (the former head) is removed: \ - Since we want a link of free list, and we don't care about the content itself, \ - provided that the node we return is older than the one we should return, \ - Therefore, we return the previous dummy head. \ - As such, it is not the original MSqueue algorithm. */ \ - M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \ - return head; \ - } \ - \ - /* Dequeue a node if the node is old enough */ \ - M_INLINE M_F(name, _lf_node_t) * \ - M_F(name, _lflist_pop_if)(M_F(name, _lflist_ct) list, \ - m_gc_ticket_ct age, m_core_backoff_ct bkoff) \ - { \ - M_F(name, _lf_node_t) *head; \ - M_F(name, _lf_node_t) *tail; \ - M_F(name, _lf_node_t) *next; \ - \ - m_core_backoff_reset(bkoff); \ - while (true) { \ - head = atomic_load(&list->head); \ - tail = atomic_load(&list->tail); \ - next = atomic_load(&head->next); \ - if (M_LIKELY(head == atomic_load_explicit(&list->head, memory_order_relaxed))) \ - { \ - if (head == tail) { \ - if (next == &list->nil) \ - return NULL; \ - atomic_compare_exchange_strong_explicit(&list->tail, &tail, next, \ - memory_order_release, \ - memory_order_relaxed); \ - } else { \ - /* Test if the node is old enough to be popped */ \ - if (atomic_load_explicit(&next->cpt, memory_order_relaxed) >= age) \ - return NULL; \ - /* Try to swing Head to the next node */ \ - if (atomic_compare_exchange_strong_explicit(&list->head, \ - &head, next, \ - memory_order_release, \ - memory_order_relaxed)) { \ - break; \ - } \ - m_core_backoff_wait(bkoff); \ - } \ - } \ - } \ - M_IF_DEBUG(atomic_store(&head->next, (M_F(name, _lf_node_t) *) 0);) \ - return head; \ - } \ - \ - M_INLINE void \ - M_F(name, _lflist_clear)(M_F(name, _lflist_ct) list) \ - { \ - m_core_backoff_ct bkoff; \ - m_core_backoff_init(bkoff); \ - while (true) { \ - M_F(name, _lf_node_t) *node = M_F(name, _lflist_pop)(list, bkoff); \ - if (node == NULL) break; \ - M_F(name, _lf_node_t) *next = atomic_load_explicit(&node->next, \ - memory_order_relaxed); \ - M_F(name, _slist_clear)(node->list); \ - M_MEMORY_DEL(m_context, node); \ - node = next; \ - } \ - /* Dummy node to free too */ \ - M_F(name, _lf_node_t) *dummy; \ - dummy = atomic_load_explicit(&list->head, memory_order_relaxed); \ - M_F(name, _slist_clear)(dummy->list); \ - M_MEMORY_DEL(m_context, dummy); \ - } \ - -/* System node allocator: request memory to the system. - As such it is a non Lock-Free path. */ -#define M_CMEMP00L_DEF_SYSTEM_ALLOC(name, type_t) \ - \ - M_INLINE M_F(name, _lf_node_t) * \ - M_F(name, _alloc_node)(unsigned int initial) \ - { \ - M_F(name, _lf_node_t) * node; \ - node = M_MEMORY_ALLOC(m_context, M_F(name, _lf_node_t)); \ - if (M_UNLIKELY_NOMEM (node == NULL)) { \ - M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ - } \ - atomic_init(&node->next, (M_F(name, _lf_node_t) *) 0); \ - atomic_init(&node->cpt, 0UL); \ - M_F(name, _slist_init)(node->list); \ - for(unsigned i = 0; i < initial; i++) { \ - M_F(name, _slist_node_ct) *n; \ - n = M_MEMORY_ALLOC(m_context, M_F(name, _slist_node_ct)); \ - if (M_UNLIKELY_NOMEM (n == NULL)) { \ - M_MEMORY_FULL(M_F(name, _lf_node_t), 1); \ - } \ - M_F(name, _slist_push)(node->list, n); \ - } \ - return node; \ - } \ - -/* Concurrent Memory pool - The data structure is the following. - Each thread has its own pool of nodes (local) that only it can - access (it is a singly list). If there is no longer any node in this - pool, it requests a new pool to the lock free queue of pool (group of - nodes). If it fails, it requests a new pool to the system allocator - (and from there it is no longer lock free). - This memory pool can only be lock free if the initial state is - sufficiently dimensioned to avoid calling the system allocator during - the normal processing. - Then each thread pushes its deleted node into another pool of nodes, - where the node is logically deleted (no contain of the node is destroyed - at this point and the node can be freely accessed by other threads). - Once the thread mempool is put to sleep, the age of the pool of logical - deleted nodes is computed and this pool is move to the Lock Free Queue - List of pools to be reclaimed. Then A Garbage Collector is performed - on this Lock Free Queue list to reclaim all pools that are sufficiently - aged (taking into account the grace period of the pool) to be moved back - to the Lock Free Queue of the free pools. - - Each pool of nodes can be in the following state: - * FREE state if it is present in the Lock Free Queue of free pools. - * EMPTY state if it is present in the Lock Free Queue of empty pools - which means that the nodes present in it has been USED directly by a thread, - * TO_BE_RECLAIMED state if it is present in the Lock Free Queue of TBR pools - - A pool of nodes will go to the following state: - FREE --> EMPTY --> TO_BE_RECLAIMED - ^ | - +----------------------+ - - The ABA problem is taken into account as a node cannot be reused in the - same queue without performing a full cycle of its state. Moreover - it can only move from TO_BE_RECLAIMED to FREE if and only if a grace - period is finished (and then we are sure that no thread references any - older node). - - Each thread has its own backoff structure (with local pseudo-random - generator). - - The grace period is detected through a global age counter (ticket) - that is incremented each time a thread is awaken / sleep. - Each thread has its own age that is set to the global ticket on sleep/awaken. - The age of the pool to be reclaimed is also set to this global age counter. - - To ensure that the grace period is finished, it tests if all threads - are younger than the age of the pool to be reclaimed. - - From a performance point of view, this puts a bottleneck on the global - age counter that is shared and incremented by all threads. However, - the sleep/awaken operations are much less frequent than other operations. - Thus, it shall not have a huge impact on the performance if the user - code is intelligent with the sleep/awaken operations. - - As such it won't support more than ULONG_MAX sleep for all threads. -*/ -#define M_CMEMP00L_DEF_LFMP_THREAD_MEMPOOL(name, type_t) \ - \ - typedef struct M_F(name, _lfmp_thread_s) { \ - M_F(name, _slist_ct) free; \ - M_F(name, _slist_ct) to_be_reclaimed; \ - M_CACHELINE_ALIGN(align1, M_F(name, _slist_ct), M_F(name, _slist_ct)); \ - } M_F(name, _lfmp_thread_ct); \ - \ - M_INLINE void \ - M_F(name, _lfmp_thread_init)(M_F(name, _lfmp_thread_ct) *t) \ - { \ - M_F(name, _slist_init)(t->free); \ - M_F(name, _slist_init)(t->to_be_reclaimed); \ - } \ - \ - M_INLINE void \ - M_F(name, _lfmp_thread_clear)(M_F(name, _lfmp_thread_ct) *t) \ - { \ - M_ASSERT(M_F(name, _slist_empty_p)(t->to_be_reclaimed)); \ - M_F(name, _slist_clear)(t->free); \ - M_F(name, _slist_clear)(t->to_be_reclaimed); \ - } \ - -/* NOTE: once a node is deleted, its data are kept readable until the future GC */ -#define M_CMEMP00L_DEF_LF_MEMPOOL(name, type_t) \ - \ - typedef struct M_F(name, _s) { \ - unsigned initial; \ - M_F(name, _lfmp_thread_ct) *thread_data; \ - M_F(name, _lflist_ct) free; \ - M_F(name, _lflist_ct) to_be_reclaimed; \ - M_F(name, _lflist_ct) empty; \ - m_cmemp00l_list_ct mempool_node; \ - struct m_gc_s *gc_mem; \ - } M_F(name, _t)[1]; \ - \ - /* Garbage collect of the nodes of the mempool on sleep */ \ - M_INLINE void \ - M_C3(m_cmemp00l_,name,_gc_on_sleep)(m_gc_t gc_mem, m_cmemp00l_list_ct *data, \ - m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) \ - { \ - /* Get back the mempool from the node */ \ - struct M_F(name, _s) *mempool = \ - M_TYPE_FROM_FIELD(struct M_F(name, _s), data, m_cmemp00l_list_ct, mempool_node); \ - \ - /* Move the local nodes of the mempool to be reclaimed to the thread into the global pool */ \ - if (!M_F(name, _slist_empty_p)(mempool->thread_data[id].to_be_reclaimed)) { \ - M_F(name, _lf_node_t) *node; \ - /* Get a new empty group of nodes */ \ - node = M_F(name, _lflist_pop)(mempool->empty, gc_mem->thread_data[id].bkoff); \ - if (M_UNLIKELY (node == NULL)) { \ - /* Fail to get an empty group of node. \ - Alloc a new one from the system */ \ - node = M_F(name, _alloc_node)(0); \ - M_ASSERT(node != NULL); \ - } \ - M_ASSERT(M_F(name, _slist_empty_p)(node->list)); \ - M_F(name, _slist_move)(node->list, mempool->thread_data[id].to_be_reclaimed); \ - atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); \ - M_F(name, _lflist_push)(mempool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); \ - } \ - \ - /* Perform a GC of the freelist of nodes */ \ - while (true) { \ - M_F(name, _lf_node_t) *node; \ - node = M_F(name, _lflist_pop_if)(mempool->to_be_reclaimed, \ - min_ticket, gc_mem->thread_data[id].bkoff); \ - if (node == NULL) break; \ - M_F(name, _lflist_push)(mempool->free, node, gc_mem->thread_data[id].bkoff); \ - } \ - } \ - \ - M_INLINE void \ - M_F(name, _init)(M_F(name, _t) mem, m_gc_t gc_mem, \ - unsigned init_node_count, unsigned init_group_count) \ - { \ - const size_t max_thread = gc_mem->max_thread; \ - /* Initialize the thread data of the mempool */ \ - mem->thread_data = M_MEMORY_REALLOC(m_context, M_F(name, _lfmp_thread_ct), NULL, 0, max_thread); \ - if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { \ - M_MEMORY_FULL(M_F(name, _lfmp_thread_ct), max_thread); \ - } \ - for(unsigned i = 0; i < max_thread;i++) { \ - M_F(name, _lfmp_thread_init)(&mem->thread_data[i]); \ - } \ - /* Preallocate some group of nodes for the mempool */ \ - mem->initial = M_MAX(M_CMEMP00L_MIN_NODE_PER_GROUP, init_node_count); \ - M_F(name, _lflist_init)(mem->free, M_F(name, _alloc_node)(init_node_count)); \ - M_F(name, _lflist_init)(mem->to_be_reclaimed, M_F(name, _alloc_node)(init_node_count)); \ - M_F(name, _lflist_init)(mem->empty, M_F(name, _alloc_node)(0)); \ - for(unsigned i = 1; i < init_group_count; i++) { \ - M_F(name, _lflist_push)(mem->free, M_F(name, _alloc_node)(init_node_count), \ - gc_mem->thread_data[0].bkoff); \ - M_F(name, _lflist_push)(mem->empty, M_F(name, _alloc_node)(0), \ - gc_mem->thread_data[0].bkoff); \ - } \ - /* Register the mempool in the GC */ \ - mem->mempool_node.gc_on_sleep = M_C3(m_cmemp00l_,name,_gc_on_sleep); \ - mem->mempool_node.next = gc_mem->mempool_list; \ - gc_mem->mempool_list = &mem->mempool_node; \ - mem->gc_mem = gc_mem; \ - } \ - \ - M_INLINE void \ - M_F(name, _clear)(M_F(name, _t) mem) \ - { \ - const unsigned max_thread = mem->gc_mem->max_thread; \ - for(unsigned i = 0; i < max_thread;i++) { \ - M_F(name, _lfmp_thread_clear)(&mem->thread_data[i]); \ - } \ - M_MEMORY_FREE(m_context, M_F(name, _lfmp_thread_ct), mem->thread_data, max_thread); \ - mem->thread_data = NULL; \ - M_F(name, _lflist_clear)(mem->empty); \ - M_F(name, _lflist_clear)(mem->free); \ - M_ASSERT(M_F(name, _lflist_empty_p)(mem->to_be_reclaimed)); \ - M_F(name, _lflist_clear)(mem->to_be_reclaimed); \ - /* TODO: Unregister from the GC? */ \ - } \ - \ - M_INLINE type_t * \ - M_F(name, _new)(M_F(name, _t) mem, m_gc_tid_t id) \ - { \ - M_F(name, _slist_node_ct) *snode; \ - M_F(name, _lf_node_t) *node; \ - while (true) { \ - /* Fast & likely path where we access the thread pool of nodes */ \ - if (M_LIKELY(!M_F(name, _slist_empty_p)(mem->thread_data[id].free))) { \ - snode = M_F(name, _slist_pop)(mem->thread_data[id].free); \ - return &snode->data; \ - } \ - /* Request a group node to the freelist of groups */ \ - node = M_F(name, _lflist_pop)(mem->free, mem->gc_mem->thread_data[id].bkoff); \ - if (M_UNLIKELY (node == NULL)) { \ - /* Request a new group to the system. Non Lock Free path */ \ - M_ASSERT(mem->initial > 0); \ - node = M_F(name, _alloc_node)(mem->initial); \ - M_ASSERT(node != NULL); \ - M_ASSERT(!M_F(name, _slist_empty_p)(node->list)); \ - } \ - M_F(name, _slist_move)(mem->thread_data[id].free, node->list); \ - /* Push back the empty group */ \ - M_ASSERT (M_F(name, _slist_empty_p)(node->list)); \ - M_F(name, _lflist_push)(mem->empty, node, mem->gc_mem->thread_data[id].bkoff); \ - } \ - } \ - \ - M_INLINE void \ - M_F(name, _del)(M_F(name, _t) mem, type_t *d, m_gc_tid_t id) \ - { \ - M_F(name, _slist_node_ct) *snode; \ - M_ASSERT( d != NULL); \ - snode = M_TYPE_FROM_FIELD(M_F(name, _slist_node_ct), d, type_t, data); \ - M_F(name, _slist_push)(mem->thread_data[id].to_be_reclaimed, snode); \ - } \ - - -/***********************************************************************/ - -/* Define the ID of a thread */ -typedef unsigned int m_gc_tid_t; - -/* Define the age of a node */ -/* TODO: Compute if sufficient (worst cast ULONG_MAX is 32 bits) */ -typedef unsigned long m_gc_ticket_ct; -typedef atomic_ulong m_gc_atomic_ticket_ct; - -/* Define the Linked List of mempools that are registered in the GC */ -struct m_gc_s; -typedef struct m_cmemp00l_list_s { - struct m_cmemp00l_list_s *next; - void (*gc_on_sleep)(struct m_gc_s *gc_mem, - struct m_cmemp00l_list_s *data, m_gc_tid_t id, - m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket); - void *data; -} m_cmemp00l_list_ct; - -/* Define the Garbage collector thread data */ -typedef struct m_gc_lfmp_thread_s { - m_gc_atomic_ticket_ct ticket; - m_core_backoff_ct bkoff; - M_CACHELINE_ALIGN(align1, atomic_ulong, m_core_backoff_ct); -} m_gc_lfmp_thread_ct; - -/* Define the Garbage collector coordinator */ -typedef struct m_gc_s { - m_gc_atomic_ticket_ct ticket; - m_gc_tid_t max_thread; - m_genint_t thread_alloc; - m_gc_lfmp_thread_ct *thread_data; - m_cmemp00l_list_ct *mempool_list; -} m_gc_t[1]; - -M_INLINE void -m_gc_init(m_gc_t gc_mem, size_t max_thread) -{ - M_ASSERT(gc_mem != NULL); - M_ASSERT(max_thread > 0 && max_thread < INT_MAX); - - atomic_init(&gc_mem->ticket, 0UL); - m_genint_init(gc_mem->thread_alloc, (unsigned int) max_thread); - gc_mem->thread_data = M_MEMORY_REALLOC(m_context, m_gc_lfmp_thread_ct, NULL, 0, max_thread); - if (M_UNLIKELY_NOMEM (gc_mem->thread_data == NULL)) { - M_MEMORY_FULL(m_gc_lfmp_thread_ct, max_thread); - } - for(unsigned i = 0; i < max_thread;i++) { - atomic_init(&gc_mem->thread_data[i].ticket, ULONG_MAX); - m_core_backoff_init(gc_mem->thread_data[i].bkoff); - } - gc_mem->max_thread = (unsigned int) max_thread; - gc_mem->mempool_list = NULL; -} - -M_INLINE void -m_gc_clear(m_gc_t gc_mem) -{ - M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0); - - for(m_gc_tid_t i = 0; i < gc_mem->max_thread;i++) { - m_core_backoff_clear(gc_mem->thread_data[i].bkoff); - } - M_MEMORY_FREE(m_context, m_gc_lfmp_thread_ct, gc_mem->thread_data, gc_mem->max_thread); - gc_mem->thread_data = NULL; - m_genint_clear(gc_mem->thread_alloc); -} - -M_INLINE m_gc_tid_t -m_gc_attach_thread(m_gc_t gc_mem) -{ - M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0); - - unsigned id = m_genint_pop(gc_mem->thread_alloc); - return M_ASSIGN_CAST(m_gc_tid_t, id); -} - -M_INLINE void -m_gc_detach_thread(m_gc_t gc_mem, m_gc_tid_t id) -{ - M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0); - M_ASSERT(id < gc_mem->max_thread); - M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX); - - m_genint_push(gc_mem->thread_alloc, id); -} - -M_INLINE void -m_gc_awake(m_gc_t gc_mem, m_gc_tid_t id) -{ - M_ASSERT(gc_mem != NULL && gc_mem->max_thread > 0); - M_ASSERT(id < gc_mem->max_thread); - M_ASSERT(atomic_load(&gc_mem->thread_data[id].ticket) == ULONG_MAX); - - m_gc_ticket_ct t = atomic_fetch_add(&gc_mem->ticket, 1UL) + 1; - atomic_store(&gc_mem->thread_data[id].ticket, t); -} - -M_INLINE m_gc_ticket_ct -m_cmemp00l_gc_min_ticket(m_gc_t gc_mem) -{ - m_gc_ticket_ct min = atomic_load(&gc_mem->thread_data[0].ticket); - for(m_gc_tid_t i = 1; i < gc_mem->max_thread; i++) { - m_gc_ticket_ct t = atomic_load(&gc_mem->thread_data[i].ticket); - min = M_MIN(t, min); - } - return min; -} - -M_INLINE void -m_gc_sleep(m_gc_t gc_mem, m_gc_tid_t id) -{ - /* Increase life time of the thread */ - m_gc_ticket_ct t = atomic_fetch_add(&gc_mem->ticket, 1UL); - atomic_store(&gc_mem->thread_data[id].ticket, t+1); - const m_gc_ticket_ct min_ticket = m_cmemp00l_gc_min_ticket(gc_mem); - /* Iterate over all registered mempools */ - m_cmemp00l_list_ct *it = gc_mem->mempool_list; - - while (it) { - /* Perform a garbage collect of the mempool */ - it->gc_on_sleep(gc_mem, it, id, t, min_ticket); - /* Next mempool to scan for GC */ - it = it->next; - } - /* Sleep the thread */ - atomic_store(&gc_mem->thread_data[id].ticket, ULONG_MAX); -} - - -/***********************************************************************/ -/* */ -/* Variable Length Array MEMPOOL */ -/* */ -/***********************************************************************/ - -M_CMEMP00L_DEF_SINGLY_LIST(m_vlapool, char) -M_CMEMP00L_DEF_LF_QUEUE(m_vlapool, char) -M_CMEMP00L_DEF_SYSTEM_ALLOC(m_vlapool, char) - -typedef struct m_vlapool_lfmp_thread_s { - m_vlapool_slist_ct to_be_reclaimed; - M_CACHELINE_ALIGN(align1, m_vlapool_slist_ct); -} m_vlapool_lfmp_thread_ct; - -M_INLINE void -m_vlapool_lfmp_thread_init(m_vlapool_lfmp_thread_ct *t) -{ - m_vlapool_slist_init(t->to_be_reclaimed); -} - -M_INLINE void -m_vlapool_lfmp_thread_clear(m_vlapool_lfmp_thread_ct *t) -{ - M_ASSERT(m_vlapool_slist_empty_p(t->to_be_reclaimed)); - m_vlapool_slist_clear(t->to_be_reclaimed); -} - -typedef struct m_vlapool_s { - m_vlapool_lflist_ct to_be_reclaimed; - m_vlapool_lflist_ct empty; - m_vlapool_lfmp_thread_ct *thread_data; - m_cmemp00l_list_ct mvla_node; - struct m_gc_s *gc_mem; -} m_vlapool_t[1]; - -/* Garbage collect of the nodes of the vla mempool on sleep */ -M_INLINE void -m_cmemp00l_vlapool_on_sleep(m_gc_t gc_mem, m_cmemp00l_list_ct *data, - m_gc_tid_t id, m_gc_ticket_ct ticket, m_gc_ticket_ct min_ticket) -{ - /* Get back the mempool from the node */ - struct m_vlapool_s *vlapool = - M_TYPE_FROM_FIELD(struct m_vlapool_s, data, m_cmemp00l_list_ct, mvla_node); - - /* Move the local nodes of the vlapool to be reclaimed to the thread into the global pool */ - if (!m_vlapool_slist_empty_p(vlapool->thread_data[id].to_be_reclaimed)) { - m_vlapool_lf_node_t *node; - /* Get a new empty group of nodes */ - node = m_vlapool_lflist_pop(vlapool->empty, gc_mem->thread_data[id].bkoff); - if (M_UNLIKELY (node == NULL)) { - /* Fail to get an empty group of node. - Alloc a new one from the system */ - node = m_vlapool_alloc_node(0); - M_ASSERT(node != NULL); - } - M_ASSERT(m_vlapool_slist_empty_p(node->list)); - m_vlapool_slist_move(node->list, vlapool->thread_data[id].to_be_reclaimed); - atomic_store_explicit(&node->cpt, ticket, memory_order_relaxed); - m_vlapool_lflist_push(vlapool->to_be_reclaimed, node, gc_mem->thread_data[id].bkoff); - } - - /* Perform a GC of the freelist of nodes */ - while (true) { - m_vlapool_lf_node_t *node; - node = m_vlapool_lflist_pop_if(vlapool->to_be_reclaimed, - min_ticket, gc_mem->thread_data[id].bkoff); - if (node == NULL) break; - // No reuse of VLA nodes. Free physically the node back to the system - m_vlapool_slist_clear(node->list); - // Add back the empty group of nodes - m_vlapool_slist_init(node->list); - m_vlapool_lflist_push(vlapool->empty, node, gc_mem->thread_data[id].bkoff); - } -} - -M_INLINE void -m_vlapool_init(m_vlapool_t mem, m_gc_t gc_mem) -{ - const size_t max_thread = gc_mem->max_thread; - - /* Initialize the thread data of the vlapool */ - mem->thread_data = M_MEMORY_REALLOC(m_context, m_vlapool_lfmp_thread_ct, NULL, 0, max_thread); - if (M_UNLIKELY_NOMEM (mem->thread_data == NULL)) { - M_MEMORY_FULL(m_vlapool_lfmp_thread_ct, max_thread); - } - for(unsigned i = 0; i < max_thread;i++) { - m_vlapool_lfmp_thread_init(&mem->thread_data[i]); - } - - /* Initialize the lists */ - m_vlapool_lflist_init(mem->to_be_reclaimed, m_vlapool_alloc_node(0)); - m_vlapool_lflist_init(mem->empty, m_vlapool_alloc_node(0)); - - /* Register the mempool in the GC */ - mem->mvla_node.gc_on_sleep = m_cmemp00l_vlapool_on_sleep; - mem->mvla_node.next = gc_mem->mempool_list; - gc_mem->mempool_list = &mem->mvla_node; - mem->gc_mem = gc_mem; -} - -M_INLINE void -m_vlapool_clear(m_vlapool_t mem) -{ - const unsigned max_thread = mem->gc_mem->max_thread; - for(unsigned i = 0; i < max_thread;i++) { - m_vlapool_lfmp_thread_clear(&mem->thread_data[i]); - } - M_MEMORY_FREE(m_context, m_vlapool_lfmp_thread_ct, mem->thread_data, max_thread); - mem->thread_data = NULL; - m_vlapool_lflist_clear(mem->empty); - M_ASSERT(m_vlapool_lflist_empty_p(mem->to_be_reclaimed)); - m_vlapool_lflist_clear(mem->to_be_reclaimed); - /* TODO: Unregister from the GC? */ -} - -M_INLINE void * -m_vlapool_new(m_vlapool_t mem, m_gc_tid_t id, size_t size) -{ - M_ASSERT(mem != NULL && mem->gc_mem != NULL); - M_ASSERT(id < mem->gc_mem->max_thread); - M_ASSERT( atomic_load(&mem->gc_mem->thread_data[id].ticket) != ULONG_MAX); - - // Nothing to do with theses parameters yet - (void) mem; - (void) id; - - // Ensure the size is big enough to also represent a node - size += offsetof(struct m_vlapool_slist_node_s, data); - - // Simply wrap around a system call to get the memory - char *ptr = M_MEMORY_REALLOC(m_context, char, NULL, 0, size); - // TODO: save the allocated size somewhere (create a new field in vla) - // FIXME: Bug, we call DEL operator to free the node, but we have allocated it with the REALLOC one! - // And they are not necessarily compatible as per the spec (even if they are if they both use 'free') - // And the generic used slist expects to use the DEL one, since the vlapool abuse the memory system. - // Honnestly, it is fundamentally broken and it needs a huge rewrite. - return M_UNLIKELY (ptr == NULL) ? NULL : M_ASSIGN_CAST(void *, ptr + offsetof(struct m_vlapool_slist_node_s, data)); -} - -M_INLINE void -m_vlapool_del(m_vlapool_t mem, void *d, m_gc_tid_t id) -{ - M_ASSERT(mem != NULL && mem->gc_mem != NULL); - M_ASSERT(id < mem->gc_mem->max_thread); - M_ASSERT(atomic_load(&mem->gc_mem->thread_data[id].ticket) != ULONG_MAX); - M_ASSERT(d != NULL); - - // Get back the pointer to a struct m_vlapool_slist_node_s. - d = M_ASSIGN_CAST(void *, M_ASSIGN_CAST(char *, d) - offsetof(struct m_vlapool_slist_node_s, data)); - m_vlapool_slist_node_ct *snode = M_ASSIGN_CAST(m_vlapool_slist_node_ct *, d); - // Push the logically free memory into the list of the nodes to be reclaimed. - m_vlapool_slist_push(mem->thread_data[id].to_be_reclaimed, snode); -} - -M_END_PROTECTED_CODE - -#if M_USE_SMALL_NAME -#define C_MEMPOOL_DEF M_C_MEMPOOL_DEF -#endif - -#endif diff --git a/tests/test-mcmempool.c b/tests/test-mcmempool.c deleted file mode 100644 index 79593030..00000000 --- a/tests/test-mcmempool.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * M*LIB - Test for Concurrent memory pool allocator - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "m-c-mempool.h" -#include "m-thread.h" - -C_MEMPOOL_DEF(lf_mempool, int) - -m_gc_t gc; - -/**********************************************************************/ - -#define MAX_VALUE 100 -#define MAX_THREAD 4 - -lf_mempool_t g; - -typedef struct { - int step; - int *ptr[MAX_VALUE]; - int value[MAX_VALUE]; -} p_t; - -p_t g_tab[MAX_THREAD]; - -static void do_stuff(m_gc_tid_t id) -{ - // Mix of local and more global allocation - int *d[MAX_VALUE]; - for(int i = 0; i < MAX_VALUE; i++) { - d[i] = lf_mempool_new(g, id); - *d[i] = i*i; - } - switch (g_tab[id].step) - { - case 0: - for(int i = 0; i < 50; i++) { - g_tab[id].value[i] += i; - g_tab[id].ptr[i] = lf_mempool_new(g, id); - *g_tab[id].ptr[i] = g_tab[id].value[i]; - } - g_tab[id].step = 1; - break; - case 1: - for(int i = 50; i < MAX_VALUE; i++) { - g_tab[id].value[i] += i; - g_tab[id].ptr[i] = lf_mempool_new(g, id); - *g_tab[id].ptr[i] = g_tab[id].value[i]; - } - g_tab[id].step = 2; - break; - case 2: - for(int i = 0; i < 50; i++) { - assert(g_tab[id].ptr[i] != NULL); - assert(*g_tab[id].ptr[i] == g_tab[id].value[i] ); - lf_mempool_del(g, g_tab[id].ptr[i], id); - g_tab[id].ptr[i] = NULL; - } - g_tab[id].step = 3; - break; - case 3: - for(int i = 50; i < MAX_VALUE; i++) { - assert(g_tab[id].ptr[i] != NULL); - assert(*g_tab[id].ptr[i] == g_tab[id].value[i] ); - lf_mempool_del(g, g_tab[id].ptr[i], id); - g_tab[id].ptr[i] = NULL; - } - g_tab[id].step = 0; - break; - default: - break; - } - for(int i = 0; i < MAX_VALUE; i++) { - assert (*d[i] == i*i); - lf_mempool_del(g, d[i], id); - } -} - -static void thread1(void *arg) -{ - (void)arg; - /* Attach this thread to the GC */ - m_gc_tid_t id = m_gc_attach_thread(gc); - for(int n = 0; n < 100000; n ++) { - /* Awake the thread: now we can alloc nodes */ - m_gc_awake(gc, id); - /* Do some stuff */ - do_stuff(id); - /* Sleep the thread. A Garbage Collect may occur if possible */ - m_gc_sleep(gc, id); - } - /* Detach the thread from the GC */ - m_gc_detach_thread(gc, id); -} - -static void thread2(void *arg) -{ - (void)arg; - m_gc_tid_t id = m_gc_attach_thread(gc); - for(int n = 0; n < 10000; n ++) { - m_gc_awake(gc, id); - do_stuff(id); - m_thread_sleep(1); - m_gc_sleep(gc, id); - } - m_gc_detach_thread(gc, id); -} - -static void test(void) -{ - /* First create the Garbage Collector */ - m_gc_init (gc, MAX_THREAD); - /* Create a mempool and attach it to the Garbage Collector */ - lf_mempool_init(g, gc, 256, MAX_THREAD); - - m_thread_t id[MAX_THREAD]; - for(int i = 0; i < MAX_THREAD; i+=2) { - m_thread_create(id[i], thread1, NULL); - m_thread_create(id[i+1], thread2, NULL); - } - for(int i = 0; i < MAX_THREAD; i++) { - m_thread_join(id[i]); - } - /* Destroy the mempool */ - lf_mempool_clear(g); - /* Destroy the Garbage Collector */ - m_gc_clear (gc); -} - -static void test2(void) -{ - /* First create the Garbage Collector */ - m_gc_init (gc, MAX_THREAD); - /* Create a mempool and attach it to the Garbage Collector */ - lf_mempool_init(g, gc, 256, MAX_THREAD); - /* Create another mempool and attach it to the Garbage Collector */ - lf_mempool_t g2; - lf_mempool_init(g2, gc, 256, MAX_THREAD); - /* Register VLA */ - m_vlapool_t vla; - m_vlapool_init(vla, gc); - - /* Attach the thread */ - m_gc_tid_t id = m_gc_attach_thread(gc); - /* Awake the thread: now we can alloc nodes */ - m_gc_awake(gc, id); - - /* Test some allocation */ - void *ptr = m_vlapool_new(vla, id, sizeof (int)); - *(int*)ptr = 42; - m_vlapool_del(vla, ptr, id); - - int *pi = lf_mempool_new(g, id); - *pi = 44; - lf_mempool_del(g, pi, id); - - int *pi2 = lf_mempool_new(g2, id); - *pi2 = 46; - lf_mempool_del(g2, pi2, id); - - /* Test that the data remain accessible - as it has only be logically deleted */ - assert (*(int*)ptr == 42); - assert (*pi == 44); - assert (*pi2 == 46); - - /* Sleep the thread */ - m_gc_sleep(gc, id); - - /* Detach the thread */ - m_gc_detach_thread(gc, id); - - /* Clear everything */ - m_vlapool_clear(vla); - lf_mempool_clear(g); - lf_mempool_clear(g2); - m_gc_clear(gc); -} - -int main(void) -{ - test(); - test2(); - exit(0); -} - From 2296f203fd8ca4551178505aecd0b20953151cca Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 21:34:18 +0200 Subject: [PATCH 87/91] Remove obsolete m-shared.h header --- README.md | 171 ------------ doc/API.txt | 2 + example/ex11-small-name.c | 1 - m-shared.h | 555 -------------------------------------- tests/test-mshared.c | 247 ----------------- 5 files changed, 2 insertions(+), 974 deletions(-) delete mode 100644 m-shared.h delete mode 100644 tests/test-mshared.c diff --git a/README.md b/README.md index 46fb7756..a08dec67 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,6 @@ Finally, headers for compatibility with non C11 compilers: * [m-thread.h](#m-thread): header for providing a very thin layer across multiple implementation of mutex/threads (C11/PTHREAD/WIN32). The following headers are obsolete and will be removed in the next major release: -* [m-shared.h](#m-shared): header for creating shared pointer of generic type, * [m-concurrent.h](#m-concurrent): header for transforming a container into a concurrent container (thread safe), * [m-i-shared.h](#m-i-shared): header for creating intrusive shared pointer of generic type (Thread Safe). * [m-mempool.h](#m-mempool): header for creating specialized & fast memory allocator, @@ -5086,176 +5085,6 @@ Create a new shared object initialized with its `INIT_SET` operator on the given This method is created only if the `INIT_SET` operator is defined. -_________________ - -### M-SHARED - -> [!NOTE] -> This header is obsolete: M-SHARED-PTR should be used instead. - -This header is for creating shared pointer. -A [shared pointer](https://en.wikipedia.org/wiki/Smart_pointer) - is a smart pointer that retains shared ownership of an object. -Several shared pointers may own the same object, sharing ownership of an object. - -#### `SHARED_PTR_DEF(name, type[, oplist])` -#### `SHARED_PTR_DEF_AS(name, name_t, type[, oplist])` - -Define the shared pointer `name_t` and its associated methods as `static inline` functions. -A shared pointer is a mechanism to keep tracks of all registered users of an object -and performs an automatic destruction of the object only when all users release -their need on this object. - -`name` shall be a C identifier that will be used to identify the shared pointer. -It will be used to create all the types (including the iterator) -and functions to handle the container. -This definition shall be done once per name and per compilation unit. - -The tracking of ownership is atomic and the destruction of the object is thread safe. - -The object oplist is expected to have at least the following operators (`CLEAR` to clear the object and `DEL` to free the allocated memory). - -There are designed to work with buffers with policy `BUFFER_PUSH_INIT_POP_MOVE` -to send a shared pointer across multiple threads. - -If the type is an incomplete type, you need to disable the `INIT` operator and not defined the `EMPLACE_TYPE` operator in the given oplist like this: - -```C - (INIT(0), CLEAR(API_2(incomplete_clear))) ) -``` - -`SHARED_PTR_DEF_AS` is the same as `SHARED_PTR_DEF` except the name of the type `name_t` -is provided. - -Example: - -```C -SHARED_PTR_DEF(shared_mpz, mpz_t, (CLEAR(mpz_clear))) -void f(void) { - shared_mpz_t p; - mpz_t z; - mpz_init(z); - shared_mpz_init2 (p, z); - buffer_uint_push(g_buff1, p); - buffer_uint_push(g_buff2, p); - shared_mpz_clear(p); -} -``` - -#### `SHARED_PTR_RELAXES_DEF(name, type[, oplist])` -#### `SHARED_PTR_RELAXES_DEF_AS(name, name_t, type[, oplist])` - -Theses are the same as `SHARED_PTR_DEF` / `SHARED_PTR_DEF_AS` -except that they are not thread safe. -See `SHARED_PTR_DEF` for other details. - -#### Created types - -The following types are automatically defined by the previous definition macro if not provided by the user: - -##### `name_t` - -Type of the shared pointer. - -#### Specialized methods - -The following specialized methods are automatically created by the previous definition macro: - -##### `void name_init(shared_t shared)` - -Initialize the shared pointer `shared` to represent the NULL pointer -(no object is therefore referenced). - -##### `void name_init2(shared_t shared, type *data)` - -Initialize the shared pointer `shared` to reference the object `*data` -and takes ownership of this object. -User code shall not use `*data` (or any pointer to it) anymore -as the shared pointer gets the exclusive ownership of the object. - -##### `void name_init_new(shared_t shared)` - -Initialize the shared pointer `shared` to a new object of type `type`. -The default constructor of type is used to initialize the object. -This method is only created if the `INIT` method is provided. - -##### `void name_init_set(shared_t shared, const shared_t src)` - -Initialize the shared pointer `shared` to the same object than the one -pointed by `src` (sharing ownership). -This function is thread safe from `src` point of view. - -##### `void name_init_with[suffix](shared_t shared, args...)` - -Initialize the shared pointer `shared` to the new object initialized with args. -The provided arguments shall therefore match one of the constructor provided -by the `EMPLACE_TYPE` operator. -There is one generated method per suffix defined in the `EMPLACE_TYPE` operator, -and the `suffix` in the generated method name corresponds to the suffix defined -in the `EMPLACE_TYPE` operator (it can be empty). -This method is created only if the `EMPLACE_TYPE` operator is provided. -See [emplace chapter](#Emplace-construction) for more details. -It is equivalent to the C++ make_shared. - -##### `bool name_NULL_p(const shared_t shared)` - -Return true if shared doesn't reference any object (i.e. is the NULL pointer). - -##### `void name_clear(shared_t shared)` - -Clear the shared pointer (destructor): -the shared pointer loses its ownership of the object and -it destroys the shared object if no longer any other shared pointers own it. -This function is thread safe. - -##### `void name_reset(shared_t shared)` - -`shared` loses ownership of its shared object and destroys it -if no longer any other shared pointers own it. -Then it makes the shared pointer `shared` references no object (NULL) -(it doesn't reference its object any-longer and loses its ownership of it). -This function is thread safe. - -##### `void name_set(shared_t shared, const shared_t src)` - -`shared` loses ownership of its object and destroy it -if no longer any other shared pointers own it. -Then it sets the shared pointer `shared` to the same object -than the one pointed by `src` (sharing ownership). -This function is thread safe. - -##### `void name_init_move(shared_t shared, shared_t src)` - -Move the shared pointer from the initialized `src` to `shared`. - -##### `void name_move(shared_t shared, shared_t src)` - -`shared` loses ownership of its object and destroy it -if no longer any other shared pointers own it. -Then it moves the shared pointer from the initialized `src` to `shared`. - -##### `void name_swap(shared_t shared1, shared_t shared2)` - -Swap the references of the objects owned by the shared pointers `shared1` and `shared2`. - -##### `bool name_equal_p(const shared_t shared1, const shared_t shared2)` - -Return true if both shared pointers own the same object. - -##### `const type *name_cref(const shared_t shared)` - -Return a constant pointer to the shared object owned by the shared pointer. -The pointer shall be kept only until another use of shared pointer method. -Keeping the pointer otherwise is undefined behavior. - -##### `type *name_ref(const shared_t shared)` - -Return a pointer to the shared object pointed by the shared pointer. -The pointer shall be kept only until another use of shared pointer method. -Keeping the pointer otherwise is undefined behavior. - -TODO: Document shared resource - _________________ ### M-I-SHARED diff --git a/doc/API.txt b/doc/API.txt index 0458e919..15c24931 100644 --- a/doc/API.txt +++ b/doc/API.txt @@ -106,3 +106,5 @@ V0.8.0 : * Memory interface massive compatibility break to allow more efficient either default INIT_MOVE operator (operator '=') is working, or a method is provided for INIT_MOVE or it is disabled. If it is an array of size 1, you can use M_COPY_A1_DEFAULT as a default method. (It's because supporting emulation layer with new memory context parameter was complicated) + * Remove obsole headers: m-c-mempool, m-mempool, m-shared, m-i-shared, -mconcurrent + diff --git a/example/ex11-small-name.c b/example/ex11-small-name.c index e05b2ea2..05d955b4 100644 --- a/example/ex11-small-name.c +++ b/example/ex11-small-name.c @@ -22,7 +22,6 @@ #include "m-rbtree.h" #include "m-serial-bin.h" #include "m-serial-json.h" -//#include "m-shared.h" // API incompatible with m-shared-ptr.h (exclusive) #include "m-shared-ptr.h" #include "m-snapshot.h" #include "m-string.h" diff --git a/m-shared.h b/m-shared.h deleted file mode 100644 index f79d5562..00000000 --- a/m-shared.h +++ /dev/null @@ -1,555 +0,0 @@ -/* - * M*LIB - SHARED Pointer Module - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef MSTARLIB_SHARED_PTR_H -#define MSTARLIB_SHARED_PTR_H - -#include "m-core.h" -#include "m-atomic.h" -#include "m-genint.h" - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L -#warning The header m-shared.h is obsolete. Use m-shared-ptr header instead. -#endif - -M_BEGIN_PROTECTED_CODE - -/* Define shared pointer and its function. - USAGE: SHARED_PTR_DEF(name, type, [, oplist]) */ -#define M_SHARED_PTR_DEF(name, ...) \ - M_SHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__) - - -/* Define shared pointer and its function - as the given name name_t - USAGE: SHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */ -#define M_SHARED_PTR_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_ATOMIC_OPLIST, name_t ), \ - (name, __VA_ARGS__ , M_SHAR3D_ATOMIC_OPLIST, name_t ))) \ - M_END_PROTECTED_CODE - - -/* Define the oplist of a shared pointer. - USAGE: SHARED_OPLIST(name [, oplist_of_the_type]) */ -#define M_SHARED_PTR_OPLIST(...) \ - M_SHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_BASIC_OPLIST ), \ - (__VA_ARGS__ ))) - - -/* Define relaxed shared pointer and its function (thread unsafe). - USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */ -#define M_SHARED_PTR_RELAXED_DEF(name, ...) \ - M_SHARED_PTR_RELAXED_DEF_AS(name, M_F(name,_t), __VA_ARGS__) - - -/* Define relaxed shared pointer and its function (thread unsafe) - as the given name name_t - USAGE: SHARED_PTR_RELAXED_DEF(name, type, [, oplist]) */ -#define M_SHARED_PTR_RELAXED_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - M_SHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), M_SHAR3D_INTEGER_OPLIST, name_t ), \ - (name, __VA_ARGS__, M_SHAR3D_INTEGER_OPLIST, name_t ))) \ - M_END_PROTECTED_CODE - - -/* Define shared resource and its function. - This is a bounded pool of resource shared by multiple owners. - USAGE: SHARED_RESOURCE_DEF(name, type, [, oplist]) */ -#define M_SHARED_RESOURCE_DEF(name, ...) \ - M_SHARED_RESOURCE_DEF_AS(name, M_F(name,_t), M_F(name,_it_t), __VA_ARGS__) - - -/* Define shared resource and its function - as the given name named_t and the iterator it_t - This is a bounded pool of resource shared by multiple owners. - USAGE: SHARED_RESOURCE_DEF_AS(name, name_t, it_t, type, [, oplist]) */ -#define M_SHARED_RESOURCE_DEF_AS(name, name_t, it_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - M_SHAR3D_RESOURCE_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t, it_t ), \ - (name, __VA_ARGS__, name_t, it_t ))) \ - M_END_PROTECTED_CODE - - - -/*****************************************************************************/ -/********************************** INTERNAL *********************************/ -/*****************************************************************************/ - -// deferred evaluation -#define M_SHAR3D_PTR_OPLIST_P1(arg) M_SHAR3D_PTR_OPLIST_P2 arg - -/* Validation of the given, shared_t oplist */ -#define M_SHAR3D_PTR_OPLIST_P2(name, oplist) \ - M_IF_OPLIST(oplist)(M_SHAR3D_PTR_OPLIST_P3, M_SHAR3D_PTR_OPLIST_FAILURE)(name, oplist) - -/* Prepare a clean compilation failure */ -#define M_SHAR3D_PTR_OPLIST_FAILURE(name, oplist) \ - ((M_LIB_ERROR(ARGUMENT_OF_SHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) - -#define M_SHAR3D_PTR_OPLIST_P3(name, oplist) ( \ - INIT(M_F(name, _init)), \ - CLEAR(M_F(name, _clear)), \ - INIT_SET(M_F(name, _init_set)), \ - SET(M_F(name, _set)) \ - INIT_MOVE(M_F(name, _init_move)), \ - RESET(M_F(name, _reset)), \ - MOVE(M_F(name, _move)), \ - SWAP(M_F(name, _swap)) \ - ,NAME(name) \ - ,TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*) \ - ) - -// OPLIST to handle a counter of atomic type -#define M_SHAR3D_ATOMIC_OPLIST (TYPE(atomic_int), \ - INIT_SET(atomic_init), \ - ADD(atomic_fetch_add), \ - SUB(atomic_fetch_sub), \ - IT_CREF(atomic_load)) - -// OPLIST to handle a counter of non-atomic type -#define M_SHAR3D_INTEGER_OPLIST (TYPE(int), \ - INIT_SET(m_shar3d_integer_init_set), \ - ADD(m_shar3d_integer_add), \ - SUB(m_shar3d_integer_sub), \ - IT_CREF(m_shar3d_integer_cref)) - -/* Atomic like interface for basic integers */ -M_INLINE void m_shar3d_integer_init_set(int *p, int val) { *p = val; } -M_INLINE int m_shar3d_integer_add(int *p, int val) { int r = *p; *p += val; return r; } -M_INLINE int m_shar3d_integer_sub(int *p, int val) { int r = *p; *p -= val; return r; } -M_INLINE int m_shar3d_integer_cref(int *p) { return *p; } - - -/********************************** INTERNAL *********************************/ - -/* Contract of a shared pointer */ -#define M_SHAR3D_CONTRACT(shared, cpt_oplist) do { \ - M_ASSERT(shared != NULL); \ - M_ASSERT(*shared == NULL || M_CALL_IT_CREF(cpt_oplist, &(*shared)->cpt) >= 1); \ - } while (0) - -// deferred evaluation -#define M_SHAR3D_PTR_DEF_P1(arg) M_ID( M_SHAR3D_PTR_DEF_P2 arg ) - -/* Validate the oplist before going further */ -#define M_SHAR3D_PTR_DEF_P2(name, type, oplist, cpt_oplist, shared_t) \ - M_IF_OPLIST(oplist)(M_SHAR3D_PTR_DEF_P3, M_SHAR3D_PTR_DEF_FAILURE)(name, type, oplist, cpt_oplist, shared_t) - -/* Stop processing with a compilation failure */ -#define M_SHAR3D_PTR_DEF_FAILURE(name, type, oplist, cpt_oplist, shared_t) \ - M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist) - -/* Code generation */ -#define M_SHAR3D_PTR_DEF_P3(name, type, oplist, cpt_oplist, shared_t) \ - M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \ - M_EMPLACE_QUEUE_DEF(name, cpt_oplist, M_F(name, _init_with), oplist, M_SHAR3D_PTR_DEF_EMPLACE) - -/* Define the types */ -#define M_SHAR3D_PTR_DEF_TYPE(name, type, oplist, cpt_oplist, shared_t) \ - \ - typedef struct M_F(name, _s){ \ - type *data; /* Pointer to the data */ \ - M_GET_TYPE cpt_oplist cpt; /* Counter of how many refs the data */ \ - bool combineAlloc; /* Does the data and the ptr share the slot? */ \ - } *shared_t[1]; \ - typedef struct M_F(name, _s) *M_F(name, _ptr); \ - typedef const struct M_F(name, _s) *M_F(name, _srcptr); \ - \ - /* Internal type for oplist */ \ - typedef shared_t M_F(name, _ct); \ - typedef type M_F(name, _subtype_ct); \ - \ - M_IF(M_OR(M_TEST_METHOD_P(INIT, oplist), M_TEST_METHOD_ALTER_P(EMPLACE_TYPE, oplist)))( \ - typedef struct M_F(name, _combine_s) { \ - struct M_F(name, _s) ptr; \ - type data; \ - } M_F(name, combine_ct)[1]; \ - , /* nothing to do */ ) - -/* Define the core functions */ -#define M_SHAR3D_PTR_DEF_CORE(name, type, oplist, cpt_oplist, shared_t) \ - \ - M_INLINE void \ - M_F(name, _init)(shared_t shared) \ - { \ - *shared = NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _init2)(shared_t shared, type *data) \ - { \ - M_ASSERT (shared != NULL); \ - /* The shared ptr get exclusive access to data */ \ - struct M_F(name, _s) *ptr; \ - if (M_UNLIKELY (data == NULL)) { \ - *shared = NULL; \ - return; \ - } \ - ptr = M_CALL_NEW(oplist, struct M_F(name, _s)); \ - if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ - M_MEMORY_FULL(struct M_F(name, _s), 1); \ - } \ - ptr->data = data; \ - M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \ - ptr->combineAlloc = false; \ - *shared = ptr; \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _init_new)(shared_t shared) \ - { \ - /* NOTE: Alloc 1 struct with both structures. */ \ - struct M_F(name, _combine_s) *p = \ - M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \ - if (M_UNLIKELY_NOMEM (p == NULL)) { \ - M_MEMORY_FULL(struct M_F(name, _combine_s), 1); \ - } \ - struct M_F(name, _s) *ptr = &p->ptr; \ - ptr->combineAlloc = true; \ - type *data = &p->data; \ - M_CALL_INIT( oplist, *data); \ - ptr->data = data; \ - M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \ - *shared = ptr; \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - } \ - , /* No INIT */ ) \ - \ - M_INLINE bool \ - M_F(name, _NULL_p)(const shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - return *shared == NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _init_set)(shared_t dest, \ - const shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - M_ASSERT (dest != shared); \ - *dest = *shared; \ - if (*dest != NULL) { \ - int n = M_CALL_ADD(cpt_oplist, &((*dest)->cpt), 1); \ - (void) n; /* unused return value */ \ - } \ - M_SHAR3D_CONTRACT(dest, cpt_oplist); \ - } \ - \ - M_INLINE void \ - M_F(name, _clear)(shared_t dest) \ - { \ - M_SHAR3D_CONTRACT(dest, cpt_oplist); \ - if (*dest != NULL) { \ - if (M_CALL_SUB(cpt_oplist, &((*dest)->cpt), 1) == 1) { \ - bool combineAlloc = (*dest)->combineAlloc; \ - /* Note: if combineAlloc is true, the address of the slot \ - combining both data & ptr is the same as the address of the \ - first element, aka data itself. Static analyzer tools don't \ - seem to detect this and report error. */ \ - M_CALL_CLEAR(oplist, *(*dest)->data); \ - if (combineAlloc == false) { \ - M_CALL_DEL(oplist, (*dest)->data); \ - } \ - M_CALL_DEL(oplist, *dest); \ - } \ - *dest = NULL; \ - } \ - M_SHAR3D_CONTRACT(dest, cpt_oplist); \ - } \ - \ - M_INLINE void \ - M_F(name, _reset)(shared_t dest) \ - { \ - /* NOTE: Clear will also set dest to NULL */ \ - M_F(name, _clear)(dest); \ - } \ - \ - M_INLINE void \ - M_F(name, _set)(shared_t dest, \ - const shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(dest, cpt_oplist); \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - M_F(name, _clear)(dest); \ - M_F(name, _init_set)(dest, shared); \ - } \ - \ - M_INLINE void \ - M_F(name, _init_move)(shared_t dest, \ - shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - M_ASSERT (dest != NULL && dest != shared); \ - *dest = *shared; \ - *shared = NULL; \ - M_SHAR3D_CONTRACT(dest, cpt_oplist); \ - } \ - \ - M_INLINE void \ - M_F(name, _move)(shared_t dest, \ - shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(dest, cpt_oplist); \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - M_ASSERT (dest != shared); \ - M_F(name, _clear)(dest); \ - M_F(name, _init_move)(dest, shared); \ - } \ - \ - M_INLINE void \ - M_F(name, _swap)(shared_t p1, \ - shared_t p2) \ - { \ - M_SHAR3D_CONTRACT(p1, cpt_oplist); \ - M_SHAR3D_CONTRACT(p2, cpt_oplist); \ - /* NOTE: SWAP is not atomic */ \ - M_SWAP (struct M_F(name, _s)*, *p1, *p2); \ - M_SHAR3D_CONTRACT(p1, cpt_oplist); \ - M_SHAR3D_CONTRACT(p2, cpt_oplist); \ - } \ - \ - M_INLINE bool \ - M_F(name, _equal_p)(const shared_t p1, \ - const shared_t p2) \ - { \ - M_SHAR3D_CONTRACT(p1, cpt_oplist); \ - M_SHAR3D_CONTRACT(p2, cpt_oplist); \ - return *p1 == *p2; \ - } \ - \ - M_INLINE type const * \ - M_F(name, _cref)(const shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - M_ASSERT(*shared != NULL); \ - type *data = (*shared)->data; \ - M_ASSERT (data != NULL); \ - return M_CONST_CAST (type, data); \ - } \ - \ - M_INLINE type * \ - M_F(name, _ref)(shared_t shared) \ - { \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - M_ASSERT(*shared != NULL); \ - type *data = (*shared)->data; \ - M_ASSERT (data != NULL); \ - return data; \ - } \ - -/* Definition of the emplace_back function for arrays */ -#define M_SHAR3D_PTR_DEF_EMPLACE(name, cpt_oplist, function_name, oplist, init_func, exp_emplace_type) \ - M_INLINE void \ - function_name(M_F(name, _ct) shared \ - M_EMPLACE_LIST_TYPE_VAR(a, exp_emplace_type) ) \ - { \ - /* NOTE: Alloc 1 struct with both structures. */ \ - struct M_F(name, _combine_s) *p = \ - M_CALL_NEW(oplist, struct M_F(name, _combine_s)); \ - if (M_UNLIKELY_NOMEM (p == NULL)) { \ - M_MEMORY_FULL(struct M_F(name, _combine_s), 1); \ - } \ - struct M_F(name, _s) *ptr = &p->ptr; \ - ptr->combineAlloc = true; \ - M_F(name, _subtype_ct) *data = &p->data; \ - M_EMPLACE_CALL_FUNC(a, init_func, oplist, *data, exp_emplace_type); \ - ptr->data = data; \ - M_CALL_INIT_SET(cpt_oplist, &ptr->cpt, 1); \ - *shared = ptr; \ - M_SHAR3D_CONTRACT(shared, cpt_oplist); \ - } \ - - - -/********************************** INTERNAL *********************************/ - -#define M_SHAR3D_RESOURCE_CONTRACT(s) do { \ - M_ASSERT (s != NULL); \ - M_ASSERT (s->buffer != NULL); \ - } while (0) - -// deferred -#define M_SHAR3D_RESOURCE_DEF_P1(arg) M_ID( M_SHAR3D_RESOURCE_DEF_P2 arg ) - -/* Validate the oplist before going further */ -#define M_SHAR3D_RESOURCE_DEF_P2(name, type, oplist, shared_t, it_t) \ - M_IF_OPLIST(oplist)(M_SHAR3D_RESOURCE_DEF_P3, M_SHAR3D_RESOURCE_DEF_FAILURE)(name, type, oplist, shared_t, it_t) - -/* Stop processing with a compilation failure */ -#define M_SHAR3D_RESOURCE_DEF_FAILURE(name, type, oplist, shared_t, it_t) \ - M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(SHARED_RESOURCE_DEF): the given argument is not a valid oplist: " #oplist) - -#define M_SHAR3D_RESOURCE_DEF_P3(name, type, oplist, shared_t, it_t) \ - M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \ - -/* Define the types */ -#define M_SHAR3D_RESOURCE_DEF_TYPE(name, type, oplist, shared_t, it_t) \ - \ - /* Create an aligned type to avoid false sharing between threads */ \ - typedef struct M_F(name, _atype_s) { \ - atomic_uint cpt; \ - type x; \ - M_CACHELINE_ALIGN(align, type, atomic_uint); \ - } M_F(name, _atype_ct); \ - \ - typedef struct M_F(name, _s) { \ - m_genint_t core; \ - M_F(name, _atype_ct) *buffer; \ - } shared_t[1]; \ - \ - typedef struct M_F(name, _it_s) { \ - unsigned int idx; \ - struct M_F(name, _s) *ref; \ - } it_t[1]; \ - \ - /* Internal Types for oplist */ \ - typedef shared_t M_F(name, _ct); \ - typedef type M_F(name, _subtype_ct); \ - -/* Define the core functions */ -#define M_SHAR3D_RESOURCE_DEF_CORE(name, type, oplist, shared_t, it_t) \ - M_INLINE void \ - M_F(name, _init)(shared_t s, size_t n) \ - { \ - M_ASSERT(s != NULL); \ - M_ASSERT (n > 0 && n < UINT_MAX); \ - s->buffer = M_CALL_REALLOC(oplist, M_F(name, _atype_ct), NULL, 0, n); \ - if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \ - M_MEMORY_FULL(M_F(name, _atype_ct), n); \ - } \ - for(size_t i = 0; i < n; i++) { \ - M_CALL_INIT(oplist, s->buffer[i].x); \ - atomic_init (&s->buffer[i].cpt, 0U); \ - } \ - m_genint_init(s->core, (unsigned int) n); \ - M_SHAR3D_RESOURCE_CONTRACT(s); \ - } \ - \ - M_INLINE void \ - M_F(name, _clear)(shared_t s) \ - { \ - M_SHAR3D_RESOURCE_CONTRACT(s); \ - size_t n = m_genint_size(s->core); \ - for(size_t i = 0; i < n; i++) { \ - M_CALL_CLEAR(oplist, s->buffer[i].x); \ - } \ - M_CALL_FREE(oplist, M_F(name, _atype_ct), s->buffer, n); \ - s->buffer = NULL; \ - m_genint_clear(s->core); \ - } \ - \ - M_INLINE void \ - M_F(name, _it)(it_t it, shared_t s) \ - { \ - M_SHAR3D_RESOURCE_CONTRACT(s); \ - M_ASSERT (it != NULL); \ - unsigned int idx = m_genint_pop(s->core); \ - it->idx = idx; \ - it->ref = s; \ - if (M_LIKELY (idx != M_GENINT_ERROR)) { \ - M_ASSERT(atomic_load(&s->buffer[idx].cpt) == 0); \ - atomic_store(&s->buffer[idx].cpt, 1U); \ - } \ - } \ - \ - M_INLINE bool \ - M_F(name, _end_p)(it_t it) \ - { \ - M_ASSERT (it != NULL); \ - return it->idx == M_GENINT_ERROR; \ - } \ - \ - M_INLINE type * \ - M_F(name, _ref)(it_t it) \ - { \ - M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \ - M_SHAR3D_RESOURCE_CONTRACT(it->ref); \ - return &it->ref->buffer[it->idx].x; \ - } \ - \ - M_INLINE type const * \ - M_F(name, _cref)(it_t it) \ - { \ - M_ASSERT (it != NULL && it->ref != NULL && it->idx != M_GENINT_ERROR); \ - M_SHAR3D_RESOURCE_CONTRACT(it->ref); \ - return M_CONST_CAST (type, &it->ref->buffer[it->idx].x); \ - } \ - \ - M_INLINE void \ - M_F(name, _end)(it_t it, shared_t s) \ - { \ - M_SHAR3D_RESOURCE_CONTRACT(s); \ - M_ASSERT (it != NULL); \ - M_ASSERT (it->ref == s); \ - unsigned int idx = it->idx; \ - if (M_LIKELY (idx != M_GENINT_ERROR)) { \ - unsigned int c = atomic_fetch_sub (&it->ref->buffer[idx].cpt, 1U); \ - if (c == 1) { \ - m_genint_push(it->ref->core, idx); \ - } \ - it->idx = M_GENINT_ERROR; \ - } \ - } \ - \ - M_INLINE void \ - M_F(name, _it_set)(it_t itd, it_t its) \ - { \ - M_ASSERT (itd != NULL && its != NULL); \ - M_SHAR3D_RESOURCE_CONTRACT(its->ref); \ - itd->ref = its->ref; \ - unsigned int idx = its->idx; \ - itd->idx = idx; \ - if (M_LIKELY (idx != M_GENINT_ERROR)) { \ - unsigned int c = atomic_fetch_add(&itd->ref->buffer[idx].cpt, 1U); \ - M_ASSERT (c >= 1); \ - } \ - } \ - -M_END_PROTECTED_CODE - -/********************************** INTERNAL *********************************/ - -#if M_USE_SMALL_NAME -#define SHARED_PTR_OPLIST M_SHARED_PTR_OPLIST -#define SHARED_PTR_DEF M_SHARED_PTR_DEF -#define SHARED_PTR_DEF_AS M_SHARED_PTR_DEF_AS -#define SHARED_PTR_RELAXED_DEF M_SHARED_PTR_RELAXED_DEF -#define SHARED_PTR_RELAXED_DEF_AS M_SHARED_PTR_RELAXED_DEF_AS -#define SHARED_RESOURCE_DEF M_SHARED_RESOURCE_DEF -#define SHARED_RESOURCE_DEF_AS M_SHARED_RESOURCE_DEF_AS -#endif - -#endif diff --git a/tests/test-mshared.c b/tests/test-mshared.c deleted file mode 100644 index 98bd78c3..00000000 --- a/tests/test-mshared.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#include "test-obj.h" -#include "m-shared.h" -#include "coverage.h" - -START_COVERAGE -SHARED_PTR_DEF(shared_int, int) -SHARED_RESOURCE_DEF(shared_ressource, testobj_t, TESTOBJ_OPLIST) -END_COVERAGE - -SHARED_PTR_DEF(shared_mpz, testobj_t, TESTOBJ_OPLIST) -SHARED_PTR_RELAXED_DEF(shared_relaxed_int, int) - -SHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double) -SHARED_PTR_RELAXED_DEF_AS(SharedDouble2, SharedDouble2, double, M_BASIC_OPLIST) -SHARED_RESOURCE_DEF_AS(SharedRessource, SharedRessource, SharedRessourceIt, double) - -// Test with incomplete structure -struct incomplete_s; -extern void incomplete_clear(struct incomplete_s *ptr); -SHARED_PTR_DEF( shared_incomplete, struct incomplete_s, (INIT(0), CLEAR(API_2(incomplete_clear))) ) - -static int f(const shared_int_t p) -{ - return *shared_int_cref(p); -} - -static void test1(void) -{ - shared_int_t p1, p2; - - int *p = M_ASSIGN_CAST(int*, malloc(sizeof(int))); - assert (p != NULL); - - shared_int_init2(p1, p); - assert(!shared_int_NULL_p(p1)); - assert(shared_int_ref(p1) != NULL); - - *shared_int_ref(p1) = 12; - - shared_int_init_set(p2, p1); - assert(f(p2) == 12); - - shared_int_reset(p1); - assert(shared_int_NULL_p(p1)); - assert(!shared_int_NULL_p(p2)); - assert(f(p2) == 12); - - shared_int_set(p1, p2); - - shared_int_reset(p2); - assert(!shared_int_NULL_p(p1)); - assert(shared_int_NULL_p(p2)); - assert(f(p1) == 12); - shared_int_set(p2, p1); - assert(!shared_int_NULL_p(p1)); - assert(!shared_int_NULL_p(p2)); - assert(f(p2) == 12); - - shared_int_reset(p2); - shared_int_reset(p1); - - assert(shared_int_NULL_p(p1)); - assert(shared_int_NULL_p(p2)); - - shared_int_clear(p2); - shared_int_clear(p1); - - shared_int_init2(p1, NULL); - assert(shared_int_NULL_p(p1)); - shared_int_clear(p1); - - shared_int_init(p1); - assert(shared_int_NULL_p(p1)); - shared_int_clear(p1); - - shared_int_init_new(p1); - assert(!shared_int_NULL_p(p1)); - *shared_int_ref(p1) = 1; - shared_int_init_new(p2); - assert(!shared_int_NULL_p(p2)); - *shared_int_ref(p2) = 2; - assert(!shared_int_equal_p(p1, p2)); - assert (*shared_int_cref(p1) == 1); - assert (*shared_int_cref(p2) == 2); - shared_int_swap(p1, p2); - assert (*shared_int_cref(p1) == 2); - assert (*shared_int_cref(p2) == 1); - shared_int_set(p1, p2); - assert(shared_int_equal_p(p1, p2)); - assert (*shared_int_cref(p1) == 1); - assert (*shared_int_cref(p2) == 1); - shared_int_clear(p1); - shared_int_init_move(p1, p2); - assert (*shared_int_cref(p1) == 1); - shared_int_init_new(p2); - assert (*shared_int_cref(p2) == 0); - shared_int_set(p2, p1); - shared_int_move(p2, p1); - assert (*shared_int_cref(p2) == 1); - shared_int_clear(p2); -} - -static void test2(void) -{ - shared_int_t p1, p2; - - shared_int_init_new (p1); - *shared_int_ref(p1) = 1; - shared_int_init_new (p2); - *shared_int_ref(p2) = 2; - shared_int_set(p1, p2); - assert (*shared_int_ref(p1) == 2); - assert (*shared_int_ref(p2) == 2); - shared_int_clear(p2); - assert (*shared_int_ref(p1) == 2); - shared_int_clear(p1); -} - -static void test_emplace(void) -{ - shared_mpz_t z; - - shared_mpz_init_with_ui(z, 23); - assert ( (*shared_mpz_ref(z))->ptr[0] == 23); - shared_mpz_clear(z); -} - -#define MAX_RESSOURCE 10 - -static void test_ressource(int n) -{ - shared_ressource_t ressource; - shared_ressource_it_t it[MAX_RESSOURCE]; - shared_ressource_it_t copy[MAX_RESSOURCE]; - shared_ressource_it_t onemore; - - shared_ressource_init (ressource, (size_t) n); - for(int i = 0; i < n ; i++) { - shared_ressource_it (it[i], ressource); - assert (!shared_ressource_end_p(it[i])); - testobj_t *z = shared_ressource_ref(it[i]); - assert (z != NULL); - testobj_set_ui(*z, (unsigned int) i); - } - shared_ressource_it (onemore, ressource); - assert (shared_ressource_end_p(onemore)); - for(int i = 0; i < n ; i++) { - shared_ressource_it_set (copy[i], it[i]); - assert (!shared_ressource_end_p(copy[i])); - const testobj_t *z = shared_ressource_cref(copy[i]); - assert (z != NULL); - assert (testobj_cmp_ui(*z, (unsigned int) i) == 0); - } - shared_ressource_it (onemore, ressource); - assert (shared_ressource_end_p(onemore)); - for(int i = 0; i < n ; i++) { - shared_ressource_end (it[i], ressource); - } - shared_ressource_it (onemore, ressource); - assert (shared_ressource_end_p(onemore)); - for(int i = n-1; i >= 0 ; i--) { - const testobj_t *z = shared_ressource_cref(copy[i]); - assert (z != NULL); - shared_ressource_end (copy[i], ressource); - assert (shared_ressource_end_p(copy[i])); - shared_ressource_it (onemore, ressource); - assert (!shared_ressource_end_p(onemore)); - shared_ressource_end (onemore, ressource); - shared_ressource_end (copy[i], ressource); - } - - shared_ressource_clear(ressource); -} - -static void test_double(void){ - SharedDouble p; - SharedDouble_init_new(p); - assert(*SharedDouble_ref(p) == 0.0); - *SharedDouble_ref(p) = 5678.0; - SharedDouble q; - SharedDouble_init_set(q, p); - assert(*SharedDouble_ref(q) == 5678.0); - SharedDouble_clear(p); - SharedDouble_clear(q); -} - -static void test_double2(void){ - SharedDouble2 p; - SharedDouble2_init_new(p); - assert(*SharedDouble2_ref(p) == 0.0); - *SharedDouble2_ref(p) = 5678.0; - SharedDouble2 q; - SharedDouble2_init_set(q, p); - assert(*SharedDouble2_ref(q) == 5678.0); - SharedDouble2_clear(p); - SharedDouble2_clear(q); -} - -static void test_double_res(void){ - SharedRessource r; - SharedRessource_init(r, 4); - SharedRessourceIt i; - SharedRessource_it(i, r); - assert(*SharedRessource_ref(i) == 0); - *SharedRessource_ref(i) = 3456.0; - SharedRessource_end(i, r); - SharedRessource_it(i, r); - assert(*SharedRessource_ref(i) == 3456.0); - SharedRessource_clear(r); -} - -int main(void) -{ - test1(); - test2(); - test_emplace(); - for(int i = 1; i < MAX_RESSOURCE; i++) { - test_ressource(i); - } - test_double(); - test_double2(); - test_double_res(); - testobj_final_check(); - exit(0); -} From 7e8cb07a6c9c7a7efc39641088d15bc3d24e0096 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 21:50:26 +0200 Subject: [PATCH 88/91] Port to shared-ptr interface --- tests/test-mbuffer.c | 59 ++++++++++---------------------------------- 1 file changed, 13 insertions(+), 46 deletions(-) diff --git a/tests/test-mbuffer.c b/tests/test-mbuffer.c index a9077c06..546db178 100644 --- a/tests/test-mbuffer.c +++ b/tests/test-mbuffer.c @@ -259,77 +259,44 @@ static void test_emplace(void) } /********************************************************************************************/ -/* Test intrusive shared pointer + buffer */ -#include "m-i-shared.h" +/* Test integration shared pointer + buffer */ +#include "m-shared-ptr.h" // Tiny test structure typedef struct test_s { - ISHARED_PTR_INTERFACE(ishared_itest, struct test_s); char buffer[52]; char bigbuffer[1000000]; } test_t; static void test_init(test_t *p) { memset(p->buffer, 0x00, 52); } static void test_clear(test_t *p) { memset(p->buffer, 0xFF, 52); } -ISHARED_PTR_DEF(ishared_itest, test_t, - (INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR), DEL(API(free, NONE, ARG2)))) +SHARED_PTR_DEF(shared_test, test_t, (INIT(test_init M_IPTR), CLEAR(test_clear M_IPTR))) -typedef struct test2_s { - ISHARED_PTR_INTERFACE(ishared_itest2, struct test_s); - char buffer[52]; -} test2_t; -static inline void ishared_itest2_init_data(test2_t *d) -{ - memset(d->buffer, 0, sizeof (d->buffer)); -} -ISHARED_PTR_DEF(ishared_itest2, test2_t, (INIT(API_2(ishared_itest2_init_data)), CLEAR(M_NOTHING_DEFAULT))) - -typedef struct test3_s { - ISHARED_PTR_INTERFACE(ishared_itest3, struct test_s); - char buffer[52]; -} test3_t; -ISHARED_PTR_DEF(ishared_itest3, test3_t, (CLEAR(M_NOTHING_DEFAULT))) - -typedef struct test4_s { - ISHARED_PTR_INTERFACE(ishared_itest4, struct test_s); - char buffer[52]; -} test4_t; -ISHARED_PTR_DEF(ishared_itest4, test4_t, (INIT(0), DEL(0), INIT(M_MEMSET_DEFAULT), CLEAR(M_NOTHING_DEFAULT))) - -static test_t *test_new(void) -{ - test_t *p = M_ASSIGN_CAST(test_t*, malloc (sizeof (test_t))); - assert (p != NULL); - test_init (p); - return ishared_itest_init(p); -} - -BUFFER_DEF(buffer_itest, test_t *, 16, BUFFER_PUSH_INIT_POP_MOVE, - ISHARED_PTR_OPLIST(ishared_itest)) +BUFFER_DEF(buffer_itest, shared_test_t *, 16, BUFFER_PUSH_INIT_POP_MOVE, SHARED_PTR_OPLIST(shared_test, (INIT(1), CLEAR(1)))) static buffer_itest_t comm1; static buffer_itest_t comm2; static void test_conso1(void *arg) { - test_t *p; + shared_test_t *p; assert (arg == NULL); for(int i = 0; i < 10;i++) { buffer_itest_pop(&p, comm1); for(int j = 0; j < 52; j++) - assert (p->buffer[j] == (char) ((j * j * 17) + j * 42 + 1)); - ishared_itest_clear(p); + assert (shared_test_ref(p)->buffer[j] == (char) ((j * j * 17) + j * 42 + 1)); + shared_test_release(p); } } static void test_conso2(void *arg) { - test_t *p; + shared_test_t *p; assert (arg == NULL); for(int i = 0; i < 10;i++) { buffer_itest_pop(&p, comm2); for(int j = 0; j < 52; j++) - assert (p->buffer[j] == (char) ((j * j * 17) + j * 42 + 1)); - ishared_itest_clear(p); + assert (shared_test_ref(p)->buffer[j] == (char) ((j * j * 17) + j * 42 + 1)); + shared_test_release(p); } } @@ -337,13 +304,13 @@ static void test_prod(void *arg) { assert (arg == NULL); for(unsigned int i = 0; i < 10;i++) { - test_t *p = test_new(); + shared_test_t *p = shared_test_new(); for(int j = 0; j < 52; j++) { - p->buffer[j] = (char) ((j * j * 17) + j * 42 + 1); + shared_test_ref(p)->buffer[j] = (char) ((j * j * 17) + j * 42 + 1); } buffer_itest_push(comm1, p); buffer_itest_push(comm2, p); - ishared_itest_clear(p); + shared_test_clear(p); } } From 25dcdeed693cbebc2a8f63ec3ccdc3a6ba08c2ed Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 21:57:53 +0200 Subject: [PATCH 89/91] Remove obsolete m-i-shared.h header --- README.md | 179 -------------------------- example/ex11-small-name.c | 1 - m-i-shared.h | 258 -------------------------------------- tests/test-mishared.c | 150 ---------------------- 4 files changed, 588 deletions(-) delete mode 100644 m-i-shared.h delete mode 100644 tests/test-mishared.c diff --git a/README.md b/README.md index a08dec67..73ef5970 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,6 @@ Finally, headers for compatibility with non C11 compilers: The following headers are obsolete and will be removed in the next major release: * [m-concurrent.h](#m-concurrent): header for transforming a container into a concurrent container (thread safe), -* [m-i-shared.h](#m-i-shared): header for creating intrusive shared pointer of generic type (Thread Safe). * [m-mempool.h](#m-mempool): header for creating specialized & fast memory allocator, Each containers define their iterators (if it is meaningful). @@ -5085,184 +5084,6 @@ Create a new shared object initialized with its `INIT_SET` operator on the given This method is created only if the `INIT_SET` operator is defined. -_________________ - -### M-I-SHARED - -> [!NOTE] -> This header is obsolete: M-SHARED-PTR should be used instead. - -This header is for creating intrusive shared pointer. - -#### `ISHARED_PTR_INTERFACE(name, type)` - -Extend the definition of the structure of an object of type `type` by adding the -necessary interface to handle it as a shared pointer named `name`. -It shall be put within the structure definition of the object (See example). - -#### `ISHARED_PTR_STATIC_INIT(name, type)` - -Provide the static initialization value of an object defined with a -`ISHARED_PTR_INTERFACE` extra fields. It shall be used only for global -variables with the _init_once function. - -Usage (provided that the interface is used as the first element of the structure): - -```C -struct mystruct variable = { ISHARED_PTR_STATIC_INIT(ishared_double, struct mystruct) }; -``` - -#### `ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type)` - -Provide the static initialization value of an object defined with a -`ISHARED_PTR_INTERFACE` extra fields. It shall be used only for global -variables with the _init_once function. - -It uses designated initializers to set the right fields. - -Usage: - -```C -struct mystruct variable = {ISHARED_PTR_STATIC_DESIGNATED_INIT(ishared_double, struct mystruct) }; -``` - -#### `ISHARED_PTR_DEF(name, type[, oplist])` -#### `ISHARED_PTR_DEF_AS(name, name_t, type[, oplist])` - -Define the associated methods to handle the shared pointer named `name` -as `static inline` functions. -A shared pointer is a mechanism to keep tracks of all `users` of an object -and performs an automatic destruction of the object whenever all users release -their need on this object. - -The destruction of the object is thread safe and occurs when the last user -of the object releases it. The destruction of the object implies: - -* calling the `CLEAR` operator to clear the object, -* calling the `DEL` operator to release the memory used by the object -(if the method has not been disabled). - -The object oplist is expected to have the following operators (`CLEAR` and `DEL`), -otherwise default methods are used. If there is no given oplist, the default -operators are also used. The created methods will use the operators to init, set -and clear the contained object. - -There are designed to work with buffers with policy `BUFFER_PUSH_INIT_POP_MOVE` -to send a shared pointer across multiple threads. - -It is recommended to use the intrusive shared pointer over the standard one if -possible. They are faster and cleaner. - -The default is to use heap allocated entities, which are allocated by `NEW` and -freed by `DEL`. - -It can be used for statically allocated entities. However, in this case, -you shall disable the operator `NEW` and `DEL` when expanding the oplist -so that the destruction doesn't try to free the objects, like this: - -```C -(NEW(0), DEL(0)) -``` - -`NEW` and `DEL` operators shall be either both defined, or both disabled. - -`ISHARED_PTR_DEF_AS` is the same as `ISHARED_PTR_DEF` except the name of the type `name_t` -is provided. - -Example (dynamic): - -```C -typedef struct mystruct_s { - ISHARED_PTR_INTERFACE(ishared_mystruct, struct mystruct_s); - char *message; -} mystruct_t; - -static inline void mystruct_init(mystruct_t *p) { p->message = NULL; } -static inline void mystruct_clear(mystruct_t *p) { free(p->message); } - -ISHARED_PTR_DEF(ishared_mystruct, mystruct_t, (INIT(mystruct_init), CLEAR(mystruct_clear M_IPTR))) - -void f(void) { - mystruct_t *p = ishared_mystruct_init_new(); - p->message = strdup ("Hello"); - buffer_mystruct_push(g_buff1, p); - buffer_mystruct_push(g_buff2, p); - ishared_mystruct_clear(p); -} -``` - -#### Created types - -The following types are automatically defined by the previous definition macro if not provided by the user: - -##### `name_t` - -It will define name_t as a pointer to shared counted object. -This is a synonymous to a pointer to the object. - -#### Specialized methods - -The following specialized methods are automatically created by the previous definition macro: - -##### `name_t name_init(type *object)` - -Return a shared pointer to `object` which owns `object`. -It initializes the private fields of `object` handling the shared pointer, -returning the same pointer to the object from a value point of view, -but with the shared pointer field initialized. - -As a consequence, the shared pointer part of `object` shall not have been initialized yet. -The other part of `object` may or may not be initialized before calling this method. - -##### `name_t name_init_set(name_t shared)` - -Return a new shared pointer to the same object than the one pointed by `shared`, -incrementing the ownership of the object. -This function is thread safe. - -##### `name_t name_init_new(void)` - -Allocate a new object, initialize it and return an initialized shared pointer to it. -The used allocation function is the `NEW` operator. - -This method is only created if the `INIT` and `NEW` methods are provided and not disabled. - -##### `name_t name_init_once(type *object)` - -Initialize the new object `object` and return an initialized shared pointer to it. -The `INIT` operator of `object` is ensured to be called only once, -even if multiple threads try to initialize it at the same time. -Once the object is fully cleared, the initialization function may occur once again. - -`object` shall be a global variable initialized with the -`ISHARED_PTR_STATIC_INIT` macro. - -This method is only created if the `INIT` and `NEW` methods are provided and not disabled. - -##### `void name_clear(name_t shared)` - -Clear the `shared` pointer, releasing ownership of the object -and destroying the shared object if no longer -any other `shared` pointers own it. -This function is thread safe. - -##### `void name_clear_ptr(name_t *shared)` - -Clear the shared pointer `*shared`, releasing ownership of the object -and destroying the shared object if no longer -any other `shared` pointers own it. -This function is thread safe. -Afterwards, `*shared` is set to NULL. - -##### `void name_set(name_t *shared1, name_t shared2)` - -Update the shared pointer `*shared1` to point to the same object than -the shared pointer `shared2`. -Destroy the shared object pointed by `*shared1` if no longer any other shared -pointers own it, set the shared pointer `shared` to the same object -than the one pointed by `src`. -This function is thread safe. - _________________ ### M-I-LIST diff --git a/example/ex11-small-name.c b/example/ex11-small-name.c index 05d955b4..2dac30b2 100644 --- a/example/ex11-small-name.c +++ b/example/ex11-small-name.c @@ -15,7 +15,6 @@ #include "m-generic.h" #include "m-genint.h" #include "m-i-list.h" -#include "m-i-shared.h" #include "m-list.h" #include "m-mempool.h" #include "m-prioqueue.h" diff --git a/m-i-shared.h b/m-i-shared.h deleted file mode 100644 index b9324b14..00000000 --- a/m-i-shared.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * M*LIB - INTRUSIVE SHARED PTR Module - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef MSTARLIB_I_SHARED_PTR_H -#define MSTARLIB_I_SHARED_PTR_H - -#include "m-core.h" -#include "m-atomic.h" - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L -#warning The header m-i-shared.h is obsolete. Use m-shared-ptr header instead. -#endif - -M_BEGIN_PROTECTED_CODE - -/* Define the oplist of a intrusive shared pointer. - USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */ -#define M_ISHARED_PTR_OPLIST(...) \ - M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_BASIC_OPLIST), \ - (__VA_ARGS__ ))) - - -/* Interface to add to a structure to allow intrusive support. - name: name of the intrusive shared pointer. - type: name of the type of the structure (aka. struct test_s) - not used currently. - NOTE: There can be only one interface of this kind in a type! */ -#define M_ISHARED_PTR_INTERFACE(name, type) \ - atomic_int M_F(name, _cpt) - - -/* Value of the interface field for static initialization (Uses C99 designated element). */ -#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \ - .M_F(name, _cpt) = M_ATOMIC_VAR_INIT(0) - -/* Value of the interface field for static initialization (Uses C89 designated element). */ -#define M_ISHARED_PTR_STATIC_INIT(name, type) \ - M_ATOMIC_VAR_INIT(0) - - -/* Define the intrusive shared pointer type and its M_INLINE functions. - USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */ -#define M_ISHARED_PTR_DEF(name, ...) \ - M_ISHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__) - - -/* Define the intrusive shared pointer type and its M_INLINE functions - as the name name_t - USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */ -#define M_ISHARED_PTR_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \ - (name, __VA_ARGS__ , name_t ))) \ - M_END_PROTECTED_CODE - - -/*****************************************************************************/ -/******************************** INTERNAL ***********************************/ -/*****************************************************************************/ - -// Deferred evaluation -#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_PTR_OPLIST_P2 arg - -/* Validation of the given oplist */ -#define M_ISHAR3D_PTR_OPLIST_P2(name, oplist) \ - M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_OPLIST_P3, M_ISHAR3D_PTR_OPLIST_FAILURE)(name, oplist) - -/* Prepare a clean compilation failure */ -#define M_ISHAR3D_PTR_OPLIST_FAILURE(name, oplist) \ - ((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) - -// Define the oplist -#define M_ISHAR3D_PTR_OPLIST_P3(name, oplist) ( \ - INIT(M_INIT_DEFAULT), \ - INIT_SET(API_4(M_F(name, _init_set))), \ - SET(M_F(name, _set) M_IPTR), \ - CLEAR(M_F(name, _clear)), \ - RESET(M_F(name, _reset) M_IPTR), \ - NAME(name), \ - TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \ - OPLIST(oplist), \ - SUBTYPE(M_F(name, _subtype_ct)) \ - ) - - -/******************************** INTERNAL ***********************************/ - -// Deferred evaluation -#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg ) - -/* Validate the oplist before going further */ -#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \ - M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_DEF_P3, M_ISHAR3D_PTR_DEF_FAILURE)(name, type, oplist, shared_t) - -/* Stop processing with a compilation failure */ -#define M_ISHAR3D_PTR_DEF_FAILURE(name, type, oplist, shared_t) \ - M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist) - -#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \ - M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \ - -/* Define the types */ -#define M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \ - \ - /* The shared pointer is only a pointer to the type */ \ - typedef type *shared_t; \ - \ - /* Define internal types for oplist */ \ - typedef shared_t M_F(name, _ct); \ - typedef type M_F(name, _subtype_ct); \ - -/* Define the core functions */ -#define M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \ - \ - M_INLINE shared_t \ - M_F(name, _init)(type *ptr) \ - { \ - /* Initialize the type referenced by the pointer */ \ - if (M_LIKELY (ptr != NULL)) { \ - atomic_init(&ptr->M_F(name, _cpt), 2); \ - } \ - return ptr; \ - } \ - \ - M_INLINE shared_t \ - M_F(name, _init_set)(shared_t shared) \ - { \ - if (M_LIKELY (shared != NULL)) { \ - int n = atomic_fetch_add(&(shared->M_F(name, _cpt)), 2); \ - (void) n; \ - } \ - return shared; \ - } \ - \ - M_IF_METHOD(INIT, oplist)( \ - M_IF_DISABLED_METHOD(NEW, oplist) \ - ( \ - /* This function is only for static object */ \ - M_INLINE shared_t \ - M_F(name, _init_once)(type *shared) \ - { \ - if (M_LIKELY (shared != NULL)) { \ - /* Pretty much like atomic_add, except the first one increment by 1, others by 2 */ \ - int o = atomic_load(&(shared->M_F(name, _cpt))); \ - int n; \ - do { \ - n = o + 1 + (o != 0); \ - } while (!atomic_compare_exchange_strong(&(shared->M_F(name, _cpt)), &o, n)); \ - if (o == 0) { \ - /* Partial initialization: _cpt is odd */ \ - /* Call the INIT function once */ \ - M_CALL_INIT(oplist, *shared); \ - /* Finish initialization: _cpt is even */ \ - atomic_fetch_add(&(shared->M_F(name, _cpt)), 1); \ - } else if ( (o&1) != 0) { \ - /* Not fully initialized yet: wait for initialization */ \ - m_core_backoff_ct bkoff; \ - m_core_backoff_init(bkoff); \ - /* Wait for _cpt to be _even */ \ - while ((atomic_load(&(shared->M_F(name, _cpt)))&1) != 0 ) { \ - m_core_backoff_wait(bkoff); \ - } \ - } \ - M_ASSERT( (atomic_load(&(shared->M_F(name, _cpt)))&1) == 0); \ - } \ - return shared; \ - } \ - , \ - /* This function is only for dynamic object */ \ - M_INLINE shared_t \ - M_F(name, _init_new)(void) \ - { \ - type *ptr = M_CALL_NEW(oplist, type); \ - if (M_UNLIKELY_NOMEM (ptr == NULL)) { \ - M_MEMORY_FULL(type, 1); \ - } \ - M_CALL_INIT(oplist, *ptr); \ - atomic_init (&ptr->M_F(name, _cpt), 2); \ - return ptr; \ - } \ - /* End of NEW */) \ - , /* End of INIT */) \ - \ - M_INLINE void \ - M_F(name, _clear)(shared_t shared) \ - { \ - if (shared != NULL) { \ - if (atomic_fetch_sub(&(shared->M_F(name, _cpt)), 2) == 2) { \ - M_CALL_CLEAR(oplist, *shared); \ - M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \ - } \ - } \ - } \ - \ - M_INLINE void \ - M_F(name, _clear_ptr)(shared_t *shared) \ - { \ - M_ASSERT(shared != NULL); \ - M_F(name, _clear)(*shared); \ - *shared = NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _reset)(shared_t *shared) \ - { \ - M_F(name, _clear)(*shared); \ - *shared = NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _set)(shared_t *ptr, shared_t shared) \ - { \ - M_ASSERT (ptr != NULL); \ - if (M_LIKELY (*ptr != shared)) { \ - M_F(name, _clear)(*ptr); \ - *ptr = M_F(name, _init_set)(shared); \ - } \ - } \ - \ - -M_END_PROTECTED_CODE - -/******************************** INTERNAL ***********************************/ - -#if M_USE_SMALL_NAME -#define ISHARED_PTR_OPLIST M_ISHARED_PTR_OPLIST -#define ISHARED_PTR_INTERFACE M_ISHARED_PTR_INTERFACE -#define ISHARED_PTR_STATIC_DESIGNATED_INIT M_ISHARED_PTR_STATIC_DESIGNATED_INIT -#define ISHARED_PTR_STATIC_INIT M_ISHARED_PTR_STATIC_INIT -#define ISHARED_PTR_DEF M_ISHARED_PTR_DEF -#define ISHARED_PTR_DEF_AS M_ISHARED_PTR_DEF_AS -#endif - -#endif diff --git a/tests/test-mishared.c b/tests/test-mishared.c deleted file mode 100644 index b65fc754..00000000 --- a/tests/test-mishared.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#include "test-obj.h" -#include "m-i-shared.h" -#include "m-thread.h" -#include "coverage.h" - -typedef struct ishared_s { - ISHARED_PTR_INTERFACE(ishared1, struct ishared_s); - ISHARED_PTR_INTERFACE(ishared2, struct ishared_s); - int data[100]; -} ishared_t[1]; - -static bool ishared_init_sleep = false; - -static void ishared_init_data(struct ishared_s *x) -{ - for(int i = 0 ; i < 100; i++) - x->data[i] = i * i; - if (ishared_init_sleep) { - // Slow down init - m_thread_sleep(100); - } -} - -static void ishared_test(struct ishared_s *x) -{ - for(int i = 0 ; i < 100; i++) { - assert (x->data[i] == i*i); - } -} - -START_COVERAGE -ISHARED_PTR_DEF(ishared1, struct ishared_s, (INIT(API_2(ishared_init_data)))) -ISHARED_PTR_DEF(ishared2, struct ishared_s, (INIT(API_2(ishared_init_data)), NEW(0), DEL(0)) ) -END_COVERAGE - -/*ISHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double) */ - -static void test_single(void) -{ - ishared1_t p1, p2; - p1 = ishared1_init_new(); - ishared_test(p1); - p2 = ishared1_init_set(p1); - ishared_test(p2); - ishared1_clear(p1); - ishared_test(p2); - - p1 = ishared1_init(NULL); - ishared1_set(&p1, p2); - ishared1_reset(&p2); - assert(p2 == NULL); - ishared_test(p1); - ishared1_clear(p1); - - p1 = ishared1_init_set(p2); - assert(p1 == NULL); - ishared1_clear(p1); - - ishared1_clear(p2); - - struct ishared_s *x = (struct ishared_s *) malloc(sizeof (struct ishared_s)); - assert(x != NULL); - ishared_init_data(x); - p1 = ishared1_init(x); - ishared_test(p1); - ishared1_clear(p1); -} - -static struct ishared_s g_var = { - ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), - ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), - { 0 } -}; - -static void test_static(void) -{ - ishared2_t p1, p2; - p1 = ishared2_init_once(NULL); - assert(p1 == NULL); - p1 = ishared2_init_once(&g_var); - ishared_test(p1); - p2 = ishared2_init_once(&g_var); - ishared_test(p2); - ishared2_clear(p1); - ishared_test(p2); - ishared2_clear(p2); -} - -#define MAX_THREAD 128 -#define MAX_VAR 5 - -#define VAL(x) { ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), { 0 } } -static struct ishared_s g_tab[MAX_VAR] = { - M_MAP_C(VAL, M_SEQ(1, MAX_VAR)) -}; - -static void func(void *arg) -{ - int id = (int)(intptr_t) arg; - int v = id % MAX_VAR; - ishared2_t p = ishared2_init_once(&g_tab[v]); - for(int i = 0; i < 100; i++) { - ishared_test(p); - } - ishared2_clear(p); -} - -static void test_shared(void) -{ - m_thread_t id[MAX_THREAD]; - - ishared_init_sleep = true; - for(int i = 0; i < MAX_THREAD; i++) { - m_thread_create(id[i], func, (void*) (intptr_t) i); - } - for(int i = 0; i < MAX_THREAD; i++) { - m_thread_join(id[i]); - } - ishared_init_sleep = false; -} - -int main(void) -{ - test_single(); - test_static(); - test_shared(); - exit(0); -} From 8c70a1f96c6c5d280d397e47d520a534e6ae36f6 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 22:01:38 +0200 Subject: [PATCH 90/91] Remove obsolete m-concurrent.h header --- README.md | 158 ------- example/ex11-small-name.c | 1 - m-concurrent.h | 911 -------------------------------------- tests/test-mconcurrent.c | 250 ----------- 4 files changed, 1320 deletions(-) delete mode 100644 m-concurrent.h delete mode 100644 tests/test-mconcurrent.c diff --git a/README.md b/README.md index 73ef5970..dc1f43d4 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,6 @@ Finally, headers for compatibility with non C11 compilers: * [m-thread.h](#m-thread): header for providing a very thin layer across multiple implementation of mutex/threads (C11/PTHREAD/WIN32). The following headers are obsolete and will be removed in the next major release: -* [m-concurrent.h](#m-concurrent): header for transforming a container into a concurrent container (thread safe), * [m-mempool.h](#m-mempool): header for creating specialized & fast memory allocator, Each containers define their iterators (if it is meaningful). @@ -5276,163 +5275,6 @@ Afterwards, `list2` is emptied. _________________ -### M-CONCURRENT - -> [!NOTE] -> This header is obsolete: M-SHARED-PTR should be used instead. - -This header is for transforming a standard container (`LIST`, `ARRAY`, `DICT`, `DEQUE`, ...) -into an equivalent container but compatible with concurrent access by different threads. -In practice, it puts a mutex lock to access the container. - -As such it is quite generic. However, it is less efficient than containers -specially tuned for multiple threads. -There is also no iterators. - -#### `CONCURRENT_DEF(name, type[, oplist])` -#### `CONCURRENT_DEF_AS(name, name_t, type[, oplist])` - -Define the concurrent container `name` based on container `type` of oplist `oplist`, -and define the associated methods to handle it as `static inline` functions. - -`name` shall be a C identifier that will be used to identify the concurrent container. -It will be used to create all the types (including the iterator) -and functions to handle the container. -This definition shall be done once per name and per compilation unit. - -It scans the `oplist` of the type to create equivalent function, -so the exact generated methods depend on explicitly the exported methods in the oplist. -The init method is only defined if the base container exports the `INIT` operator, -same for the clear method and the `CLEAR` operator, -and so on for all created methods. - -In the description below, -`subtype_t` is the type of the element within the given container `type` (if it exists), -`key_t` is the key type of the element within the given container `type` (if it exists), -`value_t` is the value type of the element within the given container `type` (if it exists). - -`CONCURRENT_DEF_AS` is the same as `CONCURRENT_DEF` except the name of the type `name_t` -is provided. - -Example: - -```C -/* Define a stack container (STACK)*/ -ARRAY_DEF(array1, int) -CONCURRENT_DEF(parray1, array1_t, ARRAY_OPLIST(array1)) - -/* Define a queue container (FIFO) */ -DEQUE_DEF(deque_uint, unsigned int) -CONCURRENT_DEF(cdeque_uint, deque_uint_t, M_OPEXTEND(DEQUE_OPLIST(deque_uint, M_BASIC_OPLIST), PUSH(deque_uint_push_front))) - -extern parray1_t x1; -extern cdeque_uint_t x2; - -void f(void) { - parray1_push (x1, 17); - cdeque_uint_push (x2, 17); -} -``` - -#### Created types - -The following types are automatically defined by the previous definition macro if not provided by the user: - -##### `name_t` - -Type of the concurrent container of `type`. - -#### Common methods - -The following methods of the common interface are defined (See [Common interface](#Common-Interface) for details): - -```C -void name_init(name_t concurrent) -void name_init_set(name_t concurrent, const name_t src) -void name_init_move(name_t concurrent, name_t src) -void name_set(name_t concurrent, const name_t src) -void name_move(name_t concurrent, name_t src) -void name_reset(name_t concurrent) -void name_clear(name_t concurrent) -void name_swap(name_t concurrent1, name_t concurrent2) -bool name_empty_p(const name_t concurrent) -void name_set_at(name_t concurrent, key_t key, value_t value) -bool name_erase(name_t concurrent, const key_t key) -void name_push(name_t concurrent, const subtype_t data) -void name_push_move(name_t concurrent, subtype_t *data) -void name_pop_move(subtype_t *data, name_t concurrent) -void name_get_str(string_t str, name_t concurrent, bool append) -void name_out_str(FILE *file, name_t concurrent) -bool name_parse_str(name_t concurrent, const char str[], const char **end) -bool name_in_str(name_t concurrent, FILE *file) -m_serial_return_code_t name_out_serial(m_serial_write_t serial, const name_t container) -m_serial_return_code_t name_in_str(name_t container, m_serial_read_t serial) -bool name_equal_p(name_t concurrent1, name_t concurrent2) -size_t name_hash(name_t concurrent) -``` - -Returns true in case of success, false otherwise. - -#### Specialized methods - -The following specialized methods are automatically created by the previous definition macro: - -##### `bool name_get_copy(value_t *value, name_t concurrent, key_t key)` - -Read the value associated to the key `key`. -If it exists, it sets `*value` to it and returns true. -Otherwise it returns false (`*value` is unchanged). -This method is only defined if the base container exports the `GET_KEY` operator. - -##### `void name_safe_get_copy(value_t *value, name_t concurrent, key_t key)` - -Read the value associated to the key `key`. -If it exists, it sets `*value` to it. -Otherwise, it creates a new value (default constructor) and sets `*value` to it. -This method is only defined if the base container exports the `SAFE_GET_KEY` operator. - -##### `void name_pop(subtype_t *data, name_t concurrent)` - -Pop data from the container and set it in `*data`. -There shall be at least one data to pop. -Testing with the operator `EMPTY_P` before calling this function is not enough -as there can be some concurrent scenario where another thread pop the last value. -`name_pop_blocking` should be used instead. -This method is only defined if the base container exports the `POP` operator. - -##### `bool name_get_blocking(value_t *value, name_t concurrent, key_t key, bool blocking)` - -Read the value associated to the key `key`. -If it exists, it sets `*value` to it and returns true. -Otherwise, if blocking is true, it waits for the data to be filled. -After the wait, it sets `*value` to it and returns true. -Otherwise, if blocking is false, it returns false. -This method is only defined if the base container exports the `GET_KEY` operator. - -##### `bool name_pop_blocking(type_t *data, name_t concurrent, bool blocking)` - -Pop a value from the container and set `*data` with it. -If the container is not empty, it sets `*data` and return true. -Otherwise, if blocking is true, it waits for the data to be pushed. -After the wait, it sets `*data` to it and returns true. -Otherwise, if blocking is false, it returns false. -This method is only defined if the base container exports the `POP` and `EMPTY_P` operators. - -##### `bool name_pop_move_blocking(type_t *data, name_t concurrent, bool blocking)` - -Pop a value from the container and initialize and set `*data` with it. -If the container is not empty, it initializes and sets `*data` and return true. -Otherwise if blocking is true, it waits for the data to be pushed. -After the wait, it initializes and sets `*data` to it and returns true. -Otherwise, if blocking is false, it returns false. - -> [!WARNING] -> `*data` remains uninitialized! - -This method is only defined if the base container exports the `POP_MOVE` and `EMPTY_P` operators. - -_________________ - ### M-BITSET This header is for using bitset. diff --git a/example/ex11-small-name.c b/example/ex11-small-name.c index 2dac30b2..2a92a3c3 100644 --- a/example/ex11-small-name.c +++ b/example/ex11-small-name.c @@ -8,7 +8,6 @@ #include "m-bptree.h" #include "m-bstring.h" #include "m-buffer.h" -#include "m-concurrent.h" #include "m-deque.h" #include "m-dict.h" #include "m-funcobj.h" diff --git a/m-concurrent.h b/m-concurrent.h deleted file mode 100644 index 53e7ade2..00000000 --- a/m-concurrent.h +++ /dev/null @@ -1,911 +0,0 @@ -/* - * M*LIB - Basic Protected Concurrent module over container. - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef MSTARLIB_CONCURRENT_H -#define MSTARLIB_CONCURRENT_H - -#include "m-core.h" -#include "m-thread.h" -#include "m-atomic.h" - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L -#warning The header m-concurrent.h is obsolete. Use m-shared-ptr header instead. -#endif - -/* Define a protected concurrent container and its associated functions - based on the given container. - USAGE: CONCURRENT_DEF(name, type [, oplist_of_the_type]) */ -#define M_CONCURRENT_DEF(name, ...) \ - M_CONCURRENT_DEF_AS(name, M_F(name,_t), __VA_ARGS__) - - -/* Define a protected concurrent container and its associated functions - based on the given container as the given name name_t - USAGE: CONCURRENT_DEF_AS(name, name_t, type [, oplist_of_the_type]) */ -#define M_CONCURRENT_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - M_C0NCURRENT_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \ - (name, __VA_ARGS__, name_t ))) \ - M_END_PROTECTED_CODE - - -/* Define a protected concurrent container and its associated functions - based on its given container. Operations that perform only read of the container - can be done in parallel. - USAGE: CONCURRENT_RP_DEF(name, type [, oplist_of_the_type]) */ -#define M_CONCURRENT_RP_DEF(name, ...) \ - M_CONCURRENT_RP_DEF_AS(name, M_F(name,_t), __VA_ARGS__) - - -/* Define a protected concurrent container and its associated functions - as the given name name_t - based on its given container. Operations that perform only read of the container - can be done in parallel. - USAGE: CONCURRENT_RP_DEF_AS(name, name_t, type [, oplist_of_the_type]) */ -#define M_CONCURRENT_RP_DEF_AS(name, name_t, ...) \ - M_BEGIN_PROTECTED_CODE \ - M_C0NCURRENT_RP_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \ - (name, __VA_ARGS__, name_t ))) \ - M_END_PROTECTED_CODE - - -/* Define the oplist of a protected concurrent container given its name and its oplist. - USAGE: CONCURRENT_OPLIST(name[, oplist of the type]) */ -#define M_CONCURRENT_OPLIST(...) \ - M_C0NCURRENT_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \ - ((__VA_ARGS__, M_BASIC_OPLIST), \ - (__VA_ARGS__ ))) - - -/*****************************************************************************/ -/******************************** INTERNAL ***********************************/ -/*****************************************************************************/ - -/* Deferred evaluation for the oplist definition, - so that all arguments are evaluated before further expansion */ -#define M_C0NCURRENT_OPLIST_P1(arg) M_C0NCURRENT_OPLIST_P2 arg - -/* Validation of the given oplist */ -#define M_C0NCURRENT_OPLIST_P2(name, oplist) \ - M_IF_OPLIST(oplist)(M_C0NCURRENT_OPLIST_P3, M_C0NCURRENT_OPLIST_FAILURE)(name, oplist) - -/* Prepare a clean compilation failure */ -#define M_C0NCURRENT_OPLIST_FAILURE(name, oplist) \ - ((M_LIB_ERROR(ARGUMENT_OF_CONCURRENT_OPLIST_IS_NOT_AN_OPLIST, name, oplist))) - -/* OPLIST definition - GET_KEY is not present as its interface is not compatible with a concurrent - container (_get returns a pointer to an internal data, data that may be - destroyed by another thread). -*/ -#define M_C0NCURRENT_OPLIST_P3(name, oplist) \ - (M_IF_METHOD(INIT, oplist)(INIT(M_F(name, _init)),) \ - ,M_IF_METHOD(INIT_SET, oplist)(INIT_SET(M_F(name, _init_set)),) \ - ,M_IF_METHOD(SET, oplist)(SET(M_F(name, _set)),) \ - ,M_IF_METHOD(CLEAR, oplist)(CLEAR(M_F(name, _clear)),) \ - ,M_IF_METHOD(INIT_MOVE, oplist)(INIT_MOVE(M_F(name, _init_move)),) \ - ,M_IF_METHOD(MOVE, oplist)(MOVE(M_F(name, _move)),) \ - ,M_IF_METHOD(SWAP,oplist)(SWAP(M_F(name, _swap)),) \ - ,NAME(name) \ - ,TYPE(M_F(name,_ct)), GENTYPE(struct M_F(name,_s)*) \ - ,SUBTYPE(M_F(name, _subtype_ct)) \ - ,OPLIST(oplist) \ - ,M_IF_METHOD(EMPTY_P, oplist)(EMPTY_P(M_F(name,_empty_p)),) \ - ,M_IF_METHOD(GET_SIZE, oplist)(GET_SIZE(M_F(name,_size)),) \ - ,M_IF_METHOD(RESET, oplist)(RESET(M_F(name,_reset)),) \ - ,M_IF_METHOD(KEY_TYPE, oplist)(KEY_TYPE(M_GET_KEY_TYPE oplist),) \ - ,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_TYPE(M_GET_VALUE_TYPE oplist),) \ - ,M_IF_METHOD(KEY_TYPE, oplist)(KEY_OPLIST(M_GET_KEY_OPLIST oplist),) \ - ,M_IF_METHOD(VALUE_TYPE, oplist)(VALUE_OPLIST(M_GET_VALUE_OPLIST oplist), ) \ - ,M_IF_METHOD(SET_KEY, oplist)(SET_KEY(M_F(name, _set_at)),) \ - ,M_IF_METHOD(ERASE_KEY, oplist)(ERASE_KEY(M_F(name, _erase)),) \ - ,M_IF_METHOD(PUSH, oplist)(PUSH(M_F(name,_push)),) \ - ,M_IF_METHOD(POP, oplist)(POP(M_F(name,_pop)),) \ - ,M_IF_METHOD(PUSH_MOVE, oplist)(PUSH_MOVE(M_F(name,_push_move)),) \ - ,M_IF_METHOD(POP_MOVE, oplist)(POP_MOVE(M_F(name,_pop_move)),) \ - ,M_IF_METHOD(GET_STR, oplist)(GET_STR(M_F(name, _get_str)),) \ - ,M_IF_METHOD(PARSE_STR, oplist)(PARSE_STR(M_F(name, _parse_str)),) \ - ,M_IF_METHOD(OUT_STR, oplist)(OUT_STR(M_F(name, _out_str)),) \ - ,M_IF_METHOD(IN_STR, oplist)(IN_STR(M_F(name, _in_str)),) \ - ,M_IF_METHOD(OUT_SERIAL, oplist)(OUT_SERIAL(M_F(name, _out_serial)),) \ - ,M_IF_METHOD(IN_SERIAL, oplist)(IN_SERIAL(M_F(name, _in_serial)),) \ - ,M_IF_METHOD(EQUAL, oplist)(EQUAL(M_F(name, _equal_p)),) \ - ,M_IF_METHOD(HASH, oplist)(HASH(M_F(name, _hash)),) \ - ) - - -/******************************** INTERNAL ***********************************/ - -/* Internal contract - NOTE: Can't check too much without locking the container itself -*/ -#define M_C0NCURRENT_CONTRACT(c) do { \ - M_ASSERT ((c) != NULL); \ - M_ASSERT ((c)->self == (c)); \ - } while (0) - -/* Deferred evaluation for the concurrent definition, - so that all arguments are evaluated before further expansion */ -#define M_C0NCURRENT_DEF_P1(arg) M_ID( M_C0NCURRENT_DEF_P2 arg ) - -/* Validate the value oplist before going further */ -#define M_C0NCURRENT_DEF_P2(name, type, oplist, concurrent_t) \ - M_IF_OPLIST(oplist)(M_C0NCURRENT_DEF_P3, M_C0NCURRENT_DEF_FAILURE)(name, type, oplist, concurrent_t) - -/* Stop processing with a compilation failure */ -#define M_C0NCURRENT_DEF_FAILURE(name, type, oplist, concurrent_t) \ - M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) - -/* Internal concurrent definition - - name: prefix to be used - - type: type of the sub container - - oplist: oplist of the type of the sub container - - concurrent_t: alias for M_F(name, _t) [ type of the container ] - */ -#define M_C0NCURRENT_DEF_P3(name, type, oplist, concurrent_t) \ - M_C0NCURRENT_DEF_TYPE(name, type, oplist, concurrent_t) \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_C0NCURRENT_DEF_CORE(name, type, oplist, concurrent_t) \ - M_C0NCURRENT_DEF_COMMON(name, type, oplist, concurrent_t) - -/* Define the type of a concurrent container */ -#define M_C0NCURRENT_DEF_TYPE(name, type, oplist, concurrent_t) \ - \ - /* Define a concurrent container using a lock */ \ - typedef struct M_F(name, _s) { \ - struct M_F(name, _s) *self; \ - m_mutex_t lock; \ - m_cond_t there_is_data; /* condition raised when there is data */ \ - type data; \ - } concurrent_t[1]; \ - \ - /* Define alias for pointer types */ \ - typedef struct M_F(name, _s) *M_F(name, _ptr); \ - typedef const struct M_F(name, _s) *M_F(name, _srcptr); \ - \ - /* Internal types for oplist */ \ - typedef concurrent_t M_F(name, _ct); \ - typedef type M_F(name, _subtype_ct); \ - \ - /* Cannot define iterator as it cannot be reliable in a concurrent type */ \ - - /* Define the internal services used for the lock strategy */ -#define M_C0NCURRENT_DEF_CORE(name, type, oplist, concurrent_t) \ - \ - /* Initial the fields of the concurrent object not associated to the \ - sub-container. */ \ - M_INLINE void \ - M_F(name, _internal_init)(concurrent_t out) \ - { \ - m_mutex_init(out->lock); \ - m_cond_init(out->there_is_data); \ - out->self = out; \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - \ - /* Clear the fields of the concurrent object not associated to the \ - sub-container. */ \ - M_INLINE void \ - M_F(name, _internal_clear)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_mutex_clear(out->lock); \ - m_cond_clear(out->there_is_data); \ - out->self = NULL; \ - } \ - \ - /* Get the read lock. Multiple threads can get it, but only for reading. \ - write lock is exclusive. \ - NOTE: This instance doesn't implement the read/write strategy, \ - and only get the lock */ \ - M_INLINE void \ - M_F(name, _read_lock)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_mutex_lock (out->self->lock); \ - } \ - \ - /* Free the read lock. See above. \ - NOTE: This instance doesn't implement the read/write strategy, \ - and only get the lock */ \ - M_INLINE void \ - M_F(name, _read_unlock)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_mutex_unlock (out->self->lock); \ - } \ - \ - /* Wait for a thread pushing some data in the container. \ - CONSTRAINT: the read lock shall be get before calling this service */ \ - M_INLINE void \ - M_F(name, _read_wait)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_cond_wait(out->self->there_is_data, out->self->lock); \ - } \ - \ - /* Get the write lock. Only one threads can get it, and no other threads \ - can get the read lock too. \ - NOTE: This instance doesn't implement the read/write strategy, \ - and only get the lock */ \ - M_INLINE void \ - M_F(name, _write_lock)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_mutex_lock (out->lock); \ - } \ - \ - /* Free the write lock. \ - NOTE: This instance doesn't implement the read/write strategy, \ - and only get the lock */ \ - M_INLINE void \ - M_F(name, _write_unlock)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_mutex_unlock (out->lock); \ - } \ - \ - /* Wait for a thread pushing some data in the container. \ - CONSTRAINT: the write lock shall be get before calling this service */ \ - M_INLINE void \ - M_F(name, _write_wait)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_cond_wait(out->self->there_is_data, out->self->lock); \ - } \ - \ - /* Wait to all threads that some data are available in the container. \ - CONSTRAINT: the write lock shall be get before calling this service */ \ - M_INLINE void \ - M_F(name, _write_signal)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - /* We need to signal this to ALL waiting threads as multiple threads \ - may wait on a some data of this container. */ \ - m_cond_broadcast(out->there_is_data); \ - } \ - -/* Internal definition of the functions commons to concurrent and rp-concurrent - - name: prefix to be used - - type: type of the sub container - - oplist: oplist of the type of the sub container - - concurrent_t: alias for M_F(name, _t) [ type of the container ] - A function is defined only if the underlying container exports the needed - services. It is usually one service declared per service exported. -*/ -#define M_C0NCURRENT_DEF_COMMON(name, type, oplist, concurrent_t) \ - \ - M_IF_METHOD(INIT, oplist)( \ - M_INLINE void \ - M_F(name, _init)(concurrent_t out) \ - { \ - M_F(name, _internal_init)(out); \ - M_CALL_INIT(oplist, out->data); \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(INIT_SET, oplist)( \ - M_INLINE void \ - M_F(name, _init_set)(concurrent_t out, concurrent_t const src) \ - { \ - M_C0NCURRENT_CONTRACT(src); \ - M_ASSERT (out != src); \ - M_F(name, _internal_init)(out); \ - M_F(name, _read_lock)(src); \ - M_CALL_INIT_SET(oplist, out->data, src->data); \ - M_F(name, _read_unlock)(src); \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(SET, oplist)( \ - M_INLINE void \ - M_F(name, _set)(concurrent_t out, concurrent_t const src) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - if (M_UNLIKELY (out == src)) return; \ - /* Need to order the locks in a total way to avoid lock deadlock. \ - Indeed, two call to _set can be done in two threads with : \ - T1: A := B \ - T2: B := A \ - If we lock first the mutex of out, then the src, it could be possible \ - in the previous scenario that both mutexes are locked: T1 has locked A \ - and T2 has locked B, and T1 is waiting for locking B, and T2 is waiting \ - for locking A, resulting in a deadlock. \ - To avoid this problem, we **always** lock the mutex which address is \ - the lowest. */ \ - if (out < src) { \ - M_F(name, _write_lock)(out); \ - M_F(name, _read_lock)(src); \ - } else { \ - M_F(name, _read_lock)(src); \ - M_F(name, _write_lock)(out); \ - } \ - M_CALL_SET(oplist, out->data, src->data); \ - if (out < src) { \ - M_F(name, _read_unlock)(src); \ - M_F(name, _write_unlock)(out); \ - } else { \ - M_F(name, _write_unlock)(out); \ - M_F(name, _read_unlock)(src); \ - } \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(CLEAR, oplist)( \ - M_INLINE void \ - M_F(name, _clear)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - /* No need to lock. A clear is supposed to be called when all operations \ - of the container in other threads are terminated */ \ - M_CALL_CLEAR(oplist, out->data); \ - M_F(name, _internal_clear)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(INIT_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _init_move)(concurrent_t out, concurrent_t src) \ - { \ - M_C0NCURRENT_CONTRACT(src); \ - M_ASSERT (out != src); \ - /* No need to lock 'src' ? */ \ - M_F(name, _internal_init)(out); \ - M_CALL_INIT_MOVE(oplist, out->data, src->data); \ - M_F(name, _internal_clear)(src); \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _move)(concurrent_t out, concurrent_t src) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_C0NCURRENT_CONTRACT(src); \ - /* No need to lock 'src' ? */ \ - M_F(name, _write_lock)(out); \ - M_CALL_MOVE(oplist, out->data, src->data); \ - M_F(name, _write_unlock)(out); \ - M_F(name, _internal_clear)(src); \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - ,) \ - \ - M_IF_METHOD(SWAP, oplist)( \ - M_INLINE void \ - M_F(name, _swap)(concurrent_t out, concurrent_t src) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_C0NCURRENT_CONTRACT(src); \ - if (M_UNLIKELY (out == src)) return; \ - /* See comment above */ \ - if (out < src) { \ - M_F(name, _write_lock)(out); \ - M_F(name, _write_lock)(src); \ - } else { \ - M_F(name, _write_lock)(src); \ - M_F(name, _write_lock)(out); \ - } \ - M_CALL_SWAP(oplist, out->data, src->data); \ - if (out < src) { \ - M_F(name, _write_unlock)(src); \ - M_F(name, _write_unlock)(out); \ - } else { \ - M_F(name, _write_unlock)(out); \ - M_F(name, _write_unlock)(src); \ - } \ - } \ - ,) \ - \ - M_IF_METHOD(RESET, oplist)( \ - M_INLINE void \ - M_F(name, _reset)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - M_CALL_RESET(oplist, out->data); \ - M_F(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(EMPTY_P, oplist)( \ - M_INLINE bool \ - M_F(name, _empty_p)(concurrent_t const out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _read_lock)(out); \ - bool b = M_CALL_EMPTY_P(oplist, out->data); \ - M_F(name, _read_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(GET_SIZE, oplist)( \ - M_INLINE size_t \ - M_F(name, _size)(concurrent_t const out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _read_lock)(out); \ - size_t r = M_CALL_GET_SIZE(oplist, out->data); \ - M_F(name, _read_unlock)(out); \ - return r; \ - } \ - ,) \ - \ - M_IF_METHOD(SET_KEY, oplist)( \ - M_INLINE void \ - M_F(name, _set_at)(concurrent_t out, M_GET_KEY_TYPE oplist const key, M_GET_VALUE_TYPE oplist const data) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - M_CALL_SET_KEY(oplist, out->data, key, data); \ - M_F(name, _write_signal)(out); \ - M_F(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(GET_KEY, oplist)( \ - M_INLINE bool \ - M_F(name, _get_copy)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT (out_data != NULL); \ - M_F(name, _read_lock)(out); \ - M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \ - if (p != NULL) { \ - M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ - } \ - M_F(name, _read_unlock)(out); \ - return p != NULL; \ - } \ - ,) \ - \ - M_IF_METHOD(SAFE_GET_KEY, oplist)( \ - M_INLINE void \ - M_F(name, _safe_get_copy)(M_GET_VALUE_TYPE oplist *out_data, concurrent_t out, M_GET_KEY_TYPE oplist const key) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT (out_data != NULL); \ - M_F(name, _write_lock)(out); \ - M_GET_VALUE_TYPE oplist *p = M_CALL_SAFE_GET_KEY(oplist, out->data, key); \ - M_ASSERT (p != NULL); \ - M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ - M_F(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(ERASE_KEY, oplist)( \ - M_INLINE bool \ - M_F(name, _erase)(concurrent_t out, M_GET_KEY_TYPE oplist const key) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - bool b = M_CALL_ERASE_KEY(oplist, out->data, key); \ - /* We suppose that the container has 'infinite' capacity, so \ - we won't signal that a free space has been created */ \ - M_F(name, _write_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(PUSH, oplist)( \ - M_INLINE void \ - M_F(name, _push)(concurrent_t out, M_GET_SUBTYPE oplist const data) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - M_CALL_PUSH(oplist, out->data, data); \ - M_F(name, _write_signal)(out); \ - M_F(name, _write_unlock)(out); \ - } \ - \ - M_EMPLACE_QUEUE_DEF(name, concurrent_t, _emplace, M_GET_OPLIST oplist, M_EMPLACE_QUEUE_GENE) \ - ,) \ - \ - M_IF_METHOD(POP, oplist)( \ - M_INLINE void \ - M_F(name, _pop)(M_GET_SUBTYPE oplist *p, concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - M_CALL_POP(oplist, p, out->data); \ - /* See comment above */ \ - M_F(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(PUSH_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _push_move)(concurrent_t out, M_GET_SUBTYPE oplist *data) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - M_CALL_PUSH_MOVE(oplist, out->data, data); \ - M_F(name, _write_signal)(out); \ - M_F(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(POP_MOVE, oplist)( \ - M_INLINE void \ - M_F(name, _pop_move)(M_GET_SUBTYPE oplist *p, concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - M_CALL_POP_MOVE(oplist, p, out->data); \ - /* See comment above */ \ - M_F(name, _write_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(GET_STR, oplist)( \ - M_INLINE void \ - M_F(name, _get_str)(m_string_t str, concurrent_t const out, bool a) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _read_lock)(out); \ - M_CALL_GET_STR(oplist, str, out->data, a); \ - M_F(name, _read_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(OUT_STR, oplist)( \ - M_INLINE void \ - M_F(name, _out_str)(FILE *f, concurrent_t const out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _read_lock)(out); \ - M_CALL_OUT_STR(oplist, f, out->data); \ - M_F(name, _read_unlock)(out); \ - } \ - ,) \ - \ - M_IF_METHOD(PARSE_STR, oplist)( \ - M_INLINE bool \ - M_F(name, _parse_str)(concurrent_t out, const char str[], const char **e) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - bool b = M_CALL_PARSE_STR(oplist, out->data, str, e); \ - M_F(name, _write_signal)(out); \ - M_F(name, _write_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(IN_STR, oplist)( \ - M_INLINE bool \ - M_F(name, _in_str)(concurrent_t out, FILE *f) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - bool b = M_CALL_IN_STR(oplist, out->data, f); \ - M_F(name, _write_signal)(out); \ - M_F(name, _write_unlock)(out); \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(OUT_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _out_serial)(m_serial_write_t f, concurrent_t const out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _read_lock)(out); \ - m_serial_return_code_t r = M_CALL_OUT_SERIAL(oplist, f, out->data); \ - M_F(name, _read_unlock)(out); \ - return r; \ - } \ - ,) \ - \ - M_IF_METHOD(IN_SERIAL, oplist)( \ - M_INLINE m_serial_return_code_t \ - M_F(name, _in_serial)(concurrent_t out, m_serial_read_t f) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _write_lock)(out); \ - m_serial_return_code_t r = M_CALL_IN_SERIAL(oplist, out->data, f); \ - M_F(name, _write_signal)(out); \ - M_F(name, _write_unlock)(out); \ - return r; \ - } \ - ,) \ - \ - M_IF_METHOD(EQUAL, oplist)( \ - M_INLINE bool \ - M_F(name, _equal_p)(concurrent_t const out1, concurrent_t const out2) \ - { \ - M_C0NCURRENT_CONTRACT(out1); \ - M_C0NCURRENT_CONTRACT(out2); \ - if (M_UNLIKELY (out1 == out2)) return true; \ - /* See comment above on mutual mutexes */ \ - if (out1 < out2) { \ - M_F(name, _read_lock)(out1); \ - M_F(name, _read_lock)(out2); \ - } else { \ - M_F(name, _read_lock)(out2); \ - M_F(name, _read_lock)(out1); \ - } \ - bool b = M_CALL_EQUAL(oplist, out1->data, out2->data); \ - if (out1 < out2) { \ - M_F(name, _read_unlock)(out2); \ - M_F(name, _read_unlock)(out1); \ - } else { \ - M_F(name, _read_unlock)(out1); \ - M_F(name, _read_unlock)(out2); \ - } \ - return b; \ - } \ - ,) \ - \ - M_IF_METHOD(GET_KEY, oplist)( \ - M_INLINE bool \ - M_F(name, _get_blocking)(M_GET_VALUE_TYPE oplist *out_data, const concurrent_t out, M_GET_KEY_TYPE oplist const key, bool blocking) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT (out_data != NULL); \ - bool ret = false; \ - M_F(name, _read_lock)(out); \ - while (true) { \ - M_GET_VALUE_TYPE oplist *p = M_CALL_GET_KEY(oplist, out->data, key); \ - if (p != NULL) { \ - M_CALL_SET(M_GET_VALUE_OPLIST oplist, *out_data, *p); \ - ret = true; \ - break; \ - } \ - if (blocking == false) break; \ - /* No data: wait for a write to signal some data */ \ - M_F(name, _read_wait)(out); \ - } \ - M_F(name, _read_unlock)(out); \ - return ret; \ - } \ - ,) \ - \ - M_IF_METHOD2(POP, EMPTY_P, oplist)( \ - M_INLINE bool \ - M_F(name, _pop_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT (p != NULL); \ - bool ret = false; \ - M_F(name, _write_lock)(out); \ - while (true) { \ - if (!M_CALL_EMPTY_P(oplist, out->data)) { \ - M_CALL_POP(oplist, p, out->data); \ - ret = true; \ - break; \ - } \ - if (blocking == false) break; \ - /* No data: wait for a write to signal some data */ \ - M_F(name, _write_wait)(out); \ - } \ - M_F(name, _write_unlock)(out); \ - return ret; \ - } \ - ,) \ - \ - M_IF_METHOD2(POP_MOVE, EMPTY_P, oplist)( \ - M_INLINE bool \ - M_F(name, _pop_move_blocking)(M_GET_SUBTYPE oplist *p, concurrent_t out, bool blocking) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT (p != NULL); \ - bool ret = false; \ - M_F(name, _write_lock)(out); \ - while (true) { \ - if (!M_CALL_EMPTY_P(oplist, out->data)) { \ - M_CALL_POP_MOVE(oplist, p, out->data); \ - ret = true; \ - break; \ - } \ - if (blocking == false) break; \ - /* No data: wait for a write to signal some data */ \ - M_F(name, _write_wait)(out); \ - } \ - M_F(name, _write_unlock)(out); \ - return ret; \ - } \ - ,) \ - \ - M_IF_METHOD(HASH, oplist)( \ - M_INLINE size_t \ - M_F(name, _hash)(concurrent_t const out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_F(name, _read_lock)(out); \ - size_t h = M_CALL_HASH(oplist, out->data); \ - M_F(name, _read_unlock)(out); \ - /* The hash is unchanged by the concurrent container */ \ - return h; \ - } \ - ,) \ - - -/******************************** INTERNAL ***********************************/ - -/* Deferred evaluation for the RP concurrent definition, - so that all arguments are evaluated before further expansion */ -#define M_C0NCURRENT_RP_DEF_P1(arg) M_ID( M_C0NCURRENT_RP_DEF_P2 arg ) - -/* Validate the value oplist before going further */ -#define M_C0NCURRENT_RP_DEF_P2(name, type, oplist, concurrent_t) \ - M_IF_OPLIST(oplist)(M_C0NCURRENT_RP_DEF_P3, M_C0NCURRENT_RP_DEF_FAILURE)(name, type, oplist, concurrent_t) - -/* Stop processing with a compilation failure */ -#define M_C0NCURRENT_RP_DEF_FAILURE(name, type, oplist, concurrent_t) \ - M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(CONCURRENT_RP_DEF): the given argument is not a valid oplist: " M_AS_STR(oplist)) - -/* Internal RP concurrent definition - - name: prefix to be used - - type: type of the sub container - - oplist: oplist of the type of the sub container - - concurrent_t: alias for M_F(name, _t) [ type of the container ] - */ -#define M_C0NCURRENT_RP_DEF_P3(name, type, oplist, concurrent_t) \ - M_C0NCURRENT_RP_DEF_TYPE(name, type, oplist, concurrent_t) \ - M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \ - M_C0NCURRENT_RP_DEF_CORE(name, type, oplist, concurrent_t) \ - M_C0NCURRENT_DEF_COMMON(name, type, oplist, concurrent_t) - -/* Define the type of a RP concurrent container */ -#define M_C0NCURRENT_RP_DEF_TYPE(name, type, oplist, concurrent_t) \ - \ - typedef struct M_F(name, _s) { \ - struct M_F(name, _s) *self; \ - m_mutex_t lock; \ - atomic_uint num_reader; /* number of reader threads */ \ - atomic_uint num_waiting_writer; /* number of waiting writer threads */ \ - m_cond_t there_is_data; /* condition raised when there is data */ \ - type data; \ - } concurrent_t[1]; \ - \ - typedef struct M_F(name, _s) *M_F(name, _ptr); \ - typedef const struct M_F(name, _s) *M_F(name, _srcptr); \ - \ - typedef type M_F(name, _subtype_ct); \ - -/* Define the internal services for the lock strategy of a RP container */ -#define M_C0NCURRENT_RP_DEF_CORE(name, type, oplist, concurrent_t) \ - \ - M_INLINE void \ - M_F(name, _internal_init)(concurrent_t out) \ - { \ - m_mutex_init(out->lock); \ - atomic_init(&out->num_reader, 0); \ - atomic_init(&out->num_waiting_writer, 0); \ - m_cond_init(out->there_is_data); \ - out->self = out; \ - M_C0NCURRENT_CONTRACT(out); \ - } \ - \ - M_INLINE void \ - M_F(name, _internal_clear)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_mutex_clear(out->lock); \ - m_cond_clear(out->there_is_data); \ - out->self = NULL; \ - } \ - \ - M_INLINE void \ - M_F(name, _read_lock)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - struct M_F(name, _s) *self = out->self; \ - m_core_backoff_ct backoff; \ - m_core_backoff_init(backoff); \ - while (true) { \ - unsigned int num = atomic_load(&self->num_reader); \ - /* To avoid reader threads that starve writer threads \ - Disable sharing of lock for reader threads if some writer thread \ - waits */ \ - /* Otherwise try to reuse the lock opened by another reader thread */ \ - if (num != 0 \ - && atomic_load(&self->num_waiting_writer) == 0 \ - && atomic_compare_exchange_strong(&self->num_reader, &num, num+1)) { \ - break; \ - } \ - /* Otherwise try to get the lock ourself */ \ - if (m_mutex_trylock(self->lock)) { \ - atomic_store(&self->num_reader, 1); \ - break; \ - } \ - /* Perform exponential backoff to avoid monopolizing the memory bus */ \ - m_core_backoff_wait(backoff); \ - } \ - m_core_backoff_clear(backoff); \ - } \ - \ - M_INLINE void \ - M_F(name, _read_unlock)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - struct M_F(name, _s) *self = out->self; \ - unsigned int num = atomic_fetch_sub(&self->num_reader, 1); \ - if (num == 1) { \ - /* We are the last reader thread: release the lock */ \ - m_mutex_unlock(self->lock); \ - } \ - } \ - \ - M_INLINE void \ - M_F(name, _write_lock)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - atomic_fetch_add(&out->num_waiting_writer, 1); \ - m_mutex_lock (out->lock); \ - atomic_fetch_sub(&out->num_waiting_writer, 1); \ - M_ASSERT(atomic_load(&out->num_reader) == 0); \ - } \ - \ - M_INLINE void \ - M_F(name, _write_unlock)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT(atomic_load(&out->num_reader) == 0); \ - m_mutex_unlock (out->lock); \ - } \ - \ - M_INLINE void \ - M_F(name, _read_wait)(const concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - struct M_F(name, _s) *self = out->self; \ - m_cond_wait(self->there_is_data, self->lock); \ - } \ - \ - M_INLINE void \ - M_F(name, _write_wait)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - m_cond_wait(out->there_is_data, out->lock); \ - } \ - \ - M_INLINE void \ - M_F(name, _write_signal)(concurrent_t out) \ - { \ - M_C0NCURRENT_CONTRACT(out); \ - M_ASSERT(atomic_load(&out->num_reader) == 0); \ - m_cond_broadcast(out->there_is_data); \ - } \ - - -/******************************** INTERNAL ***********************************/ - -#if M_USE_SMALL_NAME -#define CONCURRENT_DEF M_CONCURRENT_DEF -#define CONCURRENT_DEF_AS M_CONCURRENT_DEF_AS -#define CONCURRENT_RP_DEF M_CONCURRENT_RP_DEF -#define CONCURRENT_RP_DEF_AS M_CONCURRENT_RP_DEF_AS -#define CONCURRENT_OPLIST M_CONCURRENT_OPLIST -#endif - -#endif diff --git a/tests/test-mconcurrent.c b/tests/test-mconcurrent.c deleted file mode 100644 index 4c84c509..00000000 --- a/tests/test-mconcurrent.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#include -#include "test-obj.h" - -#include "m-array.h" -#include "m-bptree.h" -#include "m-deque.h" -#include "m-dict.h" -#include "m-list.h" -#include "m-prioqueue.h" -#include "m-rbtree.h" -#include "m-tuple.h" -#include "m-variant.h" - -#include "m-concurrent.h" -#include "coverage.h" - -TUPLE_DEF2(point, (x, int), (y, int)) -#define M_OPL_point_t() TUPLE_OPLIST(point, M_BASIC_OPLIST, M_BASIC_OPLIST) -START_COVERAGE -CONCURRENT_DEF(ppoint, point_t) -END_COVERAGE - -VARIANT_DEF2(dimension, (x, int), (y, float)) -#define M_OPL_dimension_t() VARIANT_OPLIST(dimension, M_BASIC_OPLIST, M_BASIC_OPLIST) -CONCURRENT_DEF(pdimension, dimension_t) - -ARRAY_DEF(array1, int) -CONCURRENT_DEF(parray1, array1_t, ARRAY_OPLIST(array1)) - -DICT_DEF2(dict1, int, int) -CONCURRENT_DEF(pdict1, dict1_t, DICT_OPLIST(dict1)) - -DICT_SET_DEF(dict2, int) -CONCURRENT_DEF(pdict2, dict2_t, DICT_SET_OPLIST(dict2)) - -LIST_DEF(list1, int) -CONCURRENT_DEF(plist1, list1_t, LIST_OPLIST(list1)) - -LIST_DUAL_PUSH_DEF(list2, int) -CONCURRENT_DEF(plist2, list2_t, LIST_OPLIST(list2)) - -DEQUE_DEF(deque1, int) -CONCURRENT_DEF(pdeque1, deque1_t, DEQUE_OPLIST(deque1)) - -PRIOQUEUE_DEF(prio1, int) -CONCURRENT_DEF(pprio1, prio1_t, PRIOQUEUE_OPLIST(prio1)) - -BPTREE_DEF2(bptree1, 10, int, int) -CONCURRENT_DEF(pbtree1, bptree1_t, BPTREE_OPLIST2(bptree1, M_BASIC_OPLIST, M_BASIC_OPLIST)) - -BPTREE_DEF(bptree2, 10, int) -CONCURRENT_DEF(pbtree2, bptree2_t, BPTREE_OPLIST(bptree2)) - -RBTREE_DEF(rbtree1, int) -CONCURRENT_DEF(prbtree1, rbtree1_t, RBTREE_OPLIST(rbtree1)) - -DICT_DEF2(string_pool, string_t, string_t) -#define STRING_POOL_OPLIST \ - DICT_OPLIST(string_pool, STRING_OPLIST, STRING_OPLIST) -#define M_OPL_string_pool_t() STRING_POOL_OPLIST -CONCURRENT_DEF(string_pool_ts, string_pool_t, STRING_POOL_OPLIST) -#define STRING_POOL_TS_OPLIST \ - CONCURRENT_OPLIST(string_pool_ts, STRING_POOL_OPLIST) -#define M_OPL_string_pool_ts_t() STRING_POOL_TS_OPLIST - -TUPLE_DEF2(my_tuple, (pool, string_pool_ts_t)) -#define MY_TUPLE_OPLIST TUPLE_OPLIST(my_tuple, STRING_POOL_TS_OPLIST) -#define M_OPL_my_tuple_t() MY_TUPLE_OPLIST - -ARRAY_DEF(key_list, string_t) -#define M_OPL_key_list_t() ARRAY_OPLIST(key_list, STRING_OPLIST) -CONCURRENT_DEF(key_list_ts, key_list_t) - -CONCURRENT_RP_DEF(rparray1, array1_t, ARRAY_OPLIST(array1)) - -CONCURRENT_RP_DEF(rpdict1, dict1_t, DICT_OPLIST(dict1)) - -CONCURRENT_DEF_AS(ConcurrentDouble, ConcurrentDouble, double) -CONCURRENT_RP_DEF_AS(ConcurrentRpDouble, ConcurrentRpDouble, double) - -/* OA dict needs more operators than the default ones to work */ -static inline bool int_oor_equal_p(int s, unsigned char n) -{ - return s == -n; -} -static inline void int_oor_set(int *s, unsigned char n) -{ - *s = -n; -} -#define INT_OA_OPLIST \ - M_OPEXTEND(M_BASIC_OPLIST, OOR_EQUAL(int_oor_equal_p), OOR_SET(API_2(int_oor_set))) -DICT_OA_DEF2(dict3, int, INT_OA_OPLIST, int, M_BASIC_OPLIST) -CONCURRENT_DEF(pdict3, dict3_t, DICT_OPLIST(dict3)) - -/********************************/ -parray1_t arr; - -static void conso(void *p) -{ - assert (p == NULL); - for(int i = 0; i < 1000; i++) { - int j; - bool b = parray1_pop_blocking(&j, arr, true); - assert (b); - assert (j == i); - } -} - -static void test_thread(void) -{ - m_thread_t idx; - parray1_init(arr); - m_thread_create (idx, conso, NULL); - m_thread_sleep(1000); - for(int i = 0; i < 1000; i++) { - parray1_push (arr, i); - while (!parray1_empty_p(arr)); - } - m_thread_join(idx); - parray1_clear(arr); -} - -static void test_basic(void) -{ - pdict1_t dict; - pdict1_init(dict); - int z; - pdict1_set_at(dict, 2, 3); - pdict1_get_copy(&z, dict, 2); - assert (z == 3); - z = 1; - bool b = pdict1_get_blocking(&z, dict, 2, false); - assert (b); - assert (z == 3); - assert (pdict1_size(dict) == 1); - pdict1_clear(dict); - - M_LET(str, string_t) - M_LET(pool, string_pool_ts_t) { - string_pool_ts_set_at (pool, STRING_CTE("A"), STRING_CTE("B")); - b = string_pool_ts_get_copy (&str, pool, STRING_CTE("A")); - assert (b); - assert (string_equal_str_p (str, "B")); - } - M_LET(tuple, my_tuple_t) { - assert (string_pool_ts_empty_p(tuple->pool)); - } -} - - -rparray1_t rarr; - -static void conso_rp(void *p) -{ - assert (p == NULL); - for(int i = 0; i < 1000; i++) { - int j; - bool b = rparray1_pop_blocking(&j, rarr, true); - assert (b); - assert (j == i); - } -} - -static void test_rp_thread(void) -{ - m_thread_t idx; - rparray1_init(rarr); - m_thread_create (idx, conso_rp, NULL); - m_thread_sleep(1000); - for(int i = 0; i < 1000; i++) { - rparray1_push (rarr, i); - while (!rparray1_empty_p(rarr)); - } - m_thread_join(idx); - rparray1_clear(rarr); -} - -static void test_rp_basic(void) -{ - rpdict1_t dict; - rpdict1_init(dict); - int z = 0; - rpdict1_set_at(dict, 2, 3); - rpdict1_get_copy(&z, dict, 2); - assert (z == 3); - z = 1; - bool b = rpdict1_get_blocking(&z, dict, 2, false); - assert (b); - assert (z == 3); - assert (rpdict1_size(dict) == 1); - rpdict1_clear(dict); -} - -static void test_double(void) -{ - ConcurrentDouble d; - ConcurrentDouble_init(d); - ConcurrentDouble_reset(d); - ConcurrentDouble_clear(d); - - ConcurrentRpDouble r; - ConcurrentRpDouble_init(r); - ConcurrentRpDouble_reset(r); - ConcurrentRpDouble_clear(r); -} - -static void test_emplace(void) -{ - key_list_ts_t ts; - key_list_ts_init(ts); - key_list_ts_emplace(ts, "HELLO"); - M_LET(s, string_t) { - key_list_ts_pop(&s, ts); - assert(string_equal_str_p(s, "HELLO")); - } - key_list_ts_clear(ts); -} - -int main(void) -{ - test_basic(); - test_rp_basic(); - test_thread(); - test_rp_thread(); - test_double(); - test_emplace(); - exit(0); -} From 7c4f94a674fbc381ca875315a15785b0c35eac42 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 7 May 2025 22:09:56 +0200 Subject: [PATCH 91/91] Remove obsolete m-mempool.h header --- README.md | 101 ------------------- example/ex11-small-name.c | 1 - m-core.h | 7 -- m-mempool.h | 207 -------------------------------------- tests/test-mmempool.c | 107 -------------------- 5 files changed, 423 deletions(-) delete mode 100644 m-mempool.h delete mode 100644 tests/test-mmempool.c diff --git a/README.md b/README.md index dc1f43d4..35aa9a7b 100644 --- a/README.md +++ b/README.md @@ -195,9 +195,6 @@ Finally, headers for compatibility with non C11 compilers: * [m-atomic.h](#m-atomic): header for ensuring compatibility between C's `stdatomic.h` and C++'s atomic header (provide also its own implementation if nothing is available), * [m-thread.h](#m-thread): header for providing a very thin layer across multiple implementation of mutex/threads (C11/PTHREAD/WIN32). -The following headers are obsolete and will be removed in the next major release: -* [m-mempool.h](#m-mempool): header for creating specialized & fast memory allocator, - Each containers define their iterators (if it is meaningful). All containers try to expose the same common interface: @@ -1823,39 +1820,6 @@ int main(void) { } ``` -If the given oplist contain the method `MEMPOOL`, then `LIST_DEF` macro will create -a dedicated mempool that is named with the given value of the method `MEMPOOL`. -This mempool (see [mempool chapter](#m-mempool)) is optimized for this kind of list: - -* it creates a mempool named by the concatenation of `name` and `_mempool`, -* it creates a variable named by the value of the method `MEMPOOL` with the linkage -defined by the value of the method `MEMPOOL_LINKAGE` (can be extern, static or none). -This variable is shared by all lists of the same type. -* it links the memory allocation of the list to use this mempool with this variable. - -`mempool` create heavily efficient list. However, it is only worth the -effort in some heavy performance context. -Using mempool should be therefore avoided except in performance critical code. -The created mempool has to be explicitly initialized before using any -methods of the created list by calling `mempool_list_name_init(variable)` -and cleared by calling `mempool_list_name_clear(variable)`. - -Example: - -```C -LIST_DEF(list_uint, unsigned int, (MEMPOOL(list_mpool), MEMPOOL_LINKAGE(static))) - -static void test_list (size_t n) -{ - list_uint_mempool_init(list_mpool); - M_LET(a1, LIST_OPLIST(uint)) { - for(size_t i = 0; i < n; i++) - list_uint_push_back(a1, rand_get() ); - } - list_uint_mempool_clear(list_mpool); -} -``` - #### `LIST_OPLIST(name [, oplist])` Return the oplist of the list defined by calling `LIST_DEF` @@ -7050,8 +7014,6 @@ M_GET_NEW oplist M_GET_DEL oplist M_GET_REALLOC oplist M_GET_FREE oplist -M_GET_MEMPOOL oplist -M_GET_MEMPOOL_LINKAGE oplist M_GET_HASH oplist M_GET_EQUAL oplist M_GET_CMP oplist @@ -8704,69 +8666,6 @@ The line and filename fields of the exception are filled automatically by the ma _________________ -### M-MEMPOOL - -> [!NOTE] -> This header is obsolete: `M_USE_CONTEXT` should be used instead to pass custom memory context to containers. - -This header is for generating specialized and optimized memory pools: -it will generate specialized functions to allocate and free only one kind of an object. -The mempool functions are not specially thread safe for a given mempool, -but the mempool variable can have the attribute `M_THREAD_ATTR` -so that each thread has its own instance of the mempool. - -The memory pool has to be initialized and cleared like any other variable. -Clearing the memory pool will free all the memory that has been allocated -within this memory pool. - -#### `MEMPOOL_DEF(name, type)` - -Generate specialized functions & types prefixed by `name` to `alloc` and `free` an object of type `type`. - -Example: - -```C -MEMPOOL_DEF(mempool_uint, unsigned int) - -mempool_uint_t m; - -void f(void) { - mempool_uint_init(m); - unsigned int *p = mempool_uint_alloc(m); - *p = 17; - mempool_uint_free(m, p); - mempool_uint_clear(m); -} -``` - -#### Created methods - -The following methods are automatically and properly created by the previous macros. In the following methods, name stands for the name given to the macro that is used to identify the type. - -##### `name_t` - -The type of a mempool. - -##### `void name_init(name_t m)` - -Initialize the mempool `m`. - -##### `void name_clear(name_t m)` - -Clear the mempool `m`. -All allocated objects associated to the this mempool that weren't explicitly freed will be deleted too (without calling their clear method). - -##### `type *name_alloc(name_t m)` - -Create a new object of type `type` and return a new pointer to the uninitialized object. - -##### `void name_free(name_t m, type *p)` - -Free the object `p` created by the call to `name_alloc`. -The clear method of the type is not called. - -_________________ - ### M-SERIAL-JSON This header is for defining an instance of the serial interface diff --git a/example/ex11-small-name.c b/example/ex11-small-name.c index 2a92a3c3..64b1bf6c 100644 --- a/example/ex11-small-name.c +++ b/example/ex11-small-name.c @@ -15,7 +15,6 @@ #include "m-genint.h" #include "m-i-list.h" #include "m-list.h" -#include "m-mempool.h" #include "m-prioqueue.h" #include "m-rbtree.h" #include "m-serial-bin.h" diff --git a/m-core.h b/m-core.h index 53b0fff5..f464fc6e 100644 --- a/m-core.h +++ b/m-core.h @@ -3531,8 +3531,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_X_DEL_DEL(a) ,a, #define M_X_REALLOC_REALLOC(a) ,a, #define M_X_FREE_FREE(a) ,a, -#define M_X_MEMPOOL_MEMPOOL(a) ,a, -#define M_X_MEMPOOL_LINKAGE_MEMPOOL_LINKAGE(a) ,a, #define M_X_SIZE_SIZE(a) ,a, #define M_X_CONTEXT_CONTEXT(a) ,a, #define M_X_POLICY_POLICY(a) ,a, @@ -3624,8 +3622,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_GET_DEL(...) M_GET_METHOD(DEL, M_MEMORY_DEL, __VA_ARGS__) #define M_GET_REALLOC(...) M_GET_METHOD(REALLOC, M_MEMORY_REALLOC, __VA_ARGS__) #define M_GET_FREE(...) M_GET_METHOD(FREE, M_MEMORY_FREE, __VA_ARGS__) -#define M_GET_MEMPOOL(...) M_GET_METHOD(MEMPOOL, M_NO_DEF_MEMPOOL, __VA_ARGS__) -#define M_GET_MEMPOOL_LINKAGE(...) M_GET_METHOD(MEMPOOL_LINKAGE, , __VA_ARGS__) #define M_GET_SIZE(...) M_GET_METHOD(SIZE, 0, __VA_ARGS__) #define M_GET_CONTEXT(...) M_GET_METHOD(CONTEXT, 0, __VA_ARGS__) #define M_GET_POLICY(...) M_GET_METHOD(POLICY, 0, __VA_ARGS__) @@ -3702,8 +3698,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_CALL_DEL(oplist, ...) M_APPLY_API(M_GET_DEL oplist, oplist, m_context, __VA_ARGS__) #define M_CALL_REALLOC(oplist, ...) M_APPLY_API(M_GET_REALLOC oplist, oplist, m_context, __VA_ARGS__) #define M_CALL_FREE(oplist, ...) M_APPLY_API(M_GET_FREE oplist, oplist, m_context, __VA_ARGS__) -#define M_CALL_MEMPOOL(oplist, ...) M_APPLY_API(M_GET_MEMPOOL oplist, oplist, __VA_ARGS__) -#define M_CALL_MEMPOOL_LINKAGE(oplist, ...) M_APPLY_API(M_GET_MEMPOOL_LINKAGE oplist, oplist, __VA_ARGS__) //#define M_CALL_SIZE(oplist, ...) M_APPLY_API(M_GET_SIZE oplist, oplist, __VA_ARGS__) //#define M_CALL_CONTEXT(oplist, ...) M_APPLY_API(M_GET_CONTEXT oplist, oplist, __VA_ARGS__) //#define M_CALL_POLICY(oplist, ...) M_APPLY_API(M_GET_POLICY oplist, oplist, __VA_ARGS__) @@ -3916,7 +3910,6 @@ M_INLINE size_t m_core_cstr_hash(const char str[]) #define M_NO_DEF_IN_SERIAL(...) M_NO_DEFAULT(IN_SERIAL, m_serial_return_code_t) #define M_NO_DEF_OOR_SET(...) M_NO_DEFAULT(OOR_SET, void) #define M_NO_DEF_OOR_EQUAL(...) M_NO_DEFAULT(OOR_EQUAL, bool) -#define M_NO_DEF_MEMPOOL(...) M_NO_DEFAULT(MEMPOOL, void) /* Create a type with an invalid static assertion. Creating a type allowed the macro into something not too bad diff --git a/m-mempool.h b/m-mempool.h deleted file mode 100644 index b7017a73..00000000 --- a/m-mempool.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * M*LIB - MEMPOOL module - * - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef MSTARLIB_MEMPOOL_H -#define MSTARLIB_MEMPOOL_H - -#include "m-core.h" - -// TODO: Full rework of the mempool module to provide a generic arena allocator -// instead using the new pool context pointer. - -/* Fast, fixed size, thread unsafe allocator based on memory regions. - No oplist is needed. - USAGE: - MEMPOOL_DEF(name, type) - Example: - MEMPOOL_DEF(mempool_uint, unsigned int) - ... - mempool_uint_t m; - mempool_uint_init(m); - unsigned int *ptr = mempool_uint_alloc(m); - *ptr = 17; - mempool_uint_free(m, ptr); - mempool_uint_clear(m); // Give back memory to system -*/ -#define M_MEMPOOL_DEF(name, type) \ - M_MEMPOOL_DEF_AS(name, M_F(name,_t), type) - - -/* Fast, fixed Size, thread unsafe allocator based on memory region. - USAGE: - MEMPOOL_DEF_AS(name, name_t, type) -*/ -#define M_MEMPOOL_DEF_AS(name, name_t, type) \ - M_BEGIN_PROTECTED_CODE \ - M_M3MPOOL_DEF_P2(name, type, name_t ) \ - M_END_PROTECTED_CODE - - -/* User shall be able to customize the size of the region segment and/or - the minimum number of elements. - The default is the number of elements that fits in 16KB, or 256 - is the size of the type is too big. -*/ -#ifndef M_USE_MEMPOOL_MAX_PER_SEGMENT -#define M_USE_MEMPOOL_MAX_PER_SEGMENT(type) \ - M_MAX((16*1024-sizeof(unsigned int) - 2*sizeof(void*)) / sizeof (type), 256U) -#endif - - -/*****************************************************************************/ -/********************************** INTERNAL *********************************/ -/*****************************************************************************/ - -/* - Technically, it uses a list of memory regions, where multiple - allocations are performed in each region. However, it - can not use m-list since it may be expanded from LIST_DEF - (recursive dependency problem). */ -#define M_M3MPOOL_DEF_P2(name, type, name_t) \ - M_M3MPOOL_DEF_TYPE(name, type, name_t) \ - M_M3MPOOL_DEF_CORE(name, type, name_t) - -/* Define the types of the mempool */ -#define M_M3MPOOL_DEF_TYPE(name, type, name_t) \ - \ - /* Define the type of element in a segment of the mempool. \ - Either it is the basic type or a pointer to another one. */ \ - typedef union M_F(name,_union_s) { \ - type t; \ - union M_F(name,_union_s) *next; \ - } M_F(name,_union_ct); \ - \ - /* Define a segment of a mempool. \ - It is an array of basic type, each segment is in a linked list */ \ - typedef struct M_F(name,_segment_s) { \ - unsigned int count; \ - struct M_F(name,_segment_s) *next; \ - M_F(name,_union_ct) tab[M_USE_MEMPOOL_MAX_PER_SEGMENT(type)]; \ - } M_F(name,_segment_ct); \ - \ - /* Define a mempool. \ - It is a pointer to the first free object within the segments \ - and the segments themselves */ \ - typedef struct M_F(name, _s) { \ - M_F(name,_union_ct) *free_list; \ - M_F(name,_segment_ct) *current_segment; \ - } name_t[1]; \ - - -/* Define the core functions of the mempool */ -#define M_M3MPOOL_DEF_CORE(name, type, name_t) \ - \ - M_INLINE void \ - M_F(name,_init)(name_t mem) \ - { \ - mem->free_list = NULL; \ - mem->current_segment = M_MEMORY_ALLOC(m_context, M_F(name,_segment_ct)); \ - if (M_UNLIKELY_NOMEM(mem->current_segment == NULL)) { \ - M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ - } \ - mem->current_segment->next = NULL; \ - mem->current_segment->count = 0; \ - M_M3MPOOL_CONTRACT(mem, type); \ - } \ - \ - M_INLINE void \ - M_F(name,_clear)(name_t mem) \ - { \ - M_M3MPOOL_CONTRACT(mem, type); \ - M_F(name,_segment_ct) *segment = mem->current_segment; \ - while (segment != NULL) { \ - M_F(name,_segment_ct) *next = segment->next; \ - M_MEMORY_DEL (m_context, segment); \ - segment = next; \ - } \ - /* Clean pointers to be safer */ \ - mem->free_list = NULL; \ - mem->current_segment = NULL; \ - } \ - \ - M_INLINE type * \ - M_F(name,_alloc)(name_t mem) \ - { \ - M_M3MPOOL_CONTRACT(mem, type); \ - /* Test if one object is in the free list */ \ - M_F(name,_union_ct) *ret = mem->free_list; \ - if (ret != NULL) { \ - /* Yes, so return it, and pop it from the free list */ \ - mem->free_list = ret->next; \ - return &ret->t; \ - } \ - /* No cheap free object exist. Test within a segment */ \ - M_F(name,_segment_ct) *segment = mem->current_segment; \ - M_ASSERT(segment != NULL); \ - unsigned int count = segment->count; \ - /* If segment is full, allocate a new one from the system */ \ - if (M_UNLIKELY (count >= M_USE_MEMPOOL_MAX_PER_SEGMENT(type))) { \ - M_F(name,_segment_ct) *new_segment = M_MEMORY_ALLOC (m_context, M_F(name,_segment_ct)); \ - if (M_UNLIKELY_NOMEM (new_segment == NULL)) { \ - M_MEMORY_FULL(M_F(name,_segment_ct), 1); \ - } \ - new_segment->next = segment; \ - new_segment->count = 0; \ - mem->current_segment = new_segment; \ - segment = new_segment; \ - count = 0; \ - } \ - /* Return the object as the last element of the current segment */ \ - ret = &segment->tab[count]; \ - segment->count = count + 1; \ - M_M3MPOOL_CONTRACT(mem, type); \ - return &ret->t; \ - } \ - \ - M_INLINE void \ - M_F(name,_free)(name_t mem, type *ptr) \ - { \ - M_M3MPOOL_CONTRACT(mem, type); \ - /* NOTE: Unsafe cast: suppose that the given pointer \ - was allocated by the previous alloc function. */ \ - M_F(name,_union_ct) *ret = (M_F(name,_union_ct) *)(uintptr_t)ptr; \ - /* Add the object back in the free list */ \ - ret->next = mem->free_list; \ - mem->free_list = ret; \ - /* NOTE: the objects are NOT given back to the system until the mempool \ - is fully cleared */ \ - M_M3MPOOL_CONTRACT(mem, type); \ - } \ - -/* MEMPOOL contract. We only control the current segment. */ -#define M_M3MPOOL_CONTRACT(mempool, type) do { \ - M_ASSERT((mempool) != NULL); \ - M_ASSERT((mempool)->current_segment != NULL); \ - M_ASSERT((mempool)->current_segment->count <= M_USE_MEMPOOL_MAX_PER_SEGMENT(type)); \ - } while (0) - - -/********************************** INTERNAL *********************************/ - -#if M_USE_SMALL_NAME -#define MEMPOOL_DEF M_MEMPOOL_DEF -#define MEMPOOL_DEF_AS M_MEMPOOL_DEF_AS -#endif - -#endif diff --git a/tests/test-mmempool.c b/tests/test-mmempool.c deleted file mode 100644 index b9513861..00000000 --- a/tests/test-mmempool.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2017-2025, Patrick Pelissier - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * + Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * + Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "test-obj.h" -#include "m-mempool.h" -#include "coverage.h" - -START_COVERAGE -MEMPOOL_DEF(mempool_uint, unsigned int) -END_COVERAGE - -MEMPOOL_DEF_AS(MempoolDouble, MempoolDouble, unsigned int) - -static void test(void) -{ - mempool_uint_t m; - mempool_uint_init(m); - - unsigned int *tab[100000]; - for(unsigned int i = 0; i < 100000; i++) { - tab[i] = mempool_uint_alloc(m); - *tab[i] = i; - } - for(unsigned int i = 0; i < 100000; i++) { - assert (*tab[i] == i); - } - for(unsigned int i = 0; i < 100000; i+=2) { - mempool_uint_free(m, tab[i]); - tab[i] = NULL; - } - for(unsigned int i = 1; i < 100000; i+=2) { - assert (*tab[i] == i); - } - for(unsigned int i = 0; i < 100000; i+=2) { - tab[i] = mempool_uint_alloc(m); - *tab[i] = i; - } - for(unsigned int i = 0; i < 100000; i++) { - assert (*tab[i] == i); - } - for(unsigned int i = 0; i < 100000; i++) { - mempool_uint_free(m, tab[i]); - tab[i] = NULL; - } - mempool_uint_clear(m); -} - -static void test_double(void) -{ - MempoolDouble m; - MempoolDouble_init(m); - - unsigned int *tab[100000]; - for(unsigned int i = 0; i < 100000; i++) { - tab[i] = MempoolDouble_alloc(m); - *tab[i] = i; - } - for(unsigned int i = 0; i < 100000; i++) { - assert (*tab[i] == i); - } - for(unsigned int i = 0; i < 100000; i+=2) { - MempoolDouble_free(m, tab[i]); - tab[i] = NULL; - } - for(unsigned int i = 1; i < 100000; i+=2) { - assert (*tab[i] == i); - } - for(unsigned int i = 0; i < 100000; i+=2) { - tab[i] = MempoolDouble_alloc(m); - *tab[i] = i; - } - for(unsigned int i = 0; i < 100000; i++) { - assert (*tab[i] == i); - } - for(unsigned int i = 0; i < 100000; i++) { - MempoolDouble_free(m, tab[i]); - tab[i] = NULL; - } - MempoolDouble_clear(m); -} - -int main(void) -{ - test(); - test_double(); - exit(0); -}