Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:54:52

0001 ///////////////////////////////////////////////////////////////////////////////
0002 // Copyright (c) Lewis Baker
0003 // Licenced under MIT license. See LICENSE.txt for details.
0004 ///////////////////////////////////////////////////////////////////////////////
0005 #ifndef CPPCORO_FMAP_HPP_INCLUDED
0006 #define CPPCORO_FMAP_HPP_INCLUDED
0007 
0008 #include <cppcoro/awaitable_traits.hpp>
0009 #include <cppcoro/is_awaitable.hpp>
0010 
0011 #include <utility>
0012 #include <type_traits>
0013 #include <functional>
0014 
0015 namespace cppcoro
0016 {
0017     namespace detail
0018     {
0019         template<typename FUNC, typename AWAITABLE>
0020         class fmap_awaiter
0021         {
0022             using awaiter_t = typename awaitable_traits<AWAITABLE&&>::awaiter_t;
0023             FUNC&& m_func;
0024             awaiter_t m_awaiter;
0025 
0026         public:
0027 
0028             fmap_awaiter(FUNC&& func, AWAITABLE&& awaitable)
0029                 noexcept(
0030                     std::is_nothrow_move_constructible_v<awaiter_t> &&
0031                     noexcept(detail::get_awaiter(static_cast<AWAITABLE&&>(awaitable))))
0032                 : m_func(static_cast<FUNC&&>(func))
0033                 , m_awaiter(detail::get_awaiter(static_cast<AWAITABLE&&>(awaitable)))
0034             {}
0035 
0036             decltype(auto) await_ready()
0037                 noexcept(noexcept(static_cast<awaiter_t&&>(m_awaiter).await_ready()))
0038             {
0039                 return static_cast<awaiter_t&&>(m_awaiter).await_ready();
0040             }
0041 
0042             template<typename PROMISE>
0043             decltype(auto) await_suspend(cppcoro::coroutine_handle<PROMISE> coro)
0044                 noexcept(noexcept(static_cast<awaiter_t&&>(m_awaiter).await_suspend(std::move(coro))))
0045             {
0046                 return static_cast<awaiter_t&&>(m_awaiter).await_suspend(std::move(coro));
0047             }
0048 
0049             template<
0050                 typename AWAIT_RESULT = decltype(std::declval<awaiter_t>().await_resume()),
0051                 std::enable_if_t<std::is_void_v<AWAIT_RESULT>, int> = 0>
0052             decltype(auto) await_resume()
0053                 noexcept(noexcept(std::invoke(static_cast<FUNC&&>(m_func))))
0054             {
0055                 static_cast<awaiter_t&&>(m_awaiter).await_resume();
0056                 return std::invoke(static_cast<FUNC&&>(m_func));
0057             }
0058 
0059             template<
0060                 typename AWAIT_RESULT = decltype(std::declval<awaiter_t>().await_resume()),
0061                 std::enable_if_t<!std::is_void_v<AWAIT_RESULT>, int> = 0>
0062             decltype(auto) await_resume()
0063                 noexcept(noexcept(std::invoke(static_cast<FUNC&&>(m_func), static_cast<awaiter_t&&>(m_awaiter).await_resume())))
0064             {
0065                 return std::invoke(
0066                     static_cast<FUNC&&>(m_func),
0067                     static_cast<awaiter_t&&>(m_awaiter).await_resume());
0068             }
0069         };
0070 
0071         template<typename FUNC, typename AWAITABLE>
0072         class fmap_awaitable
0073         {
0074             static_assert(!std::is_lvalue_reference_v<FUNC>);
0075             static_assert(!std::is_lvalue_reference_v<AWAITABLE>);
0076         public:
0077 
0078             template<
0079                 typename FUNC_ARG,
0080                 typename AWAITABLE_ARG,
0081                 std::enable_if_t<
0082                     std::is_constructible_v<FUNC, FUNC_ARG&&> &&
0083                     std::is_constructible_v<AWAITABLE, AWAITABLE_ARG&&>, int> = 0>
0084             explicit fmap_awaitable(FUNC_ARG&& func, AWAITABLE_ARG&& awaitable)
0085                 noexcept(
0086                     std::is_nothrow_constructible_v<FUNC, FUNC_ARG&&> &&
0087                     std::is_nothrow_constructible_v<AWAITABLE, AWAITABLE_ARG&&>)
0088                 : m_func(static_cast<FUNC_ARG&&>(func))
0089                 , m_awaitable(static_cast<AWAITABLE_ARG&&>(awaitable))
0090             {}
0091 
0092             auto operator co_await() const &
0093             {
0094                 return fmap_awaiter<const FUNC&, const AWAITABLE&>(m_func, m_awaitable);
0095             }
0096 
0097             auto operator co_await() &
0098             {
0099                 return fmap_awaiter<FUNC&, AWAITABLE&>(m_func, m_awaitable);
0100             }
0101 
0102             auto operator co_await() &&
0103             {
0104                 return fmap_awaiter<FUNC&&, AWAITABLE&&>(
0105                     static_cast<FUNC&&>(m_func),
0106                     static_cast<AWAITABLE&&>(m_awaitable));
0107             }
0108 
0109         private:
0110 
0111             FUNC m_func;
0112             AWAITABLE m_awaitable;
0113 
0114         };
0115     }
0116 
0117     template<typename FUNC>
0118     struct fmap_transform
0119     {
0120         explicit fmap_transform(FUNC&& f)
0121             noexcept(std::is_nothrow_move_constructible_v<FUNC>)
0122             : func(std::forward<FUNC>(f))
0123         {}
0124 
0125         FUNC func;
0126     };
0127 
0128     template<
0129         typename FUNC,
0130         typename AWAITABLE,
0131         std::enable_if_t<cppcoro::is_awaitable_v<AWAITABLE>, int> = 0>
0132     auto fmap(FUNC&& func, AWAITABLE&& awaitable)
0133     {
0134         return detail::fmap_awaitable<
0135             std::remove_cv_t<std::remove_reference_t<FUNC>>,
0136             std::remove_cv_t<std::remove_reference_t<AWAITABLE>>>(
0137             std::forward<FUNC>(func),
0138             std::forward<AWAITABLE>(awaitable));
0139     }
0140 
0141     template<typename FUNC>
0142     auto fmap(FUNC&& func)
0143     {
0144         return fmap_transform<FUNC>{ std::forward<FUNC>(func) };
0145     }
0146 
0147     template<typename T, typename FUNC>
0148     decltype(auto) operator|(T&& value, fmap_transform<FUNC>&& transform)
0149     {
0150         // Use ADL for finding fmap() overload.
0151         return fmap(std::forward<FUNC>(transform.func), std::forward<T>(value));
0152     }
0153 
0154     template<typename T, typename FUNC>
0155     decltype(auto) operator|(T&& value, const fmap_transform<FUNC>& transform)
0156     {
0157         // Use ADL for finding fmap() overload.
0158         return fmap(transform.func, std::forward<T>(value));
0159     }
0160 
0161     template<typename T, typename FUNC>
0162     decltype(auto) operator|(T&& value, fmap_transform<FUNC>& transform)
0163     {
0164         // Use ADL for finding fmap() overload.
0165         return fmap(transform.func, std::forward<T>(value));
0166     }
0167 }
0168 
0169 #endif