diff options
-rw-r--r-- | compat/borrowed-ptr-fwd.hpp | 1 | ||||
-rw-r--r-- | compat/borrowed-ptr.cpp | 28 | ||||
-rw-r--r-- | compat/borrowed-ptr.hpp | 66 | ||||
-rw-r--r-- | compat/borrowed-ptr.inl | 60 | ||||
-rw-r--r-- | compat/weak-borrowed-ptr.hpp | 45 | ||||
-rw-r--r-- | compat/weak-borrowed-ptr.inl | 129 |
6 files changed, 281 insertions, 48 deletions
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<typename T> class bptr; +template<typename T> class weak_bptr; template<typename T> bptr(T* ptr) -> bptr<T>; template<typename T> bptr(const T* ptr) -> bptr<const T>; 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 <compare> +#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<typename From, typename To> concept StaticCastable = requires(From* from) { static_cast<To*>(from); + requires std::is_base_of_v<std::remove_cvref_t<From>, std::remove_cvref_t<To>>; }; template<typename From, typename To> concept DerivedFrom = requires(From* x) { - std::is_convertible_v<From*, To*>; - std::is_convertible_v<From*, const bptr_base*>; +#if 0 + requires std::is_convertible_v<From*, To*>; + requires std::is_convertible_v<From*, const bptr_base*>; + requires std::is_convertible_v<To*, const bptr_base*>; + requires std::is_base_of_v<bptr_base, From>; + requires std::is_base_of_v<bptr_base, To>; + requires std::is_base_of_v<std::remove_cvref_t<To>, std::remove_cvref_t<From>>; +#else + static_cast<To*>(std::declval<From*>()); +#endif }; } // namespace floormat::detail_bptr @@ -50,7 +70,7 @@ class bptr final // NOLINT(*-special-member-functions) public: template<typename... Ts> - requires std::is_constructible_v<std::remove_const_t<T>, Ts&&...> + //requires std::is_constructible_v<std::remove_const_t<T>, Ts&&...> explicit bptr(InPlaceInitT, Ts&&... args) noexcept; template<detail_bptr::DerivedFrom<T> Y> explicit bptr(Y* ptr) noexcept; @@ -82,27 +102,49 @@ public: explicit operator bool() const noexcept; - bool operator==(const bptr<const std::remove_const_t<T>>& other) const noexcept; - bool operator==(const bptr<std::remove_const_t<T>>& other) const noexcept; - bool operator==(const std::nullptr_t& other) const noexcept; - - std::strong_ordering operator<=>(const bptr<const std::remove_const_t<T>>& other) const noexcept; - std::strong_ordering operator<=>(const bptr<std::remove_const_t<T>>& other) const noexcept; - std::strong_ordering operator<=>(const std::nullptr_t& other) const noexcept; + bool operator==(const bptr<const T>& other) const noexcept; + std::strong_ordering operator<=>(const bptr<const T>& other) const noexcept; template<typename U> friend class bptr; + template<typename U> friend class weak_bptr; + + template<typename To, typename From> + requires detail_bptr::StaticCastable<From, To> + friend bptr<To> static_pointer_cast(bptr<From>&& p) noexcept; template<typename To, typename From> requires detail_bptr::StaticCastable<From, To> friend bptr<To> static_pointer_cast(const bptr<From>& p) noexcept; }; +template<typename T> bptr<T>::bptr(std::nullptr_t) noexcept: blk{nullptr} {} + +template<typename To, typename From> +requires detail_bptr::StaticCastable<From, To> +bptr<To> static_pointer_cast(bptr<From>&& p) noexcept +{ + if (p.blk && p.blk->_ptr) [[likely]] + { + bptr<To> ret{nullptr}; + ret.blk = p.blk; + p.blk = nullptr; + return ret; + } + return bptr<To>{nullptr}; +} + template<typename To, typename From> requires detail_bptr::StaticCastable<From, To> bptr<To> static_pointer_cast(const bptr<From>& p) noexcept { if (p.blk && p.blk->_ptr) [[likely]] - return bptr<To>{p}; + { + bptr<To> ret{nullptr}; + ++p.blk->_soft_count; + ++p.blk->_hard_count; + ret.blk = p.blk; + return ret; + } return bptr<To>{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<typename T> template<typename... Ts> -requires std::is_constructible_v<std::remove_const_t<T>, Ts&&...> +//requires std::is_constructible_v<std::remove_const_t<T>, Ts&&...> bptr<T>::bptr(InPlaceInitT, Ts&&... args) noexcept: bptr{ new std::remove_const_t<T>{ forward<Ts>(args)... } } {} -template<typename T> bptr<T>::bptr(std::nullptr_t) noexcept: blk{nullptr} {} template<typename T> bptr<T>::bptr() noexcept: bptr{nullptr} {} template<typename T> template<detail_bptr::DerivedFrom<T> Y> bptr<T>::bptr(Y* ptr) noexcept: - blk{ptr ? new detail_bptr::control_block{const_cast<std::remove_const_t<Y>*>(ptr), 1} : nullptr} + blk{ptr ? new detail_bptr::control_block{const_cast<std::remove_const_t<Y>*>(ptr), 1, 1} : nullptr} {} -template<typename T> bptr<T>::~bptr() noexcept { if (blk) blk->decrement(blk); } +template<typename T> bptr<T>::~bptr() noexcept { if (blk) detail_bptr::control_block::decrement(blk); } template<typename T> bptr<T>::bptr(const bptr& other) noexcept: bptr{other, nullptr} {} template<typename T> bptr<T>::bptr(bptr&& other) noexcept: bptr{move(other), nullptr} {} @@ -67,15 +53,15 @@ template<detail_bptr::DerivedFrom<T> Y> bptr<T>& bptr<T>::operator=(bptr<Y>&& other) noexcept { return _move_assign(move(other)); } -template<typename T> void bptr<T>::reset() noexcept { if (blk) blk->decrement(blk); } +template<typename T> void bptr<T>::reset() noexcept { if (blk) detail_bptr::control_block::decrement(blk); } template<typename T> template<detail_bptr::DerivedFrom<T> Y> void bptr<T>::reset(Y* ptr) noexcept { if (blk) - blk->decrement(blk); - blk = ptr ? new detail_bptr::control_block{const_cast<std::remove_const_t<Y>*>(ptr), 1} : nullptr; + detail_bptr::control_block::decrement(blk); + blk = ptr ? new detail_bptr::control_block{const_cast<std::remove_const_t<Y>*>(ptr), 1, 1} : nullptr; } template<typename T> @@ -95,7 +81,10 @@ bptr<T>::bptr(const bptr<Y>& other, std::nullptr_t) noexcept: blk{other.blk} { if (blk) - ++blk->_count; + { + ++blk->_soft_count; + ++blk->_hard_count; + } } template<typename T> @@ -113,10 +102,13 @@ bptr<T>& bptr<T>::_copy_assign(const bptr<Y>& 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<typename Y> bptr<T>& bptr<T>::_move_assign(bptr<Y>&& 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<typename T> T& bptr<T>::operator*() const noexcept { return *operator-> template<typename T> bptr<T>::operator bool() const noexcept { return blk && blk->_ptr; } -template<typename T> bool bptr<T>::operator==(const bptr<const std::remove_const_t<T>>& other) const noexcept { return get() == other.get(); } -template<typename T> bool bptr<T>::operator==(const bptr<std::remove_const_t<T>>& other) const noexcept { return get() == other.get(); } -template<typename T> bool bptr<T>::operator==(const std::nullptr_t&) const noexcept { return !blk || !blk->_ptr; } +template<typename T> +bool bptr<T>::operator==(const bptr<const T>& other) const noexcept +{ + return !blk == !other.blk && blk->_ptr == other.blk->_ptr; +} -template<typename T> std::strong_ordering bptr<T>::operator<=>(const bptr<const std::remove_const_t<T>>& other) const noexcept { return get() <=> other.get(); } -template<typename T> std::strong_ordering bptr<T>::operator<=>(const bptr<std::remove_const_t<T>>& other) const noexcept { return get() <=> other.get(); } -template<typename T> std::strong_ordering bptr<T>::operator<=>(const std::nullptr_t&) const noexcept { return get() <=> (T*)nullptr; } +template<typename T> +std::strong_ordering bptr<T>::operator<=>(const bptr<const T>& other) const noexcept +{ + return get() <=> other.get(); +} template<typename T> void bptr<T>::swap(bptr& other) noexcept { floormat::swap(blk, other.blk); } @@ -167,15 +163,13 @@ template<typename T> uint32_t bptr<T>::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<typename T> +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<detail_bptr::DerivedFrom<T> Y> weak_bptr(const bptr<Y>& ptr) noexcept; + template<detail_bptr::DerivedFrom<T> Y> weak_bptr(const weak_bptr<Y>& ptr) noexcept; + weak_bptr(const weak_bptr& ptr) noexcept; + + template<detail_bptr::DerivedFrom<T> Y> weak_bptr& operator=(const bptr<Y>& ptr) noexcept; + template<detail_bptr::DerivedFrom<T> Y> weak_bptr& operator=(const weak_bptr<Y>& ptr) noexcept; + weak_bptr& operator=(const weak_bptr& ptr) noexcept; + + template<detail_bptr::DerivedFrom<T> Y> weak_bptr(weak_bptr<Y>&& ptr) noexcept; + weak_bptr(weak_bptr&& ptr) noexcept; + + template<detail_bptr::DerivedFrom<T> Y> weak_bptr& operator=(weak_bptr<Y>&& 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<T> lock() const noexcept; + + bool operator==(const weak_bptr<const T>& 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<typename T> detail_bptr::control_block* weak_bptr<T>::_copy(detail_bptr::control_block* ptr) +{ + if (ptr && ptr->_ptr) + { + ++ptr->_soft_count; + return ptr; + } + else + return nullptr; +} + +template<typename T> +weak_bptr<T>& weak_bptr<T>::_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<typename T> +weak_bptr<T>& weak_bptr<T>::_move_assign(detail_bptr::control_block*& other) noexcept +{ + detail_bptr::control_block::weak_decrement(blk); + blk = other; + other = nullptr; + return *this; +} + +template<typename T> weak_bptr<T>::weak_bptr(std::nullptr_t) noexcept: blk{nullptr} {} + +template<typename T> +weak_bptr<T>& weak_bptr<T>::operator=(std::nullptr_t) noexcept +{ + detail_bptr::control_block::weak_decrement(blk); + return *this; +} + +template<typename T> weak_bptr<T>::weak_bptr() noexcept: weak_bptr{nullptr} {} + +template<typename T> weak_bptr<T>::~weak_bptr() noexcept +{ + detail_bptr::control_block::weak_decrement(blk); +} + +template<typename T> template<detail_bptr::DerivedFrom<T> Y> weak_bptr<T>::weak_bptr(const bptr<Y>& ptr) noexcept: blk{_copy(ptr.blk)} {} +template<typename T> template<detail_bptr::DerivedFrom<T> Y> weak_bptr<T>::weak_bptr(const weak_bptr<Y>& ptr) noexcept: blk{_copy(ptr.blk)} {} +template<typename T> weak_bptr<T>::weak_bptr(const weak_bptr& ptr) noexcept: blk{_copy(ptr.blk)} {} + +template<typename T> template<detail_bptr::DerivedFrom<T> Y> weak_bptr<T>& weak_bptr<T>::operator=(const bptr<Y>& ptr) noexcept { return _copy_assign(ptr.blk); } +template<typename T> template<detail_bptr::DerivedFrom<T> Y> weak_bptr<T>& weak_bptr<T>::operator=(const weak_bptr<Y>& ptr) noexcept { return _copy_assign(ptr.blk); } +template<typename T> weak_bptr<T>& weak_bptr<T>::operator=(const weak_bptr& ptr) noexcept { return _copy_assign(ptr.blk); } + +template<typename T> +template<detail_bptr::DerivedFrom<T> Y> +weak_bptr<T>::weak_bptr(weak_bptr<Y>&& ptr) noexcept: blk{ptr.blk} +{ ptr.blk = nullptr; } + +template<typename T> weak_bptr<T>::weak_bptr(weak_bptr&& ptr) noexcept: blk{ptr.blk} +{ ptr.blk = nullptr; } + +template<typename T> +template<detail_bptr::DerivedFrom<T> Y> +weak_bptr<T>& weak_bptr<T>::operator=(weak_bptr<Y>&& ptr) noexcept +{ return _move_assign(ptr.blk); } + +template<typename T> weak_bptr<T>& weak_bptr<T>::operator=(weak_bptr&& ptr) noexcept { return _move_assign(ptr.blk); } + +template<typename T> void weak_bptr<T>::reset() noexcept +{ if (blk) detail_bptr::control_block::weak_decrement(blk); } + +template<typename T> void weak_bptr<T>::swap(weak_bptr& other) noexcept +{ floormat::swap(blk, other.blk); } + +template<typename T> uint32_t weak_bptr<T>::use_count() const noexcept +{ + if (blk && blk->_ptr) + return blk->_hard_count; + else + return 0; +} + +template<typename T> bool weak_bptr<T>::expired() const noexcept { return use_count() == 0; } + +template<typename T> +bptr<T> weak_bptr<T>::lock() const noexcept +{ + if (blk && blk->_ptr) + { + fm_bptr_assert(blk->_hard_count > 0); + ++blk->_soft_count; + ++blk->_hard_count; + bptr<T> ret{nullptr}; + ret.blk = blk; + return ret; + } + else + return bptr<T>{nullptr}; +} + +template<typename T> bool weak_bptr<T>::operator==(const weak_bptr<const T>& other) const noexcept +{ + return lock().get() == other.lock().get(); +} + +} // namespace floormat + +#ifdef __GNUG__ +#pragma GCC diagnostic pop +#endif |