parent_of_member.h 6.8 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. #include "common/common_types.h"
  8. namespace Common {
  9. namespace detail {
  10. template <typename T, size_t Size, size_t Align>
  11. struct TypedStorageImpl {
  12. std::aligned_storage_t<Size, Align> storage_;
  13. };
  14. } // namespace detail
  15. template <typename T>
  16. using TypedStorage = detail::TypedStorageImpl<T, sizeof(T), alignof(T)>;
  17. template <typename T>
  18. static constexpr T* GetPointer(TypedStorage<T>& ts) {
  19. return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_)));
  20. }
  21. template <typename T>
  22. static constexpr const T* GetPointer(const TypedStorage<T>& ts) {
  23. return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_)));
  24. }
  25. namespace impl {
  26. template <size_t MaxDepth>
  27. struct OffsetOfUnionHolder {
  28. template <typename ParentType, typename MemberType, size_t Offset>
  29. union UnionImpl {
  30. using PaddingMember = char;
  31. static constexpr size_t GetOffset() {
  32. return Offset;
  33. }
  34. #pragma pack(push, 1)
  35. struct {
  36. PaddingMember padding[Offset];
  37. MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
  38. } data;
  39. #pragma pack(pop)
  40. UnionImpl<ParentType, MemberType, Offset + 1> next_union;
  41. };
  42. template <typename ParentType, typename MemberType>
  43. union UnionImpl<ParentType, MemberType, 0> {
  44. static constexpr size_t GetOffset() {
  45. return 0;
  46. }
  47. struct {
  48. MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
  49. } data;
  50. UnionImpl<ParentType, MemberType, 1> next_union;
  51. };
  52. template <typename ParentType, typename MemberType>
  53. union UnionImpl<ParentType, MemberType, MaxDepth> {};
  54. };
  55. template <typename ParentType, typename MemberType>
  56. struct OffsetOfCalculator {
  57. using UnionHolder =
  58. typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType,
  59. 0>;
  60. union Union {
  61. char c{};
  62. UnionHolder first_union;
  63. TypedStorage<ParentType> parent;
  64. constexpr Union() : c() {}
  65. };
  66. static constexpr Union U = {};
  67. static constexpr const MemberType* GetNextAddress(const MemberType* start,
  68. const MemberType* target) {
  69. while (start < target) {
  70. start++;
  71. }
  72. return start;
  73. }
  74. static constexpr std::ptrdiff_t GetDifference(const MemberType* start,
  75. const MemberType* target) {
  76. return (target - start) * sizeof(MemberType);
  77. }
  78. template <typename CurUnion>
  79. static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member,
  80. CurUnion& cur_union) {
  81. constexpr size_t Offset = CurUnion::GetOffset();
  82. const auto target = std::addressof(GetPointer(U.parent)->*member);
  83. const auto start = std::addressof(cur_union.data.members[0]);
  84. const auto next = GetNextAddress(start, target);
  85. if (next != target) {
  86. if constexpr (Offset < sizeof(MemberType) - 1) {
  87. return OffsetOfImpl(member, cur_union.next_union);
  88. } else {
  89. UNREACHABLE();
  90. }
  91. }
  92. return (next - start) * sizeof(MemberType) + 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. static inline 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