// Copyright (c) 2022 Klemens D. Morgenstern // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_COBALT_UTIL_HPP #define BOOST_COBALT_UTIL_HPP #include <boost/cobalt/config.hpp> #include <boost/cobalt/this_thread.hpp> #include <boost/core/no_exceptions_support.hpp> #include <boost/system/result.hpp> #include <boost/variant2/variant.hpp> #include <limits> #include <type_traits> #include <coroutine> namespace boost::variant2 { struct monostate; } namespace boost::cobalt::detail { template<typename T> constexpr std::size_t variadic_first(std::size_t = 0u) { return std::numeric_limits<std::size_t>::max(); } template<typename T, typename First, typename ... Args> constexpr std::size_t variadic_first(std::size_t pos = 0u) { if constexpr (std::is_same_v<std::decay_t<First>, T>) return pos; else return variadic_first<T, Args...>(pos+1); } template<typename T, typename ... Args> constexpr bool variadic_has = variadic_first<T, Args...>() < sizeof...(Args); template<std::size_t Idx, typename First, typename ... Args> requires (Idx <= sizeof...(Args)) constexpr decltype(auto) get_variadic(First && first, Args && ... args) { if constexpr (Idx == 0u) return static_cast<First>(first); else return get_variadic<Idx-1u>(static_cast<Args>(args)...); } template<std::size_t Idx, typename ... Args> struct variadic_element; template<std::size_t Idx, typename First, typename ...Tail> struct variadic_element<Idx, First, Tail...> { using type = typename variadic_element<Idx-1, Tail...>::type; }; template<typename First, typename ...Tail> struct variadic_element<0u, First, Tail...> { using type = First; }; template<std::size_t Idx, typename ... Args> using variadic_element_t = typename variadic_element<Idx, Args...>::type; template<typename ... Args> struct variadic_last { using type = variadic_element_t<sizeof...(Args) - 1, Args...>; }; template<> struct variadic_last<> { using type = void; }; template<typename ... Args> using variadic_last_t = typename variadic_last<Args...>::type; template<typename First> constexpr decltype(auto) get_last_variadic(First && first) { return first; } template<typename First, typename ... Args> constexpr decltype(auto) get_last_variadic(First &&, Args && ... args) { return get_last_variadic(static_cast<Args>(args)...); } template<typename Awaitable> auto get_resume_result(Awaitable & aw) -> system::result<decltype(aw.await_resume()), std::exception_ptr> { using type = decltype(aw.await_resume()); BOOST_TRY { if constexpr (std::is_void_v<type>) { aw.await_resume(); return {}; } else return aw.await_resume(); } BOOST_CATCH(...) { return std::current_exception(); } BOOST_CATCH_END } #if BOOST_COBALT_NO_SELF_DELETE BOOST_COBALT_DECL void self_destroy(std::coroutine_handle<void> h, const cobalt::executor & exec) noexcept; template<typename T> inline void self_destroy(std::coroutine_handle<T> h) noexcept { if constexpr (requires {h.promise().get_executor();}) self_destroy(h, h.promise().get_executor()); else self_destroy(h, this_thread::get_executor()); } #else template<typename T> inline void self_destroy(std::coroutine_handle<T> h) noexcept { h.destroy(); } template<typename T, typename Executor> inline void self_destroy(std::coroutine_handle<T> h, const Executor &) noexcept { h.destroy(); } #endif template<typename T> using void_as_monostate = std::conditional_t<std::is_void_v<T>, variant2::monostate, T>; template<typename T> using monostate_as_void = std::conditional_t<std::is_same_v<T, variant2::monostate>, void, T>; } #endif //BOOST_COBALT_UTIL_HPP