1 | // |
2 | // associated_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_ASSOCIATED_ALLOCATOR_HPP |
12 | #define BOOST_ASIO_ASSOCIATED_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 <memory> |
20 | #include <boost/asio/associator.hpp> |
21 | #include <boost/asio/detail/functional.hpp> |
22 | #include <boost/asio/detail/type_traits.hpp> |
23 | |
24 | #include <boost/asio/detail/push_options.hpp> |
25 | |
26 | namespace boost { |
27 | namespace asio { |
28 | |
29 | template <typename T, typename Allocator> |
30 | struct associated_allocator; |
31 | |
32 | namespace detail { |
33 | |
34 | template <typename T, typename = void> |
35 | struct has_allocator_type : false_type |
36 | { |
37 | }; |
38 | |
39 | template <typename T> |
40 | struct has_allocator_type<T, void_t<typename T::allocator_type>> : true_type |
41 | { |
42 | }; |
43 | |
44 | template <typename T, typename A, typename = void, typename = void> |
45 | struct associated_allocator_impl |
46 | { |
47 | typedef void asio_associated_allocator_is_unspecialised; |
48 | |
49 | typedef A type; |
50 | |
51 | static type get(const T&) noexcept |
52 | { |
53 | return type(); |
54 | } |
55 | |
56 | static const type& get(const T&, const A& a) noexcept |
57 | { |
58 | return a; |
59 | } |
60 | }; |
61 | |
62 | template <typename T, typename A> |
63 | struct associated_allocator_impl<T, A, void_t<typename T::allocator_type>> |
64 | { |
65 | typedef typename T::allocator_type type; |
66 | |
67 | static auto get(const T& t) noexcept |
68 | -> decltype(t.get_allocator()) |
69 | { |
70 | return t.get_allocator(); |
71 | } |
72 | |
73 | static auto get(const T& t, const A&) noexcept |
74 | -> decltype(t.get_allocator()) |
75 | { |
76 | return t.get_allocator(); |
77 | } |
78 | }; |
79 | |
80 | template <typename T, typename A> |
81 | struct associated_allocator_impl<T, A, |
82 | enable_if_t< |
83 | !has_allocator_type<T>::value |
84 | >, |
85 | void_t< |
86 | typename associator<associated_allocator, T, A>::type |
87 | >> : associator<associated_allocator, T, A> |
88 | { |
89 | }; |
90 | |
91 | } // namespace detail |
92 | |
93 | /// Traits type used to obtain the allocator associated with an object. |
94 | /** |
95 | * A program may specialise this traits type if the @c T template parameter in |
96 | * the specialisation is a user-defined type. The template parameter @c |
97 | * Allocator shall be a type meeting the Allocator requirements. |
98 | * |
99 | * Specialisations shall meet the following requirements, where @c t is a const |
100 | * reference to an object of type @c T, and @c a is an object of type @c |
101 | * Allocator. |
102 | * |
103 | * @li Provide a nested typedef @c type that identifies a type meeting the |
104 | * Allocator requirements. |
105 | * |
106 | * @li Provide a noexcept static member function named @c get, callable as @c |
107 | * get(t) and with return type @c type or a (possibly const) reference to @c |
108 | * type. |
109 | * |
110 | * @li Provide a noexcept static member function named @c get, callable as @c |
111 | * get(t,a) and with return type @c type or a (possibly const) reference to @c |
112 | * type. |
113 | */ |
114 | template <typename T, typename Allocator = std::allocator<void>> |
115 | struct associated_allocator |
116 | #if !defined(GENERATING_DOCUMENTATION) |
117 | : detail::associated_allocator_impl<T, Allocator> |
118 | #endif // !defined(GENERATING_DOCUMENTATION) |
119 | { |
120 | #if defined(GENERATING_DOCUMENTATION) |
121 | /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>. |
122 | /// Otherwise @c Allocator. |
123 | typedef see_below type; |
124 | |
125 | /// If @c T has a nested type @c allocator_type, returns |
126 | /// <tt>t.get_allocator()</tt>. Otherwise returns @c type(). |
127 | static decltype(auto) get(const T& t) noexcept; |
128 | |
129 | /// If @c T has a nested type @c allocator_type, returns |
130 | /// <tt>t.get_allocator()</tt>. Otherwise returns @c a. |
131 | static decltype(auto) get(const T& t, const Allocator& a) noexcept; |
132 | #endif // defined(GENERATING_DOCUMENTATION) |
133 | }; |
134 | |
135 | /// Helper function to obtain an object's associated allocator. |
136 | /** |
137 | * @returns <tt>associated_allocator<T>::get(t)</tt> |
138 | */ |
139 | template <typename T> |
140 | BOOST_ASIO_NODISCARD inline typename associated_allocator<T>::type |
141 | get_associated_allocator(const T& t) noexcept |
142 | { |
143 | return associated_allocator<T>::get(t); |
144 | } |
145 | |
146 | /// Helper function to obtain an object's associated allocator. |
147 | /** |
148 | * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt> |
149 | */ |
150 | template <typename T, typename Allocator> |
151 | BOOST_ASIO_NODISCARD inline auto get_associated_allocator( |
152 | const T& t, const Allocator& a) noexcept |
153 | -> decltype(associated_allocator<T, Allocator>::get(t, a)) |
154 | { |
155 | return associated_allocator<T, Allocator>::get(t, a); |
156 | } |
157 | |
158 | template <typename T, typename Allocator = std::allocator<void>> |
159 | using associated_allocator_t |
160 | = typename associated_allocator<T, Allocator>::type; |
161 | |
162 | namespace detail { |
163 | |
164 | template <typename T, typename A, typename = void> |
165 | struct associated_allocator_forwarding_base |
166 | { |
167 | }; |
168 | |
169 | template <typename T, typename A> |
170 | struct associated_allocator_forwarding_base<T, A, |
171 | enable_if_t< |
172 | is_same< |
173 | typename associated_allocator<T, |
174 | A>::asio_associated_allocator_is_unspecialised, |
175 | void |
176 | >::value |
177 | >> |
178 | { |
179 | typedef void asio_associated_allocator_is_unspecialised; |
180 | }; |
181 | |
182 | } // namespace detail |
183 | |
184 | /// Specialisation of associated_allocator for @c std::reference_wrapper. |
185 | template <typename T, typename Allocator> |
186 | struct associated_allocator<reference_wrapper<T>, Allocator> |
187 | #if !defined(GENERATING_DOCUMENTATION) |
188 | : detail::associated_allocator_forwarding_base<T, Allocator> |
189 | #endif // !defined(GENERATING_DOCUMENTATION) |
190 | { |
191 | /// Forwards @c type to the associator specialisation for the unwrapped type |
192 | /// @c T. |
193 | typedef typename associated_allocator<T, Allocator>::type type; |
194 | |
195 | /// Forwards the request to get the allocator to the associator specialisation |
196 | /// for the unwrapped type @c T. |
197 | static type get(reference_wrapper<T> t) noexcept |
198 | { |
199 | return associated_allocator<T, Allocator>::get(t.get()); |
200 | } |
201 | |
202 | /// Forwards the request to get the allocator to the associator specialisation |
203 | /// for the unwrapped type @c T. |
204 | static auto get(reference_wrapper<T> t, const Allocator& a) noexcept |
205 | -> decltype(associated_allocator<T, Allocator>::get(t.get(), a)) |
206 | { |
207 | return associated_allocator<T, Allocator>::get(t.get(), a); |
208 | } |
209 | }; |
210 | |
211 | } // namespace asio |
212 | } // namespace boost |
213 | |
214 | #include <boost/asio/detail/pop_options.hpp> |
215 | |
216 | #endif // BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP |
217 | |