File indexing completed on 2025-01-18 09:54:52
0001
0002
0003
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
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
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
0165 return fmap(transform.func, std::forward<T>(value));
0166 }
0167 }
0168
0169 #endif