summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-07-14 17:01:46 +0200
committerStanislaw Halik <sthalik@misaki.pl>2024-07-14 17:17:45 +0200
commit25057f99ac871684695175738f9ac31890bb4bba (patch)
treefc482b9077032ae8ae2c973a0085dc2824c9a3c3
parentb47f6164b82c166afb6d560caa3ffb79db15c7b7 (diff)
w
-rw-r--r--compat/borrowed-ptr-cast.hpp38
-rw-r--r--compat/borrowed-ptr-fwd.hpp17
-rw-r--r--compat/borrowed-ptr.hpp31
-rw-r--r--compat/borrowed-ptr.inl90
-rw-r--r--test/bptr.cpp15
5 files changed, 112 insertions, 79 deletions
diff --git a/compat/borrowed-ptr-cast.hpp b/compat/borrowed-ptr-cast.hpp
deleted file mode 100644
index 18f0a50e..00000000
--- a/compat/borrowed-ptr-cast.hpp
+++ /dev/null
@@ -1,38 +0,0 @@
-#pragma once
-#include "borrowed-ptr-fwd.hpp"
-#include "compat/assert.hpp"
-
-namespace floormat::detail_borrowed_ptr {
-
-//static_assert(std::is_same_v<T, U> || std::has_virtual_destructor_v<T> && std::has_virtual_destructor_v<T>); // todo! for simple_bptr
-
-template<typename From, typename To>
-concept StaticCastable = requires(From* from) {
- static_cast<To*>(from);
-};
-
-} // namespace floormat::detail_borrowed_ptr
-
-namespace floormat {
-
-template<typename To, typename From>
-bptr<To> static_pointer_cast(const bptr<From>& p) noexcept
-{
- // hack to generate better error message
- if constexpr (detail_borrowed_ptr::StaticCastable<From, To>)
- {
- if (p.blk && p.blk->_ptr) [[likely]]
- return bptr<To>{p, nullptr};
- }
- else
- {
- using detail_borrowed_ptr::StaticCastable;
- // concepts can't be forward-declared so use static_assert
- static_assert(StaticCastable<From, To>,
- "cannot static_cast, classes must be related by inheritance");
- }
-
- return bptr<To>{nullptr};
-}
-
-} // namespace floormat
diff --git a/compat/borrowed-ptr-fwd.hpp b/compat/borrowed-ptr-fwd.hpp
index 38927cc6..5f9c09f4 100644
--- a/compat/borrowed-ptr-fwd.hpp
+++ b/compat/borrowed-ptr-fwd.hpp
@@ -1,10 +1,19 @@
#pragma once
+
namespace floormat {
struct bptr_base;
-template<typename T> class bptr;
-template<typename To, typename From> bptr<To> static_pointer_cast(const bptr<From>& p) noexcept;
-template<typename T> bptr(T* ptr) -> bptr<T>;
-template<typename T> bptr(const T* ptr) -> bptr<const T>;
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+class bptr;
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr(T* ptr) -> bptr<T>;
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr(const T* ptr) -> bptr<const T>;
} // namespace floormat
diff --git a/compat/borrowed-ptr.hpp b/compat/borrowed-ptr.hpp
index 146fc334..2f7f00d2 100644
--- a/compat/borrowed-ptr.hpp
+++ b/compat/borrowed-ptr.hpp
@@ -4,18 +4,22 @@
namespace floormat::detail_borrowed_ptr {
struct control_block;
+
+template<typename From, typename To>
+concept StaticCastable = requires(From* from) {
+ static_cast<To*>(from);
+};
+
template<typename From, typename To>
concept DerivedFrom = requires(From* x) {
- requires !std::is_same_v<From, To>;
- requires std::is_nothrow_convertible_v<From*, To*>;
+ !std::is_same_v<From, To>;
+ std::is_convertible_v<From*, To*>;
};
} // namespace floormat::detail_borrowed_ptr
namespace floormat {
-template<typename T> class bptr;
-
struct bptr_base
{
virtual ~bptr_base() noexcept;
@@ -27,6 +31,7 @@ struct bptr_base
};
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
class bptr final // NOLINT(*-special-member-functions)
{
detail_borrowed_ptr::control_block* blk;
@@ -58,8 +63,6 @@ public:
template<detail_borrowed_ptr::DerivedFrom<T> Y> CORRADE_ALWAYS_INLINE bptr(bptr<Y>&&) noexcept;
template<detail_borrowed_ptr::DerivedFrom<T> Y> CORRADE_ALWAYS_INLINE bptr& operator=(bptr<Y>&&) noexcept;
- operator bptr<const T>() const noexcept requires (!std::is_const_v<T>);
-
void reset() noexcept;
void destroy() noexcept;
void swap(bptr& other) noexcept;
@@ -73,8 +76,20 @@ public:
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;
- template<typename U> friend class bptr;
- template<typename U, typename Tʹ> friend bptr<U> static_pointer_cast(const bptr<Tʹ>& p) noexcept;
+ template<typename U> requires std::is_convertible_v<U*, const bptr_base*> friend class bptr;
+
+ template<typename To, typename From>
+ requires (std::is_convertible_v<To*, const bptr_base*> && detail_borrowed_ptr::StaticCastable<From, To>)
+ friend bptr<To> static_pointer_cast(const bptr<From>& p) noexcept;
};
+template<typename To, typename From>
+requires (std::is_convertible_v<To*, const bptr_base*> && detail_borrowed_ptr::StaticCastable<From, To>)
+bptr<To> static_pointer_cast(const bptr<From>& p) noexcept
+{
+ if (p.blk && p.blk->_ptr) [[likely]]
+ return bptr<To>{p, nullptr};
+ return bptr<To>{nullptr};
+}
+
} // namespace floormat
diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl
index e7b4bbbd..c4f19de5 100644
--- a/compat/borrowed-ptr.inl
+++ b/compat/borrowed-ptr.inl
@@ -39,6 +39,7 @@ struct control_block
namespace floormat {
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<typename... Ts>
requires std::is_constructible_v<std::remove_const_t<T>, Ts&&...>
bptr<T>::bptr(InPlaceInitT, Ts&&... args) noexcept:
@@ -46,65 +47,75 @@ 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>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>::bptr(std::nullptr_t) noexcept: blk{nullptr} {}
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>::bptr() noexcept: bptr{nullptr} {}
-template<typename T> bptr<T>::bptr(T* ptr) noexcept:
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>::bptr(T* ptr) noexcept:
blk{ptr ? new detail_borrowed_ptr::control_block{const_cast<std::remove_const_t<T>*>(ptr), 1} : nullptr}
{}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
bptr<T>::~bptr() noexcept
{
if (blk)
blk->decrement(blk);
}
-template<typename T> bptr<T>::bptr(const bptr& other) noexcept: bptr{other, nullptr} {}
-template<typename T> bptr<T>& bptr<T>::operator=(const bptr& other) noexcept { return _copy_assign(other); }
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>::bptr(const bptr& other) noexcept: bptr{other, nullptr} {}
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>& bptr<T>::operator=(const bptr& other) noexcept { return _copy_assign(other); }
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<detail_borrowed_ptr::DerivedFrom<T> Y>
bptr<T>::bptr(const bptr<Y>& other) noexcept: bptr{other, nullptr} {}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<detail_borrowed_ptr::DerivedFrom<T> Y>
bptr<T>& bptr<T>::operator=(const bptr<Y>& other) noexcept
{ return _copy_assign(other); }
-template<typename T> bptr<T>& bptr<T>::operator=(bptr&& other) noexcept { return _move_assign(move(other)); }
-template<typename T> bptr<T>::bptr(bptr&& other) noexcept: bptr{move(other), nullptr} {}
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>& bptr<T>::operator=(bptr&& other) noexcept { return _move_assign(move(other)); }
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>::bptr(bptr&& other) noexcept: bptr{move(other), nullptr} {}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<detail_borrowed_ptr::DerivedFrom<T> Y>
bptr<T>::bptr(bptr<Y>&& other) noexcept: bptr{move(other), nullptr} {}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<detail_borrowed_ptr::DerivedFrom<T> Y>
bptr<T>& bptr<T>::operator=(bptr<Y>&& other) noexcept
{ return _move_assign(move(other)); }
template<typename T>
-bptr<T>::operator bptr<const T>() const noexcept requires (!std::is_const_v<T>) {
- if (blk && blk->_ptr)
- {
- ++blk->_count;
- return bptr<const T>{};
- }
- return bptr<const T>{nullptr};
-}
-
-template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
void bptr<T>::reset() noexcept
{
if (blk)
- {
blk->decrement(blk);
- blk = nullptr;
- }
}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
void bptr<T>::destroy() noexcept
{
if (!blk)
@@ -113,9 +124,12 @@ void bptr<T>::destroy() noexcept
blk->_ptr = nullptr;
}
-template<typename T> bptr<T>& bptr<T>::operator=(std::nullptr_t) noexcept { reset(); return *this; }
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>& bptr<T>::operator=(std::nullptr_t) noexcept { reset(); return *this; }
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<typename Y>
bptr<T>::bptr(const bptr<Y>& other, std::nullptr_t) noexcept:
blk{other.blk}
@@ -128,6 +142,7 @@ bptr<T>::bptr(const bptr<Y>& other, std::nullptr_t) noexcept:
}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<typename Y>
bptr<T>& bptr<T>::_copy_assign(const bptr<Y>& other) noexcept
{
@@ -143,6 +158,7 @@ bptr<T>& bptr<T>::_copy_assign(const bptr<Y>& other) noexcept
}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<typename Y>
bptr<T>::bptr(bptr<Y>&& other, std::nullptr_t) noexcept:
blk{other.blk}
@@ -151,6 +167,7 @@ bptr<T>::bptr(bptr<Y>&& other, std::nullptr_t) noexcept:
}
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
template<typename Y>
bptr<T>& bptr<T>::_move_assign(bptr<Y>&& other) noexcept
{
@@ -161,7 +178,9 @@ bptr<T>& bptr<T>::_move_assign(bptr<Y>&& other) noexcept
return *this;
}
-template<typename T> T* bptr<T>::get() const noexcept
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+T* bptr<T>::get() const noexcept
{
if (blk) [[likely]]
return static_cast<T*>(blk->_ptr);
@@ -169,26 +188,41 @@ template<typename T> T* bptr<T>::get() const noexcept
return nullptr;
}
-template<typename T> T* bptr<T>::operator->() const noexcept
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+T* bptr<T>::operator->() const noexcept
{
auto* ret = get();
fm_bptr_assert(ret);
return ret;
}
-template<typename T> T& bptr<T>::operator*() const noexcept { return *operator->(); }
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+T& bptr<T>::operator*() const noexcept { return *operator->(); }
-template<typename T> bptr<T>::operator bool() const noexcept { return get(); }
-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>
+requires std::is_convertible_v<T*, const bptr_base*>
+bptr<T>::operator bool() const noexcept { return get(); }
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bool bptr<T>::operator==(const bptr<const std::remove_const_t<T>>& other) const noexcept { return get() == other.get(); }
template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+bool bptr<T>::operator==(const bptr<std::remove_const_t<T>>& other) const noexcept { return get() == other.get(); }
+
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
void bptr<T>::swap(bptr& other) noexcept
{
floormat::swap(blk, other.blk);
}
-template<typename T> uint32_t bptr<T>::use_count() const noexcept
+template<typename T>
+requires std::is_convertible_v<T*, const bptr_base*>
+uint32_t bptr<T>::use_count() const noexcept
{
if (blk && blk->_ptr) [[likely]]
return blk->_count;
diff --git a/test/bptr.cpp b/test/bptr.cpp
index ffff5b19..e9d0dff3 100644
--- a/test/bptr.cpp
+++ b/test/bptr.cpp
@@ -1,6 +1,5 @@
#include "app.hpp"
#include "compat/borrowed-ptr.inl"
-#include "compat/borrowed-ptr-cast.hpp"
#include "compat/assert.hpp"
#include "compat/defs.hpp"
#include <array>
@@ -376,6 +375,19 @@ void test11()
auto p3 = static_pointer_cast<bptr_base>(p1);
fm_assert(p2->x == 1);
fm_assert(p3);
+ p1.destroy();
+ fm_assert(!p2); fm_assert(!p3);
+}
+
+void test12()
+{
+ auto p1 = bptr<bptr_base>{new Foo{1}};
+ {
+ fm_assert(p1.use_count() == 1);
+ auto p2 = static_pointer_cast<Foo>(p1);
+ fm_assert(p1.use_count() == 2);
+ }
+ fm_assert(p1.use_count() == 1);
}
} // namespace
@@ -393,6 +405,7 @@ void Test::test_bptr()
test9();
test10();
test11();
+ test12();
}
} // namespace floormat