diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2021-07-22 17:52:54 +0100 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2021-07-22 17:52:54 +0100 |
commit | acaebca84fa1d81fd48fecf29ef9eb65f0707e5b (patch) | |
tree | 265a04fddb82a541821c42837ae398897fc867b6 | |
parent | fd044f4cf02a5cad4d023af5df375d1f124e31bd (diff) | |
download | rspamd-acaebca84fa1d81fd48fecf29ef9eb65f0707e5b.tar.gz rspamd-acaebca84fa1d81fd48fecf29ef9eb65f0707e5b.zip |
[Minor] Add weak ptr counterpart
-rw-r--r-- | src/libutil/cxx/local_shared_ptr.hxx | 128 | ||||
-rw-r--r-- | test/rspamd_cxx_unit_utils.hxx | 79 |
2 files changed, 205 insertions, 2 deletions
diff --git a/src/libutil/cxx/local_shared_ptr.hxx b/src/libutil/cxx/local_shared_ptr.hxx index 5a9cccb38..7eb5b0d9f 100644 --- a/src/libutil/cxx/local_shared_ptr.hxx +++ b/src/libutil/cxx/local_shared_ptr.hxx @@ -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 diff --git a/test/rspamd_cxx_unit_utils.hxx b/test/rspamd_cxx_unit_utils.hxx index be5d193f4..47e6c889b 100644 --- a/test/rspamd_cxx_unit_utils.hxx +++ b/test/rspamd_cxx_unit_utils.hxx @@ -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 |