/* * 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 <http://www.gnu.org/licenses/>. */ #pragma once #include <vapours.hpp> #include <stratosphere/tipc/tipc_common.hpp> #include <stratosphere/tipc/tipc_service_object_base.hpp> namespace ams::tipc { template<typename T> concept IsServiceObjectAllocator = requires (T &t) { { t.Allocate() } -> std::convertible_to<ServiceObjectBase *>; }; template<typename T, size_t N> requires IsServiceObject<T> class SingletonAllocator final { static_assert(N >= 1); private: T m_singleton; public: constexpr ALWAYS_INLINE SingletonAllocator() : m_singleton() { /* ... */ } ALWAYS_INLINE ServiceObjectBase *Allocate() { return std::addressof(m_singleton); } }; template<typename T, size_t N> requires IsServiceObject<T> class SlabAllocator final : public ServiceObjectDeleter { private: struct Entry { bool used; util::TypedStorage<T> storage; }; private: Entry m_entries[N]; os::SdkMutex m_mutex; public: constexpr ALWAYS_INLINE SlabAllocator() : m_entries(), m_mutex() { /* ... */ } T *Allocate() { std::scoped_lock lk(m_mutex); for (size_t i = 0; i < N; ++i) { if (!m_entries[i].used) { m_entries[i].used = true; return util::ConstructAt(m_entries[i].storage); } } return nullptr; } void Deallocate(ServiceObjectBase *object) { std::scoped_lock lk(m_mutex); for (size_t i = 0; i < N; ++i) { if (m_entries[i].used && GetPointer(m_entries[i].storage) == object) { util::DestroyAt(m_entries[i].storage); m_entries[i].used = false; return; } } AMS_ABORT("Failed to deallocate entry in SlabAllocator<T, N>"); } public: virtual void DeleteServiceObject(ServiceObjectBase *object) override { return this->Deallocate(object); } }; static_assert(IsServiceObjectAllocator<SlabAllocator<ServiceObjectBase, 1>>); static_assert(IsServiceObjectDeleter<SlabAllocator<ServiceObjectBase, 1>>); }