Skip to content

Commit

Permalink
shared_ptr.hpp: fix is_same_ptr<>() trait
Browse files Browse the repository at this point in the history
Implemented as constexpr function.
  • Loading branch information
Nekotekina committed Dec 13, 2020
1 parent cb8ef46 commit 5b6934f
Showing 1 changed file with 38 additions and 43 deletions.
81 changes: 38 additions & 43 deletions rpcs3/util/shared_ptr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,47 @@

namespace stx
{
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined_var_template"
#endif

// Not defined anywhere (and produces a useless warning)
template <typename X>
extern X sample;

// Checks whether the cast between two types is the same pointer
template <typename T, typename U>
constexpr bool is_same_ptr() noexcept
{
// I would like to make it a trait if there is some trick.
// And believe it shall possible with constexpr bit_cast.
// Otherwise I hope it will compile in null code anyway.
const auto u = reinterpret_cast<U*>(0x11223344556);
const volatile void* x = u;
return static_cast<T*>(u) == x;
if constexpr (std::is_void_v<T> || std::is_void_v<U> || std::is_same_v<T, U>)
{
return true;
}
else if constexpr (std::is_base_of_v<T, U> && std::is_convertible_v<U*, T*>)
{
const auto u = &sample<U>;
const volatile void* x = u;
return static_cast<T*>(u) == x;
}
else if constexpr (std::is_base_of_v<U, T> && std::is_convertible_v<T*, U*>)
{
const auto t = &sample<T>;
const volatile void* x = t;
return static_cast<U*>(t) == x;
}
else
{
return false;
}
}

// TODO
template <typename T, typename U>
constexpr bool is_same_ptr_v = true;
constexpr bool is_same_ptr_cast_v = std::is_convertible_v<U*, T*> && is_same_ptr<T, U>();

template <typename T, typename U>
constexpr bool is_same_ptr_cast_v = std::is_same_v<T, U> || (std::is_convertible_v<U, T> && is_same_ptr_v<T, U>);
#ifdef __clang__
#pragma clang diagnostic pop
#endif

template <typename T>
class single_ptr;
Expand Down Expand Up @@ -125,7 +149,6 @@ namespace stx
single_ptr(single_ptr<U>&& r) noexcept
: m_ptr(r.m_ptr)
{
ensure(is_same_ptr<T, U>());
r.m_ptr = nullptr;
}

Expand All @@ -146,7 +169,6 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
single_ptr& operator=(single_ptr<U>&& r) noexcept
{
ensure(is_same_ptr<T, U>());
m_ptr = r.m_ptr;
r.m_ptr = nullptr;
return *this;
Expand Down Expand Up @@ -216,11 +238,9 @@ namespace stx
}

// "Moving" "static cast"
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr_v<U, T>>>
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>()>>
explicit operator single_ptr<U>() && noexcept
{
ensure(is_same_ptr<U, T>());

single_ptr<U> r;
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
return r;
Expand Down Expand Up @@ -369,7 +389,6 @@ namespace stx
shared_ptr(const shared_ptr<U>& r) noexcept
: m_ptr(r.m_ptr)
{
ensure(is_same_ptr<T, U>());
if (m_ptr)
d()->refs++;
}
Expand All @@ -384,15 +403,13 @@ namespace stx
shared_ptr(shared_ptr<U>&& r) noexcept
: m_ptr(r.m_ptr)
{
ensure(is_same_ptr<T, U>());
r.m_ptr = nullptr;
}

template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
shared_ptr(single_ptr<U>&& r) noexcept
: m_ptr(r.m_ptr)
{
ensure(is_same_ptr<T, U>());
r.m_ptr = nullptr;
}

Expand All @@ -410,7 +427,6 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
shared_ptr& operator=(const shared_ptr<U>& r) noexcept
{
ensure(is_same_ptr<T, U>());
shared_ptr(r).swap(*this);
return *this;
}
Expand All @@ -424,15 +440,13 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
shared_ptr& operator=(shared_ptr<U>&& r) noexcept
{
ensure(is_same_ptr<T, U>());
shared_ptr(std::move(r)).swap(*this);
return *this;
}

template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
shared_ptr& operator=(single_ptr<U>&& r) noexcept
{
ensure(is_same_ptr<T, U>());
shared_ptr(std::move(r)).swap(*this);
return *this;
}
Expand All @@ -450,11 +464,9 @@ 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_v<U, T>>>
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>()>>
explicit operator single_ptr<U>() && noexcept
{
ensure(is_same_ptr<U, T>());

const auto o = d();

if (m_ptr && !--o->refs)
Expand Down Expand Up @@ -537,11 +549,9 @@ 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_v<U, T>>>
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>()>>
explicit operator shared_ptr<U>() const& noexcept
{
ensure(is_same_ptr<U, T>());

if (m_ptr)
{
d()->refs++;
Expand All @@ -553,11 +563,9 @@ namespace stx
}

// "Moving" "static cast"
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr_v<U, T>>>
template <typename U, typename = decltype(static_cast<U*>(std::declval<T*>())), typename = std::enable_if_t<is_same_ptr<U, T>()>>
explicit operator shared_ptr<U>() && noexcept
{
ensure(is_same_ptr<U, T>());

shared_ptr<U> r;
r.m_ptr = static_cast<decltype(r.m_ptr)>(std::exchange(m_ptr, nullptr));
return r;
Expand Down Expand Up @@ -614,8 +622,6 @@ namespace stx
atomic_ptr(const shared_ptr<U>& r) noexcept
: m_val(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size)
{
ensure(is_same_ptr<T, U>());

// Obtain a ref + as many refs as an atomic_ptr can additionally reference
if (m_val)
d()->refs += c_ref_mask + 1;
Expand All @@ -625,7 +631,6 @@ namespace stx
atomic_ptr(shared_ptr<U>&& r) noexcept
: m_val(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size)
{
ensure(is_same_ptr<T, U>());
r.m_ptr = nullptr;

if (m_val)
Expand All @@ -636,7 +641,6 @@ namespace stx
atomic_ptr(single_ptr<U>&& r) noexcept
: m_val(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size)
{
ensure(is_same_ptr<T, U>());
r.m_ptr = nullptr;

if (m_val)
Expand Down Expand Up @@ -668,23 +672,20 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
atomic_ptr& operator=(const shared_ptr<U>& r) noexcept
{
ensure(is_same_ptr<T, U>());
store(r);
return *this;
}

template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
atomic_ptr& operator=(shared_ptr<U>&& r) noexcept
{
ensure(is_same_ptr<T, U>());
store(std::move(r));
return *this;
}

template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
atomic_ptr& operator=(single_ptr<U>&& r) noexcept
{
ensure(is_same_ptr<T, U>());
store(std::move(r));
return *this;
}
Expand Down Expand Up @@ -948,8 +949,6 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
shared_type compare_and_swap(const shared_ptr<U>& cmp, shared_type exch)
{
ensure(is_same_ptr<T, U>());

shared_type old = cmp;

if (compare_exchange(old, std::move(exch)))
Expand All @@ -966,8 +965,6 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
bool compare_and_swap_test(const shared_ptr<U>& cmp, shared_type exch)
{
ensure(is_same_ptr<T, U>());

const uptr _old = reinterpret_cast<uptr>(cmp.m_ptr);
const uptr _new = reinterpret_cast<uptr>(exch.m_ptr);

Expand Down Expand Up @@ -1007,8 +1004,6 @@ namespace stx
template <typename U, typename = std::enable_if_t<is_same_ptr_cast_v<T, U>>>
shared_type compare_and_swap(const single_ptr<U>& cmp, shared_type exch)
{
ensure(is_same_ptr<T, U>());

shared_type old = cmp;

if (compare_exchange(old, std::move(exch)))
Expand Down

0 comments on commit 5b6934f

Please sign in to comment.