bind_allocator.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. //
  2. // bind_allocator.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 BOOST_ASIO_BIND_ALLOCATOR_HPP
  11. #define BOOST_ASIO_BIND_ALLOCATOR_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/detail/type_traits.hpp>
  17. #include <boost/asio/associated_allocator.hpp>
  18. #include <boost/asio/associator.hpp>
  19. #include <boost/asio/async_result.hpp>
  20. #include <boost/asio/detail/push_options.hpp>
  21. namespace boost {
  22. namespace asio {
  23. namespace detail {
  24. // Helper to automatically define nested typedef result_type.
  25. template <typename T, typename = void>
  26. struct allocator_binder_result_type
  27. {
  28. protected:
  29. typedef void result_type_or_void;
  30. };
  31. template <typename T>
  32. struct allocator_binder_result_type<T, void_t<typename T::result_type>>
  33. {
  34. typedef typename T::result_type result_type;
  35. protected:
  36. typedef result_type result_type_or_void;
  37. };
  38. template <typename R>
  39. struct allocator_binder_result_type<R(*)()>
  40. {
  41. typedef R result_type;
  42. protected:
  43. typedef result_type result_type_or_void;
  44. };
  45. template <typename R>
  46. struct allocator_binder_result_type<R(&)()>
  47. {
  48. typedef R result_type;
  49. protected:
  50. typedef result_type result_type_or_void;
  51. };
  52. template <typename R, typename A1>
  53. struct allocator_binder_result_type<R(*)(A1)>
  54. {
  55. typedef R result_type;
  56. protected:
  57. typedef result_type result_type_or_void;
  58. };
  59. template <typename R, typename A1>
  60. struct allocator_binder_result_type<R(&)(A1)>
  61. {
  62. typedef R result_type;
  63. protected:
  64. typedef result_type result_type_or_void;
  65. };
  66. template <typename R, typename A1, typename A2>
  67. struct allocator_binder_result_type<R(*)(A1, A2)>
  68. {
  69. typedef R result_type;
  70. protected:
  71. typedef result_type result_type_or_void;
  72. };
  73. template <typename R, typename A1, typename A2>
  74. struct allocator_binder_result_type<R(&)(A1, A2)>
  75. {
  76. typedef R result_type;
  77. protected:
  78. typedef result_type result_type_or_void;
  79. };
  80. // Helper to automatically define nested typedef argument_type.
  81. template <typename T, typename = void>
  82. struct allocator_binder_argument_type {};
  83. template <typename T>
  84. struct allocator_binder_argument_type<T, void_t<typename T::argument_type>>
  85. {
  86. typedef typename T::argument_type argument_type;
  87. };
  88. template <typename R, typename A1>
  89. struct allocator_binder_argument_type<R(*)(A1)>
  90. {
  91. typedef A1 argument_type;
  92. };
  93. template <typename R, typename A1>
  94. struct allocator_binder_argument_type<R(&)(A1)>
  95. {
  96. typedef A1 argument_type;
  97. };
  98. // Helper to automatically define nested typedefs first_argument_type and
  99. // second_argument_type.
  100. template <typename T, typename = void>
  101. struct allocator_binder_argument_types {};
  102. template <typename T>
  103. struct allocator_binder_argument_types<T,
  104. void_t<typename T::first_argument_type>>
  105. {
  106. typedef typename T::first_argument_type first_argument_type;
  107. typedef typename T::second_argument_type second_argument_type;
  108. };
  109. template <typename R, typename A1, typename A2>
  110. struct allocator_binder_argument_type<R(*)(A1, A2)>
  111. {
  112. typedef A1 first_argument_type;
  113. typedef A2 second_argument_type;
  114. };
  115. template <typename R, typename A1, typename A2>
  116. struct allocator_binder_argument_type<R(&)(A1, A2)>
  117. {
  118. typedef A1 first_argument_type;
  119. typedef A2 second_argument_type;
  120. };
  121. } // namespace detail
  122. /// A call wrapper type to bind an allocator of type @c Allocator
  123. /// to an object of type @c T.
  124. template <typename T, typename Allocator>
  125. class allocator_binder
  126. #if !defined(GENERATING_DOCUMENTATION)
  127. : public detail::allocator_binder_result_type<T>,
  128. public detail::allocator_binder_argument_type<T>,
  129. public detail::allocator_binder_argument_types<T>
  130. #endif // !defined(GENERATING_DOCUMENTATION)
  131. {
  132. public:
  133. /// The type of the target object.
  134. typedef T target_type;
  135. /// The type of the associated allocator.
  136. typedef Allocator allocator_type;
  137. #if defined(GENERATING_DOCUMENTATION)
  138. /// The return type if a function.
  139. /**
  140. * The type of @c result_type is based on the type @c T of the wrapper's
  141. * target object:
  142. *
  143. * @li if @c T is a pointer to function type, @c result_type is a synonym for
  144. * the return type of @c T;
  145. *
  146. * @li if @c T is a class type with a member type @c result_type, then @c
  147. * result_type is a synonym for @c T::result_type;
  148. *
  149. * @li otherwise @c result_type is not defined.
  150. */
  151. typedef see_below result_type;
  152. /// The type of the function's argument.
  153. /**
  154. * The type of @c argument_type is based on the type @c T of the wrapper's
  155. * target object:
  156. *
  157. * @li if @c T is a pointer to a function type accepting a single argument,
  158. * @c argument_type is a synonym for the return type of @c T;
  159. *
  160. * @li if @c T is a class type with a member type @c argument_type, then @c
  161. * argument_type is a synonym for @c T::argument_type;
  162. *
  163. * @li otherwise @c argument_type is not defined.
  164. */
  165. typedef see_below argument_type;
  166. /// The type of the function's first argument.
  167. /**
  168. * The type of @c first_argument_type is based on the type @c T of the
  169. * wrapper's target object:
  170. *
  171. * @li if @c T is a pointer to a function type accepting two arguments, @c
  172. * first_argument_type is a synonym for the return type of @c T;
  173. *
  174. * @li if @c T is a class type with a member type @c first_argument_type,
  175. * then @c first_argument_type is a synonym for @c T::first_argument_type;
  176. *
  177. * @li otherwise @c first_argument_type is not defined.
  178. */
  179. typedef see_below first_argument_type;
  180. /// The type of the function's second argument.
  181. /**
  182. * The type of @c second_argument_type is based on the type @c T of the
  183. * wrapper's target object:
  184. *
  185. * @li if @c T is a pointer to a function type accepting two arguments, @c
  186. * second_argument_type is a synonym for the return type of @c T;
  187. *
  188. * @li if @c T is a class type with a member type @c first_argument_type,
  189. * then @c second_argument_type is a synonym for @c T::second_argument_type;
  190. *
  191. * @li otherwise @c second_argument_type is not defined.
  192. */
  193. typedef see_below second_argument_type;
  194. #endif // defined(GENERATING_DOCUMENTATION)
  195. /// Construct an allocator wrapper for the specified object.
  196. /**
  197. * This constructor is only valid if the type @c T is constructible from type
  198. * @c U.
  199. */
  200. template <typename U>
  201. allocator_binder(const allocator_type& s, U&& u)
  202. : allocator_(s),
  203. target_(static_cast<U&&>(u))
  204. {
  205. }
  206. /// Copy constructor.
  207. allocator_binder(const allocator_binder& other)
  208. : allocator_(other.get_allocator()),
  209. target_(other.get())
  210. {
  211. }
  212. /// Construct a copy, but specify a different allocator.
  213. allocator_binder(const allocator_type& s, const allocator_binder& other)
  214. : allocator_(s),
  215. target_(other.get())
  216. {
  217. }
  218. /// Construct a copy of a different allocator wrapper type.
  219. /**
  220. * This constructor is only valid if the @c Allocator type is
  221. * constructible from type @c OtherAllocator, and the type @c T is
  222. * constructible from type @c U.
  223. */
  224. template <typename U, typename OtherAllocator>
  225. allocator_binder(const allocator_binder<U, OtherAllocator>& other)
  226. : allocator_(other.get_allocator()),
  227. target_(other.get())
  228. {
  229. }
  230. /// Construct a copy of a different allocator wrapper type, but
  231. /// specify a different allocator.
  232. /**
  233. * This constructor is only valid if the type @c T is constructible from type
  234. * @c U.
  235. */
  236. template <typename U, typename OtherAllocator>
  237. allocator_binder(const allocator_type& s,
  238. const allocator_binder<U, OtherAllocator>& other)
  239. : allocator_(s),
  240. target_(other.get())
  241. {
  242. }
  243. /// Move constructor.
  244. allocator_binder(allocator_binder&& other)
  245. : allocator_(static_cast<allocator_type&&>(
  246. other.get_allocator())),
  247. target_(static_cast<T&&>(other.get()))
  248. {
  249. }
  250. /// Move construct the target object, but specify a different allocator.
  251. allocator_binder(const allocator_type& s,
  252. allocator_binder&& other)
  253. : allocator_(s),
  254. target_(static_cast<T&&>(other.get()))
  255. {
  256. }
  257. /// Move construct from a different allocator wrapper type.
  258. template <typename U, typename OtherAllocator>
  259. allocator_binder(
  260. allocator_binder<U, OtherAllocator>&& other)
  261. : allocator_(static_cast<OtherAllocator&&>(
  262. other.get_allocator())),
  263. target_(static_cast<U&&>(other.get()))
  264. {
  265. }
  266. /// Move construct from a different allocator wrapper type, but
  267. /// specify a different allocator.
  268. template <typename U, typename OtherAllocator>
  269. allocator_binder(const allocator_type& s,
  270. allocator_binder<U, OtherAllocator>&& other)
  271. : allocator_(s),
  272. target_(static_cast<U&&>(other.get()))
  273. {
  274. }
  275. /// Destructor.
  276. ~allocator_binder()
  277. {
  278. }
  279. /// Obtain a reference to the target object.
  280. target_type& get() noexcept
  281. {
  282. return target_;
  283. }
  284. /// Obtain a reference to the target object.
  285. const target_type& get() const noexcept
  286. {
  287. return target_;
  288. }
  289. /// Obtain the associated allocator.
  290. allocator_type get_allocator() const noexcept
  291. {
  292. return allocator_;
  293. }
  294. /// Forwarding function call operator.
  295. template <typename... Args>
  296. result_of_t<T(Args...)> operator()(Args&&... args)
  297. {
  298. return target_(static_cast<Args&&>(args)...);
  299. }
  300. /// Forwarding function call operator.
  301. template <typename... Args>
  302. result_of_t<T(Args...)> operator()(Args&&... args) const
  303. {
  304. return target_(static_cast<Args&&>(args)...);
  305. }
  306. private:
  307. Allocator allocator_;
  308. T target_;
  309. };
  310. /// Associate an object of type @c T with an allocator of type
  311. /// @c Allocator.
  312. template <typename Allocator, typename T>
  313. BOOST_ASIO_NODISCARD inline allocator_binder<decay_t<T>, Allocator>
  314. bind_allocator(const Allocator& s, T&& t)
  315. {
  316. return allocator_binder<decay_t<T>, Allocator>(s, static_cast<T&&>(t));
  317. }
  318. #if !defined(GENERATING_DOCUMENTATION)
  319. namespace detail {
  320. template <typename TargetAsyncResult, typename Allocator, typename = void>
  321. class allocator_binder_completion_handler_async_result
  322. {
  323. public:
  324. template <typename T>
  325. explicit allocator_binder_completion_handler_async_result(T&)
  326. {
  327. }
  328. };
  329. template <typename TargetAsyncResult, typename Allocator>
  330. class allocator_binder_completion_handler_async_result<
  331. TargetAsyncResult, Allocator,
  332. void_t<typename TargetAsyncResult::completion_handler_type>>
  333. {
  334. public:
  335. typedef allocator_binder<
  336. typename TargetAsyncResult::completion_handler_type, Allocator>
  337. completion_handler_type;
  338. explicit allocator_binder_completion_handler_async_result(
  339. typename TargetAsyncResult::completion_handler_type& handler)
  340. : target_(handler)
  341. {
  342. }
  343. typename TargetAsyncResult::return_type get()
  344. {
  345. return target_.get();
  346. }
  347. private:
  348. TargetAsyncResult target_;
  349. };
  350. template <typename TargetAsyncResult, typename = void>
  351. struct allocator_binder_async_result_return_type
  352. {
  353. };
  354. template <typename TargetAsyncResult>
  355. struct allocator_binder_async_result_return_type<
  356. TargetAsyncResult, void_type<typename TargetAsyncResult::return_type>>
  357. {
  358. typedef typename TargetAsyncResult::return_type return_type;
  359. };
  360. } // namespace detail
  361. template <typename T, typename Allocator, typename Signature>
  362. class async_result<allocator_binder<T, Allocator>, Signature> :
  363. public detail::allocator_binder_completion_handler_async_result<
  364. async_result<T, Signature>, Allocator>,
  365. public detail::allocator_binder_async_result_return_type<
  366. async_result<T, Signature>>
  367. {
  368. public:
  369. explicit async_result(allocator_binder<T, Allocator>& b)
  370. : detail::allocator_binder_completion_handler_async_result<
  371. async_result<T, Signature>, Allocator>(b.get())
  372. {
  373. }
  374. template <typename Initiation>
  375. struct init_wrapper
  376. {
  377. template <typename Init>
  378. init_wrapper(const Allocator& allocator, Init&& init)
  379. : allocator_(allocator),
  380. initiation_(static_cast<Init&&>(init))
  381. {
  382. }
  383. template <typename Handler, typename... Args>
  384. void operator()(Handler&& handler, Args&&... args)
  385. {
  386. static_cast<Initiation&&>(initiation_)(
  387. allocator_binder<decay_t<Handler>, Allocator>(
  388. allocator_, static_cast<Handler&&>(handler)),
  389. static_cast<Args&&>(args)...);
  390. }
  391. template <typename Handler, typename... Args>
  392. void operator()(Handler&& handler, Args&&... args) const
  393. {
  394. initiation_(
  395. allocator_binder<decay_t<Handler>, Allocator>(
  396. allocator_, static_cast<Handler&&>(handler)),
  397. static_cast<Args&&>(args)...);
  398. }
  399. Allocator allocator_;
  400. Initiation initiation_;
  401. };
  402. template <typename Initiation, typename RawCompletionToken, typename... Args>
  403. static auto initiate(Initiation&& initiation,
  404. RawCompletionToken&& token, Args&&... args)
  405. -> decltype(
  406. async_initiate<T, Signature>(
  407. declval<init_wrapper<decay_t<Initiation>>>(),
  408. token.get(), static_cast<Args&&>(args)...))
  409. {
  410. return async_initiate<T, Signature>(
  411. init_wrapper<decay_t<Initiation>>(token.get_allocator(),
  412. static_cast<Initiation&&>(initiation)),
  413. token.get(), static_cast<Args&&>(args)...);
  414. }
  415. private:
  416. async_result(const async_result&) = delete;
  417. async_result& operator=(const async_result&) = delete;
  418. async_result<T, Signature> target_;
  419. };
  420. template <template <typename, typename> class Associator,
  421. typename T, typename Allocator, typename DefaultCandidate>
  422. struct associator<Associator, allocator_binder<T, Allocator>, DefaultCandidate>
  423. : Associator<T, DefaultCandidate>
  424. {
  425. static typename Associator<T, DefaultCandidate>::type get(
  426. const allocator_binder<T, Allocator>& b) noexcept
  427. {
  428. return Associator<T, DefaultCandidate>::get(b.get());
  429. }
  430. static auto get(const allocator_binder<T, Allocator>& b,
  431. const DefaultCandidate& c) noexcept
  432. -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
  433. {
  434. return Associator<T, DefaultCandidate>::get(b.get(), c);
  435. }
  436. };
  437. template <typename T, typename Allocator, typename Allocator1>
  438. struct associated_allocator<allocator_binder<T, Allocator>, Allocator1>
  439. {
  440. typedef Allocator type;
  441. static auto get(const allocator_binder<T, Allocator>& b,
  442. const Allocator1& = Allocator1()) noexcept
  443. -> decltype(b.get_allocator())
  444. {
  445. return b.get_allocator();
  446. }
  447. };
  448. #endif // !defined(GENERATING_DOCUMENTATION)
  449. } // namespace asio
  450. } // namespace boost
  451. #include <boost/asio/detail/pop_options.hpp>
  452. #endif // BOOST_ASIO_BIND_ALLOCATOR_HPP