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:
Nekotekina 2021-05-29 11:21:57 +03:00
parent eec9578619
commit f5e529db61
4 changed files with 130 additions and 149 deletions

View file

@ -9,6 +9,7 @@
#include <array>
#include <tuple>
#include <compare>
#include <memory>
#include <bit>
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 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>());