parent_of_member.h 6.8 KB

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