From 92d60403f3de094dc2d040a7fce869a5bb60695a Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 4 May 2024 22:57:32 +0200 Subject: a --- compat/borrowed-ptr-fwd.hpp | 42 +++++++++++++++++------ compat/borrowed-ptr.cpp | 2 +- compat/borrowed-ptr.inl | 84 ++++++++++++++++++++++++++++----------------- test/bptr.cpp | 52 ++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 43 deletions(-) diff --git a/compat/borrowed-ptr-fwd.hpp b/compat/borrowed-ptr-fwd.hpp index 465e9bf4..01dd20f7 100644 --- a/compat/borrowed-ptr-fwd.hpp +++ b/compat/borrowed-ptr-fwd.hpp @@ -1,6 +1,15 @@ #pragma once -namespace floormat::detail_borrowed_ptr { struct control_block_; } +namespace floormat::detail_borrowed_ptr { + +struct control_block; +template +concept DerivedFrom = requires(From* x) { + requires !std::is_same_v; + requires std::is_nothrow_convertible_v; +}; + +} // namespace floormat::detail_borrowed_ptr namespace floormat { @@ -11,26 +20,39 @@ template class bptr final // NOLINT(*-special-member-functions) { mutable T* casted_ptr; - detail_borrowed_ptr::control_block_* blk; + detail_borrowed_ptr::control_block* blk; - explicit bptr(DirectInitT, T* casted_ptr, detail_borrowed_ptr::control_block_* blk) noexcept; - //explicit bptr(NoInitT) noexcept; + explicit bptr(DirectInitT, T* casted_ptr, detail_borrowed_ptr::control_block* blk) noexcept; + + struct private_tag_t final {}; + static constexpr private_tag_t private_tag{}; + + template bptr(const bptr& other, private_tag_t) noexcept; + template bptr& _copy_assign(const bptr& other) noexcept; + template bptr(bptr&& other, private_tag_t) noexcept; + template bptr& _move_assign(bptr&& other) noexcept; public: template requires std::is_constructible_v explicit bptr(InPlaceInitT, Ts&&... args) noexcept; - bptr(std::nullptr_t) noexcept; // NOLINT(*-explicit-conversions) - bptr() noexcept; explicit bptr(T* ptr) noexcept; + bptr() noexcept; ~bptr() noexcept; + bptr(std::nullptr_t) noexcept; // NOLINT(*-explicit-conversions) bptr& operator=(std::nullptr_t) noexcept; - template requires std::is_convertible_v bptr(const bptr&) noexcept; - template requires std::is_convertible_v bptr& operator=(const bptr&) noexcept; - template requires std::is_convertible_v bptr(bptr&&) noexcept; - template requires std::is_convertible_v bptr& operator=(bptr&&) noexcept; + + bptr(const bptr&) noexcept; + bptr& operator=(const bptr&) noexcept; + template Y> bptr(const bptr&) noexcept; + template Y> bptr& operator=(const bptr&) noexcept; + + bptr(bptr&&) noexcept; + bptr& operator=(bptr&&) noexcept; + template Y> bptr(bptr&&) noexcept; + template Y> bptr& operator=(bptr&&) noexcept; friend bool operator==(const bptr& a, const bptr& b) noexcept; explicit operator bool() const noexcept; diff --git a/compat/borrowed-ptr.cpp b/compat/borrowed-ptr.cpp index 413527cb..a73b869f 100644 --- a/compat/borrowed-ptr.cpp +++ b/compat/borrowed-ptr.cpp @@ -13,7 +13,7 @@ namespace floormat::detail_borrowed_ptr { #pragma warning(push) #pragma warning(disable : 5205) #endif -void control_block_::decrement(control_block_*& blk) noexcept +void control_block::decrement(control_block*& blk) noexcept { fm_bptr_assert(blk); auto c = --blk->_count; diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl index fd2d25d2..98e0fec5 100644 --- a/compat/borrowed-ptr.inl +++ b/compat/borrowed-ptr.inl @@ -1,6 +1,7 @@ #pragma once #include "borrowed-ptr.hpp" #include "compat/assert.hpp" +#include #define FM_BPTR_DEBUG @@ -21,22 +22,22 @@ namespace floormat::detail_borrowed_ptr { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" #endif -struct control_block_ +struct control_block { void* _ptr; // todo maybe add directly embeddable objects? uint32_t _count; virtual void free_ptr() noexcept = 0; - static void decrement(control_block_*& blk) noexcept; + static void decrement(control_block*& blk) noexcept; }; #ifdef __GNUG__ #pragma GCC diagnostic pop #endif template -struct control_block_impl final: control_block_ +struct control_block_impl final: control_block { void free_ptr() noexcept override; - [[nodiscard]] static control_block_* create(T* ptr) noexcept; + [[nodiscard]] static control_block* create(T* ptr) noexcept; protected: explicit control_block_impl(T* ptr) noexcept; }; @@ -56,7 +57,7 @@ void control_block_impl::free_ptr() noexcept } template -control_block_* control_block_impl::create(T* ptr) noexcept +control_block* control_block_impl::create(T* ptr) noexcept { if (ptr) { @@ -71,12 +72,10 @@ control_block_* control_block_impl::create(T* ptr) noexcept namespace floormat { -template bptr::bptr(DirectInitT, T* casted_ptr, detail_borrowed_ptr::control_block_* blk) noexcept: +template bptr::bptr(DirectInitT, T* casted_ptr, detail_borrowed_ptr::control_block* blk) noexcept: casted_ptr{casted_ptr}, blk{blk} {} -//template bptr::bptr(NoInitT) noexcept {} - template template requires std::is_constructible_v @@ -103,28 +102,29 @@ bptr::~bptr() noexcept blk->decrement(blk); } +template bptr::bptr(const bptr& other) noexcept: bptr{other, private_tag} {} +template bptr& bptr::operator=(const bptr& other) noexcept { return _copy_assign(other); } + template -template -requires std::is_convertible_v -bptr::bptr(const bptr& other) noexcept: - casted_ptr{other.casted_ptr}, blk{other.blk} -{ - if (blk) - { - ++blk->_count; - fm_bptr_assert(blk->_count > 1); - } -} +template Y> +bptr::bptr(const bptr& other) noexcept: bptr{other, private_tag} {} template -template -requires std::is_convertible_v -bptr::bptr(bptr&& other) noexcept: - casted_ptr{other.casted_ptr}, blk{other.blk} -{ - other.casted_ptr = nullptr; - other.blk = nullptr; -} +template Y> +bptr& bptr::operator=(const bptr& other) noexcept +{ return _copy_assign(other); } + +template bptr& bptr::operator=(bptr&& other) noexcept { return _move_assign(move(other)); } +template bptr::bptr(bptr&& other) noexcept: bptr{move(other), private_tag} {} + +template +template Y> +bptr::bptr(bptr&& other) noexcept: bptr{move(other), private_tag} {} + +template +template Y> +bptr& bptr::operator=(bptr&& other) noexcept +{ return _move_assign(move(other)); } template void bptr::reset() noexcept @@ -153,8 +153,19 @@ template bptr& bptr::operator=(std::nullptr_t) noexcept { rese template template -requires std::is_convertible_v -bptr& bptr::operator=(const bptr& other) noexcept +bptr::bptr(const bptr& other, private_tag_t) noexcept: + casted_ptr{other.casted_ptr}, blk{other.blk} +{ + if (blk) + { + ++blk->_count; + fm_bptr_assert(blk->_count > 1); + } +} + +template +template +bptr& bptr::_copy_assign(const bptr& other) noexcept { if (blk != other.blk) { @@ -170,10 +181,19 @@ bptr& bptr::operator=(const bptr& other) noexcept template template -requires std::is_convertible_v -bptr& bptr::operator=(bptr&& other) noexcept +bptr::bptr(bptr&& other, private_tag_t) noexcept: + casted_ptr{other.casted_ptr}, blk{other.blk} { - blk->decrement(blk); + other.casted_ptr = nullptr; + other.blk = nullptr; +} + +template +template +bptr& bptr::_move_assign(bptr&& other) noexcept +{ + if (blk) + blk->decrement(blk); casted_ptr = other.casted_ptr; blk = other.blk; other.casted_ptr = nullptr; diff --git a/test/bptr.cpp b/test/bptr.cpp index 99d6cd2c..6f823344 100644 --- a/test/bptr.cpp +++ b/test/bptr.cpp @@ -39,8 +39,59 @@ template bptr static_pointer_cast(const bptr&) noexcept; namespace { +int A_total = 0, A_alive = 0; // NOLINT + +struct A +{ + int val, serial; + explicit A(int val) : val{val}, serial{++A_total} { ++A_alive; } + ~A() noexcept { --A_alive; fm_assert(A_alive >= 0); } +}; + void test1() { + A_total = 0; A_alive = 0; + + auto p1 = bptr{InPlace, 1}; + fm_assert(p1.use_count() == 1); + fm_assert(p1.get()); + fm_assert(A_total == 1); + fm_assert(A_alive == 1); + + p1 = nullptr; + fm_assert(p1.use_count() == 0); + fm_assert(!p1.get()); + fm_assert(A_total == 1); + fm_assert(A_alive == 0); +} + +void test2() +{ + A_total = 0; A_alive = 0; + + auto p1 = bptr{InPlace, 2}; + auto p2 = p1; + + fm_assert(p1.get()); + fm_assert(p1.get() == p2.get()); + fm_assert(p1->val == 2); + fm_assert(p1->serial == 1); + fm_assert(A_total == 1); + fm_assert(A_alive == 1); + + p1 = nullptr; + fm_assert(!p1.get()); + fm_assert(p2.get()); + fm_assert(p2->val == 2); + fm_assert(p2->serial == 1); + fm_assert(A_total == 1); + fm_assert(A_alive == 1); + + p2 = nullptr; + fm_assert(!p1.get()); + fm_assert(!p2.get()); + fm_assert(A_total == 1); + fm_assert(A_alive == 0); } } // namespace @@ -48,6 +99,7 @@ void test1() void test_app::test_bptr() { test1(); + test2(); } } // namespace floormat -- cgit v1.2.3