summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2020-03-06 18:49:46 +0000
committerFrediano Ziglio <freddy77@gmail.com>2020-05-01 06:58:09 +0100
commitbf04d7d721c939c058bb17d72c5d68a51ffe8b19 (patch)
treeed7197bbaac52ec04543475019804f05b03bffac
parent54c083091943f61a8ebe0b4d420c3311c37df3e6 (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.hpp161
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"