constexpr: resign ourselves to gcc dropping void -> T support

This commit is contained in:
Michael Scire
2021-10-17 02:39:16 -07:00
parent 96d3187f3e
commit ad4c794aea
16 changed files with 201 additions and 290 deletions

View File

@@ -43,16 +43,6 @@ namespace ams::util {
UnionImpl<ParentType, MemberType, Offset + 1> next_union;
};
template<typename ParentType, typename MemberType>
union UnionImpl<ParentType, MemberType, 0> {
static constexpr size_t GetOffset() { return 0; }
struct {
MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
} data;
UnionImpl<ParentType, MemberType, 1> next_union;
};
template<typename ParentType, typename MemberType>
union UnionImpl<ParentType, MemberType, MaxDepth> { /* Empty ... */ };
};
@@ -63,10 +53,11 @@ namespace ams::util {
union Union {
char c;
UnionHolder first_union;
TypedStorage<ParentType> parent;
ParentType parent;
/* This coerces the active member to be c. */
constexpr Union() : c() { /* ... */ }
constexpr ~Union() { std::destroy_at(std::addressof(c)); }
};
static constexpr Union U = {};
@@ -84,7 +75,7 @@ namespace ams::util {
template<typename CurUnion>
static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, CurUnion &cur_union) {
constexpr size_t Offset = CurUnion::GetOffset();
const auto target = std::addressof(GetPointer(U.parent)->*member);
const auto target = std::addressof(U.parent.*member);
const auto start = std::addressof(cur_union.data.members[0]);
const auto next = GetNextAddress(start, target);
@@ -107,11 +98,20 @@ namespace ams::util {
#else
template<typename T>
union HelperUnion {
T v;
char c;
constexpr HelperUnion() : c() { /* ... */ }
constexpr ~HelperUnion() { std::destroy_at(std::addressof(c)); }
};
template<typename ParentType, typename MemberType>
struct OffsetOfCalculator {
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
constexpr TypedStorage<ParentType> Holder = {};
const auto *parent = GetPointer(Holder);
constexpr HelperUnion<ParentType> Holder = {};
const auto *parent = std::addressof(Holder.v);
const auto *target = std::addressof(parent->*member);
return static_cast<const uint8_t *>(static_cast<const void *>(target)) - static_cast<const uint8_t *>(static_cast<const void *>(parent));
}
@@ -134,141 +134,63 @@ namespace ams::util {
template<auto MemberPtr>
using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
template<auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
constexpr inline std::ptrdiff_t OffsetOf = [] {
using DeducedParentType = GetParentType<MemberPtr>;
using MemberType = GetMemberType<MemberPtr>;
static_assert(std::is_base_of<DeducedParentType, RealParentType>::value || std::is_same<RealParentType, DeducedParentType>::value);
/* DEPRECATED: static_assert(std::is_literal_type<MemberType>::value); */
return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
}();
template<auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> requires (std::derived_from<RealParentType, GetParentType<MemberPtr>> || std::same_as<RealParentType, GetParentType<MemberPtr>>)
struct OffsetOf {
using MemberType = GetMemberType<MemberPtr>;
static constexpr std::ptrdiff_t Value = OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
};
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> *member) {
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> *member) {
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>::Value;
return *static_cast<RealParentType *>(static_cast<void *>(static_cast<uint8_t *>(static_cast<void *>(member)) - Offset));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const *member) {
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>;
ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const *member) {
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>::Value;
return *static_cast<const RealParentType *>(static_cast<const void *>(static_cast<const uint8_t *>(static_cast<const void *>(member)) - Offset));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType<MemberPtr> *member) {
ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType<MemberPtr> *member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType<MemberPtr> const *member) {
ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType<MemberPtr> const *member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> &member) {
ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> &member) {
return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const &member) {
ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const &member) {
return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType<MemberPtr> &member) {
ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType<MemberPtr> &member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
constexpr ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType<MemberPtr> const &member) {
ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType<MemberPtr> const &member) {
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
}
/* Defines, for use by other code. */
/* Defines, for use by other code. */
#define OFFSETOF(parent, member) (::ams::util::impl::OffsetOf<&parent::member, parent>)
#define OFFSETOF(parent, member) (::ams::util::impl::OffsetOf<&parent::member, parent>::Value)
#define GET_PARENT_PTR(parent, member, _arg) (::ams::util::GetParentPointer<&parent::member, parent>(_arg))
#define GET_PARENT_PTR(parent, member, _arg) (::ams::util::GetParentPointer<&parent::member, parent>(_arg))
#define GET_PARENT_REF(parent, member, _arg) (::ams::util::GetParentReference<&parent::member, parent>(_arg))
namespace test {
struct Struct1 {
uint32_t a;
};
struct Struct2 {
uint32_t b;
};
struct Struct3 : public Struct1, Struct2 {
uint32_t c;
};
static_assert(impl::OffsetOf<&Struct1::a> == 0);
static_assert(impl::OffsetOf<&Struct2::b> == 0);
static_assert(impl::OffsetOf<&Struct3::a> == 0);
static_assert(impl::OffsetOf<&Struct3::b> == 0);
static_assert(impl::OffsetOf<&Struct3::a, Struct3> == 0 || impl::OffsetOf<&Struct3::b, Struct3> == 0);
static_assert(impl::OffsetOf<&Struct3::a, Struct3> == sizeof(Struct2) || impl::OffsetOf<&Struct3::b, Struct3> == sizeof(Struct1));
static_assert(impl::OffsetOf<&Struct3::c> == sizeof(Struct1) + sizeof(Struct2));
constexpr Struct3 TestStruct3 = {};
static_assert(std::addressof(TestStruct3) == GET_PARENT_PTR(Struct3, a, TestStruct3.a));
static_assert(std::addressof(TestStruct3) == GET_PARENT_PTR(Struct3, a, std::addressof(TestStruct3.a)));
static_assert(std::addressof(TestStruct3) == GET_PARENT_PTR(Struct3, b, TestStruct3.b));
static_assert(std::addressof(TestStruct3) == GET_PARENT_PTR(Struct3, b, std::addressof(TestStruct3.b)));
static_assert(std::addressof(TestStruct3) == GET_PARENT_PTR(Struct3, c, TestStruct3.c));
static_assert(std::addressof(TestStruct3) == GET_PARENT_PTR(Struct3, c, std::addressof(TestStruct3.c)));
struct CharArray {
char c0;
char c1;
char c2;
char c3;
char c4;
char c5;
char c6;
char c7;
};
static_assert(impl::OffsetOf<&CharArray::c0> == 0);
static_assert(impl::OffsetOf<&CharArray::c1> == 1);
static_assert(impl::OffsetOf<&CharArray::c2> == 2);
static_assert(impl::OffsetOf<&CharArray::c3> == 3);
static_assert(impl::OffsetOf<&CharArray::c4> == 4);
static_assert(impl::OffsetOf<&CharArray::c5> == 5);
static_assert(impl::OffsetOf<&CharArray::c6> == 6);
static_assert(impl::OffsetOf<&CharArray::c7> == 7);
constexpr CharArray TestCharArray = {};
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c0, TestCharArray.c0));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c0, std::addressof(TestCharArray.c0)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c1, TestCharArray.c1));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c1, std::addressof(TestCharArray.c1)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c2, TestCharArray.c2));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c2, std::addressof(TestCharArray.c2)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c3, TestCharArray.c3));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c3, std::addressof(TestCharArray.c3)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c4, TestCharArray.c4));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c4, std::addressof(TestCharArray.c4)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c5, TestCharArray.c5));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c5, std::addressof(TestCharArray.c5)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c6, TestCharArray.c6));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c6, std::addressof(TestCharArray.c6)));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c7, TestCharArray.c7));
static_assert(std::addressof(TestCharArray) == GET_PARENT_PTR(CharArray, c7, std::addressof(TestCharArray.c7)));
}
#define GET_PARENT_REF(parent, member, _arg) (::ams::util::GetParentReference<&parent::member, parent>(_arg))
}