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