mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
shared_ptr.hpp: don't use fake objects
This lifts the limitation for casting with abstract classes. Use new C++20 feature (constexpr allocator) to test viability. Add SamePtr concept to types.hpp
This commit is contained in:
parent
eec9578619
commit
f5e529db61
@ -11,3 +11,52 @@ static_assert(be_t<u16>(1) + be_t<u32>(2) + be_t<u64>(3) == 6);
|
|||||||
static_assert(le_t<u16>(1) + le_t<u32>(2) + le_t<u64>(3) == 6);
|
static_assert(le_t<u16>(1) + le_t<u32>(2) + le_t<u64>(3) == 6);
|
||||||
|
|
||||||
static_assert(sizeof(nullptr) == sizeof(void*));
|
static_assert(sizeof(nullptr) == sizeof(void*));
|
||||||
|
|
||||||
|
static_assert(__cpp_constexpr_dynamic_alloc >= 201907L);
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct A
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B : A
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Z
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct C
|
||||||
|
{
|
||||||
|
virtual ~C() = 0;
|
||||||
|
int C;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D : Z, B
|
||||||
|
{
|
||||||
|
int d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct E : C, B
|
||||||
|
{
|
||||||
|
int e;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct F : C
|
||||||
|
{
|
||||||
|
virtual ~F() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(is_same_ptr<B, A>());
|
||||||
|
static_assert(is_same_ptr<A, B>());
|
||||||
|
static_assert(is_same_ptr<D, B>());
|
||||||
|
static_assert(is_same_ptr<B, D>());
|
||||||
|
static_assert(!is_same_ptr<E, B>());
|
||||||
|
static_assert(!is_same_ptr<B, E>());
|
||||||
|
static_assert(is_same_ptr<F, C>());
|
||||||
|
static_assert(is_same_ptr<C, F>());
|
||||||
|
}
|
||||||
|
@ -6,63 +6,8 @@
|
|||||||
|
|
||||||
namespace stx
|
namespace stx
|
||||||
{
|
{
|
||||||
namespace detail
|
template <typename To, typename From>
|
||||||
{
|
constexpr bool same_ptr_implicit_v = std::is_convertible_v<const volatile From*, const volatile To*> ? is_same_ptr<From, To>() : false;
|
||||||
template <typename T>
|
|
||||||
union fake_t
|
|
||||||
{
|
|
||||||
char dummy;
|
|
||||||
T data;
|
|
||||||
|
|
||||||
fake_t() noexcept {}
|
|
||||||
~fake_t() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
static const
|
|
||||||
#else
|
|
||||||
static thread_local const
|
|
||||||
#endif
|
|
||||||
fake_t<std::remove_cv_t<T>> sample{};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Classify compile-time information available for pointers
|
|
||||||
enum class same_ptr
|
|
||||||
{
|
|
||||||
no,
|
|
||||||
yes,
|
|
||||||
maybe
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename X, typename Y>
|
|
||||||
constexpr bool is_same_ptr_test(const volatile Y* ptr = std::addressof(detail::sample<Y>.data))
|
|
||||||
{
|
|
||||||
return static_cast<const volatile X*>(ptr) == static_cast<const volatile void*>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks whether the cast between two types is the same pointer
|
|
||||||
template <typename T, typename U>
|
|
||||||
constexpr same_ptr is_same_ptr() noexcept
|
|
||||||
{
|
|
||||||
if constexpr (std::is_void_v<T> || std::is_void_v<U> || std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>)
|
|
||||||
{
|
|
||||||
return same_ptr::yes;
|
|
||||||
}
|
|
||||||
else if constexpr (PtrCastable<T, U> && !std::is_abstract_v<U>)
|
|
||||||
{
|
|
||||||
return is_same_ptr_test<T, U>() ? same_ptr::yes : same_ptr::no;
|
|
||||||
}
|
|
||||||
else if constexpr (PtrCastable<T, U> && !std::is_abstract_v<T>)
|
|
||||||
{
|
|
||||||
return is_same_ptr_test<T, U>() ? same_ptr::yes : same_ptr::no;
|
|
||||||
}
|
|
||||||
|
|
||||||
return same_ptr::maybe;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
constexpr same_ptr is_same_ptr_cast_v = std::is_convertible_v<U*, T*> ? is_same_ptr<T, U>() : same_ptr::no;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class single_ptr;
|
class single_ptr;
|
||||||
@ -175,12 +120,9 @@ namespace stx
|
|||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
single_ptr(single_ptr<U>&& r) noexcept
|
single_ptr(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
m_ptr = r.m_ptr;
|
m_ptr = r.m_ptr;
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
@ -200,12 +142,9 @@ namespace stx
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
single_ptr& operator=(single_ptr<U>&& r) noexcept
|
single_ptr& operator=(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
single_ptr(std::move(r)).swap(*this);
|
single_ptr(std::move(r)).swap(*this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -269,12 +208,9 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "Moving" "static cast"
|
// "Moving" "static cast"
|
||||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
template <typename U> requires PtrSame<T, U>
|
||||||
explicit operator single_ptr<U>() && noexcept
|
explicit operator single_ptr<U>() && noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<U, T>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<U, T>(m_ptr));
|
|
||||||
|
|
||||||
single_ptr<U> r;
|
single_ptr<U> r;
|
||||||
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
|
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
|
||||||
return r;
|
return r;
|
||||||
@ -436,12 +372,9 @@ namespace stx
|
|||||||
ensure((d()->refs++ - 1) >> 58 == 0);
|
ensure((d()->refs++ - 1) >> 58 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_ptr(const shared_ptr<U>& r) noexcept
|
shared_ptr(const shared_ptr<U>& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
m_ptr = r.m_ptr;
|
m_ptr = r.m_ptr;
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
d()->refs++;
|
d()->refs++;
|
||||||
@ -453,22 +386,16 @@ namespace stx
|
|||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_ptr(shared_ptr<U>&& r) noexcept
|
shared_ptr(shared_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
m_ptr = r.m_ptr;
|
m_ptr = r.m_ptr;
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_ptr(single_ptr<U>&& r) noexcept
|
shared_ptr(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
m_ptr = r.m_ptr;
|
m_ptr = r.m_ptr;
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
@ -486,12 +413,9 @@ namespace stx
|
|||||||
|
|
||||||
[[deprecated("Use null_ptr")]] shared_ptr& operator=(std::nullptr_t) = delete;
|
[[deprecated("Use null_ptr")]] shared_ptr& operator=(std::nullptr_t) = delete;
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_ptr& operator=(const shared_ptr<U>& r) noexcept
|
shared_ptr& operator=(const shared_ptr<U>& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
shared_ptr(r).swap(*this);
|
shared_ptr(r).swap(*this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -502,22 +426,16 @@ namespace stx
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_ptr& operator=(shared_ptr<U>&& r) noexcept
|
shared_ptr& operator=(shared_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
shared_ptr(std::move(r)).swap(*this);
|
shared_ptr(std::move(r)).swap(*this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_ptr& operator=(single_ptr<U>&& r) noexcept
|
shared_ptr& operator=(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
shared_ptr(std::move(r)).swap(*this);
|
shared_ptr(std::move(r)).swap(*this);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -535,12 +453,9 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Converts to unique (single) ptr if reference is 1, otherwise returns null. Nullifies self.
|
// Converts to unique (single) ptr if reference is 1, otherwise returns null. Nullifies self.
|
||||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
template <typename U> requires PtrSame<T, U>
|
||||||
explicit operator single_ptr<U>() && noexcept
|
explicit operator single_ptr<U>() && noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<U, T>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<U, T>(m_ptr));
|
|
||||||
|
|
||||||
const auto o = d();
|
const auto o = d();
|
||||||
|
|
||||||
if (m_ptr && !--o->refs)
|
if (m_ptr && !--o->refs)
|
||||||
@ -618,12 +533,9 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Basic "static cast" support
|
// Basic "static cast" support
|
||||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
template <typename U> requires PtrSame<T, U>
|
||||||
explicit operator shared_ptr<U>() const& noexcept
|
explicit operator shared_ptr<U>() const& noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<U, T>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<U, T>(m_ptr));
|
|
||||||
|
|
||||||
if (m_ptr)
|
if (m_ptr)
|
||||||
{
|
{
|
||||||
d()->refs++;
|
d()->refs++;
|
||||||
@ -635,12 +547,9 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "Moving" "static cast"
|
// "Moving" "static cast"
|
||||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
template <typename U> requires PtrSame<T, U>
|
||||||
explicit operator shared_ptr<U>() && noexcept
|
explicit operator shared_ptr<U>() && noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<U, T>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<U, T>(m_ptr));
|
|
||||||
|
|
||||||
shared_ptr<U> r;
|
shared_ptr<U> r;
|
||||||
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
|
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
|
||||||
return r;
|
return r;
|
||||||
@ -702,24 +611,18 @@ namespace stx
|
|||||||
d()->refs.raw() += c_ref_mask;
|
d()->refs.raw() += c_ref_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr(const shared_ptr<U>& r) noexcept
|
atomic_ptr(const shared_ptr<U>& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
// Obtain a ref + as many refs as an atomic_ptr can additionally reference
|
// Obtain a ref + as many refs as an atomic_ptr can additionally reference
|
||||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
||||||
if (m_val)
|
if (m_val)
|
||||||
d()->refs += c_ref_mask + 1;
|
d()->refs += c_ref_mask + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr(shared_ptr<U>&& r) noexcept
|
atomic_ptr(shared_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
|
|
||||||
@ -727,12 +630,9 @@ namespace stx
|
|||||||
d()->refs += c_ref_mask;
|
d()->refs += c_ref_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr(single_ptr<U>&& r) noexcept
|
atomic_ptr(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
||||||
r.m_ptr = nullptr;
|
r.m_ptr = nullptr;
|
||||||
|
|
||||||
@ -762,32 +662,23 @@ namespace stx
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr& operator=(const shared_ptr<U>& r) noexcept
|
atomic_ptr& operator=(const shared_ptr<U>& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
store(r);
|
store(r);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr& operator=(shared_ptr<U>&& r) noexcept
|
atomic_ptr& operator=(shared_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
store(std::move(r));
|
store(std::move(r));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr& operator=(single_ptr<U>&& r) noexcept
|
atomic_ptr& operator=(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(r.m_ptr));
|
|
||||||
|
|
||||||
store(std::move(r));
|
store(std::move(r));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -1048,24 +939,18 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unoptimized
|
// Unoptimized
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_type compare_and_swap(const shared_ptr<U>& cmp, shared_type exch)
|
shared_type compare_and_swap(const shared_ptr<U>& cmp, shared_type exch)
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(cmp.m_ptr));
|
|
||||||
|
|
||||||
shared_type old = cmp;
|
shared_type old = cmp;
|
||||||
static_cast<void>(compare_exchange(old, std::move(exch)));
|
static_cast<void>(compare_exchange(old, std::move(exch)));
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
// More lightweight than compare_exchange
|
// More lightweight than compare_exchange
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
bool compare_and_swap_test(const shared_ptr<U>& cmp, shared_type exch)
|
bool compare_and_swap_test(const shared_ptr<U>& cmp, shared_type exch)
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(cmp.m_ptr));
|
|
||||||
|
|
||||||
const uptr _old = reinterpret_cast<uptr>(cmp.m_ptr);
|
const uptr _old = reinterpret_cast<uptr>(cmp.m_ptr);
|
||||||
const uptr _new = reinterpret_cast<uptr>(exch.m_ptr);
|
const uptr _new = reinterpret_cast<uptr>(exch.m_ptr);
|
||||||
|
|
||||||
@ -1102,24 +987,18 @@ namespace stx
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unoptimized
|
// Unoptimized
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
shared_type compare_and_swap(const single_ptr<U>& cmp, shared_type exch)
|
shared_type compare_and_swap(const single_ptr<U>& cmp, shared_type exch)
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(cmp.m_ptr));
|
|
||||||
|
|
||||||
shared_type old = cmp;
|
shared_type old = cmp;
|
||||||
static_cast<void>(compare_exchange(old, std::move(exch)));
|
static_cast<void>(compare_exchange(old, std::move(exch)));
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supplementary
|
// Supplementary
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
bool compare_and_swap_test(const single_ptr<U>& cmp, shared_type exch)
|
bool compare_and_swap_test(const single_ptr<U>& cmp, shared_type exch)
|
||||||
{
|
{
|
||||||
if constexpr (is_same_ptr<T, U>() == same_ptr::maybe)
|
|
||||||
ensure(is_same_ptr_test<T, U>(cmp.m_ptr));
|
|
||||||
|
|
||||||
return compare_and_swap_test(reinterpret_cast<const shared_ptr<U>&>(cmp), std::move(exch));
|
return compare_and_swap_test(reinterpret_cast<const shared_ptr<U>&>(cmp), std::move(exch));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1169,13 +1048,13 @@ namespace stx
|
|||||||
return m_val != 0;
|
return m_val != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
bool is_equal(const shared_ptr<U>& r) const noexcept
|
bool is_equal(const shared_ptr<U>& r) const noexcept
|
||||||
{
|
{
|
||||||
return observe() == r.get();
|
return observe() == r.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
bool is_equal(const single_ptr<U>& r) const noexcept
|
bool is_equal(const single_ptr<U>& r) const noexcept
|
||||||
{
|
{
|
||||||
return observe() == r.get();
|
return observe() == r.get();
|
||||||
|
@ -250,7 +250,7 @@ namespace stx
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
static_assert(sizeof(As) > 0);
|
static_assert(sizeof(As) > 0);
|
||||||
static_assert(is_same_ptr<T, As>() == same_ptr::yes); // TODO
|
static_assert(PtrSame<T, As>);
|
||||||
return type_counter<Info>::template dyn_type<T, As>.index();
|
return type_counter<Info>::template dyn_type<T, As>.index();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,7 +269,7 @@ namespace stx
|
|||||||
ATTR_PURE inline const Info& typedata() noexcept
|
ATTR_PURE inline const Info& typedata() noexcept
|
||||||
{
|
{
|
||||||
static_assert(sizeof(T) > 0 && sizeof(As) > 0);
|
static_assert(sizeof(T) > 0 && sizeof(As) > 0);
|
||||||
static_assert(is_same_ptr<T, As>() == same_ptr::yes); // TODO
|
static_assert(PtrSame<T, As>); // TODO
|
||||||
|
|
||||||
return type_counter<Info>::template dyn_type<T, As>;
|
return type_counter<Info>::template dyn_type<T, As>;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <compare>
|
#include <compare>
|
||||||
|
#include <memory>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
|
|
||||||
using std::chrono::steady_clock;
|
using std::chrono::steady_clock;
|
||||||
@ -1017,3 +1018,55 @@ concept PtrCastable = requires(const volatile X* x, const volatile Y* y)
|
|||||||
static_cast<const volatile Y*>(x);
|
static_cast<const volatile Y*>(x);
|
||||||
static_cast<const volatile X*>(y);
|
static_cast<const volatile X*>(y);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename X, typename Y> requires PtrCastable<X, Y>
|
||||||
|
constexpr bool is_same_ptr()
|
||||||
|
{
|
||||||
|
if constexpr (std::is_void_v<X> || std::is_void_v<Y> || std::is_same_v<std::remove_cv_t<X>, std::remove_cv_t<Y>>)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof(X) == sizeof(Y))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (std::is_constant_evaluated())
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if constexpr (sizeof(X) < sizeof(Y))
|
||||||
|
{
|
||||||
|
std::allocator<Y> a{};
|
||||||
|
Y* ptr = a.allocate(1);
|
||||||
|
result = static_cast<X*>(ptr) == static_cast<void*>(ptr);
|
||||||
|
a.deallocate(ptr, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::allocator<X> a{};
|
||||||
|
X* ptr = a.allocate(1);
|
||||||
|
result = static_cast<Y*>(ptr) == static_cast<void*>(ptr);
|
||||||
|
a.deallocate(ptr, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::aligned_union_t<0, X, Y> s;
|
||||||
|
Y* ptr = reinterpret_cast<Y*>(&s);
|
||||||
|
return static_cast<X*>(ptr) == static_cast<void*>(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename X, typename Y> requires PtrCastable<X, Y>
|
||||||
|
constexpr bool is_same_ptr(const volatile Y* ptr)
|
||||||
|
{
|
||||||
|
return static_cast<const volatile X*>(ptr) == static_cast<const volatile void*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename X, typename Y>
|
||||||
|
concept PtrSame = (is_same_ptr<X, Y>());
|
||||||
|
Loading…
Reference in New Issue
Block a user