mlib icon indicating copy to clipboard operation
mlib copied to clipboard

New Shared Pointer interface

Open P-p-H-d opened this issue 1 year ago • 0 comments

Here is the proposal for the new shared pointer interface. It will put m-shared, m-i-shared and m-concurrent as obsolete headers. It provides:

  • optional full encapsulation of the data between header and C file by default,
  • user select level of concurrency protection for the data (like m-concurrent)
  • shared pointer semantic as pure pointer (like m-i-shared)

Note: Header definition doesn't need to provide a working oplist: only the types are needed and the existence of methods are only tested here.

// 3 Cases:
// * atomic_int + lock		:	SHARED_STRONG_PTR
// * atomic_int + no lock	:	SHARED_PTR
// * int + no lock		:	SHARED_WEAK_PTR

// For each case, 3 macros:

// Only declare functions (For header file)
SHARED_PTR_DECL(shared, shared_t, oplist)

// Declare & definition as static inline
SHARED_PTR_DEF(name, type, oplist)

// Definition only (For C file)
SHARED_PTR_DEF_EXTERN(name, type, oplist)

// Header define only:
typedef struct shared_s shared_t;

// C define as:
struct shared_s {
  atomic_int cpt;  // Or int
  mlock      lock; // Optional
  cond       cond; // Optional
  type       data;
};

// 
shared_t *shared_new(void);   				// If INIT
shared_t *shared_new_copy(const shared_t *); 		// If INIT_SET
void	  shared_copy(shared_t *, const shared_t *); 	// If SET
shared_t *shared_acquire_owner(shared_t *);
void      shared_release_owner(shared_t *);
void      shared_clear(shared *);                       // Same as shared_release_owner
shared_t *shared_make[_...](... [EMPLACE_TYPE] ... );	// If EMPLACE_TYPE

void      shared_swap(shared_t *, shared_t *);          // If SWAP
void      shared_reset(shared_t*);                      // If RESET
bool      shared_empty_p(const shared_t*);		// If EMPTY_P
size_t    shared_size(const shared_t*); 		// If GET_SIZE
bool      shared_equal_p(const shared_t*, const shared_t*); // If EQUAL
size_t    shared_hash(const shared_t*); 		// If HASH
int       shared_cmp(const shared_t*,const shared_t*); 	// If CMP

void      shared_add(shared_t *, const shared_t *);      // If ADD
void      shared_sub(shared_t *, const shared_t *);      // If SUB
void      shared_mul(shared_t *, const shared_t *);      // If MUL
void      shared_div(shared_t *, const shared_t *);      // If DIV

// Map interface if KEY_TYPE / VALUE_TYPE & GET_KEY / SAFE_GET_KEY / SET_KEY / ERASE_KEY
bool M_F(name, _get_key)(value_type *value, shared_t *, const key_type key);
void M_F(name, _safe_get_key)(value_type *value, shared_t *, const key_type key);
void M_F(name, _set_key))(shared_t *, const key_type key, const value_type value);
bool M_F(name, _erase_key)(shared_t *, const key_type key);

// Push interface if SUBTYPE & PUSH / PUSH_MOVE / POP / POP_MOVE
void M_F(name, _push)(shared_t *, subtype obj);
void M_F(name, _push_move)(shared_t *, subtype *obj);
bool M_F(name, _try_push)(shared_t *, subtype obj);
bool M_F(name, _try_push_move)(shared_t *, subtype *obj);
void M_F(name, _emplace_ ...)(shared_t *, ...); // If OPLIST.EMPLACE_TYPE
bool M_F(name, _try_emplace_ ...)(shared_t *, ...); // If OPLIST.EMPLACE_TYPE
void M_F(name, _pop)(subtype *obj, shared_t *);
bool M_F(name, _try_pop)(subtype *obj, shared_t *);
void M_F(name, _pop_move)(subtype *obj, shared_t *);
bool M_F(name, _try_pop_move)(subtype *obj, shared_t *);

// Iterators if IT_TYPE
// For each element from FIRST LAST, apply callback and break if callback returns false
// Return true if all elements have been scanned, false otherwise
bool M_F(name, _apply)(shared_t*, bool(*callback)(void *data, subtype*), void *data);
bool M_F(name, _for_each)(shared_t*, bool(*callback)(void *data, const subtype*), void *data);
// If IT_PREVIOUS & IT_LAST
// For each element from LAST to FIRST, apply callback and break if callback returns false
// Return true if all elements have been scanned, false otherwise
bool M_F(name, _apply_reverse)(shared_t*, bool(*callback)(void *data, subtype*), void *data);
bool M_F(name, _for_each_reverse)(shared_t*, bool(*callback)(void *data, const subtype*), void *data);

// IO
void M_F(name, _out_str)(FILE *, shared_t *);
bool M_F(name, _in_str)(shared_t *, FILE *);
void M_F(name, _get_str)(string_t, shared_t *, bool append);
bool M_F(name, _parse_str)(shared_t *, const char cstr[], const char **e);
m_serial_return_code_t M_F(name, _out_serial)(m_serial_write_t f, shared_t *);
m_serial_return_code_t M_F(name, _in_serial)(shared_t *, m_serial_write_t f);

// Not exported:
void M_F(name, _read_lock)(shared_t *);
void M_F(name, _read_wait)(shared_t *);
void M_F(name, _read_unlock)(shared_t *);
void M_F(name, _write_lock)(shared_t *);
void M_F(name, _write_wait)(shared_t *);
void M_F(name, _write_signal)(shared_t *);
void M_F(name, _write_unlock)(shared_t *);

type *M_F(name, _ref)(shared_t *);
const type *M_F(name, _cref)(shared_t *);

// 2 OPLISTS
SHARED_PTR_OPLIST // Oplist where the data is the shared pointer itself (acquire / release)
SHARED_OBJ_OPLIST // Oplist where the data is the shared object (object copy)

Don't hesitate to comment on the interface.

P-p-H-d avatar Oct 12 '24 13:10 P-p-H-d