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); -}