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

source code of boost/libs/asio/include/boost/asio/bind_allocator.hpp