diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp index 9eb5b23c5..d423f5b79 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp @@ -502,7 +502,7 @@ namespace ams::util { return util::GetParentPointer(node); } private: - static_assert(util::IsAligned(util::impl::OffsetOf::Value, alignof(void *))); + static_assert(util::IsAligned(util::impl::OffsetOf::value, alignof(void *))); }; template> @@ -516,7 +516,7 @@ namespace ams::util { using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl; static constexpr bool IsValid() { - return util::IsAligned(util::impl::OffsetOf::Value, alignof(void *)); + return util::IsAligned(util::impl::OffsetOf::value, alignof(void *)); } private: template diff --git a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp index 6a899a65d..74ddc40f7 100644 --- a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp +++ b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp @@ -23,98 +23,85 @@ namespace ams::util { 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 - template - struct OffsetOfUnionHolder { - template - union UnionImpl { - 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 next_union; - }; - - template - union UnionImpl { /* Empty ... */ }; - }; - - template - struct OffsetOfCalculator { - using UnionHolder = typename OffsetOfUnionHolder::template UnionImpl; - union Union { + template + consteval std::strong_ordering TestOffsetForOffsetOfImpl() { + #pragma pack(push, 1) + const union Union { char c; - UnionHolder first_union; - ParentType parent; + struct { + char padding[Offset]; + M members[1 + (sizeof(P) / std::max(sizeof(M), 1))]; + }; + P p; - /* This coerces the active member to be c. */ constexpr Union() : c() { /* ... */ } - constexpr ~Union() { std::destroy_at(std::addressof(c)); } - }; - static constexpr Union U = {}; + constexpr ~Union() { /* ... */ } + } U; + #pragma pack(pop) - static constexpr const MemberType *GetNextAddress(const MemberType *start, const MemberType *target) { - while (start < target) { - start++; - } - 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; + //} + } + + template + consteval std::ptrdiff_t OffsetOfImpl() { + static_assert(Low <= High); + + constexpr std::ptrdiff_t Guess = (Low + High) / 2; + constexpr auto Order = TestOffsetForOffsetOfImpl(); + + if constexpr (Order == std::strong_ordering::equal) { + return Guess; + } else if constexpr (Order == std::strong_ordering::less) { + return OffsetOfImpl(); + } else { + static_assert(Order == std::strong_ordering::greater); + return OffsetOfImpl(); } + } - static constexpr std::ptrdiff_t GetDifference(const MemberType *start, const MemberType *target) { - return (target - start) * sizeof(MemberType); - } - - template - static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, CurUnion &cur_union) { - 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 (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) { - return OffsetOfImpl(member, U.first_union); - } + template + struct OffsetOfCalculator { + static constexpr const std::ptrdiff_t Value = OffsetOfImpl<0, sizeof(P), P, M, Ptr>(); }; #else - template - union HelperUnion { - T v; - char c; - - constexpr HelperUnion() : c() { /* ... */ } - constexpr ~HelperUnion() { std::destroy_at(std::addressof(c)); } - }; - - template + template struct OffsetOfCalculator { - static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) { - constexpr HelperUnion Holder = {}; - const auto *parent = std::addressof(Holder.v); - const auto *target = std::addressof(parent->*member); - return static_cast(static_cast(target)) - static_cast(static_cast(parent)); - } + private: + static consteval std::ptrdiff_t Calculate() { + const union Union { + ParentType p; + char c; + + constexpr Union() : c() { /* ... */ } + constexpr ~Union() { /* ... */ } + } U; + + const auto *parent = std::addressof(U.p); + const auto *target = std::addressof(parent->*Ptr); + + return static_cast(static_cast(target)) - static_cast(static_cast(parent)); + } + public: + static constexpr const std::ptrdiff_t Value = Calculate(); }; #endif @@ -135,22 +122,19 @@ namespace ams::util { using GetMemberType = typename GetMemberPointerTraits::Member; template> requires (std::derived_from> || std::same_as>) - struct OffsetOf { - using MemberType = GetMemberType; + struct OffsetOf : public std::integral_constant, MemberPtr>::Value> {}; - static constexpr std::ptrdiff_t Value = OffsetOfCalculator::OffsetOf(MemberPtr); - }; } template> ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType *member) { - constexpr std::ptrdiff_t Offset = impl::OffsetOf::Value; + constexpr std::ptrdiff_t Offset = impl::OffsetOf::value; return *static_cast(static_cast(static_cast(static_cast(member)) - Offset)); } template> ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType const *member) { - constexpr std::ptrdiff_t Offset = impl::OffsetOf::Value; + constexpr std::ptrdiff_t Offset = impl::OffsetOf::value; return *static_cast(static_cast(static_cast(static_cast(member)) - Offset)); } @@ -187,7 +171,7 @@ namespace ams::util { /* 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))