parent_of_member.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <type_traits>
  6. #include "common/assert.h"
  7. namespace Common {
  8. namespace detail {
  9. template <typename T, size_t Size, size_t Align>
  10. struct TypedStorageImpl {
  11. std::aligned_storage_t<Size, Align> storage_;
  12. };
  13. } // namespace detail
  14. template <typename T>
  15. using TypedStorage = detail::TypedStorageImpl<T, sizeof(T), alignof(T)>;
  16. template <typename T>
  17. static constexpr T* GetPointer(TypedStorage<T>& ts) {
  18. return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_)));
  19. }
  20. template <typename T>
  21. static constexpr const T* GetPointer(const TypedStorage<T>& ts) {
  22. return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_)));
  23. }
  24. namespace impl {
  25. template <size_t MaxDepth>
  26. struct OffsetOfUnionHolder {
  27. template <typename ParentType, typename MemberType, size_t Offset>
  28. union UnionImpl {
  29. using PaddingMember = char;
  30. static constexpr size_t GetOffset() {
  31. return Offset;
  32. }
  33. #pragma pack(push, 1)
  34. struct {
  35. PaddingMember padding[Offset];
  36. MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
  37. } data;
  38. #pragma pack(pop)
  39. UnionImpl<ParentType, MemberType, Offset + 1> next_union;
  40. };
  41. template <typename ParentType, typename MemberType>
  42. union UnionImpl<ParentType, MemberType, 0> {
  43. static constexpr size_t GetOffset() {
  44. return 0;
  45. }
  46. struct {
  47. MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
  48. } data;
  49. UnionImpl<ParentType, MemberType, 1> next_union;
  50. };
  51. template <typename ParentType, typename MemberType>
  52. union UnionImpl<ParentType, MemberType, MaxDepth> {};
  53. };
  54. template <typename ParentType, typename MemberType>
  55. struct OffsetOfCalculator {
  56. using UnionHolder =
  57. typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType,
  58. 0>;
  59. union Union {
  60. char c{};
  61. UnionHolder first_union;
  62. TypedStorage<ParentType> parent;
  63. constexpr Union() : c() {}
  64. };
  65. static constexpr Union U = {};
  66. static constexpr const MemberType* GetNextAddress(const MemberType* start,
  67. const MemberType* target) {
  68. while (start < target) {
  69. start++;
  70. }
  71. return start;
  72. }
  73. static constexpr std::ptrdiff_t GetDifference(const MemberType* start,
  74. const MemberType* target) {
  75. return (target - start) * sizeof(MemberType);
  76. }
  77. template <typename CurUnion>
  78. static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member,
  79. CurUnion& cur_union) {
  80. constexpr size_t Offset = CurUnion::GetOffset();
  81. const auto target = std::addressof(GetPointer(U.parent)->*member);
  82. const auto start = std::addressof(cur_union.data.members[0]);
  83. const auto next = GetNextAddress(start, target);
  84. if (next != target) {
  85. if constexpr (Offset < sizeof(MemberType) - 1) {
  86. return OffsetOfImpl(member, cur_union.next_union);
  87. } else {
  88. UNREACHABLE();
  89. }
  90. }
  91. return static_cast<ptrdiff_t>(static_cast<size_t>(next - start) * sizeof(MemberType) +
  92. Offset);
  93. }
  94. static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
  95. return OffsetOfImpl(member, U.first_union);
  96. }
  97. };
  98. template <typename T>
  99. struct GetMemberPointerTraits;
  100. template <typename P, typename M>
  101. struct GetMemberPointerTraits<M P::*> {
  102. using Parent = P;
  103. using Member = M;
  104. };
  105. template <auto MemberPtr>
  106. using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent;
  107. template <auto MemberPtr>
  108. using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
  109. template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
  110. constexpr std::ptrdiff_t OffsetOf() {
  111. using DeducedParentType = GetParentType<MemberPtr>;
  112. using MemberType = GetMemberType<MemberPtr>;
  113. static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
  114. std::is_same<RealParentType, DeducedParentType>::value);
  115. return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
  116. };
  117. } // namespace impl
  118. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  119. constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
  120. std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
  121. return *static_cast<RealParentType*>(
  122. static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
  123. }
  124. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  125. constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
  126. std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
  127. return *static_cast<const RealParentType*>(static_cast<const void*>(
  128. static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
  129. }
  130. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  131. constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) {
  132. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  133. }
  134. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  135. constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) {
  136. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  137. }
  138. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  139. constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) {
  140. return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
  141. }
  142. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  143. constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) {
  144. return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
  145. }
  146. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  147. constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) {
  148. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  149. }
  150. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  151. constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) {
  152. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  153. }
  154. } // namespace Common