]> source.dussan.org Git - rspamd.git/commitdiff
[Minor] Add weak ptr counterpart
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 22 Jul 2021 16:52:54 +0000 (17:52 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 22 Jul 2021 16:52:54 +0000 (17:52 +0100)
src/libutil/cxx/local_shared_ptr.hxx
test/rspamd_cxx_unit_utils.hxx

index 5a9cccb38fcb28082d2b05d5a887d24561ac14d5..7eb5b0d9faaaa954a1c3f02ad71ebff37923566f 100644 (file)
@@ -39,6 +39,9 @@ public:
        constexpr auto add_shared() -> refcount_t {
                return ++ref_shared;
        }
+       constexpr auto add_weak() -> refcount_t {
+               return ++ref_weak;
+       }
        constexpr auto release_shared() -> refcount_t {
                return --ref_shared;
        }
@@ -48,6 +51,9 @@ public:
        constexpr auto shared_count() const -> refcount_t {
                return ref_shared;
        }
+       constexpr auto weak_count() const -> refcount_t {
+               return ref_weak;
+       }
        virtual ~ref_cnt() {}
        virtual void dispose() = 0;
 private:
@@ -135,7 +141,11 @@ public:
                r.px = nullptr;
                r.cnt = nullptr;
        }
-       template<class Y> explicit local_shared_ptr(const local_weak_ptr<Y>& r);
+       template<class Y> explicit local_shared_ptr(const local_weak_ptr<Y>& r) : px(r.px), cnt(r.cnt) {
+               if (cnt) {
+                       cnt->add_shared();
+               }
+       }
        local_shared_ptr(nullptr_t) : local_shared_ptr() { }
 
        ~local_shared_ptr() {
@@ -143,7 +153,7 @@ public:
                        if (cnt->release_shared() <= 0) {
                                cnt->dispose();
 
-                               if (cnt->release_weak() <= 0) {
+                               if (cnt->weak_count() == 0) {
                                        delete cnt;
                                }
                        }
@@ -213,6 +223,7 @@ private:
 
        template<class _T, class ... Args>
        friend local_shared_ptr<_T> local_make_shared(Args && ... args);
+       friend class local_weak_ptr<T>;
 };
 
 template<class T, class ... Args>
@@ -226,6 +237,119 @@ local_shared_ptr<T> local_make_shared(Args && ... args)
        return ptr;
 }
 
+template<class T>
+class local_weak_ptr
+{
+public:
+       typedef T element_type;
+
+       // constructors
+       constexpr local_weak_ptr() noexcept : px(nullptr), cnt(nullptr) {}
+       template<class Y, typename std::enable_if<
+                       std::is_convertible<Y*, element_type*>::value, bool>::type = true>
+       local_weak_ptr(local_shared_ptr<Y> const& r) noexcept : px(r.px),cnt(r.cnt) {
+               if (cnt) {
+                       cnt->add_weak();
+               }
+       }
+
+       local_weak_ptr(local_weak_ptr const& r) noexcept : px(r.px),cnt(r.cnt) {
+               if (cnt) {
+                       cnt->add_weak();
+               }
+       }
+       local_weak_ptr(local_weak_ptr && r) noexcept : px(r.px), cnt(r.cnt) {
+               r.px = nullptr;
+               r.cnt = nullptr;
+       }
+
+       ~local_weak_ptr()
+       {
+               if (cnt) {
+                       if (cnt->release_weak() <= 0 && cnt->shared_count() == 0) {
+                               delete cnt;
+                       }
+               }
+       }
+
+       // assignment
+       local_weak_ptr& operator=(local_weak_ptr const& r) noexcept {
+               local_weak_ptr(r).swap(*this);
+               return *this;
+       }
+       local_weak_ptr& operator=(local_shared_ptr<T> const& r) noexcept {
+               local_weak_ptr(r).swap(*this);
+               return *this;
+       }
+
+       template<class Y, typename std::enable_if<
+                       std::is_convertible<Y*, element_type*>::value, bool>::type = true>
+       local_weak_ptr& operator=(local_weak_ptr<Y> const& r) noexcept {
+               local_weak_ptr(r).swap(*this);
+               return *this;
+       }
+       local_weak_ptr& operator=(local_weak_ptr&& r) noexcept {
+               local_weak_ptr(std::move(r)).swap(*this);
+               return *this;
+       }
+
+       // modifiers
+       void swap(local_weak_ptr& r) noexcept {
+               std::swap(this->cnt, r.cnt);
+               std::swap(this->px, r.px);
+       }
+       void reset() noexcept {
+               local_weak_ptr().swap(*this);
+       }
+
+       // observers
+       long use_count() const noexcept {
+               if (cnt) {
+                       return cnt->shared_count();
+               }
+               return 0;
+       }
+       bool expired() const noexcept {
+               if (cnt) {
+                       return cnt->shared_count() == 0;
+               }
+
+               return true;
+       }
+
+       local_shared_ptr<T> lock() const noexcept {
+               local_shared_ptr<T> tmp;
+               tmp.cnt = cnt;
+
+               if (cnt) {
+                       cnt->add_shared();
+                       tmp.px = px;
+               }
+
+               return tmp;
+       }
+private:
+       element_type* px;
+       detail::ref_cnt *cnt;
+};
+
+
+}
+
+/* Hashing stuff */
+namespace std {
+template <class T>
+struct hash<rspamd::local_shared_ptr<T>> {
+       inline size_t operator()(const rspamd::local_shared_ptr<T> &p) const noexcept {
+               return hash<T *>()(p.get());
+       }
+};
+template <class T>
+struct hash<rspamd::local_weak_ptr<T>> {
+       inline size_t operator()(const rspamd::local_weak_ptr<T> &p) const noexcept {
+               return hash<T *>()(p.get());
+       }
+};
 }
 
 #endif //RSPAMD_LOCAL_SHARED_PTR_HXX
index be5d193f48f86820231aceebe267148c723a11b9..47e6c889b63cfbbf36d48cdbf01db1d93260c993 100644 (file)
@@ -236,6 +236,85 @@ TEST_CASE("make_shared dtor") {
        CHECK(t == true);
 }
 
+TEST_CASE("shared_ptr dtor") {
+       bool t;
+
+       {
+               rspamd::local_shared_ptr<deleter_test> pi(new deleter_test{t});
+
+               CHECK((!pi ? false : true));
+               CHECK(!!pi);
+               CHECK(pi.get() != nullptr);
+               CHECK(pi.use_count() == 1);
+               CHECK(pi.unique());
+               CHECK(t == false);
+       }
+
+       CHECK(t == true);
+
+       {
+               rspamd::local_shared_ptr<deleter_test> pi(new deleter_test{t});
+
+               CHECK((!pi ? false : true));
+               CHECK(!!pi);
+               CHECK(pi.get() != nullptr);
+               CHECK(pi.use_count() == 1);
+               CHECK(pi.unique());
+               CHECK(t == false);
+
+               rspamd::local_shared_ptr<deleter_test> pi2(pi);
+               CHECK(pi2 == pi);
+               CHECK(pi.use_count() == 2);
+               pi.reset();
+               CHECK(!(pi2 == pi));
+               CHECK(pi2.use_count() == 1);
+               CHECK(t == false);
+
+               pi = pi2;
+               CHECK(pi2 == pi);
+               CHECK(pi.use_count() == 2);
+               CHECK(t == false);
+       }
+
+       CHECK(t == true);
+}
+
+TEST_CASE("weak_ptr") {
+       bool t;
+
+       {
+               rspamd::local_shared_ptr<deleter_test> pi(new deleter_test{t});
+
+               CHECK((!pi ? false : true));
+               CHECK(!!pi);
+               CHECK(pi.get() != nullptr);
+               CHECK(pi.use_count() == 1);
+               CHECK(pi.unique());
+               CHECK(t == false);
+
+               rspamd::local_weak_ptr<deleter_test> wp(pi);
+               CHECK(wp.lock().get() != nullptr);
+               CHECK(pi.use_count() == 1);
+               CHECK(wp.use_count() == 1);
+               pi.reset();
+               CHECK(pi.use_count() == 0);
+               CHECK(wp.use_count() == 0);
+       }
+
+       CHECK(t == true);
+
+       rspamd::local_weak_ptr<deleter_test> wp;
+       {
+               rspamd::local_shared_ptr<deleter_test> pi(new deleter_test{t});
+               wp = pi;
+               CHECK(!wp.expired());
+               CHECK(wp.lock().get() != nullptr);
+       }
+
+       CHECK(t == true);
+       CHECK(wp.expired());
+}
+
 }
 
 #endif