mlib
mlib copied to clipboard
New Shared Pointer interface
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.