mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-11 02:22:28 +00:00
util: faster constexpr offsetof calc, at the cost of standards compliance
This commit is contained in:
parent
a6e3a93c07
commit
b8072b1398
1 changed files with 84 additions and 66 deletions
|
@ -23,83 +23,101 @@ namespace ams::util {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
template<size_t MaxDepth>
|
#define AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT 0
|
||||||
struct OffsetOfUnionHolder {
|
|
||||||
template<typename ParentType, typename MemberType, size_t Offset>
|
|
||||||
union UnionImpl {
|
|
||||||
using PaddingMember = char;
|
|
||||||
static constexpr size_t GetOffset() { return Offset; }
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#if AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT
|
||||||
struct {
|
|
||||||
PaddingMember padding[Offset];
|
template<size_t MaxDepth>
|
||||||
MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
|
struct OffsetOfUnionHolder {
|
||||||
} data;
|
template<typename ParentType, typename MemberType, size_t Offset>
|
||||||
#pragma pack(pop)
|
union UnionImpl {
|
||||||
UnionImpl<ParentType, MemberType, Offset + 1> next_union;
|
using PaddingMember = char;
|
||||||
|
static constexpr size_t GetOffset() { return Offset; }
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct {
|
||||||
|
PaddingMember padding[Offset];
|
||||||
|
MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
|
||||||
|
} data;
|
||||||
|
#pragma pack(pop)
|
||||||
|
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 ... */ };
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ParentType, typename MemberType>
|
template<typename ParentType, typename MemberType>
|
||||||
union UnionImpl<ParentType, MemberType, 0> {
|
struct OffsetOfCalculator {
|
||||||
static constexpr size_t GetOffset() { return 0; }
|
using UnionHolder = typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType, 0>;
|
||||||
|
union Union {
|
||||||
|
char c;
|
||||||
|
UnionHolder first_union;
|
||||||
|
TYPED_STORAGE(ParentType) parent;
|
||||||
|
|
||||||
struct {
|
/* This coerces the active member to be c. */
|
||||||
MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
|
constexpr Union() : c() { /* ... */ }
|
||||||
} data;
|
};
|
||||||
UnionImpl<ParentType, MemberType, 1> next_union;
|
static constexpr Union U = {};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ParentType, typename MemberType>
|
static constexpr const MemberType *GetNextAddress(const MemberType *start, const MemberType *target) {
|
||||||
union UnionImpl<ParentType, MemberType, MaxDepth> { /* Empty ... */ };
|
while (start < target) {
|
||||||
};
|
start++;
|
||||||
|
|
||||||
template<typename ParentType, typename MemberType>
|
|
||||||
struct OffsetOfCalculator {
|
|
||||||
using UnionHolder = typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType, 0>;
|
|
||||||
union Union {
|
|
||||||
char c;
|
|
||||||
UnionHolder first_union;
|
|
||||||
TYPED_STORAGE(ParentType) parent;
|
|
||||||
|
|
||||||
/* This coerces the active member to be c. */
|
|
||||||
constexpr Union() : c() { /* ... */ }
|
|
||||||
};
|
|
||||||
static constexpr Union U = {};
|
|
||||||
|
|
||||||
static constexpr const MemberType *GetNextAddress(const MemberType *start, const MemberType *target) {
|
|
||||||
while (start < target) {
|
|
||||||
start++;
|
|
||||||
}
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr std::ptrdiff_t GetDifference(const MemberType *start, const MemberType *target) {
|
|
||||||
return (target - start) * sizeof(MemberType);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 start = std::addressof(cur_union.data.members[0]);
|
|
||||||
const auto next = GetNextAddress(start, target);
|
|
||||||
|
|
||||||
if (next != target) {
|
|
||||||
if constexpr (Offset < sizeof(MemberType) - 1) {
|
|
||||||
return OffsetOfImpl(member, cur_union.next_union);
|
|
||||||
} else {
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
}
|
||||||
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (next - start) * sizeof(MemberType) + Offset;
|
static constexpr std::ptrdiff_t GetDifference(const MemberType *start, const MemberType *target) {
|
||||||
}
|
return (target - start) * sizeof(MemberType);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 start = std::addressof(cur_union.data.members[0]);
|
||||||
|
const auto next = GetNextAddress(start, target);
|
||||||
|
|
||||||
|
if (next != target) {
|
||||||
|
if constexpr (Offset < sizeof(MemberType) - 1) {
|
||||||
|
return OffsetOfImpl(member, cur_union.next_union);
|
||||||
|
} else {
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (next - start) * sizeof(MemberType) + Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
||||||
return OffsetOfImpl(member, U.first_union);
|
return OffsetOfImpl(member, U.first_union);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template<typename ParentType, typename MemberType>
|
||||||
|
struct OffsetOfCalculator {
|
||||||
|
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
||||||
|
constexpr TYPED_STORAGE(ParentType) Holder = {};
|
||||||
|
const auto *parent = GetPointer(Holder);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct GetMemberPointerTraits;
|
struct GetMemberPointerTraits;
|
||||||
|
|
Loading…
Reference in a new issue