1 //
2 // detail/handler_alloc_helpers.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 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_DETAIL_HANDLER_ALLOC_HELPERS_HPP
12 #define BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_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/memory.hpp>
20 #include <boost/asio/detail/noncopyable.hpp>
21 #include <boost/asio/detail/recycling_allocator.hpp>
22 #include <boost/asio/detail/thread_info_base.hpp>
23 #include <boost/asio/associated_allocator.hpp>
24 #include <boost/asio/handler_alloc_hook.hpp>
25
26 #include <boost/asio/detail/push_options.hpp>
27
28 // Calls to asio_handler_allocate and asio_handler_deallocate must be made from
29 // a namespace that does not contain any overloads of these functions. The
30 // boost_asio_handler_alloc_helpers namespace is defined here for that purpose.
31 namespace boost_asio_handler_alloc_helpers {
32
33 #if defined(BOOST_ASIO_NO_DEPRECATED)
34 template <typename Handler>
error_if_hooks_are_defined(Handler & h)35 inline void error_if_hooks_are_defined(Handler& h)
36 {
37 using boost::asio::asio_handler_allocate;
38 // If you get an error here it is because some of your handlers still
39 // overload asio_handler_allocate, but this hook is no longer used.
40 (void)static_cast<boost::asio::asio_handler_allocate_is_no_longer_used>(
41 asio_handler_allocate(static_cast<std::size_t>(0),
42 boost::asio::detail::addressof(h)));
43
44 using boost::asio::asio_handler_deallocate;
45 // If you get an error here it is because some of your handlers still
46 // overload asio_handler_deallocate, but this hook is no longer used.
47 (void)static_cast<boost::asio::asio_handler_deallocate_is_no_longer_used>(
48 asio_handler_deallocate(static_cast<void*>(0),
49 static_cast<std::size_t>(0), boost::asio::detail::addressof(h)));
50 }
51 #endif // defined(BOOST_ASIO_NO_DEPRECATED)
52
53 template <typename Handler>
allocate(std::size_t s,Handler & h)54 inline void* allocate(std::size_t s, Handler& h)
55 {
56 #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
57 return ::operator new(s);
58 #elif defined(BOOST_ASIO_NO_DEPRECATED)
59 // The asio_handler_allocate hook is no longer used to obtain memory.
60 (void)&error_if_hooks_are_defined<Handler>;
61 (void)h;
62 #if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
63 return boost::asio::detail::thread_info_base::allocate(
64 boost::asio::detail::thread_context::top_of_thread_call_stack(), s);
65 #else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
66 return ::operator new(size);
67 #endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
68 #else
69 using boost::asio::asio_handler_allocate;
70 return asio_handler_allocate(s, boost::asio::detail::addressof(h));
71 #endif
72 }
73
74 template <typename Handler>
deallocate(void * p,std::size_t s,Handler & h)75 inline void deallocate(void* p, std::size_t s, Handler& h)
76 {
77 #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
78 ::operator delete(p);
79 #elif defined(BOOST_ASIO_NO_DEPRECATED)
80 // The asio_handler_allocate hook is no longer used to obtain memory.
81 (void)&error_if_hooks_are_defined<Handler>;
82 (void)h;
83 #if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
84 boost::asio::detail::thread_info_base::deallocate(
85 boost::asio::detail::thread_context::top_of_thread_call_stack(), p, s);
86 #else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
87 (void)s;
88 ::operator delete(p);
89 #endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING)
90 #else
91 using boost::asio::asio_handler_deallocate;
92 asio_handler_deallocate(p, s, boost::asio::detail::addressof(h));
93 #endif
94 }
95
96 } // namespace boost_asio_handler_alloc_helpers
97
98 namespace boost {
99 namespace asio {
100 namespace detail {
101
102 template <typename Handler, typename T>
103 class hook_allocator
104 {
105 public:
106 typedef T value_type;
107
108 template <typename U>
109 struct rebind
110 {
111 typedef hook_allocator<Handler, U> other;
112 };
113
hook_allocator(Handler & h)114 explicit hook_allocator(Handler& h)
115 : handler_(h)
116 {
117 }
118
119 template <typename U>
hook_allocator(const hook_allocator<Handler,U> & a)120 hook_allocator(const hook_allocator<Handler, U>& a)
121 : handler_(a.handler_)
122 {
123 }
124
allocate(std::size_t n)125 T* allocate(std::size_t n)
126 {
127 return static_cast<T*>(
128 boost_asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));
129 }
130
deallocate(T * p,std::size_t n)131 void deallocate(T* p, std::size_t n)
132 {
133 boost_asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_);
134 }
135
136 //private:
137 Handler& handler_;
138 };
139
140 template <typename Handler>
141 class hook_allocator<Handler, void>
142 {
143 public:
144 typedef void value_type;
145
146 template <typename U>
147 struct rebind
148 {
149 typedef hook_allocator<Handler, U> other;
150 };
151
hook_allocator(Handler & h)152 explicit hook_allocator(Handler& h)
153 : handler_(h)
154 {
155 }
156
157 template <typename U>
hook_allocator(const hook_allocator<Handler,U> & a)158 hook_allocator(const hook_allocator<Handler, U>& a)
159 : handler_(a.handler_)
160 {
161 }
162
163 //private:
164 Handler& handler_;
165 };
166
167 template <typename Handler, typename Allocator>
168 struct get_hook_allocator
169 {
170 typedef Allocator type;
171
getboost::asio::detail::get_hook_allocator172 static type get(Handler&, const Allocator& a)
173 {
174 return a;
175 }
176 };
177
178 template <typename Handler, typename T>
179 struct get_hook_allocator<Handler, std::allocator<T> >
180 {
181 typedef hook_allocator<Handler, T> type;
182
getboost::asio::detail::get_hook_allocator183 static type get(Handler& handler, const std::allocator<T>&)
184 {
185 return type(handler);
186 }
187 };
188
189 } // namespace detail
190 } // namespace asio
191 } // namespace boost
192
193 #define BOOST_ASIO_DEFINE_HANDLER_PTR(op) \
194 struct ptr \
195 { \
196 Handler* h; \
197 op* v; \
198 op* p; \
199 ~ptr() \
200 { \
201 reset(); \
202 } \
203 static op* allocate(Handler& handler) \
204 { \
205 typedef typename ::boost::asio::associated_allocator< \
206 Handler>::type associated_allocator_type; \
207 typedef typename ::boost::asio::detail::get_hook_allocator< \
208 Handler, associated_allocator_type>::type hook_allocator_type; \
209 BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
210 ::boost::asio::detail::get_hook_allocator< \
211 Handler, associated_allocator_type>::get( \
212 handler, ::boost::asio::get_associated_allocator(handler))); \
213 return a.allocate(1); \
214 } \
215 void reset() \
216 { \
217 if (p) \
218 { \
219 p->~op(); \
220 p = 0; \
221 } \
222 if (v) \
223 { \
224 typedef typename ::boost::asio::associated_allocator< \
225 Handler>::type associated_allocator_type; \
226 typedef typename ::boost::asio::detail::get_hook_allocator< \
227 Handler, associated_allocator_type>::type hook_allocator_type; \
228 BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
229 ::boost::asio::detail::get_hook_allocator< \
230 Handler, associated_allocator_type>::get( \
231 *h, ::boost::asio::get_associated_allocator(*h))); \
232 a.deallocate(static_cast<op*>(v), 1); \
233 v = 0; \
234 } \
235 } \
236 } \
237 /**/
238
239 #define BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(purpose, op) \
240 struct ptr \
241 { \
242 const Alloc* a; \
243 void* v; \
244 op* p; \
245 ~ptr() \
246 { \
247 reset(); \
248 } \
249 static op* allocate(const Alloc& a) \
250 { \
251 typedef typename ::boost::asio::detail::get_recycling_allocator< \
252 Alloc, purpose>::type recycling_allocator_type; \
253 BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
254 ::boost::asio::detail::get_recycling_allocator< \
255 Alloc, purpose>::get(a)); \
256 return a1.allocate(1); \
257 } \
258 void reset() \
259 { \
260 if (p) \
261 { \
262 p->~op(); \
263 p = 0; \
264 } \
265 if (v) \
266 { \
267 typedef typename ::boost::asio::detail::get_recycling_allocator< \
268 Alloc, purpose>::type recycling_allocator_type; \
269 BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
270 ::boost::asio::detail::get_recycling_allocator< \
271 Alloc, purpose>::get(*a)); \
272 a1.deallocate(static_cast<op*>(v), 1); \
273 v = 0; \
274 } \
275 } \
276 } \
277 /**/
278
279 #define BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \
280 BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( \
281 ::boost::asio::detail::thread_info_base::default_tag, op ) \
282 /**/
283
284 #include <boost/asio/detail/pop_options.hpp>
285
286 #endif // BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
287