/* * Copyright (c) Atmosphère-NX * * 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 . */ #pragma once #include #include namespace ams::kern { /* NOTE: This header is included after all other KAutoObjects. */ namespace impl { template requires std::derived_from consteval bool IsAutoObjectInheritanceValidImpl() { #define CLASS_TOKEN_HANDLER(CLASSNAME) \ if constexpr (std::same_as) { \ if (T::GetStaticTypeObj().GetClassToken() != ::ams::kern::ClassToken) { \ return false; \ } \ } else { \ if (T::GetStaticTypeObj().IsDerivedFrom(CLASSNAME::GetStaticTypeObj()) != std::derived_from) { \ return false; \ } \ } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return true; } consteval bool IsEveryAutoObjectInheritanceValid() { #define CLASS_TOKEN_HANDLER(CLASSNAME) if (!IsAutoObjectInheritanceValidImpl()) { return false; } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return true; } static_assert(IsEveryAutoObjectInheritanceValid()); template concept IsAutoObjectWithSpecializedGetId = std::derived_from && requires (const T &t, const KAutoObjectWithList &l) { { t.GetIdImpl() } -> std::same_as; }; template struct AutoObjectWithListComparatorImpl { using RedBlackKeyType = u64; static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; } static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KAutoObjectWithList &v) { if constexpr (IsAutoObjectWithSpecializedGetId) { return static_cast(v).GetIdImpl(); } else { return reinterpret_cast(std::addressof(v)); } } template requires (std::same_as || std::same_as) static ALWAYS_INLINE int Compare(const U &lhs, const KAutoObjectWithList &rhs) { const u64 lid = GetRedBlackKey(lhs); const u64 rid = GetRedBlackKey(rhs); if (lid < rid) { return -1; } else if (lid > rid) { return 1; } else { return 0; } } }; template using AutoObjectWithListComparator = AutoObjectWithListComparatorImpl, T, KAutoObjectWithList>::type>; template using TrueObjectContainerListType = typename KAutoObjectWithListContainer::ListType>; template ALWAYS_INLINE TrueObjectContainerListType &GetTrueObjectContainerList(typename KAutoObjectWithListContainer::DummyListType &l) { static_assert(alignof(l) == alignof(impl::TrueObjectContainerListType)); static_assert(sizeof(l) == sizeof(impl::TrueObjectContainerListType)); return *reinterpret_cast *>(std::addressof(l)); } } ALWAYS_INLINE void KAutoObject::ScheduleDestruction() { MESOSPHERE_ASSERT_THIS(); /* Set our object to destroy. */ m_next_closed_object = GetCurrentThread().GetClosedObject(); /* Set ourselves as the thread's next object to destroy. */ GetCurrentThread().SetClosedObject(this); } template class KAutoObjectWithListContainer::ListAccessor : public impl::KAutoObjectWithListContainerBase::ListAccessorImpl> { NON_COPYABLE(ListAccessor); NON_MOVEABLE(ListAccessor); private: using BaseListAccessor = impl::KAutoObjectWithListContainerBase::ListAccessorImpl>; public: explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer *container) : BaseListAccessor(container, impl::GetTrueObjectContainerList(container->m_dummy_object_list)) { /* ... */ } explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer &container) : BaseListAccessor(container, impl::GetTrueObjectContainerList(container.m_dummy_object_list)) { /* ... */ } ALWAYS_INLINE ~ListAccessor() { /* ... */ } }; template ALWAYS_INLINE void KAutoObjectWithListContainer::Register(T *obj) { return this->RegisterImpl(obj, impl::GetTrueObjectContainerList(m_dummy_object_list)); } template ALWAYS_INLINE void KAutoObjectWithListContainer::Unregister(T *obj) { return this->UnregisterImpl(obj, impl::GetTrueObjectContainerList(m_dummy_object_list)); } template ALWAYS_INLINE size_t KAutoObjectWithListContainer::GetOwnedCountChecked(const KProcess *owner) { return this->GetOwnedCountImpl(owner, impl::GetTrueObjectContainerList(m_dummy_object_list)); } inline u64 KAutoObjectWithList::GetId() const { #define CLASS_TOKEN_HANDLER(CLASSNAME) \ if constexpr (impl::IsAutoObjectWithSpecializedGetId) { \ if (const CLASSNAME * const derived = this->DynamicCast(); derived != nullptr) { \ return [](const T * const t_derived) ALWAYS_INLINE_LAMBDA -> u64 { \ static_assert(std::same_as); \ if constexpr (impl::IsAutoObjectWithSpecializedGetId) { \ return impl::AutoObjectWithListComparator::GetRedBlackKey(*t_derived); \ } else { \ AMS_ASSUME(false); \ } \ }(derived); \ } \ } FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER) #undef CLASS_TOKEN_HANDLER return impl::AutoObjectWithListComparator::GetRedBlackKey(*this); } }