Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:58

0001 //
0002 // impl/use_future.hpp
0003 // ~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IMPL_USE_FUTURE_HPP
0012 #define BOOST_ASIO_IMPL_USE_FUTURE_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <tuple>
0020 #include <boost/asio/async_result.hpp>
0021 #include <boost/asio/detail/memory.hpp>
0022 #include <boost/asio/dispatch.hpp>
0023 #include <boost/system/error_code.hpp>
0024 #include <boost/asio/execution.hpp>
0025 #include <boost/asio/packaged_task.hpp>
0026 #include <boost/system/system_error.hpp>
0027 #include <boost/asio/system_executor.hpp>
0028 
0029 #include <boost/asio/detail/push_options.hpp>
0030 
0031 namespace boost {
0032 namespace asio {
0033 namespace detail {
0034 
0035 template <typename T, typename F, typename... Args>
0036 inline void promise_invoke_and_set(std::promise<T>& p,
0037     F& f, Args&&... args)
0038 {
0039 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0040   try
0041 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0042   {
0043     p.set_value(f(static_cast<Args&&>(args)...));
0044   }
0045 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0046   catch (...)
0047   {
0048     p.set_exception(std::current_exception());
0049   }
0050 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0051 }
0052 
0053 template <typename F, typename... Args>
0054 inline void promise_invoke_and_set(std::promise<void>& p,
0055     F& f, Args&&... args)
0056 {
0057 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0058   try
0059 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0060   {
0061     f(static_cast<Args&&>(args)...);
0062     p.set_value();
0063   }
0064 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0065   catch (...)
0066   {
0067     p.set_exception(std::current_exception());
0068   }
0069 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0070 }
0071 
0072 // A function object adapter to invoke a nullary function object and capture
0073 // any exception thrown into a promise.
0074 template <typename T, typename F>
0075 class promise_invoker
0076 {
0077 public:
0078   promise_invoker(const shared_ptr<std::promise<T>>& p,
0079       F&& f)
0080     : p_(p), f_(static_cast<F&&>(f))
0081   {
0082   }
0083 
0084   void operator()()
0085   {
0086 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0087     try
0088 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0089     {
0090       f_();
0091     }
0092 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0093     catch (...)
0094     {
0095       p_->set_exception(std::current_exception());
0096     }
0097 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0098   }
0099 
0100 private:
0101   shared_ptr<std::promise<T>> p_;
0102   decay_t<F> f_;
0103 };
0104 
0105 // An executor that adapts the system_executor to capture any exeption thrown
0106 // by a submitted function object and save it into a promise.
0107 template <typename T, typename Blocking = execution::blocking_t::possibly_t>
0108 class promise_executor
0109 {
0110 public:
0111   explicit promise_executor(const shared_ptr<std::promise<T>>& p)
0112     : p_(p)
0113   {
0114   }
0115 
0116   execution_context& query(execution::context_t) const noexcept
0117   {
0118     return boost::asio::query(system_executor(), execution::context);
0119   }
0120 
0121   static constexpr Blocking query(execution::blocking_t)
0122   {
0123     return Blocking();
0124   }
0125 
0126   promise_executor<T, execution::blocking_t::possibly_t>
0127   require(execution::blocking_t::possibly_t) const
0128   {
0129     return promise_executor<T, execution::blocking_t::possibly_t>(p_);
0130   }
0131 
0132   promise_executor<T, execution::blocking_t::never_t>
0133   require(execution::blocking_t::never_t) const
0134   {
0135     return promise_executor<T, execution::blocking_t::never_t>(p_);
0136   }
0137 
0138   template <typename F>
0139   void execute(F&& f) const
0140   {
0141     boost::asio::require(system_executor(), Blocking()).execute(
0142         promise_invoker<T, F>(p_, static_cast<F&&>(f)));
0143   }
0144 
0145 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0146   execution_context& context() const noexcept
0147   {
0148     return system_executor().context();
0149   }
0150 
0151   void on_work_started() const noexcept {}
0152   void on_work_finished() const noexcept {}
0153 
0154   template <typename F, typename A>
0155   void dispatch(F&& f, const A&) const
0156   {
0157     promise_invoker<T, F>(p_, static_cast<F&&>(f))();
0158   }
0159 
0160   template <typename F, typename A>
0161   void post(F&& f, const A& a) const
0162   {
0163     system_executor().post(
0164         promise_invoker<T, F>(p_, static_cast<F&&>(f)), a);
0165   }
0166 
0167   template <typename F, typename A>
0168   void defer(F&& f, const A& a) const
0169   {
0170     system_executor().defer(
0171         promise_invoker<T, F>(p_, static_cast<F&&>(f)), a);
0172   }
0173 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0174 
0175   friend bool operator==(const promise_executor& a,
0176       const promise_executor& b) noexcept
0177   {
0178     return a.p_ == b.p_;
0179   }
0180 
0181   friend bool operator!=(const promise_executor& a,
0182       const promise_executor& b) noexcept
0183   {
0184     return a.p_ != b.p_;
0185   }
0186 
0187 private:
0188   shared_ptr<std::promise<T>> p_;
0189 };
0190 
0191 // The base class for all completion handlers that create promises.
0192 template <typename T>
0193 class promise_creator
0194 {
0195 public:
0196   typedef promise_executor<T> executor_type;
0197 
0198   executor_type get_executor() const noexcept
0199   {
0200     return executor_type(p_);
0201   }
0202 
0203   typedef std::future<T> future_type;
0204 
0205   future_type get_future()
0206   {
0207     return p_->get_future();
0208   }
0209 
0210 protected:
0211   template <typename Allocator>
0212   void create_promise(const Allocator& a)
0213   {
0214     BOOST_ASIO_REBIND_ALLOC(Allocator, char) b(a);
0215     p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b);
0216   }
0217 
0218   shared_ptr<std::promise<T>> p_;
0219 };
0220 
0221 // For completion signature void().
0222 class promise_handler_0
0223   : public promise_creator<void>
0224 {
0225 public:
0226   void operator()()
0227   {
0228     this->p_->set_value();
0229   }
0230 };
0231 
0232 // For completion signature void(error_code).
0233 class promise_handler_ec_0
0234   : public promise_creator<void>
0235 {
0236 public:
0237   void operator()(const boost::system::error_code& ec)
0238   {
0239     if (ec)
0240     {
0241       this->p_->set_exception(
0242           std::make_exception_ptr(
0243             boost::system::system_error(ec)));
0244     }
0245     else
0246     {
0247       this->p_->set_value();
0248     }
0249   }
0250 };
0251 
0252 // For completion signature void(exception_ptr).
0253 class promise_handler_ex_0
0254   : public promise_creator<void>
0255 {
0256 public:
0257   void operator()(const std::exception_ptr& ex)
0258   {
0259     if (ex)
0260     {
0261       this->p_->set_exception(ex);
0262     }
0263     else
0264     {
0265       this->p_->set_value();
0266     }
0267   }
0268 };
0269 
0270 // For completion signature void(T).
0271 template <typename T>
0272 class promise_handler_1
0273   : public promise_creator<T>
0274 {
0275 public:
0276   template <typename Arg>
0277   void operator()(Arg&& arg)
0278   {
0279     this->p_->set_value(static_cast<Arg&&>(arg));
0280   }
0281 };
0282 
0283 // For completion signature void(error_code, T).
0284 template <typename T>
0285 class promise_handler_ec_1
0286   : public promise_creator<T>
0287 {
0288 public:
0289   template <typename Arg>
0290   void operator()(const boost::system::error_code& ec,
0291       Arg&& arg)
0292   {
0293     if (ec)
0294     {
0295       this->p_->set_exception(
0296           std::make_exception_ptr(
0297             boost::system::system_error(ec)));
0298     }
0299     else
0300       this->p_->set_value(static_cast<Arg&&>(arg));
0301   }
0302 };
0303 
0304 // For completion signature void(exception_ptr, T).
0305 template <typename T>
0306 class promise_handler_ex_1
0307   : public promise_creator<T>
0308 {
0309 public:
0310   template <typename Arg>
0311   void operator()(const std::exception_ptr& ex,
0312       Arg&& arg)
0313   {
0314     if (ex)
0315       this->p_->set_exception(ex);
0316     else
0317       this->p_->set_value(static_cast<Arg&&>(arg));
0318   }
0319 };
0320 
0321 // For completion signature void(T1, ..., Tn);
0322 template <typename T>
0323 class promise_handler_n
0324   : public promise_creator<T>
0325 {
0326 public:
0327   template <typename... Args>
0328   void operator()(Args&&... args)
0329   {
0330     this->p_->set_value(
0331         std::forward_as_tuple(
0332           static_cast<Args&&>(args)...));
0333   }
0334 };
0335 
0336 // For completion signature void(error_code, T1, ..., Tn);
0337 template <typename T>
0338 class promise_handler_ec_n
0339   : public promise_creator<T>
0340 {
0341 public:
0342   template <typename... Args>
0343   void operator()(const boost::system::error_code& ec, Args&&... args)
0344   {
0345     if (ec)
0346     {
0347       this->p_->set_exception(
0348           std::make_exception_ptr(
0349             boost::system::system_error(ec)));
0350     }
0351     else
0352     {
0353       this->p_->set_value(
0354           std::forward_as_tuple(
0355             static_cast<Args&&>(args)...));
0356     }
0357   }
0358 };
0359 
0360 // For completion signature void(exception_ptr, T1, ..., Tn);
0361 template <typename T>
0362 class promise_handler_ex_n
0363   : public promise_creator<T>
0364 {
0365 public:
0366   template <typename... Args>
0367   void operator()(const std::exception_ptr& ex,
0368       Args&&... args)
0369   {
0370     if (ex)
0371       this->p_->set_exception(ex);
0372     else
0373     {
0374       this->p_->set_value(
0375           std::forward_as_tuple(
0376             static_cast<Args&&>(args)...));
0377     }
0378   }
0379 };
0380 
0381 // Helper template to choose the appropriate concrete promise handler
0382 // implementation based on the supplied completion signature.
0383 template <typename> class promise_handler_selector;
0384 
0385 template <>
0386 class promise_handler_selector<void()>
0387   : public promise_handler_0 {};
0388 
0389 template <>
0390 class promise_handler_selector<void(boost::system::error_code)>
0391   : public promise_handler_ec_0 {};
0392 
0393 template <>
0394 class promise_handler_selector<void(std::exception_ptr)>
0395   : public promise_handler_ex_0 {};
0396 
0397 template <typename Arg>
0398 class promise_handler_selector<void(Arg)>
0399   : public promise_handler_1<Arg> {};
0400 
0401 template <typename Arg>
0402 class promise_handler_selector<void(boost::system::error_code, Arg)>
0403   : public promise_handler_ec_1<Arg> {};
0404 
0405 template <typename Arg>
0406 class promise_handler_selector<void(std::exception_ptr, Arg)>
0407   : public promise_handler_ex_1<Arg> {};
0408 
0409 template <typename... Arg>
0410 class promise_handler_selector<void(Arg...)>
0411   : public promise_handler_n<std::tuple<Arg...>> {};
0412 
0413 template <typename... Arg>
0414 class promise_handler_selector<void(boost::system::error_code, Arg...)>
0415   : public promise_handler_ec_n<std::tuple<Arg...>> {};
0416 
0417 template <typename... Arg>
0418 class promise_handler_selector<void(std::exception_ptr, Arg...)>
0419   : public promise_handler_ex_n<std::tuple<Arg...>> {};
0420 
0421 // Completion handlers produced from the use_future completion token, when not
0422 // using use_future::operator().
0423 template <typename Signature, typename Allocator>
0424 class promise_handler
0425   : public promise_handler_selector<Signature>
0426 {
0427 public:
0428   typedef Allocator allocator_type;
0429   typedef void result_type;
0430 
0431   promise_handler(use_future_t<Allocator> u)
0432     : allocator_(u.get_allocator())
0433   {
0434     this->create_promise(allocator_);
0435   }
0436 
0437   allocator_type get_allocator() const noexcept
0438   {
0439     return allocator_;
0440   }
0441 
0442 private:
0443   Allocator allocator_;
0444 };
0445 
0446 template <typename Function>
0447 struct promise_function_wrapper
0448 {
0449   explicit promise_function_wrapper(Function& f)
0450     : function_(static_cast<Function&&>(f))
0451   {
0452   }
0453 
0454   explicit promise_function_wrapper(const Function& f)
0455     : function_(f)
0456   {
0457   }
0458 
0459   void operator()()
0460   {
0461     function_();
0462   }
0463 
0464   Function function_;
0465 };
0466 
0467 // Helper base class for async_result specialisation.
0468 template <typename Signature, typename Allocator>
0469 class promise_async_result
0470 {
0471 public:
0472   typedef promise_handler<Signature, Allocator> completion_handler_type;
0473   typedef typename completion_handler_type::future_type return_type;
0474 
0475   explicit promise_async_result(completion_handler_type& h)
0476     : future_(h.get_future())
0477   {
0478   }
0479 
0480   return_type get()
0481   {
0482     return static_cast<return_type&&>(future_);
0483   }
0484 
0485 private:
0486   return_type future_;
0487 };
0488 
0489 // Return value from use_future::operator().
0490 template <typename Function, typename Allocator>
0491 class packaged_token
0492 {
0493 public:
0494   packaged_token(Function f, const Allocator& a)
0495     : function_(static_cast<Function&&>(f)),
0496       allocator_(a)
0497   {
0498   }
0499 
0500 //private:
0501   Function function_;
0502   Allocator allocator_;
0503 };
0504 
0505 // Completion handlers produced from the use_future completion token, when
0506 // using use_future::operator().
0507 template <typename Function, typename Allocator, typename Result>
0508 class packaged_handler
0509   : public promise_creator<Result>
0510 {
0511 public:
0512   typedef Allocator allocator_type;
0513   typedef void result_type;
0514 
0515   packaged_handler(packaged_token<Function, Allocator> t)
0516     : function_(static_cast<Function&&>(t.function_)),
0517       allocator_(t.allocator_)
0518   {
0519     this->create_promise(allocator_);
0520   }
0521 
0522   allocator_type get_allocator() const noexcept
0523   {
0524     return allocator_;
0525   }
0526 
0527   template <typename... Args>
0528   void operator()(Args&&... args)
0529   {
0530     (promise_invoke_and_set)(*this->p_,
0531         function_, static_cast<Args&&>(args)...);
0532   }
0533 
0534 private:
0535   Function function_;
0536   Allocator allocator_;
0537 };
0538 
0539 // Helper base class for async_result specialisation.
0540 template <typename Function, typename Allocator, typename Result>
0541 class packaged_async_result
0542 {
0543 public:
0544   typedef packaged_handler<Function, Allocator, Result> completion_handler_type;
0545   typedef typename completion_handler_type::future_type return_type;
0546 
0547   explicit packaged_async_result(completion_handler_type& h)
0548     : future_(h.get_future())
0549   {
0550   }
0551 
0552   return_type get()
0553   {
0554     return static_cast<return_type&&>(future_);
0555   }
0556 
0557 private:
0558   return_type future_;
0559 };
0560 
0561 } // namespace detail
0562 
0563 template <typename Allocator> template <typename Function>
0564 inline detail::packaged_token<decay_t<Function>, Allocator>
0565 use_future_t<Allocator>::operator()(Function&& f) const
0566 {
0567   return detail::packaged_token<decay_t<Function>, Allocator>(
0568       static_cast<Function&&>(f), allocator_);
0569 }
0570 
0571 #if !defined(GENERATING_DOCUMENTATION)
0572 
0573 template <typename Allocator, typename Result, typename... Args>
0574 class async_result<use_future_t<Allocator>, Result(Args...)>
0575   : public detail::promise_async_result<
0576       void(decay_t<Args>...), Allocator>
0577 {
0578 public:
0579   explicit async_result(
0580     typename detail::promise_async_result<void(decay_t<Args>...),
0581       Allocator>::completion_handler_type& h)
0582     : detail::promise_async_result<
0583         void(decay_t<Args>...), Allocator>(h)
0584   {
0585   }
0586 };
0587 
0588 template <typename Function, typename Allocator,
0589     typename Result, typename... Args>
0590 class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)>
0591   : public detail::packaged_async_result<Function, Allocator,
0592       result_of_t<Function(Args...)>>
0593 {
0594 public:
0595   explicit async_result(
0596     typename detail::packaged_async_result<Function, Allocator,
0597       result_of_t<Function(Args...)>>::completion_handler_type& h)
0598     : detail::packaged_async_result<Function, Allocator,
0599         result_of_t<Function(Args...)>>(h)
0600   {
0601   }
0602 };
0603 
0604 namespace traits {
0605 
0606 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0607 
0608 template <typename T, typename Blocking>
0609 struct equality_comparable<
0610     boost::asio::detail::promise_executor<T, Blocking>>
0611 {
0612   static constexpr bool is_valid = true;
0613   static constexpr bool is_noexcept = true;
0614 };
0615 
0616 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0617 
0618 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0619 
0620 template <typename T, typename Blocking, typename Function>
0621 struct execute_member<
0622     boost::asio::detail::promise_executor<T, Blocking>, Function>
0623 {
0624   static constexpr bool is_valid = true;
0625   static constexpr bool is_noexcept = false;
0626   typedef void result_type;
0627 };
0628 
0629 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0630 
0631 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
0632 
0633 template <typename T, typename Blocking, typename Property>
0634 struct query_static_constexpr_member<
0635     boost::asio::detail::promise_executor<T, Blocking>,
0636     Property,
0637     typename boost::asio::enable_if<
0638       boost::asio::is_convertible<
0639         Property,
0640         boost::asio::execution::blocking_t
0641       >::value
0642     >::type
0643   >
0644 {
0645   static constexpr bool is_valid = true;
0646   static constexpr bool is_noexcept = true;
0647   typedef Blocking result_type;
0648 
0649   static constexpr result_type value() noexcept
0650   {
0651     return Blocking();
0652   }
0653 };
0654 
0655 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
0656 
0657 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
0658 
0659 template <typename T, typename Blocking>
0660 struct query_member<
0661     boost::asio::detail::promise_executor<T, Blocking>,
0662     execution::context_t
0663   >
0664 {
0665   static constexpr bool is_valid = true;
0666   static constexpr bool is_noexcept = true;
0667   typedef boost::asio::system_context& result_type;
0668 };
0669 
0670 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
0671 
0672 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0673 
0674 template <typename T, typename Blocking>
0675 struct require_member<
0676     boost::asio::detail::promise_executor<T, Blocking>,
0677     execution::blocking_t::possibly_t
0678   >
0679 {
0680   static constexpr bool is_valid = true;
0681   static constexpr bool is_noexcept = true;
0682   typedef boost::asio::detail::promise_executor<T,
0683       execution::blocking_t::possibly_t> result_type;
0684 };
0685 
0686 template <typename T, typename Blocking>
0687 struct require_member<
0688     boost::asio::detail::promise_executor<T, Blocking>,
0689     execution::blocking_t::never_t
0690   >
0691 {
0692   static constexpr bool is_valid = true;
0693   static constexpr bool is_noexcept = true;
0694   typedef boost::asio::detail::promise_executor<T,
0695       execution::blocking_t::never_t> result_type;
0696 };
0697 
0698 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0699 
0700 } // namespace traits
0701 
0702 #endif // !defined(GENERATING_DOCUMENTATION)
0703 
0704 } // namespace asio
0705 } // namespace boost
0706 
0707 #include <boost/asio/detail/pop_options.hpp>
0708 
0709 #endif // BOOST_ASIO_IMPL_USE_FUTURE_HPP