commit acaebca: [Minor] Add weak ptr counterpart

Vsevolod Stakhov vsevolod at highsecure.ru
Thu Jul 22 16:56:07 UTC 2021


Author: Vsevolod Stakhov
Date: 2021-07-22 17:52:54 +0100
URL: https://github.com/rspamd/rspamd/commit/acaebca84fa1d81fd48fecf29ef9eb65f0707e5b (HEAD -> master)

[Minor] Add weak ptr counterpart

---
 src/libutil/cxx/local_shared_ptr.hxx | 128 ++++++++++++++++++++++++++++++++++-
 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


More information about the Commits mailing list