mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-23 04:12:02 +00:00
util: improve (and use) offsetof that's """standard compliant"""
This commit is contained in:
parent
ad4c794aea
commit
ec6d1a92ef
2 changed files with 71 additions and 87 deletions
|
@ -502,7 +502,7 @@ namespace ams::util {
|
||||||
return util::GetParentPointer<Member, Derived>(node);
|
return util::GetParentPointer<Member, Derived>(node);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static_assert(util::IsAligned(util::impl::OffsetOf<Member, Derived>::Value, alignof(void *)));
|
static_assert(util::IsAligned(util::impl::OffsetOf<Member, Derived>::value, alignof(void *)));
|
||||||
};
|
};
|
||||||
|
|
||||||
template<auto T, class Derived = util::impl::GetParentType<T>>
|
template<auto T, class Derived = util::impl::GetParentType<T>>
|
||||||
|
@ -516,7 +516,7 @@ namespace ams::util {
|
||||||
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
|
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
|
||||||
|
|
||||||
static constexpr bool IsValid() {
|
static constexpr bool IsValid() {
|
||||||
return util::IsAligned(util::impl::OffsetOf<Member, Derived>::Value, alignof(void *));
|
return util::IsAligned(util::impl::OffsetOf<Member, Derived>::value, alignof(void *));
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
template<class, class, class>
|
template<class, class, class>
|
||||||
|
|
|
@ -23,98 +23,85 @@ namespace ams::util {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
#define AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT 0
|
#define AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT 1
|
||||||
|
|
||||||
#if AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT
|
#if AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT
|
||||||
|
|
||||||
template<size_t MaxDepth>
|
template<std::ptrdiff_t Offset, typename P, typename M, auto Ptr>
|
||||||
struct OffsetOfUnionHolder {
|
consteval std::strong_ordering TestOffsetForOffsetOfImpl() {
|
||||||
template<typename ParentType, typename MemberType, size_t Offset>
|
|
||||||
union UnionImpl {
|
|
||||||
using PaddingMember = char;
|
|
||||||
static constexpr size_t GetOffset() { return Offset; }
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct {
|
const union Union {
|
||||||
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, MaxDepth> { /* Empty ... */ };
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename ParentType, typename MemberType>
|
|
||||||
struct OffsetOfCalculator {
|
|
||||||
using UnionHolder = typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType, 0>;
|
|
||||||
union Union {
|
|
||||||
char c;
|
char c;
|
||||||
UnionHolder first_union;
|
struct {
|
||||||
ParentType parent;
|
char padding[Offset];
|
||||||
|
M members[1 + (sizeof(P) / std::max<size_t>(sizeof(M), 1))];
|
||||||
/* This coerces the active member to be c. */
|
|
||||||
constexpr Union() : c() { /* ... */ }
|
|
||||||
constexpr ~Union() { std::destroy_at(std::addressof(c)); }
|
|
||||||
};
|
};
|
||||||
static constexpr Union U = {};
|
P p;
|
||||||
|
|
||||||
static constexpr const MemberType *GetNextAddress(const MemberType *start, const MemberType *target) {
|
constexpr Union() : c() { /* ... */ }
|
||||||
while (start < target) {
|
constexpr ~Union() { /* ... */ }
|
||||||
start++;
|
} U;
|
||||||
}
|
#pragma pack(pop)
|
||||||
return start;
|
|
||||||
|
const M *target = std::addressof(U.p.*Ptr);
|
||||||
|
const M *guess = std::addressof(U.members[0]);
|
||||||
|
|
||||||
|
/* NOTE: target == guess is definitely legal, target < guess is probably legal, definitely legal if Offset <= true offsetof. */
|
||||||
|
/* <=> may or may not be legal, but it definitely seems to work. Evaluate again, if it breaks. */
|
||||||
|
return guess <=> target;
|
||||||
|
|
||||||
|
//if (guess == target) {
|
||||||
|
// return std::strong_ordering::equal;
|
||||||
|
//} else if (guess < target) {
|
||||||
|
// return std::strong_ordering::less;
|
||||||
|
//} else {
|
||||||
|
// return std::strong_ordering::greater;
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::ptrdiff_t GetDifference(const MemberType *start, const MemberType *target) {
|
template<std::ptrdiff_t Low, std::ptrdiff_t High, typename P, typename M, auto Ptr>
|
||||||
return (target - start) * sizeof(MemberType);
|
consteval std::ptrdiff_t OffsetOfImpl() {
|
||||||
}
|
static_assert(Low <= High);
|
||||||
|
|
||||||
template<typename CurUnion>
|
constexpr std::ptrdiff_t Guess = (Low + High) / 2;
|
||||||
static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, CurUnion &cur_union) {
|
constexpr auto Order = TestOffsetForOffsetOfImpl<Guess, P, M, Ptr>();
|
||||||
constexpr size_t Offset = CurUnion::GetOffset();
|
|
||||||
const auto target = std::addressof(U.parent.*member);
|
|
||||||
const auto start = std::addressof(cur_union.data.members[0]);
|
|
||||||
const auto next = GetNextAddress(start, target);
|
|
||||||
|
|
||||||
if (next != target) {
|
if constexpr (Order == std::strong_ordering::equal) {
|
||||||
if constexpr (Offset < sizeof(MemberType) - 1) {
|
return Guess;
|
||||||
return OffsetOfImpl(member, cur_union.next_union);
|
} else if constexpr (Order == std::strong_ordering::less) {
|
||||||
|
return OffsetOfImpl<Guess + 1, High, P, M, Ptr>();
|
||||||
} else {
|
} else {
|
||||||
__builtin_unreachable();
|
static_assert(Order == std::strong_ordering::greater);
|
||||||
|
return OffsetOfImpl<Low, Guess - 1, P, M, Ptr>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (next - start) * sizeof(MemberType) + Offset;
|
template<typename P, typename M, auto Ptr>
|
||||||
}
|
struct OffsetOfCalculator {
|
||||||
|
static constexpr const std::ptrdiff_t Value = OffsetOfImpl<0, sizeof(P), P, M, Ptr>();
|
||||||
|
|
||||||
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
|
||||||
return OffsetOfImpl(member, U.first_union);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
template<typename T>
|
template<typename ParentType, typename MemberType, auto Ptr>
|
||||||
union HelperUnion {
|
struct OffsetOfCalculator {
|
||||||
T v;
|
private:
|
||||||
|
static consteval std::ptrdiff_t Calculate() {
|
||||||
|
const union Union {
|
||||||
|
ParentType p;
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
constexpr HelperUnion() : c() { /* ... */ }
|
constexpr Union() : c() { /* ... */ }
|
||||||
constexpr ~HelperUnion() { std::destroy_at(std::addressof(c)); }
|
constexpr ~Union() { /* ... */ }
|
||||||
};
|
} U;
|
||||||
|
|
||||||
|
const auto *parent = std::addressof(U.p);
|
||||||
|
const auto *target = std::addressof(parent->*Ptr);
|
||||||
|
|
||||||
template<typename ParentType, typename MemberType>
|
|
||||||
struct OffsetOfCalculator {
|
|
||||||
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
|
||||||
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));
|
return static_cast<const uint8_t *>(static_cast<const void *>(target)) - static_cast<const uint8_t *>(static_cast<const void *>(parent));
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
static constexpr const std::ptrdiff_t Value = Calculate();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -135,22 +122,19 @@ namespace ams::util {
|
||||||
using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
|
using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
|
||||||
|
|
||||||
template<auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> requires (std::derived_from<RealParentType, GetParentType<MemberPtr>> || std::same_as<RealParentType, GetParentType<MemberPtr>>)
|
template<auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> requires (std::derived_from<RealParentType, GetParentType<MemberPtr>> || std::same_as<RealParentType, GetParentType<MemberPtr>>)
|
||||||
struct OffsetOf {
|
struct OffsetOf : public std::integral_constant<std::ptrdiff_t, OffsetOfCalculator<RealParentType, GetMemberType<MemberPtr>, MemberPtr>::Value> {};
|
||||||
using MemberType = GetMemberType<MemberPtr>;
|
|
||||||
|
|
||||||
static constexpr std::ptrdiff_t Value = OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
||||||
ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> *member) {
|
ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> *member) {
|
||||||
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>::Value;
|
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));
|
return *static_cast<RealParentType *>(static_cast<void *>(static_cast<uint8_t *>(static_cast<void *>(member)) - Offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
||||||
ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const *member) {
|
ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const *member) {
|
||||||
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>::Value;
|
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));
|
return *static_cast<const RealParentType *>(static_cast<const void *>(static_cast<const uint8_t *>(static_cast<const void *>(member)) - Offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +171,7 @@ namespace ams::util {
|
||||||
|
|
||||||
/* Defines, for use by other code. */
|
/* Defines, for use by other code. */
|
||||||
|
|
||||||
#define OFFSETOF(parent, member) (::ams::util::impl::OffsetOf<&parent::member, parent>::Value)
|
#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))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue