any_completion_handler.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. //
  2. // any_completion_handler.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ASIO_ANY_COMPLETION_HANDLER_HPP
  11. #define ASIO_ANY_COMPLETION_HANDLER_HPP
  12. #include "asio/detail/config.hpp"
  13. #include <cstring>
  14. #include <functional>
  15. #include <memory>
  16. #include <utility>
  17. #include "asio/any_completion_executor.hpp"
  18. #include "asio/any_io_executor.hpp"
  19. #include "asio/associated_allocator.hpp"
  20. #include "asio/associated_cancellation_slot.hpp"
  21. #include "asio/associated_executor.hpp"
  22. #include "asio/associated_immediate_executor.hpp"
  23. #include "asio/cancellation_state.hpp"
  24. #include "asio/recycling_allocator.hpp"
  25. #include "asio/detail/push_options.hpp"
  26. namespace asio {
  27. namespace detail {
  28. class any_completion_handler_impl_base
  29. {
  30. public:
  31. template <typename S>
  32. explicit any_completion_handler_impl_base(S&& slot)
  33. : cancel_state_(static_cast<S&&>(slot), enable_total_cancellation())
  34. {
  35. }
  36. cancellation_slot get_cancellation_slot() const noexcept
  37. {
  38. return cancel_state_.slot();
  39. }
  40. private:
  41. cancellation_state cancel_state_;
  42. };
  43. template <typename Handler>
  44. class any_completion_handler_impl :
  45. public any_completion_handler_impl_base
  46. {
  47. public:
  48. template <typename S, typename H>
  49. any_completion_handler_impl(S&& slot, H&& h)
  50. : any_completion_handler_impl_base(static_cast<S&&>(slot)),
  51. handler_(static_cast<H&&>(h))
  52. {
  53. }
  54. struct uninit_deleter
  55. {
  56. typename std::allocator_traits<
  57. associated_allocator_t<Handler,
  58. asio::recycling_allocator<void>>>::template
  59. rebind_alloc<any_completion_handler_impl> alloc;
  60. void operator()(any_completion_handler_impl* ptr)
  61. {
  62. std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
  63. }
  64. };
  65. struct deleter
  66. {
  67. typename std::allocator_traits<
  68. associated_allocator_t<Handler,
  69. asio::recycling_allocator<void>>>::template
  70. rebind_alloc<any_completion_handler_impl> alloc;
  71. void operator()(any_completion_handler_impl* ptr)
  72. {
  73. std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr);
  74. std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
  75. }
  76. };
  77. template <typename S, typename H>
  78. static any_completion_handler_impl* create(S&& slot, H&& h)
  79. {
  80. uninit_deleter d{
  81. (get_associated_allocator)(h,
  82. asio::recycling_allocator<void>())};
  83. std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr(
  84. std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d);
  85. any_completion_handler_impl* ptr =
  86. new (uninit_ptr.get()) any_completion_handler_impl(
  87. static_cast<S&&>(slot), static_cast<H&&>(h));
  88. uninit_ptr.release();
  89. return ptr;
  90. }
  91. void destroy()
  92. {
  93. deleter d{
  94. (get_associated_allocator)(handler_,
  95. asio::recycling_allocator<void>())};
  96. d(this);
  97. }
  98. any_completion_executor executor(
  99. const any_completion_executor& candidate) const noexcept
  100. {
  101. return any_completion_executor(std::nothrow,
  102. (get_associated_executor)(handler_, candidate));
  103. }
  104. any_completion_executor immediate_executor(
  105. const any_io_executor& candidate) const noexcept
  106. {
  107. return any_completion_executor(std::nothrow,
  108. (get_associated_immediate_executor)(handler_, candidate));
  109. }
  110. void* allocate(std::size_t size, std::size_t align) const
  111. {
  112. typename std::allocator_traits<
  113. associated_allocator_t<Handler,
  114. asio::recycling_allocator<void>>>::template
  115. rebind_alloc<unsigned char> alloc(
  116. (get_associated_allocator)(handler_,
  117. asio::recycling_allocator<void>()));
  118. std::size_t space = size + align - 1;
  119. unsigned char* base =
  120. std::allocator_traits<decltype(alloc)>::allocate(
  121. alloc, space + sizeof(std::ptrdiff_t));
  122. void* p = base;
  123. if (detail::align(align, size, p, space))
  124. {
  125. std::ptrdiff_t off = static_cast<unsigned char*>(p) - base;
  126. std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off));
  127. return p;
  128. }
  129. std::bad_alloc ex;
  130. asio::detail::throw_exception(ex);
  131. return nullptr;
  132. }
  133. void deallocate(void* p, std::size_t size, std::size_t align) const
  134. {
  135. if (p)
  136. {
  137. typename std::allocator_traits<
  138. associated_allocator_t<Handler,
  139. asio::recycling_allocator<void>>>::template
  140. rebind_alloc<unsigned char> alloc(
  141. (get_associated_allocator)(handler_,
  142. asio::recycling_allocator<void>()));
  143. std::ptrdiff_t off;
  144. std::memcpy(&off, static_cast<unsigned char*>(p) + size, sizeof(off));
  145. unsigned char* base = static_cast<unsigned char*>(p) - off;
  146. std::allocator_traits<decltype(alloc)>::deallocate(
  147. alloc, base, size + align -1 + sizeof(std::ptrdiff_t));
  148. }
  149. }
  150. template <typename... Args>
  151. void call(Args&&... args)
  152. {
  153. deleter d{
  154. (get_associated_allocator)(handler_,
  155. asio::recycling_allocator<void>())};
  156. std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d);
  157. Handler handler(static_cast<Handler&&>(handler_));
  158. ptr.reset();
  159. static_cast<Handler&&>(handler)(
  160. static_cast<Args&&>(args)...);
  161. }
  162. private:
  163. Handler handler_;
  164. };
  165. template <typename Signature>
  166. class any_completion_handler_call_fn;
  167. template <typename R, typename... Args>
  168. class any_completion_handler_call_fn<R(Args...)>
  169. {
  170. public:
  171. using type = void(*)(any_completion_handler_impl_base*, Args...);
  172. constexpr any_completion_handler_call_fn(type fn)
  173. : call_fn_(fn)
  174. {
  175. }
  176. void call(any_completion_handler_impl_base* impl, Args... args) const
  177. {
  178. call_fn_(impl, static_cast<Args&&>(args)...);
  179. }
  180. template <typename Handler>
  181. static void impl(any_completion_handler_impl_base* impl, Args... args)
  182. {
  183. static_cast<any_completion_handler_impl<Handler>*>(impl)->call(
  184. static_cast<Args&&>(args)...);
  185. }
  186. private:
  187. type call_fn_;
  188. };
  189. template <typename... Signatures>
  190. class any_completion_handler_call_fns;
  191. template <typename Signature>
  192. class any_completion_handler_call_fns<Signature> :
  193. public any_completion_handler_call_fn<Signature>
  194. {
  195. public:
  196. using any_completion_handler_call_fn<
  197. Signature>::any_completion_handler_call_fn;
  198. using any_completion_handler_call_fn<Signature>::call;
  199. };
  200. template <typename Signature, typename... Signatures>
  201. class any_completion_handler_call_fns<Signature, Signatures...> :
  202. public any_completion_handler_call_fn<Signature>,
  203. public any_completion_handler_call_fns<Signatures...>
  204. {
  205. public:
  206. template <typename CallFn, typename... CallFns>
  207. constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns)
  208. : any_completion_handler_call_fn<Signature>(fn),
  209. any_completion_handler_call_fns<Signatures...>(fns...)
  210. {
  211. }
  212. using any_completion_handler_call_fn<Signature>::call;
  213. using any_completion_handler_call_fns<Signatures...>::call;
  214. };
  215. class any_completion_handler_destroy_fn
  216. {
  217. public:
  218. using type = void(*)(any_completion_handler_impl_base*);
  219. constexpr any_completion_handler_destroy_fn(type fn)
  220. : destroy_fn_(fn)
  221. {
  222. }
  223. void destroy(any_completion_handler_impl_base* impl) const
  224. {
  225. destroy_fn_(impl);
  226. }
  227. template <typename Handler>
  228. static void impl(any_completion_handler_impl_base* impl)
  229. {
  230. static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy();
  231. }
  232. private:
  233. type destroy_fn_;
  234. };
  235. class any_completion_handler_executor_fn
  236. {
  237. public:
  238. using type = any_completion_executor(*)(
  239. any_completion_handler_impl_base*, const any_completion_executor&);
  240. constexpr any_completion_handler_executor_fn(type fn)
  241. : executor_fn_(fn)
  242. {
  243. }
  244. any_completion_executor executor(any_completion_handler_impl_base* impl,
  245. const any_completion_executor& candidate) const
  246. {
  247. return executor_fn_(impl, candidate);
  248. }
  249. template <typename Handler>
  250. static any_completion_executor impl(any_completion_handler_impl_base* impl,
  251. const any_completion_executor& candidate)
  252. {
  253. return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor(
  254. candidate);
  255. }
  256. private:
  257. type executor_fn_;
  258. };
  259. class any_completion_handler_immediate_executor_fn
  260. {
  261. public:
  262. using type = any_completion_executor(*)(
  263. any_completion_handler_impl_base*, const any_io_executor&);
  264. constexpr any_completion_handler_immediate_executor_fn(type fn)
  265. : immediate_executor_fn_(fn)
  266. {
  267. }
  268. any_completion_executor immediate_executor(
  269. any_completion_handler_impl_base* impl,
  270. const any_io_executor& candidate) const
  271. {
  272. return immediate_executor_fn_(impl, candidate);
  273. }
  274. template <typename Handler>
  275. static any_completion_executor impl(any_completion_handler_impl_base* impl,
  276. const any_io_executor& candidate)
  277. {
  278. return static_cast<any_completion_handler_impl<Handler>*>(
  279. impl)->immediate_executor(candidate);
  280. }
  281. private:
  282. type immediate_executor_fn_;
  283. };
  284. class any_completion_handler_allocate_fn
  285. {
  286. public:
  287. using type = void*(*)(any_completion_handler_impl_base*,
  288. std::size_t, std::size_t);
  289. constexpr any_completion_handler_allocate_fn(type fn)
  290. : allocate_fn_(fn)
  291. {
  292. }
  293. void* allocate(any_completion_handler_impl_base* impl,
  294. std::size_t size, std::size_t align) const
  295. {
  296. return allocate_fn_(impl, size, align);
  297. }
  298. template <typename Handler>
  299. static void* impl(any_completion_handler_impl_base* impl,
  300. std::size_t size, std::size_t align)
  301. {
  302. return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate(
  303. size, align);
  304. }
  305. private:
  306. type allocate_fn_;
  307. };
  308. class any_completion_handler_deallocate_fn
  309. {
  310. public:
  311. using type = void(*)(any_completion_handler_impl_base*,
  312. void*, std::size_t, std::size_t);
  313. constexpr any_completion_handler_deallocate_fn(type fn)
  314. : deallocate_fn_(fn)
  315. {
  316. }
  317. void deallocate(any_completion_handler_impl_base* impl,
  318. void* p, std::size_t size, std::size_t align) const
  319. {
  320. deallocate_fn_(impl, p, size, align);
  321. }
  322. template <typename Handler>
  323. static void impl(any_completion_handler_impl_base* impl,
  324. void* p, std::size_t size, std::size_t align)
  325. {
  326. static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate(
  327. p, size, align);
  328. }
  329. private:
  330. type deallocate_fn_;
  331. };
  332. template <typename... Signatures>
  333. class any_completion_handler_fn_table
  334. : private any_completion_handler_destroy_fn,
  335. private any_completion_handler_executor_fn,
  336. private any_completion_handler_immediate_executor_fn,
  337. private any_completion_handler_allocate_fn,
  338. private any_completion_handler_deallocate_fn,
  339. private any_completion_handler_call_fns<Signatures...>
  340. {
  341. public:
  342. template <typename... CallFns>
  343. constexpr any_completion_handler_fn_table(
  344. any_completion_handler_destroy_fn::type destroy_fn,
  345. any_completion_handler_executor_fn::type executor_fn,
  346. any_completion_handler_immediate_executor_fn::type immediate_executor_fn,
  347. any_completion_handler_allocate_fn::type allocate_fn,
  348. any_completion_handler_deallocate_fn::type deallocate_fn,
  349. CallFns... call_fns)
  350. : any_completion_handler_destroy_fn(destroy_fn),
  351. any_completion_handler_executor_fn(executor_fn),
  352. any_completion_handler_immediate_executor_fn(immediate_executor_fn),
  353. any_completion_handler_allocate_fn(allocate_fn),
  354. any_completion_handler_deallocate_fn(deallocate_fn),
  355. any_completion_handler_call_fns<Signatures...>(call_fns...)
  356. {
  357. }
  358. using any_completion_handler_destroy_fn::destroy;
  359. using any_completion_handler_executor_fn::executor;
  360. using any_completion_handler_immediate_executor_fn::immediate_executor;
  361. using any_completion_handler_allocate_fn::allocate;
  362. using any_completion_handler_deallocate_fn::deallocate;
  363. using any_completion_handler_call_fns<Signatures...>::call;
  364. };
  365. template <typename Handler, typename... Signatures>
  366. struct any_completion_handler_fn_table_instance
  367. {
  368. static constexpr any_completion_handler_fn_table<Signatures...>
  369. value = any_completion_handler_fn_table<Signatures...>(
  370. &any_completion_handler_destroy_fn::impl<Handler>,
  371. &any_completion_handler_executor_fn::impl<Handler>,
  372. &any_completion_handler_immediate_executor_fn::impl<Handler>,
  373. &any_completion_handler_allocate_fn::impl<Handler>,
  374. &any_completion_handler_deallocate_fn::impl<Handler>,
  375. &any_completion_handler_call_fn<Signatures>::template impl<Handler>...);
  376. };
  377. template <typename Handler, typename... Signatures>
  378. constexpr any_completion_handler_fn_table<Signatures...>
  379. any_completion_handler_fn_table_instance<Handler, Signatures...>::value;
  380. } // namespace detail
  381. template <typename... Signatures>
  382. class any_completion_handler;
  383. /// An allocator type that forwards memory allocation operations through an
  384. /// instance of @c any_completion_handler.
  385. template <typename T, typename... Signatures>
  386. class any_completion_handler_allocator
  387. {
  388. private:
  389. template <typename...>
  390. friend class any_completion_handler;
  391. template <typename, typename...>
  392. friend class any_completion_handler_allocator;
  393. const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
  394. detail::any_completion_handler_impl_base* impl_;
  395. constexpr any_completion_handler_allocator(int,
  396. const any_completion_handler<Signatures...>& h) noexcept
  397. : fn_table_(h.fn_table_),
  398. impl_(h.impl_)
  399. {
  400. }
  401. public:
  402. /// The type of objects that may be allocated by the allocator.
  403. typedef T value_type;
  404. /// Rebinds an allocator to another value type.
  405. template <typename U>
  406. struct rebind
  407. {
  408. /// Specifies the type of the rebound allocator.
  409. typedef any_completion_handler_allocator<U, Signatures...> other;
  410. };
  411. /// Construct from another @c any_completion_handler_allocator.
  412. template <typename U>
  413. constexpr any_completion_handler_allocator(
  414. const any_completion_handler_allocator<U, Signatures...>& a)
  415. noexcept
  416. : fn_table_(a.fn_table_),
  417. impl_(a.impl_)
  418. {
  419. }
  420. /// Equality operator.
  421. constexpr bool operator==(
  422. const any_completion_handler_allocator& other) const noexcept
  423. {
  424. return fn_table_ == other.fn_table_ && impl_ == other.impl_;
  425. }
  426. /// Inequality operator.
  427. constexpr bool operator!=(
  428. const any_completion_handler_allocator& other) const noexcept
  429. {
  430. return fn_table_ != other.fn_table_ || impl_ != other.impl_;
  431. }
  432. /// Allocate space for @c n objects of the allocator's value type.
  433. T* allocate(std::size_t n) const
  434. {
  435. if (fn_table_)
  436. {
  437. return static_cast<T*>(
  438. fn_table_->allocate(
  439. impl_, sizeof(T) * n, alignof(T)));
  440. }
  441. std::bad_alloc ex;
  442. asio::detail::throw_exception(ex);
  443. return nullptr;
  444. }
  445. /// Deallocate space for @c n objects of the allocator's value type.
  446. void deallocate(T* p, std::size_t n) const
  447. {
  448. fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T));
  449. }
  450. };
  451. /// A protoco-allocator type that may be rebound to obtain an allocator that
  452. /// forwards memory allocation operations through an instance of
  453. /// @c any_completion_handler.
  454. template <typename... Signatures>
  455. class any_completion_handler_allocator<void, Signatures...>
  456. {
  457. private:
  458. template <typename...>
  459. friend class any_completion_handler;
  460. template <typename, typename...>
  461. friend class any_completion_handler_allocator;
  462. const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
  463. detail::any_completion_handler_impl_base* impl_;
  464. constexpr any_completion_handler_allocator(int,
  465. const any_completion_handler<Signatures...>& h) noexcept
  466. : fn_table_(h.fn_table_),
  467. impl_(h.impl_)
  468. {
  469. }
  470. public:
  471. /// @c void as no objects can be allocated through a proto-allocator.
  472. typedef void value_type;
  473. /// Rebinds an allocator to another value type.
  474. template <typename U>
  475. struct rebind
  476. {
  477. /// Specifies the type of the rebound allocator.
  478. typedef any_completion_handler_allocator<U, Signatures...> other;
  479. };
  480. /// Construct from another @c any_completion_handler_allocator.
  481. template <typename U>
  482. constexpr any_completion_handler_allocator(
  483. const any_completion_handler_allocator<U, Signatures...>& a)
  484. noexcept
  485. : fn_table_(a.fn_table_),
  486. impl_(a.impl_)
  487. {
  488. }
  489. /// Equality operator.
  490. constexpr bool operator==(
  491. const any_completion_handler_allocator& other) const noexcept
  492. {
  493. return fn_table_ == other.fn_table_ && impl_ == other.impl_;
  494. }
  495. /// Inequality operator.
  496. constexpr bool operator!=(
  497. const any_completion_handler_allocator& other) const noexcept
  498. {
  499. return fn_table_ != other.fn_table_ || impl_ != other.impl_;
  500. }
  501. };
  502. /// Polymorphic wrapper for completion handlers.
  503. /**
  504. * The @c any_completion_handler class template is a polymorphic wrapper for
  505. * completion handlers that propagates the associated executor, associated
  506. * allocator, and associated cancellation slot through a type-erasing interface.
  507. *
  508. * When using @c any_completion_handler, specify one or more completion
  509. * signatures as template parameters. These will dictate the arguments that may
  510. * be passed to the handler through the polymorphic interface.
  511. *
  512. * Typical uses for @c any_completion_handler include:
  513. *
  514. * @li Separate compilation of asynchronous operation implementations.
  515. *
  516. * @li Enabling interoperability between asynchronous operations and virtual
  517. * functions.
  518. */
  519. template <typename... Signatures>
  520. class any_completion_handler
  521. {
  522. #if !defined(GENERATING_DOCUMENTATION)
  523. private:
  524. template <typename, typename...>
  525. friend class any_completion_handler_allocator;
  526. template <typename, typename>
  527. friend struct associated_executor;
  528. template <typename, typename>
  529. friend struct associated_immediate_executor;
  530. const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
  531. detail::any_completion_handler_impl_base* impl_;
  532. #endif // !defined(GENERATING_DOCUMENTATION)
  533. public:
  534. /// The associated allocator type.
  535. using allocator_type = any_completion_handler_allocator<void, Signatures...>;
  536. /// The associated cancellation slot type.
  537. using cancellation_slot_type = cancellation_slot;
  538. /// Construct an @c any_completion_handler in an empty state, without a target
  539. /// object.
  540. constexpr any_completion_handler()
  541. : fn_table_(nullptr),
  542. impl_(nullptr)
  543. {
  544. }
  545. /// Construct an @c any_completion_handler in an empty state, without a target
  546. /// object.
  547. constexpr any_completion_handler(nullptr_t)
  548. : fn_table_(nullptr),
  549. impl_(nullptr)
  550. {
  551. }
  552. /// Construct an @c any_completion_handler to contain the specified target.
  553. template <typename H, typename Handler = decay_t<H>>
  554. any_completion_handler(H&& h,
  555. constraint_t<
  556. !is_same<decay_t<H>, any_completion_handler>::value
  557. > = 0)
  558. : fn_table_(
  559. &detail::any_completion_handler_fn_table_instance<
  560. Handler, Signatures...>::value),
  561. impl_(detail::any_completion_handler_impl<Handler>::create(
  562. (get_associated_cancellation_slot)(h), static_cast<H&&>(h)))
  563. {
  564. }
  565. /// Move-construct an @c any_completion_handler from another.
  566. /**
  567. * After the operation, the moved-from object @c other has no target.
  568. */
  569. any_completion_handler(any_completion_handler&& other) noexcept
  570. : fn_table_(other.fn_table_),
  571. impl_(other.impl_)
  572. {
  573. other.fn_table_ = nullptr;
  574. other.impl_ = nullptr;
  575. }
  576. /// Move-assign an @c any_completion_handler from another.
  577. /**
  578. * After the operation, the moved-from object @c other has no target.
  579. */
  580. any_completion_handler& operator=(
  581. any_completion_handler&& other) noexcept
  582. {
  583. any_completion_handler(
  584. static_cast<any_completion_handler&&>(other)).swap(*this);
  585. return *this;
  586. }
  587. /// Assignment operator that sets the polymorphic wrapper to the empty state.
  588. any_completion_handler& operator=(nullptr_t) noexcept
  589. {
  590. any_completion_handler().swap(*this);
  591. return *this;
  592. }
  593. /// Destructor.
  594. ~any_completion_handler()
  595. {
  596. if (impl_)
  597. fn_table_->destroy(impl_);
  598. }
  599. /// Test if the polymorphic wrapper is empty.
  600. constexpr explicit operator bool() const noexcept
  601. {
  602. return impl_ != nullptr;
  603. }
  604. /// Test if the polymorphic wrapper is non-empty.
  605. constexpr bool operator!() const noexcept
  606. {
  607. return impl_ == nullptr;
  608. }
  609. /// Swap the content of an @c any_completion_handler with another.
  610. void swap(any_completion_handler& other) noexcept
  611. {
  612. std::swap(fn_table_, other.fn_table_);
  613. std::swap(impl_, other.impl_);
  614. }
  615. /// Get the associated allocator.
  616. allocator_type get_allocator() const noexcept
  617. {
  618. return allocator_type(0, *this);
  619. }
  620. /// Get the associated cancellation slot.
  621. cancellation_slot_type get_cancellation_slot() const noexcept
  622. {
  623. return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type();
  624. }
  625. /// Function call operator.
  626. /**
  627. * Invokes target completion handler with the supplied arguments.
  628. *
  629. * This function may only be called once, as the target handler is moved from.
  630. * The polymorphic wrapper is left in an empty state.
  631. *
  632. * Throws @c std::bad_function_call if the polymorphic wrapper is empty.
  633. */
  634. template <typename... Args>
  635. auto operator()(Args&&... args)
  636. -> decltype(fn_table_->call(impl_, static_cast<Args&&>(args)...))
  637. {
  638. if (detail::any_completion_handler_impl_base* impl = impl_)
  639. {
  640. impl_ = nullptr;
  641. return fn_table_->call(impl, static_cast<Args&&>(args)...);
  642. }
  643. std::bad_function_call ex;
  644. asio::detail::throw_exception(ex);
  645. }
  646. /// Equality operator.
  647. friend constexpr bool operator==(
  648. const any_completion_handler& a, nullptr_t) noexcept
  649. {
  650. return a.impl_ == nullptr;
  651. }
  652. /// Equality operator.
  653. friend constexpr bool operator==(
  654. nullptr_t, const any_completion_handler& b) noexcept
  655. {
  656. return nullptr == b.impl_;
  657. }
  658. /// Inequality operator.
  659. friend constexpr bool operator!=(
  660. const any_completion_handler& a, nullptr_t) noexcept
  661. {
  662. return a.impl_ != nullptr;
  663. }
  664. /// Inequality operator.
  665. friend constexpr bool operator!=(
  666. nullptr_t, const any_completion_handler& b) noexcept
  667. {
  668. return nullptr != b.impl_;
  669. }
  670. };
  671. template <typename... Signatures, typename Candidate>
  672. struct associated_executor<any_completion_handler<Signatures...>, Candidate>
  673. {
  674. using type = any_completion_executor;
  675. static type get(const any_completion_handler<Signatures...>& handler,
  676. const Candidate& candidate = Candidate()) noexcept
  677. {
  678. any_completion_executor any_candidate(std::nothrow, candidate);
  679. return handler.fn_table_
  680. ? handler.fn_table_->executor(handler.impl_, any_candidate)
  681. : any_candidate;
  682. }
  683. };
  684. template <typename... Signatures, typename Candidate>
  685. struct associated_immediate_executor<
  686. any_completion_handler<Signatures...>, Candidate>
  687. {
  688. using type = any_completion_executor;
  689. static type get(const any_completion_handler<Signatures...>& handler,
  690. const Candidate& candidate = Candidate()) noexcept
  691. {
  692. any_io_executor any_candidate(std::nothrow, candidate);
  693. return handler.fn_table_
  694. ? handler.fn_table_->immediate_executor(handler.impl_, any_candidate)
  695. : any_candidate;
  696. }
  697. };
  698. } // namespace asio
  699. #include "asio/detail/pop_options.hpp"
  700. #endif // ASIO_ANY_COMPLETION_HANDLER_HPP