summaryrefslogtreecommitdiff
path: root/src/common/parent_of_member.h
diff options
context:
space:
mode:
authorGravatar bunnei2020-12-27 01:58:16 -0800
committerGravatar bunnei2021-01-11 14:23:16 -0800
commitfb43b8efd22eaf0eaccf0c9ddc70cf2e06deafeb (patch)
tree021d00f3bcdca20b1e573d9ce91cfbbe9e06b562 /src/common/parent_of_member.h
parentcore: hle: kernel: Update KSynchronizationObject. (diff)
downloadyuzu-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.h189
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
12namespace Common {
13
14template <typename T, size_t Size, size_t Align>
15struct 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
21template <typename T>
22static constexpr T* GetPointer(TYPED_STORAGE(T) & ts) {
23 return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_)));
24}
25
26template <typename T>
27static 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
31namespace impl {
32
33template <size_t MaxDepth>
34struct 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
67template <typename ParentType, typename MemberType>
68struct 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
118template <typename T>
119struct GetMemberPointerTraits;
120
121template <typename P, typename M>
122struct GetMemberPointerTraits<M P::*> {
123 using Parent = P;
124 using Member = M;
125};
126
127template <auto MemberPtr>
128using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent;
129
130template <auto MemberPtr>
131using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
132
133template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
134static 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
145template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
146constexpr 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
152template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
153constexpr 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
159template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
160constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) {
161 return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
162}
163
164template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
165constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) {
166 return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
167}
168
169template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
170constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) {
171 return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
172}
173
174template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
175constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) {
176 return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
177}
178
179template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
180constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) {
181 return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
182}
183
184template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
185constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) {
186 return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
187}
188
189} // namespace Common