mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-18 19:03:16 +00:00
554 lines
37 KiB
C
554 lines
37 KiB
C
/*
|
|
* M*LIB - SHARED Pointer Module
|
|
*
|
|
* Copyright (c) 2017-2023, 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"
|
|
|
|
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)) \
|
|
)
|
|
|
|
// 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); \
|
|
\
|
|
typedef struct M_F(name, _combine_s) { \
|
|
struct M_F(name, _s) ptr; \
|
|
type data; \
|
|
} M_F(name, combine_ct)[1]; \
|
|
|
|
/* 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(sizeof(struct M_F(name, _s))); \
|
|
return; \
|
|
} \
|
|
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(sizeof(struct M_F(name, _combine_s))); \
|
|
return; \
|
|
} \
|
|
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(sizeof(struct M_F(name, _combine_s))); \
|
|
return; \
|
|
} \
|
|
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, n); \
|
|
if (M_UNLIKELY_NOMEM (s->buffer == NULL)) { \
|
|
M_MEMORY_FULL(sizeof(M_F(name, _atype_ct)) * n); \
|
|
return; \
|
|
} \
|
|
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, s->buffer); \
|
|
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
|