| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #pragma once
- #include <type_traits>
- #include "common/assert.h"
- namespace Common {
- namespace detail {
- template <typename T, size_t Size, size_t Align>
- struct TypedStorageImpl {
- alignas(Align) u8 storage_[Size];
- };
- } // namespace detail
- template <typename T>
- using TypedStorage = detail::TypedStorageImpl<T, sizeof(T), alignof(T)>;
- template <typename T>
- static constexpr T* GetPointer(TypedStorage<T>& ts) {
- return static_cast<T*>(static_cast<void*>(std::addressof(ts.storage_)));
- }
- template <typename T>
- static constexpr const T* GetPointer(const TypedStorage<T>& ts) {
- return static_cast<const T*>(static_cast<const void*>(std::addressof(ts.storage_)));
- }
- namespace impl {
- template <size_t MaxDepth>
- struct OffsetOfUnionHolder {
- template <typename ParentType, typename MemberType, size_t Offset>
- union UnionImpl {
- using PaddingMember = char;
- static constexpr size_t GetOffset() {
- return Offset;
- }
- #pragma pack(push, 1)
- struct {
- PaddingMember padding[Offset];
- MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
- } data;
- #pragma pack(pop)
- UnionImpl<ParentType, MemberType, Offset + 1> next_union;
- };
- template <typename ParentType, typename MemberType>
- union UnionImpl<ParentType, MemberType, 0> {
- static constexpr size_t GetOffset() {
- return 0;
- }
- struct {
- MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1];
- } data;
- UnionImpl<ParentType, MemberType, 1> next_union;
- };
- template <typename ParentType, typename MemberType>
- union UnionImpl<ParentType, MemberType, MaxDepth> {};
- };
- template <typename ParentType, typename MemberType>
- struct OffsetOfCalculator {
- using UnionHolder =
- typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType,
- 0>;
- union Union {
- char c{};
- UnionHolder first_union;
- TypedStorage<ParentType> parent;
- constexpr Union() : c() {}
- };
- static constexpr Union U = {};
- static constexpr const MemberType* GetNextAddress(const MemberType* start,
- const MemberType* target) {
- while (start < target) {
- start++;
- }
- return start;
- }
- static constexpr std::ptrdiff_t GetDifference(const MemberType* start,
- const MemberType* target) {
- return (target - start) * sizeof(MemberType);
- }
- template <typename CurUnion>
- static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member,
- CurUnion& cur_union) {
- constexpr size_t Offset = CurUnion::GetOffset();
- const auto target = std::addressof(GetPointer(U.parent)->*member);
- const auto start = std::addressof(cur_union.data.members[0]);
- const auto next = GetNextAddress(start, target);
- if (next != target) {
- if constexpr (Offset < sizeof(MemberType) - 1) {
- return OffsetOfImpl(member, cur_union.next_union);
- } else {
- UNREACHABLE();
- }
- }
- return static_cast<ptrdiff_t>(static_cast<size_t>(next - start) * sizeof(MemberType) +
- Offset);
- }
- static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
- return OffsetOfImpl(member, U.first_union);
- }
- };
- template <typename T>
- struct GetMemberPointerTraits;
- template <typename P, typename M>
- struct GetMemberPointerTraits<M P::*> {
- using Parent = P;
- using Member = M;
- };
- template <auto MemberPtr>
- using GetParentType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Parent;
- template <auto MemberPtr>
- using GetMemberType = typename GetMemberPointerTraits<decltype(MemberPtr)>::Member;
- template <auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>>
- constexpr std::ptrdiff_t OffsetOf() {
- using DeducedParentType = GetParentType<MemberPtr>;
- using MemberType = GetMemberType<MemberPtr>;
- static_assert(std::is_base_of<DeducedParentType, RealParentType>::value ||
- std::is_same<RealParentType, DeducedParentType>::value);
- return OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
- };
- } // namespace impl
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>* member) {
- std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
- return *static_cast<RealParentType*>(
- static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(member)) - Offset));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const* member) {
- std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>();
- return *static_cast<const RealParentType*>(static_cast<const void*>(
- static_cast<const uint8_t*>(static_cast<const void*>(member)) - Offset));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>* member) {
- return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const* member) {
- return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType& GetParentReference(impl::GetMemberType<MemberPtr>& member) {
- return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType const& GetParentReference(impl::GetMemberType<MemberPtr> const& member) {
- return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType* GetParentPointer(impl::GetMemberType<MemberPtr>& member) {
- return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
- }
- template <auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
- constexpr RealParentType const* GetParentPointer(impl::GetMemberType<MemberPtr> const& member) {
- return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
- }
- } // namespace Common
|