mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-26 04:32:35 +01:00
shared_ptr.hpp: further fixes
Improved is_same_ptr() trait (added third "maybe" category). Fallback to pseudo-runtime check in certain cases (if "maybe"). Fix single_ptr moving assignment operator.
This commit is contained in:
parent
332c512eed
commit
8c5f2b249c
@ -25,16 +25,23 @@ namespace stx
|
||||
static thread_local const
|
||||
#endif
|
||||
fake_t<std::remove_cv_t<T>> sample{};
|
||||
|
||||
template <typename From, typename To, typename = void>
|
||||
struct can_static_cast : std::false_type {};
|
||||
|
||||
template <typename From, typename To>
|
||||
struct can_static_cast<From, To, std::void_t<decltype(static_cast<To>(std::declval<From>()))>> : std::true_type {};
|
||||
}
|
||||
|
||||
// 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*, ...)
|
||||
{
|
||||
// Can't sample abstract class
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename X, typename Y, std::enable_if_t<!std::is_abstract_v<Y>, int> = 0>
|
||||
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);
|
||||
@ -42,26 +49,26 @@ namespace stx
|
||||
|
||||
// Checks whether the cast between two types is the same pointer
|
||||
template <typename T, typename U>
|
||||
constexpr bool is_same_ptr() noexcept
|
||||
constexpr same_ptr is_same_ptr() noexcept
|
||||
{
|
||||
if constexpr (std::is_void_v<T> || std::is_void_v<U> || std::is_same_v<T, U>)
|
||||
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 true;
|
||||
return same_ptr::yes;
|
||||
}
|
||||
else if constexpr (std::is_convertible_v<U*, T*>)
|
||||
else if constexpr (detail::can_static_cast<U*, T*>::value && !std::is_abstract_v<U>)
|
||||
{
|
||||
return is_same_ptr_test<T, U>();
|
||||
return is_same_ptr_test<T, U>() ? same_ptr::yes : same_ptr::no;
|
||||
}
|
||||
else if constexpr (std::is_convertible_v<T*, U*>)
|
||||
else if constexpr (detail::can_static_cast<T*, U*>::value && !std::is_abstract_v<T>)
|
||||
{
|
||||
return is_same_ptr_test<U, T>();
|
||||
return is_same_ptr_test<U, T>() ? same_ptr::yes : same_ptr::no;
|
||||
}
|
||||
|
||||
return !std::is_class_v<T> && !std::is_class_v<U> && !std::is_union_v<T> && !std::is_union_v<U>;
|
||||
return same_ptr::maybe;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool is_same_ptr_cast_v = std::is_convertible_v<U*, T*> && is_same_ptr<T, 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>
|
||||
class single_ptr;
|
||||
@ -166,10 +173,13 @@ namespace stx
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
single_ptr(single_ptr<U>&& r) noexcept
|
||||
: m_ptr(r.m_ptr)
|
||||
{
|
||||
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;
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
@ -182,16 +192,17 @@ namespace stx
|
||||
|
||||
single_ptr& operator=(single_ptr&& r) noexcept
|
||||
{
|
||||
m_ptr = r.m_ptr;
|
||||
r.m_ptr = nullptr;
|
||||
single_ptr(std::move(r)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
single_ptr& operator=(single_ptr<U>&& r) noexcept
|
||||
{
|
||||
m_ptr = r.m_ptr;
|
||||
r.m_ptr = nullptr;
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -259,9 +270,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// "Moving" "static cast"
|
||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>()>>
|
||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
||||
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;
|
||||
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
|
||||
return r;
|
||||
@ -424,10 +438,13 @@ namespace stx
|
||||
d()->refs++;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
shared_ptr(const shared_ptr<U>& r) noexcept
|
||||
: m_ptr(r.m_ptr)
|
||||
{
|
||||
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;
|
||||
if (m_ptr)
|
||||
d()->refs++;
|
||||
}
|
||||
@ -438,17 +455,23 @@ namespace stx
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
shared_ptr(shared_ptr<U>&& r) noexcept
|
||||
: m_ptr(r.m_ptr)
|
||||
{
|
||||
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;
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
shared_ptr(single_ptr<U>&& r) noexcept
|
||||
: m_ptr(r.m_ptr)
|
||||
{
|
||||
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;
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
@ -463,9 +486,12 @@ namespace stx
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
@ -476,16 +502,22 @@ namespace stx
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
@ -503,9 +535,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// 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>()>>
|
||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
||||
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();
|
||||
|
||||
if (m_ptr && !--o->refs)
|
||||
@ -588,9 +623,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// 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>()>>
|
||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
||||
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)
|
||||
{
|
||||
d()->refs++;
|
||||
@ -602,9 +640,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// "Moving" "static cast"
|
||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>()>>
|
||||
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>() != same_ptr::no>>
|
||||
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;
|
||||
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
|
||||
return r;
|
||||
@ -660,29 +701,38 @@ namespace stx
|
||||
d()->refs.raw() += c_ref_mask;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
atomic_ptr(const shared_ptr<U>& r) noexcept
|
||||
: m_val(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size)
|
||||
{
|
||||
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
|
||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
||||
if (m_val)
|
||||
d()->refs += c_ref_mask + 1;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
atomic_ptr(shared_ptr<U>&& r) noexcept
|
||||
: m_val(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size)
|
||||
{
|
||||
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;
|
||||
r.m_ptr = nullptr;
|
||||
|
||||
if (m_val)
|
||||
d()->refs += c_ref_mask;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
atomic_ptr(single_ptr<U>&& r) noexcept
|
||||
: m_val(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size)
|
||||
{
|
||||
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;
|
||||
r.m_ptr = nullptr;
|
||||
|
||||
if (m_val)
|
||||
@ -711,23 +761,32 @@ namespace stx
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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));
|
||||
return *this;
|
||||
}
|
||||
@ -988,9 +1047,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// Unoptimized
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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;
|
||||
|
||||
if (compare_exchange(old, std::move(exch)))
|
||||
@ -1004,9 +1066,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// More lightweight than compare_exchange
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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 _new = reinterpret_cast<uptr>(exch.m_ptr);
|
||||
|
||||
@ -1043,9 +1108,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// Unoptimized
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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;
|
||||
|
||||
if (compare_exchange(old, std::move(exch)))
|
||||
@ -1059,9 +1127,12 @@ namespace stx
|
||||
}
|
||||
|
||||
// Supplementary
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
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));
|
||||
}
|
||||
|
||||
@ -1111,13 +1182,13 @@ namespace stx
|
||||
return m_val != 0;
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
bool is_equal(const shared_ptr<U>& r) const noexcept
|
||||
{
|
||||
return observe() == r.get();
|
||||
}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
|
||||
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U> != same_ptr::no>>
|
||||
bool is_equal(const single_ptr<U>& r) const noexcept
|
||||
{
|
||||
return observe() == r.get();
|
||||
|
@ -255,7 +255,7 @@ namespace stx
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(As) > 0);
|
||||
static_assert(is_same_ptr<T, As>());
|
||||
static_assert(is_same_ptr<T, As>() == same_ptr::yes); // TODO
|
||||
return type_counter<Info>::template dyn_type<T, As>.index();
|
||||
}
|
||||
}
|
||||
@ -274,7 +274,7 @@ namespace stx
|
||||
ATTR_PURE inline const Info& typedata() noexcept
|
||||
{
|
||||
static_assert(sizeof(T) > 0 && sizeof(As) > 0);
|
||||
static_assert(is_same_ptr<T, As>());
|
||||
static_assert(is_same_ptr<T, As>() == same_ptr::yes); // TODO
|
||||
|
||||
return type_counter<Info>::template dyn_type<T, As>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user