2019-12-09 11:57:37 +00:00
|
|
|
/*
|
2021-10-04 19:59:10 +00:00
|
|
|
* Copyright (c) Atmosphère-NX
|
2019-12-09 11:57:37 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms and conditions of the GNU General Public License,
|
|
|
|
* version 2, as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
2020-02-23 07:05:14 +00:00
|
|
|
#include <vapours/common.hpp>
|
|
|
|
#include <vapours/assert.hpp>
|
|
|
|
#include <vapours/util/util_typed_storage.hpp>
|
2019-12-09 11:57:37 +00:00
|
|
|
|
|
|
|
namespace ams::util {
|
|
|
|
|
|
|
|
namespace impl {
|
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
#define AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT 0
|
|
|
|
|
|
|
|
#if AMS_UTIL_OFFSET_OF_STANDARD_COMPLIANT
|
|
|
|
|
|
|
|
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, MaxDepth> { /* Empty ... */ };
|
2020-01-16 05:35:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename ParentType, typename MemberType>
|
2021-01-08 12:07:42 +00:00
|
|
|
struct OffsetOfCalculator {
|
|
|
|
using UnionHolder = typename OffsetOfUnionHolder<sizeof(MemberType)>::template UnionImpl<ParentType, MemberType, 0>;
|
|
|
|
union Union {
|
|
|
|
char c;
|
|
|
|
UnionHolder first_union;
|
2021-10-17 09:39:16 +00:00
|
|
|
ParentType parent;
|
2021-01-08 12:07:42 +00:00
|
|
|
|
|
|
|
/* This coerces the active member to be c. */
|
|
|
|
constexpr Union() : c() { /* ... */ }
|
2021-10-17 09:39:16 +00:00
|
|
|
constexpr ~Union() { std::destroy_at(std::addressof(c)); }
|
2021-01-08 12:07:42 +00:00
|
|
|
};
|
|
|
|
static constexpr Union U = {};
|
|
|
|
|
|
|
|
static constexpr const MemberType *GetNextAddress(const MemberType *start, const MemberType *target) {
|
|
|
|
while (start < target) {
|
|
|
|
start++;
|
|
|
|
}
|
|
|
|
return start;
|
|
|
|
}
|
2020-01-16 05:35:14 +00:00
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
static constexpr std::ptrdiff_t GetDifference(const MemberType *start, const MemberType *target) {
|
|
|
|
return (target - start) * sizeof(MemberType);
|
|
|
|
}
|
2020-01-16 05:35:14 +00:00
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
template<typename CurUnion>
|
|
|
|
static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, CurUnion &cur_union) {
|
|
|
|
constexpr size_t Offset = CurUnion::GetOffset();
|
2021-10-17 09:39:16 +00:00
|
|
|
const auto target = std::addressof(U.parent.*member);
|
2021-01-08 12:07:42 +00:00
|
|
|
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 {
|
|
|
|
__builtin_unreachable();
|
|
|
|
}
|
|
|
|
}
|
2019-12-09 11:57:37 +00:00
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
return (next - start) * sizeof(MemberType) + Offset;
|
|
|
|
}
|
2020-01-16 05:35:14 +00:00
|
|
|
|
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
|
|
|
return OffsetOfImpl(member, U.first_union);
|
2020-01-16 05:35:14 +00:00
|
|
|
}
|
2021-01-08 12:07:42 +00:00
|
|
|
};
|
2020-01-16 05:35:14 +00:00
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
#else
|
2020-01-16 05:35:14 +00:00
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
template<typename T>
|
|
|
|
union HelperUnion {
|
|
|
|
T v;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
constexpr HelperUnion() : c() { /* ... */ }
|
|
|
|
constexpr ~HelperUnion() { std::destroy_at(std::addressof(c)); }
|
|
|
|
};
|
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
template<typename ParentType, typename MemberType>
|
|
|
|
struct OffsetOfCalculator {
|
|
|
|
static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) {
|
2021-10-17 09:39:16 +00:00
|
|
|
constexpr HelperUnion<ParentType> Holder = {};
|
|
|
|
const auto *parent = std::addressof(Holder.v);
|
2021-01-08 12:07:42 +00:00
|
|
|
const auto *target = std::addressof(parent->*member);
|
|
|
|
return static_cast<const uint8_t *>(static_cast<const void *>(target)) - static_cast<const uint8_t *>(static_cast<const void *>(parent));
|
|
|
|
}
|
|
|
|
};
|
2020-01-16 05:35:14 +00:00
|
|
|
|
2021-01-08 12:07:42 +00:00
|
|
|
#endif
|
2019-12-09 11:57:37 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
template<auto MemberPtr, typename RealParentType = GetParentType<MemberPtr>> requires (std::derived_from<RealParentType, GetParentType<MemberPtr>> || std::same_as<RealParentType, GetParentType<MemberPtr>>)
|
|
|
|
struct OffsetOf {
|
|
|
|
using MemberType = GetMemberType<MemberPtr>;
|
2020-01-16 05:35:14 +00:00
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
static constexpr std::ptrdiff_t Value = OffsetOfCalculator<RealParentType, MemberType>::OffsetOf(MemberPtr);
|
|
|
|
};
|
2020-01-16 05:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> *member) {
|
|
|
|
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>::Value;
|
2020-01-16 07:47:14 +00:00
|
|
|
return *static_cast<RealParentType *>(static_cast<void *>(static_cast<uint8_t *>(static_cast<void *>(member)) - Offset));
|
2019-12-09 11:57:37 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 05:35:14 +00:00
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const *member) {
|
|
|
|
constexpr std::ptrdiff_t Offset = impl::OffsetOf<MemberPtr, RealParentType>::Value;
|
2020-01-16 07:47:14 +00:00
|
|
|
return *static_cast<const RealParentType *>(static_cast<const void *>(static_cast<const uint8_t *>(static_cast<const void *>(member)) - Offset));
|
2019-12-09 11:57:37 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 05:35:14 +00:00
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType<MemberPtr> *member) {
|
2020-01-16 05:35:14 +00:00
|
|
|
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
|
2019-12-09 11:57:37 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 05:35:14 +00:00
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType<MemberPtr> const *member) {
|
2020-01-16 05:35:14 +00:00
|
|
|
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
|
2019-12-09 11:57:37 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 07:47:14 +00:00
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType<MemberPtr> &member) {
|
2020-01-16 07:47:14 +00:00
|
|
|
return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType<MemberPtr> const &member) {
|
2020-01-16 07:47:14 +00:00
|
|
|
return GetParentReference<MemberPtr, RealParentType>(std::addressof(member));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType<MemberPtr> &member) {
|
2020-01-16 07:47:14 +00:00
|
|
|
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<auto MemberPtr, typename RealParentType = impl::GetParentType<MemberPtr>>
|
2021-10-17 09:39:16 +00:00
|
|
|
ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType<MemberPtr> const &member) {
|
2020-01-16 07:47:14 +00:00
|
|
|
return std::addressof(GetParentReference<MemberPtr, RealParentType>(member));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
/* Defines, for use by other code. */
|
2020-01-16 07:47:14 +00:00
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
#define OFFSETOF(parent, member) (::ams::util::impl::OffsetOf<&parent::member, parent>::Value)
|
2020-01-16 07:47:14 +00:00
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
#define GET_PARENT_PTR(parent, member, _arg) (::ams::util::GetParentPointer<&parent::member, parent>(_arg))
|
2020-01-16 07:47:14 +00:00
|
|
|
|
2021-10-17 09:39:16 +00:00
|
|
|
#define GET_PARENT_REF(parent, member, _arg) (::ams::util::GetParentReference<&parent::member, parent>(_arg))
|
2019-12-09 11:57:37 +00:00
|
|
|
|
2020-01-16 05:35:14 +00:00
|
|
|
}
|