bind_allocator.hpp 14 KB

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