Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:29:50

0001 // Copyright (c) 2022 Klemens D. Morgenstern
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 #ifndef BOOST_COBALT_HANDLER_HPP
0006 #define BOOST_COBALT_HANDLER_HPP
0007 
0008 #include <boost/cobalt/this_coro.hpp>
0009 #include <boost/cobalt/unique_handle.hpp>
0010 #include <boost/cobalt/detail/util.hpp>
0011 
0012 #include <boost/cobalt/detail/sbo_resource.hpp>
0013 #include <boost/asio/bind_allocator.hpp>
0014 #include <boost/asio/post.hpp>
0015 #include <boost/system/result.hpp>
0016 
0017 #include <memory>
0018 #include <optional>
0019 
0020 namespace boost::cobalt
0021 {
0022 
0023 namespace detail
0024 {
0025 
0026 template<typename ... Args>
0027 struct composition_promise;
0028 enum class completed_immediately_t
0029 {
0030   no, maybe, yes, initiating
0031 };
0032 
0033 struct completion_handler_noop_executor
0034 {
0035   executor exec;
0036   completed_immediately_t * completed_immediately = nullptr;
0037 
0038   template<typename Fn>
0039   void execute(Fn && fn) const
0040   {
0041     // only allow it when we're still initializing
0042     if (completed_immediately &&
0043         ((*completed_immediately == completed_immediately_t::initiating)
0044       || (*completed_immediately == completed_immediately_t::maybe)))
0045     {
0046       // only use this indicator if the fn will actually call our completion-handler
0047       // otherwise this was a single op in a composed operation
0048       *completed_immediately = completed_immediately_t::maybe;
0049       fn();
0050       // yes means completion_handler::operator() was called, so we're good.
0051       if (*completed_immediately != completed_immediately_t::yes)
0052         *completed_immediately = completed_immediately_t::initiating;
0053     }
0054     else
0055     {
0056       asio::post(exec, std::forward<Fn>(fn));
0057     }
0058   }
0059 
0060   friend bool operator==(const completion_handler_noop_executor&, const completion_handler_noop_executor&) noexcept
0061   {
0062     return true;
0063   }
0064 
0065   friend bool operator!=(const completion_handler_noop_executor&, const completion_handler_noop_executor&) noexcept
0066   {
0067     return false;
0068   }
0069 
0070   completion_handler_noop_executor(const completion_handler_noop_executor & rhs) noexcept = default;
0071   completion_handler_noop_executor(cobalt::executor inner, completed_immediately_t * completed_immediately)
0072         : exec(std::move(inner)), completed_immediately(completed_immediately)
0073   {
0074   }
0075 
0076 };
0077 
0078 template<typename Promise>
0079 executor
0080 get_executor(std::coroutine_handle<Promise> h)
0081 {
0082   if constexpr (requires {h.promise().get_executor();})
0083   {
0084     return h.promise().get_executor();
0085   }
0086   else
0087     return this_thread::get_executor();
0088 }
0089 
0090 inline executor
0091 get_executor(std::coroutine_handle<>)
0092 {
0093   return this_thread::get_executor();
0094 }
0095 
0096 
0097 struct completion_handler_base
0098 {
0099   using cancellation_slot_type = asio::cancellation_slot;
0100   cancellation_slot_type cancellation_slot ;
0101   cancellation_slot_type get_cancellation_slot() const noexcept
0102   {
0103       return cancellation_slot ;
0104   }
0105 
0106   using executor_type = executor;
0107   executor_type executor_ ;
0108   const executor_type & get_executor() const noexcept
0109   {
0110     return executor_ ;
0111   }
0112 
0113 #if !defined(BOOST_COBALT_NO_PMR)
0114   using allocator_type = pmr::polymorphic_allocator<void>;
0115   pmr::polymorphic_allocator<void> allocator ;
0116   allocator_type get_allocator() const noexcept
0117   {
0118     return allocator ;
0119   }
0120 #else
0121   using allocator_type = detail::sbo_allocator<void>;
0122   detail::sbo_allocator<void> allocator ;
0123   allocator_type get_allocator() const noexcept
0124   {
0125     return allocator ;
0126   }
0127 #endif
0128   using immediate_executor_type = completion_handler_noop_executor;
0129   completed_immediately_t * completed_immediately = nullptr;
0130   immediate_executor_type get_immediate_executor() const noexcept
0131   {
0132     return {get_executor(), completed_immediately};
0133   }
0134 
0135   template<typename Promise>
0136   completion_handler_base(std::coroutine_handle<Promise> h,
0137                           completed_immediately_t * completed_immediately = nullptr)
0138           : cancellation_slot(asio::get_associated_cancellation_slot(h.promise())),
0139             executor_(cobalt::detail::get_executor(h)),
0140 #if !defined(BOOST_COBALT_NO_PMR)
0141             allocator(asio::get_associated_allocator(h.promise(), this_thread::get_allocator())),
0142 #else
0143             allocator(detail::get_null_sbo_resource()),
0144 #endif
0145             completed_immediately(completed_immediately)
0146   {
0147   }
0148 #if !defined(BOOST_COBALT_NO_PMR)
0149   template<typename Promise>
0150   completion_handler_base(std::coroutine_handle<Promise> h,
0151                           pmr::memory_resource * resource,
0152                           completed_immediately_t * completed_immediately = nullptr)
0153           : cancellation_slot(asio::get_associated_cancellation_slot(h.promise())),
0154             executor_(cobalt::detail::get_executor(h)),
0155             allocator(resource),
0156             completed_immediately(completed_immediately)
0157   {
0158   }
0159 #else
0160   template<typename Promise>
0161   completion_handler_base(std::coroutine_handle<Promise> h,
0162                           detail::sbo_resource * resource,
0163                           completed_immediately_t * completed_immediately = nullptr)
0164       : cancellation_slot(asio::get_associated_cancellation_slot(h.promise())),
0165         executor_(cobalt::detail::get_executor(h)),
0166         allocator(resource),
0167         completed_immediately(completed_immediately)
0168   {
0169   }
0170 
0171 #endif
0172 };
0173 
0174 
0175 template<typename Handler>
0176 void assign_cancellation(std::coroutine_handle<void>, Handler &&) {}
0177 
0178 template<typename Promise, typename Handler>
0179 void assign_cancellation(std::coroutine_handle<Promise> h, Handler && func)
0180 {
0181   if constexpr (requires {h.promise().get_cancellation_slot();})
0182     if (h.promise().get_cancellation_slot().is_connected())
0183       h.promise().get_cancellation_slot().assign(std::forward<Handler>(func));
0184 }
0185 
0186 }
0187 
0188 template<typename ... Args>
0189 struct handler
0190 {
0191   void operator()(Args ... args)
0192   {
0193     result.emplace(static_cast<Args>(args)...);
0194   }
0195   handler(std::optional<std::tuple<Args...>> &result) : result(result) {}
0196  private:
0197   std::optional<std::tuple<Args...>> &result;
0198 };
0199 
0200 template<typename ... Args>
0201 handler(std::optional<std::tuple<Args...>> &result) -> handler<Args...>;
0202 
0203 template<typename ... Args>
0204 struct completion_handler : detail::completion_handler_base
0205 {
0206     completion_handler(completion_handler && ) = default;
0207 
0208     template<typename Promise>
0209     completion_handler(std::coroutine_handle<Promise> h,
0210                        std::optional<std::tuple<Args...>> &result,
0211                        detail::completed_immediately_t * completed_immediately = nullptr
0212 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0213                      , const boost::source_location & loc = BOOST_CURRENT_LOCATION
0214 #endif
0215           ) : completion_handler_base(h, completed_immediately),
0216               self(h.address()), result(result)
0217 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0218             , loc_(loc)
0219 #endif
0220     {
0221     }
0222 
0223 #if !defined(BOOST_COBALT_NO_PMR)
0224     template<typename Promise>
0225     completion_handler(std::coroutine_handle<Promise> h,
0226                        std::optional<std::tuple<Args...>> &result,
0227                        pmr::memory_resource * resource,
0228                        detail::completed_immediately_t * completed_immediately = nullptr
0229 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0230                      , const boost::source_location & loc = BOOST_CURRENT_LOCATION
0231 #endif
0232           ) : completion_handler_base(h, resource, completed_immediately),
0233               self(h.address()), result(result)
0234 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0235             , loc_(loc)
0236 #endif
0237     {
0238     }
0239 #else
0240     template<typename Promise>
0241     completion_handler(std::coroutine_handle<Promise> h,
0242                        std::optional<std::tuple<Args...>> &result,
0243                        detail::sbo_resource * resource,
0244                        detail::completed_immediately_t * completed_immediately = nullptr)
0245         : completion_handler_base(h, resource, completed_immediately),
0246           self(h.address()), result(result)
0247     {
0248     }
0249 #endif
0250 
0251 
0252     void operator()(Args ... args)
0253     {
0254 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0255       BOOST_ASIO_HANDLER_LOCATION((loc_.file_name(), loc_.line(), loc_.function_name()));
0256 #endif
0257         result.emplace(std::move(args)...);
0258         BOOST_ASSERT(this->self != nullptr);
0259         auto p = this->self.release();
0260         if (completed_immediately != nullptr
0261         && *completed_immediately == detail::completed_immediately_t::maybe)
0262         {
0263           *completed_immediately = detail::completed_immediately_t::yes;
0264           return;
0265         }
0266 
0267         std::move(p)();
0268     }
0269     using result_type = std::optional<std::tuple<Args...>>;
0270 
0271     ~completion_handler()
0272     {
0273       if (self && completed_immediately
0274         && *completed_immediately == detail::completed_immediately_t::initiating
0275         && std::uncaught_exceptions() > 0)
0276         self.release();
0277     }
0278  private:
0279     unique_handle<void> self;
0280     std::optional<std::tuple<Args...>> &result;
0281 #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
0282     boost::source_location loc_;
0283 #endif
0284 
0285     template<typename ... Args_>
0286     friend struct detail::composition_promise;
0287 };
0288 
0289 };
0290 
0291 #endif //BOOST_COBALT_HANDLER_HPP