Remove obsolete m-shared.h header

This commit is contained in:
Patrick Pelissier committed 2025-05-07 21:34:18 +02:00
1 parent 790ae33334
commit 2296f203fd
5 files changed
+2 -974

No files matched your search

-171
View File
@@ -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
+2
View File
@@ -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
-1
View File
@@ -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"
-555
View File
@@ -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
-247
View File
@@ -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);
}