diff options
author | Frediano Ziglio <fziglio@redhat.com> | 2020-03-06 18:49:46 +0000 |
---|---|---|
committer | Frediano Ziglio <freddy77@gmail.com> | 2020-05-01 06:58:09 +0100 |
commit | bf04d7d721c939c058bb17d72c5d68a51ffe8b19 (patch) | |
tree | ed7197bbaac52ec04543475019804f05b03bffac | |
parent | 54c083091943f61a8ebe0b4d420c3311c37df3e6 (diff) |
utils: Very skinny share_ptr implementation for our references
It will be used to refactor reference counting code.
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r-- | server/utils.hpp | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/server/utils.hpp b/server/utils.hpp index 1712cbf1..dc4a36f0 100644 --- a/server/utils.hpp +++ b/server/utils.hpp @@ -20,6 +20,7 @@ #pragma once #include <memory> +#include <atomic> #include "push-visibility.h" @@ -94,6 +95,166 @@ constexpr size_t size(const T (&array)[N]) noexcept } +/* Basic shared pointer for internal reference + * + * Similar to STL version but using intrusive. This to allow creating multiple + * shared pointers from the raw pointer without problems having the object + * freed when one single set of shared pointer is removed. The code used + * to increment the reference to make sure the object was not deleted in + * some cases of self destruction. + * + * This class is inspired to boost::intrusive_ptr. + * + * To allow to reference and unrefered any object the object should + * define shared_ptr_add_ref and shared_ptr_unref, both taking a pointer and incrementing and + * decrementing respectively. You should not call these function yourselves. + */ +template <typename T> +class shared_ptr +{ +public: + explicit shared_ptr(T *p=nullptr): p(p) + { + if (p) { + shared_ptr_add_ref(p); + } + } + template <class Q> + explicit shared_ptr(Q *p): shared_ptr(static_cast<T*>(p)) + { + } + shared_ptr(const shared_ptr& rhs): p(rhs.p) + { + if (p) { + shared_ptr_add_ref(p); + } + } + template <class Q> + shared_ptr(const shared_ptr<Q>& rhs): shared_ptr(static_cast<T*>(rhs.get())) + { + } + shared_ptr& operator=(const shared_ptr& rhs) + { + if (rhs.p != p) { + reset(rhs.p); + } + return *this; + } + template <class Q> + shared_ptr& operator=(const shared_ptr<Q>& rhs) + { + reset(rhs.get()); + return *this; + } + shared_ptr(shared_ptr&& rhs): p(rhs.p) + { + rhs.p = nullptr; + } + shared_ptr& operator=(shared_ptr&& rhs) + { + if (p) { + shared_ptr_unref(p); + } + p = rhs.p; + rhs.p = nullptr; + return *this; + } + ~shared_ptr() + { + if (p) { + shared_ptr_unref(p); + } + } + void reset(T *ptr=nullptr) + { + if (ptr) { + shared_ptr_add_ref(ptr); + } + if (p) { + shared_ptr_unref(p); + } + p = ptr; + } + T *release() + { + T *ptr = p; + if (p) { + shared_ptr_unref(p); + p = nullptr; + } + return ptr; + } + operator bool() const + { + return p; + } + T& operator*() const noexcept + { + return *p; + } + T* operator->() const noexcept + { + return p; + } + T *get() const noexcept + { + return p; + } +private: + T* p; +}; + +template <class T, class O> +inline bool operator==(const shared_ptr<T>& a, const shared_ptr<O>& b) +{ + return a.get() == b.get(); +} + +template <class T, class O> +inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<O>& b) +{ + return a.get() != b.get(); +} + +/* Utility to help implementing shared_ptr requirement + * + * You should inherit publicly this class in order to have base internal reference counting + * implementation. + * + * This class uses aromic operations and virtual destructor so it's not really light. + */ +class shared_ptr_counted +{ +public: + SPICE_CXX_GLIB_ALLOCATOR + + shared_ptr_counted(): ref_count(0) + { + } +protected: + virtual ~shared_ptr_counted() {} +private: + std::atomic_int ref_count; + shared_ptr_counted(const shared_ptr_counted& rhs)=delete; + void operator=(const shared_ptr_counted& rhs)=delete; + friend inline void shared_ptr_add_ref(shared_ptr_counted*); + friend inline void shared_ptr_unref(shared_ptr_counted*); +}; + +// implements requirements for shared_ptr +inline void shared_ptr_add_ref(shared_ptr_counted* p) +{ + ++p->ref_count; +} + +inline void shared_ptr_unref(shared_ptr_counted* p) +{ + if (--p->ref_count == 0) { + delete p; + } +} + + } // namespace red #include "pop-visibility.h" |