diff options
| author | 2020-12-27 01:58:16 -0800 | |
|---|---|---|
| committer | 2021-01-11 14:23:16 -0800 | |
| commit | fb43b8efd22eaf0eaccf0c9ddc70cf2e06deafeb (patch) | |
| tree | 021d00f3bcdca20b1e573d9ce91cfbbe9e06b562 /src/common/parent_of_member.h | |
| parent | core: hle: kernel: Update KSynchronizationObject. (diff) | |
| download | yuzu-fb43b8efd22eaf0eaccf0c9ddc70cf2e06deafeb.tar.gz yuzu-fb43b8efd22eaf0eaccf0c9ddc70cf2e06deafeb.tar.xz yuzu-fb43b8efd22eaf0eaccf0c9ddc70cf2e06deafeb.zip | |
common: Introduce useful tree structures.
Diffstat (limited to 'src/common/parent_of_member.h')
| -rw-r--r-- | src/common/parent_of_member.h | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/common/parent_of_member.h b/src/common/parent_of_member.h new file mode 100644 index 000000000..1af31ee44 --- /dev/null +++ b/src/common/parent_of_member.h | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <type_traits> | ||
| 8 | |||
| 9 | #include "common/assert.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Common { | ||
| 13 | |||
| 14 | template <typename T, size_t Size, size_t Align> | ||
| 15 | struct TypedStorage { | ||
| 16 | std::aligned_storage_t<Size, Align> storage_; | ||
| 17 | }; | ||
| 18 | |||
| 19 | #define TYPED_STORAGE(...) TypedStorage<__VA_ARGS__, sizeof(__VA_ARGS__), alignof(__VA_ARGS__)> | ||
| 20 | |||
| 21 | template <typename T> | ||
| 22 | static constexpr T* GetPointer(TYPED_STORAGE(T) & ts) { | ||
| 23 | return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_))); | ||
| 24 | } | ||
| 25 | |||
| 26 | template <typename T> | ||
| 27 | static constexpr const T* GetPointer(const TYPED_STORAGE(T) & ts) { | ||
| 28 | return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_))); | ||
| 29 | } | ||
| 30 | |||
| 31 | namespace impl { | ||
| 32 | |||
| 33 | template <size_t MaxDepth> | ||
| 34 | struct OffsetOfUnionHolder { | ||
| 35 | template <typename ParentType, typename MemberType, size_t Offset> | ||
| 36 | union UnionImpl { | ||
| 37 | using PaddingMember = char; | ||
| 38 | static constexpr size_t GetOffset() { | ||
| 39 | return Offset; | ||
| 40 | } | ||
| 41 | |||
| 42 | #pragma pack(push, 1) | ||
| 43 | struct { | ||
| 44 | PaddingMember padding[Offset]; | ||
| 45 | MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; | ||
| 46 | } data; | ||
| 47 | #pragma pack(pop) | ||
| 48 | UnionImpl<ParentType, MemberType, Offset + 1> next_union; | ||
| 49 | }; | ||
| 50 | |||
| 51 | template <typename ParentType, typename MemberType> | ||
| 52 | union UnionImpl<ParentType, MemberType, 0> { | ||
| 53 | static constexpr size_t GetOffset() { | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | struct { | ||
| 58 | MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; | ||
| 59 | } data; | ||
| 60 | UnionImpl<ParentType, MemberType, 1> next_union; | ||
| 61 | }; | ||
| 62 | |||
| 63 | template <typename ParentType, typename MemberType> | ||
| 64 | union UnionImpl<ParentType, MemberType, MaxDepth> {}; | ||
| 65 | }; | ||
| 66 | |||
| 67 | template <typename ParentType, typename MemberType> | ||
| 68 | struct OffsetOfCalculator { | ||
| 69 | using UnionHolder = | ||
| 70 | typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType, | ||
| 71 | 0>; | ||
| 72 | union Union { | ||
| 73 | char c{}; | ||
| 74 | UnionHolder first_union; | ||
| 75 | TYPED_STORAGE(ParentType) parent; | ||
| 76 | |||
| 77 | constexpr Union() : c() {} | ||
| 78 | }; | ||
| 79 | static constexpr Union U = {}; | ||
| 80 | |||
| 81 | static constexpr const MemberType* GetNextAddress(const MemberType* start, | ||
| 82 | const MemberType* target) { | ||
| 83 | while (start < target) { | ||
| 84 | start++; | ||
| 85 | } | ||
| 86 | return start; | ||
| 87 | } | ||
| 88 | |||
| 89 | static constexpr std::ptrdiff_t GetDifference(const MemberType* start, | ||
| 90 | const MemberType* target) { | ||
| 91 | return (target - start) * sizeof(MemberType); | ||
| 92 | } | ||
| 93 | |||
| 94 | template <typename CurUnion> | ||
| 95 | static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, | ||
| 96 | CurUnion& cur_union) { | ||
| 97 | constexpr size_t Offset = CurUnion::GetOffset(); | ||
| 98 | const auto target = std::addressof(GetPointer(U.parent)->*member); | ||
| 99 | const auto start = std::addressof(cur_union.data.members[0]); | ||
| 100 | const auto next = GetNextAddress(start, target); | ||
| 101 | |||
| 102 | if (next != target) { | ||
| 103 | if constexpr (Offset < sizeof(MemberType) - 1) { | ||
| 104 | return OffsetOfImpl(member, cur_union.next_union); | ||
| 105 | } else { | ||
| 106 | UNREACHABLE(); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | return (next - start) * sizeof(MemberType) + Offset; | ||
| 111 | } | ||
| 112 | |||
| 113 | static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) { | ||
| 114 | return OffsetOfImpl(member, U.first_union); | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | |||
| 118 | template <typename T> | ||
| 119 | struct GetMemberPointerTraits; | ||
| 120 | |||
| 121 | template <typename P, typename M> | ||
| 122 | struct GetMemberPointerTraits<M P::*> { | ||
| 123 | using Parent = P; | ||
| 124 | using Member = M; | ||
| 125 | }; | ||
| 126 | |||
| 127 | template <auto MemberPtr> | ||
| 128 | using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent; | ||
| 129 | |||
| 130 | template <auto MemberPtr> | ||
| 131 | using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member; | ||
| 132 | |||
| 133 | template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> | ||
| 134 | static inline std::ptrdiff_t OffsetOf = [] { | ||
| 135 | using DeducedParentType = GetParentType<MemberPtr>; | ||
| 136 | using MemberType = GetMemberType<MemberPtr>; | ||
| 137 | static_assert(std::is_base_of<DeducedParentType, RealParentType>::value || | ||
| 138 | std::is_same<RealParentType, DeducedParentType>::value); | ||
| 139 | |||
| 140 | return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr); | ||
| 141 | }(); | ||
| 142 | |||
| 143 | } // namespace impl | ||
| 144 | |||
| 145 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 146 | constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) { | ||
| 147 | std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; | ||
| 148 | return *static_cast<RealParentType*>( | ||
| 149 | static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset)); | ||
| 150 | } | ||
| 151 | |||
| 152 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 153 | constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) { | ||
| 154 | std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>; | ||
| 155 | return *static_cast<const RealParentType*>(static_cast<const void*>( | ||
| 156 | static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset)); | ||
| 157 | } | ||
| 158 | |||
| 159 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 160 | constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) { | ||
| 161 | return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); | ||
| 162 | } | ||
| 163 | |||
| 164 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 165 | constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) { | ||
| 166 | return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); | ||
| 167 | } | ||
| 168 | |||
| 169 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 170 | constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) { | ||
| 171 | return GetParentReference<MemberPtr, RealParentType>(std::addressof(member)); | ||
| 172 | } | ||
| 173 | |||
| 174 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 175 | constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) { | ||
| 176 | return GetParentReference<MemberPtr, RealParentType>(std::addressof(member)); | ||
| 177 | } | ||
| 178 | |||
| 179 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 180 | constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) { | ||
| 181 | return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); | ||
| 182 | } | ||
| 183 | |||
| 184 | template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>> | ||
| 185 | constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) { | ||
| 186 | return std::addressof(GetParentReference<MemberPtr, RealParentType>(member)); | ||
| 187 | } | ||
| 188 | |||
| 189 | } // namespace Common | ||