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;
}
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:
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() {
if (cnt->release_shared() <= 0) {
cnt->dispose();
- if (cnt->release_weak() <= 0) {
+ if (cnt->weak_count() == 0) {
delete cnt;
}
}
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>
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
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