// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include "core/hle/service/os/multi_wait.h" namespace Service { namespace impl { class AutoMultiWaitHolder { private: MultiWaitHolder m_holder; public: template explicit AutoMultiWaitHolder(MultiWait* multi_wait, T&& arg) : m_holder(arg) { m_holder.LinkToMultiWait(multi_wait); } ~AutoMultiWaitHolder() { m_holder.UnlinkFromMultiWait(); } std::pair ConvertResult(const std::pair result, int index) { if (result.first == std::addressof(m_holder)) { return std::make_pair(static_cast(nullptr), index); } else { return result; } } }; using WaitAnyFunction = decltype(&MultiWait::WaitAny); inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, MultiWait* multi_wait, WaitAnyFunction func, int) { return std::pair((multi_wait->*func)(kernel), -1); } template inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, MultiWait* multi_wait, WaitAnyFunction func, int index, T&& x, Args&&... args) { AutoMultiWaitHolder holder(multi_wait, std::forward(x)); return holder.ConvertResult( WaitAnyImpl(kernel, multi_wait, func, index + 1, std::forward(args)...), index); } template inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, MultiWait* multi_wait, WaitAnyFunction func, Args&&... args) { return WaitAnyImpl(kernel, multi_wait, func, 0, std::forward(args)...); } template inline std::pair WaitAnyImpl(Kernel::KernelCore& kernel, WaitAnyFunction func, Args&&... args) { MultiWait temp_multi_wait; return WaitAnyImpl(kernel, std::addressof(temp_multi_wait), func, 0, std::forward(args)...); } class NotBoolButInt { public: constexpr NotBoolButInt(int v) : m_value(v) {} constexpr operator int() const { return m_value; } explicit operator bool() const = delete; private: int m_value; }; } // namespace impl template requires(sizeof...(Args) > 0) inline std::pair WaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait, Args&&... args) { return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, multi_wait, std::forward(args)...); } template requires(sizeof...(Args) > 0) inline int WaitAny(Kernel::KernelCore& kernel, Args&&... args) { return impl::WaitAnyImpl(kernel, &MultiWait::WaitAny, std::forward(args)...).second; } template requires(sizeof...(Args) > 0) inline std::pair TryWaitAny(Kernel::KernelCore& kernel, MultiWait* multi_wait, Args&&... args) { return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, multi_wait, std::forward(args)...); } template requires(sizeof...(Args) > 0) inline impl::NotBoolButInt TryWaitAny(Kernel::KernelCore& kernel, Args&&... args) { return impl::WaitAnyImpl(kernel, &MultiWait::TryWaitAny, std::forward(args)...).second; } } // namespace Service