From eba565a6359957a7ba5c3af645af36eefd58fbf3 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Tue, 16 Jul 2024 10:52:09 +0200 Subject: w --- compat/borrowed-ptr-fwd.hpp | 1 + compat/borrowed-ptr.cpp | 28 +++++++++- compat/borrowed-ptr.hpp | 66 ++++++++++++++++++---- compat/borrowed-ptr.inl | 60 +++++++++----------- compat/weak-borrowed-ptr.hpp | 45 +++++++++++++++ compat/weak-borrowed-ptr.inl | 129 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 281 insertions(+), 48 deletions(-) create mode 100644 compat/weak-borrowed-ptr.hpp create mode 100644 compat/weak-borrowed-ptr.inl diff --git a/compat/borrowed-ptr-fwd.hpp b/compat/borrowed-ptr-fwd.hpp index 6a3db763..8fcc5dde 100644 --- a/compat/borrowed-ptr-fwd.hpp +++ b/compat/borrowed-ptr-fwd.hpp @@ -5,6 +5,7 @@ namespace floormat { struct bptr_base; template class bptr; +template class weak_bptr; template bptr(T* ptr) -> bptr; template bptr(const T* ptr) -> bptr; diff --git a/compat/borrowed-ptr.cpp b/compat/borrowed-ptr.cpp index f6f098fa..3048e48a 100644 --- a/compat/borrowed-ptr.cpp +++ b/compat/borrowed-ptr.cpp @@ -4,15 +4,37 @@ namespace floormat::detail_bptr { void control_block::decrement(control_block*& blk) noexcept { - auto c = --blk->_count; + auto c2 = --blk->_hard_count; + fm_bptr_assert(c2 != (uint32_t)-1); + if (c2 == 0) + { + delete blk->_ptr; + blk->_ptr = nullptr; + } + + auto c = --blk->_soft_count; fm_bptr_assert(c != (uint32_t)-1); if (c == 0) { - delete blk->_ptr; + fm_bptr_assert(!blk->_ptr); + delete blk; + } + blk = nullptr; +} + +void control_block::weak_decrement(control_block*& blk) noexcept +{ + if (!blk) + return; + fm_bptr_assert(blk->_hard_count < blk->_soft_count); + auto c = --blk->_soft_count; + //fm_bptr_assert(c != (uint32_t)-1); + if (c == 0) + { + fm_bptr_assert(!blk->_ptr); delete blk; } blk = nullptr; - //blk = (control_block*)-1; } } // namespace floormat::detail_bptr diff --git a/compat/borrowed-ptr.hpp b/compat/borrowed-ptr.hpp index 92c1f761..62394087 100644 --- a/compat/borrowed-ptr.hpp +++ b/compat/borrowed-ptr.hpp @@ -2,6 +2,16 @@ #include "borrowed-ptr-fwd.hpp" #include +#define FM_BPTR_DEBUG + +#ifdef __CLION_IDE__ +#define fm_bptr_assert(...) (void(__VA_ARGS__)) +#elif defined FM_BPTR_DEBUG && !defined FM_NO_DEBUG +#define fm_bptr_assert(...) fm_assert(__VA_ARGS__) +#else +#define fm_bptr_assert(...) void() +#endif + namespace floormat { struct bptr_base; } namespace floormat::detail_bptr { @@ -9,19 +19,29 @@ namespace floormat::detail_bptr { struct control_block final { bptr_base* _ptr; - uint32_t _count; + uint32_t _soft_count, _hard_count; static void decrement(control_block*& blk) noexcept; + static void weak_decrement(control_block*& blk) noexcept; }; template concept StaticCastable = requires(From* from) { static_cast(from); + requires std::is_base_of_v, std::remove_cvref_t>; }; template concept DerivedFrom = requires(From* x) { - std::is_convertible_v; - std::is_convertible_v; +#if 0 + requires std::is_convertible_v; + requires std::is_convertible_v; + requires std::is_convertible_v; + requires std::is_base_of_v; + requires std::is_base_of_v; + requires std::is_base_of_v, std::remove_cvref_t>; +#else + static_cast(std::declval()); +#endif }; } // namespace floormat::detail_bptr @@ -50,7 +70,7 @@ class bptr final // NOLINT(*-special-member-functions) public: template - requires std::is_constructible_v, Ts&&...> + //requires std::is_constructible_v, Ts&&...> explicit bptr(InPlaceInitT, Ts&&... args) noexcept; template Y> explicit bptr(Y* ptr) noexcept; @@ -82,27 +102,49 @@ public: explicit operator bool() const noexcept; - bool operator==(const bptr>& other) const noexcept; - bool operator==(const bptr>& other) const noexcept; - bool operator==(const std::nullptr_t& other) const noexcept; - - std::strong_ordering operator<=>(const bptr>& other) const noexcept; - std::strong_ordering operator<=>(const bptr>& other) const noexcept; - std::strong_ordering operator<=>(const std::nullptr_t& other) const noexcept; + bool operator==(const bptr& other) const noexcept; + std::strong_ordering operator<=>(const bptr& other) const noexcept; template friend class bptr; + template friend class weak_bptr; + + template + requires detail_bptr::StaticCastable + friend bptr static_pointer_cast(bptr&& p) noexcept; template requires detail_bptr::StaticCastable friend bptr static_pointer_cast(const bptr& p) noexcept; }; +template bptr::bptr(std::nullptr_t) noexcept: blk{nullptr} {} + +template +requires detail_bptr::StaticCastable +bptr static_pointer_cast(bptr&& p) noexcept +{ + if (p.blk && p.blk->_ptr) [[likely]] + { + bptr ret{nullptr}; + ret.blk = p.blk; + p.blk = nullptr; + return ret; + } + return bptr{nullptr}; +} + template requires detail_bptr::StaticCastable bptr static_pointer_cast(const bptr& p) noexcept { if (p.blk && p.blk->_ptr) [[likely]] - return bptr{p}; + { + bptr ret{nullptr}; + ++p.blk->_soft_count; + ++p.blk->_hard_count; + ret.blk = p.blk; + return ret; + } return bptr{nullptr}; } diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl index 0abdea8f..2ffd1e92 100644 --- a/compat/borrowed-ptr.inl +++ b/compat/borrowed-ptr.inl @@ -2,43 +2,29 @@ #include "borrowed-ptr.hpp" #include "compat/assert.hpp" -#define FM_BPTR_DEBUG - -#ifdef __CLION_IDE__ -#define fm_bptr_assert(...) (void(__VA_ARGS__)) -#elif defined FM_BPTR_DEBUG && !defined FM_NO_DEBUG -#define fm_bptr_assert(...) fm_assert(__VA_ARGS__) -#else -#define fm_bptr_assert(...) void() -#endif - -#if 0 #ifdef __GNUG__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" -#endif #endif namespace floormat { template template -requires std::is_constructible_v, Ts&&...> +//requires std::is_constructible_v, Ts&&...> bptr::bptr(InPlaceInitT, Ts&&... args) noexcept: bptr{ new std::remove_const_t{ forward(args)... } } {} -template bptr::bptr(std::nullptr_t) noexcept: blk{nullptr} {} template bptr::bptr() noexcept: bptr{nullptr} {} template template Y> bptr::bptr(Y* ptr) noexcept: - blk{ptr ? new detail_bptr::control_block{const_cast*>(ptr), 1} : nullptr} + blk{ptr ? new detail_bptr::control_block{const_cast*>(ptr), 1, 1} : nullptr} {} -template bptr::~bptr() noexcept { if (blk) blk->decrement(blk); } +template bptr::~bptr() noexcept { if (blk) detail_bptr::control_block::decrement(blk); } template bptr::bptr(const bptr& other) noexcept: bptr{other, nullptr} {} template bptr::bptr(bptr&& other) noexcept: bptr{move(other), nullptr} {} @@ -67,15 +53,15 @@ template Y> bptr& bptr::operator=(bptr&& other) noexcept { return _move_assign(move(other)); } -template void bptr::reset() noexcept { if (blk) blk->decrement(blk); } +template void bptr::reset() noexcept { if (blk) detail_bptr::control_block::decrement(blk); } template template Y> void bptr::reset(Y* ptr) noexcept { if (blk) - blk->decrement(blk); - blk = ptr ? new detail_bptr::control_block{const_cast*>(ptr), 1} : nullptr; + detail_bptr::control_block::decrement(blk); + blk = ptr ? new detail_bptr::control_block{const_cast*>(ptr), 1, 1} : nullptr; } template @@ -95,7 +81,10 @@ bptr::bptr(const bptr& other, std::nullptr_t) noexcept: blk{other.blk} { if (blk) - ++blk->_count; + { + ++blk->_soft_count; + ++blk->_hard_count; + } } template @@ -113,10 +102,13 @@ bptr& bptr::_copy_assign(const bptr& other) noexcept if (blk != other.blk) { if (blk) - blk->decrement(blk); + detail_bptr::control_block::decrement(blk); blk = other.blk; if (blk) - ++blk->_count; + { + ++blk->_soft_count; + ++blk->_hard_count; + } } return *this; } @@ -126,7 +118,7 @@ template bptr& bptr::_move_assign(bptr&& other) noexcept { if (blk) - blk->decrement(blk); + detail_bptr::control_block::decrement(blk); blk = other.blk; other.blk = nullptr; return *this; @@ -153,13 +145,17 @@ template T& bptr::operator*() const noexcept { return *operator-> template bptr::operator bool() const noexcept { return blk && blk->_ptr; } -template bool bptr::operator==(const bptr>& other) const noexcept { return get() == other.get(); } -template bool bptr::operator==(const bptr>& other) const noexcept { return get() == other.get(); } -template bool bptr::operator==(const std::nullptr_t&) const noexcept { return !blk || !blk->_ptr; } +template +bool bptr::operator==(const bptr& other) const noexcept +{ + return !blk == !other.blk && blk->_ptr == other.blk->_ptr; +} -template std::strong_ordering bptr::operator<=>(const bptr>& other) const noexcept { return get() <=> other.get(); } -template std::strong_ordering bptr::operator<=>(const bptr>& other) const noexcept { return get() <=> other.get(); } -template std::strong_ordering bptr::operator<=>(const std::nullptr_t&) const noexcept { return get() <=> (T*)nullptr; } +template +std::strong_ordering bptr::operator<=>(const bptr& other) const noexcept +{ + return get() <=> other.get(); +} template void bptr::swap(bptr& other) noexcept { floormat::swap(blk, other.blk); } @@ -167,15 +163,13 @@ template uint32_t bptr::use_count() const noexcept { if (blk && blk->_ptr) [[likely]] - return blk->_count; + return blk->_hard_count; else return 0; } } // namespace floormat -#if 0 #ifdef __GNUG__ #pragma GCC diagnostic pop #endif -#endif diff --git a/compat/weak-borrowed-ptr.hpp b/compat/weak-borrowed-ptr.hpp new file mode 100644 index 00000000..ac512c5c --- /dev/null +++ b/compat/weak-borrowed-ptr.hpp @@ -0,0 +1,45 @@ +#pragma once +#include "borrowed-ptr.hpp" + +namespace floormat { + +template +class weak_bptr final +{ + detail_bptr::control_block* blk; + + static detail_bptr::control_block* _copy(detail_bptr::control_block* ptr); + weak_bptr& _copy_assign(detail_bptr::control_block* other) noexcept; + weak_bptr& _move_assign(detail_bptr::control_block*& other) noexcept; + +public: + weak_bptr(std::nullptr_t) noexcept; + weak_bptr& operator=(std::nullptr_t) noexcept; + weak_bptr() noexcept; + ~weak_bptr() noexcept; + + template Y> weak_bptr(const bptr& ptr) noexcept; + template Y> weak_bptr(const weak_bptr& ptr) noexcept; + weak_bptr(const weak_bptr& ptr) noexcept; + + template Y> weak_bptr& operator=(const bptr& ptr) noexcept; + template Y> weak_bptr& operator=(const weak_bptr& ptr) noexcept; + weak_bptr& operator=(const weak_bptr& ptr) noexcept; + + template Y> weak_bptr(weak_bptr&& ptr) noexcept; + weak_bptr(weak_bptr&& ptr) noexcept; + + template Y> weak_bptr& operator=(weak_bptr&& ptr) noexcept; + weak_bptr& operator=(weak_bptr&& ptr) noexcept; + + void reset() noexcept; + void swap(weak_bptr& other) noexcept; + + uint32_t use_count() const noexcept; + bool expired() const noexcept; + bptr lock() const noexcept; + + bool operator==(const weak_bptr& other) const noexcept; +}; + +} // namespace floormat diff --git a/compat/weak-borrowed-ptr.inl b/compat/weak-borrowed-ptr.inl new file mode 100644 index 00000000..bb040188 --- /dev/null +++ b/compat/weak-borrowed-ptr.inl @@ -0,0 +1,129 @@ +#pragma once +#include "weak-borrowed-ptr.hpp" + +#ifdef __GNUG__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +namespace floormat { + +template detail_bptr::control_block* weak_bptr::_copy(detail_bptr::control_block* ptr) +{ + if (ptr && ptr->_ptr) + { + ++ptr->_soft_count; + return ptr; + } + else + return nullptr; +} + +template +weak_bptr& weak_bptr::_copy_assign(detail_bptr::control_block* other) noexcept +{ + if (blk != other) + { + detail_bptr::control_block::weak_decrement(blk); + + if (other && other->_ptr) + { + ++other->_soft_count; + blk = other; + } + else + blk = nullptr; + } + return *this; +} + +template +weak_bptr& weak_bptr::_move_assign(detail_bptr::control_block*& other) noexcept +{ + detail_bptr::control_block::weak_decrement(blk); + blk = other; + other = nullptr; + return *this; +} + +template weak_bptr::weak_bptr(std::nullptr_t) noexcept: blk{nullptr} {} + +template +weak_bptr& weak_bptr::operator=(std::nullptr_t) noexcept +{ + detail_bptr::control_block::weak_decrement(blk); + return *this; +} + +template weak_bptr::weak_bptr() noexcept: weak_bptr{nullptr} {} + +template weak_bptr::~weak_bptr() noexcept +{ + detail_bptr::control_block::weak_decrement(blk); +} + +template template Y> weak_bptr::weak_bptr(const bptr& ptr) noexcept: blk{_copy(ptr.blk)} {} +template template Y> weak_bptr::weak_bptr(const weak_bptr& ptr) noexcept: blk{_copy(ptr.blk)} {} +template weak_bptr::weak_bptr(const weak_bptr& ptr) noexcept: blk{_copy(ptr.blk)} {} + +template template Y> weak_bptr& weak_bptr::operator=(const bptr& ptr) noexcept { return _copy_assign(ptr.blk); } +template template Y> weak_bptr& weak_bptr::operator=(const weak_bptr& ptr) noexcept { return _copy_assign(ptr.blk); } +template weak_bptr& weak_bptr::operator=(const weak_bptr& ptr) noexcept { return _copy_assign(ptr.blk); } + +template +template Y> +weak_bptr::weak_bptr(weak_bptr&& ptr) noexcept: blk{ptr.blk} +{ ptr.blk = nullptr; } + +template weak_bptr::weak_bptr(weak_bptr&& ptr) noexcept: blk{ptr.blk} +{ ptr.blk = nullptr; } + +template +template Y> +weak_bptr& weak_bptr::operator=(weak_bptr&& ptr) noexcept +{ return _move_assign(ptr.blk); } + +template weak_bptr& weak_bptr::operator=(weak_bptr&& ptr) noexcept { return _move_assign(ptr.blk); } + +template void weak_bptr::reset() noexcept +{ if (blk) detail_bptr::control_block::weak_decrement(blk); } + +template void weak_bptr::swap(weak_bptr& other) noexcept +{ floormat::swap(blk, other.blk); } + +template uint32_t weak_bptr::use_count() const noexcept +{ + if (blk && blk->_ptr) + return blk->_hard_count; + else + return 0; +} + +template bool weak_bptr::expired() const noexcept { return use_count() == 0; } + +template +bptr weak_bptr::lock() const noexcept +{ + if (blk && blk->_ptr) + { + fm_bptr_assert(blk->_hard_count > 0); + ++blk->_soft_count; + ++blk->_hard_count; + bptr ret{nullptr}; + ret.blk = blk; + return ret; + } + else + return bptr{nullptr}; +} + +template bool weak_bptr::operator==(const weak_bptr& other) const noexcept +{ + return lock().get() == other.lock().get(); +} + +} // namespace floormat + +#ifdef __GNUG__ +#pragma GCC diagnostic pop +#endif -- cgit v1.2.3