parent_of_member.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 static_cast<ptrdiff_t>(static_cast<size_t>(next - start) * sizeof(MemberType) +
  93. Offset);
  94. }
  95. static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
  96. return OffsetOfImpl(member, U.first_union);
  97. }
  98. };
  99. template <typename T>
  100. struct GetMemberPointerTraits;
  101. template <typename P, typename M>
  102. struct GetMemberPointerTraits<M P::*> {
  103. using Parent = P;
  104. using Member = M;
  105. };
  106. template <auto MemberPtr>
  107. using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent;
  108. template <auto MemberPtr>
  109. using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
  110. template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
  111. constexpr std::ptrdiff_t OffsetOf() {
  112. using DeducedParentType = GetParentType<MemberPtr>;
  113. using MemberType = GetMemberType<MemberPtr>;
  114. static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
  115. std::is_same<RealParentType, DeducedParentType>::value);
  116. return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
  117. };
  118. } // namespace impl
  119. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  120. constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
  121. std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
  122. return *static_cast<RealParentType*>(
  123. static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
  124. }
  125. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  126. constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
  127. std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
  128. return *static_cast<const RealParentType*>(static_cast<const void*>(
  129. static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
  130. }
  131. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  132. constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) {
  133. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  134. }
  135. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  136. constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) {
  137. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  138. }
  139. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  140. constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) {
  141. return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
  142. }
  143. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  144. constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) {
  145. return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
  146. }
  147. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  148. constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) {
  149. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  150. }
  151. template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
  152. constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) {
  153. return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
  154. }
  155. } // namespace Common