summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compat/borrowed-ptr-fwd.hpp1
-rw-r--r--compat/borrowed-ptr.cpp28
-rw-r--r--compat/borrowed-ptr.hpp66
-rw-r--r--compat/borrowed-ptr.inl60
-rw-r--r--compat/weak-borrowed-ptr.hpp45
-rw-r--r--compat/weak-borrowed-ptr.inl129
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