/* Copyright 2005 Chris Thomasson */ #if ! defined(__cplusplus) #error C++ required! #elif ! defined(REFCOUNT_SYS_HPP_INCLUDED) #define REFCOUNT_SYS_HPP_INCLUDED #if defined(_MSC_VER) && (_MSC_VER < 1300) #pragma warning(disable : 4100 4505 4512 4514) #endif #include "refcount.h" #include // std::auto_ptr // refcount++ system C API extern "C" { static void vzsync_sys_refcount_dtor_capi(void*) throw(); static int vzsync_sys_refcount_error_capi(int) throw(); } // refcount++ system C++ API namespace vzsync { namespace sys { namespace refcount { template class ptr_base; template class userstate; static void libinit(); namespace capi { class impl_base; class userstate_base; class userstate_base { friend class impl; friend void ::vzsync_sys_refcount_dtor_capi(void*) throw(); private: mutable refcount_t m_rc; protected: userstate_base(int count) { int ret = ::refcount_init(&m_rc, count, ::vzsync_sys_refcount_dtor_capi, this); if (ret != REFCOUNT_BOOL_TRUE) { (void)::vzsync_sys_refcount_error_capi(ret); throw; } } virtual ~userstate_base() throw() {} private: static void dtor_capi(userstate_base *_this) throw() { try { delete _this; } catch(...) { assert(false); } } public: inline refcount_t const* load_naked() const { return &m_rc; } inline refcount_t* load_naked() { return &m_rc; } }; class impl_base { mutable refcount_t *m_rc; public: impl_base() throw() : m_rc(0) {} impl_base(refcount_t *rc) throw() : m_rc(rc) {} ~impl_base() throw() { (void)::refcount_sub_strong(m_rc, 1); } public: void ctor(refcount_t *rc) throw() { (void)swap_naked(rc); } public: inline refcount_t* load_naked() const throw() { return m_rc; } inline refcount_t* swap_naked(refcount_t *rhs) const throw() { refcount_t *oldrc = m_rc; const_cast(this)->m_rc = rhs; return oldrc; } public: inline void const* atomic_state_load_depends() const throw() { return ::refcount_state_load_depends(m_rc); } inline void* atomic_state_load_depends() throw() { return ::refcount_state_load_depends(m_rc); } public: inline refcount_t* atomic_add_load_strong(int count) const throw() { return ::refcount_add_load_strong(&m_rc, count); } inline refcount_t* atomic_add_swap_weak(refcount_t *rhs, int count) const throw() { return ::refcount_add_swap_weak(&m_rc, rhs, count); } inline void atomic_add_weak(int count) const throw() { if (m_rc) { // check for null in assembly! (void)::refcount_add_weak(m_rc, count); } } inline bool atomic_sub_strong(int count) const throw() { return (::refcount_sub_strong(m_rc, count) == REFCOUNT_BOOL_TRUE); } }; } // namespace capi template class userstate : public capi::userstate_base { friend class ptr_base; T* const m_state; public: userstate(T *state, int count) throw() : capi::userstate_base(count), m_state(state) { assert(m_state); } ~userstate() throw() { assert(m_state); try { delete m_state; } catch(...) { assert(false); } } }; template class ptr_base : private capi::impl_base { typedef userstate ustate_t; protected: ptr_base() throw() {} ptr_base(T *state, int count) { std::auto_ptr ustate(new ustate_t(state, count)); ctor(ustate->load_naked()); ustate.release(); } ~ptr_base() throw() {} protected: inline T* load_ptr() throw() { return static_cast*>(atomic_state_load_depends())->m_state; } inline T const* load_ptr() const throw() { return static_cast*>(atomic_state_load_depends())->m_state; } inline T& load_ref() { T *state = load_ptr(); if (! state) { assert(state); throw; } return *state; } inline T const& load_ref() const { T *state = load_ptr(); if (! state) { assert(state); throw; } return *state; } protected: inline void global_copy_global(ptr_base const &rhs, int count) const throw() { atomic_add_swap_weak(rhs.atomic_add_load_strong(count), 0); } inline void global_copy_local(ptr_base const &rhs, int count) const throw() { atomic_add_swap_weak(rhs.load_naked(), count); } inline void global_set_global(ptr_base const &rhs, int count) const throw() { capi::impl_base old(atomic_add_swap_weak(rhs.atomic_add_load_strong(count), 0)); } inline void global_set_local(ptr_base const &rhs, int count) const throw() { capi::impl_base old(atomic_add_swap_weak(rhs.load_naked(), count)); } protected: inline void local_copy_global(ptr_base const &rhs, int count) const throw() { swap_naked(rhs.atomic_add_load_strong(count)); } inline void local_copy_local(ptr_base const &rhs, int count) const throw() { rhs.atomic_add_weak(count); swap_naked(rhs.load_naked()); } inline void local_set_global(ptr_base const &rhs, int count) const throw() { capi::impl_base old(swap_naked(rhs.atomic_add_load_strong(count))); } inline void local_set_local(ptr_base const &rhs, int count) const throw() { rhs.atomic_add_weak(count); capi::impl_base old(swap_naked(rhs.load_naked())); } public: inline operator bool() const throw() { return (load_naked() != 0); } inline bool operator !() const throw() { return (load_naked() == 0); } inline bool operator ==(ptr_base const &rhs) const throw() { return (load_naked() == rhs.load_naked()); } inline bool operator !=(ptr_base const &rhs) const throw() { return (load_naked() != rhs.load_naked()); } inline bool operator >(ptr_base const &rhs) const throw() { return (load_naked() > rhs.load_naked()); } inline bool operator >=(ptr_base const &rhs) const throw() { return (load_naked() >= rhs.load_naked()); } inline bool operator <(ptr_base const &rhs) const throw() { return (load_naked() > rhs.load_naked()); } inline bool operator <=(ptr_base const &rhs) const throw() { return (load_naked() >= rhs.load_naked()); } }; void libinit() { ::refcount_libinit(); } }}} // namespace vzsync::sys::refcount // refcount C api extern "C" { void vzsync_sys_refcount_dtor_capi(void *state) throw() { typedef vzsync::sys::refcount::capi::userstate_base usbase_t; (void)usbase_t::dtor_capi(static_cast(state)); } int vzsync_sys_refcount_error_capi(int err) throw() { assert(err == REFCOUNT_BOOL_TRUE); return err; } } #endif