1 //
2 // execution/allocator.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_EXECUTION_ALLOCATOR_HPP
12 #define BOOST_ASIO_EXECUTION_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/execution/executor.hpp>
21 #include <boost/asio/execution/scheduler.hpp>
22 #include <boost/asio/execution/sender.hpp>
23 #include <boost/asio/is_applicable_property.hpp>
24 #include <boost/asio/traits/query_static_constexpr_member.hpp>
25 #include <boost/asio/traits/static_query.hpp>
26 
27 #include <boost/asio/detail/push_options.hpp>
28 
29 namespace boost {
30 namespace asio {
31 
32 #if defined(GENERATING_DOCUMENTATION)
33 
34 namespace execution {
35 
36 /// A property to describe which allocator an executor will use to allocate the
37 /// memory required to store a submitted function object.
38 template <typename ProtoAllocator>
39 struct allocator_t
40 {
41   /// The allocator_t property applies to executors, senders, and schedulers.
42   template <typename T>
43   static constexpr bool is_applicable_property_v =
44     is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>;
45 
46   /// The allocator_t property can be required.
47   static constexpr bool is_requirable = true;
48 
49   /// The allocator_t property can be preferred.
50   static constexpr bool is_preferable = true;
51 
52   /// Default constructor.
53   constexpr allocator_t();
54 
55   /// Obtain the allocator stored in the allocator_t property object.
56   /**
57    * Present only if @c ProtoAllocator is non-void.
58    */
59   constexpr ProtoAllocator value() const;
60 
61   /// Create an allocator_t object with a different allocator.
62   /**
63    * Present only if @c ProtoAllocator is void.
64    */
65   template <typename OtherAllocator>
66   allocator_t<OtherAllocator operator()(const OtherAllocator& a);
67 };
68 
69 /// A special value used for accessing the allocator_t property.
70 constexpr allocator_t<void> allocator;
71 
72 } // namespace execution
73 
74 #else // defined(GENERATING_DOCUMENTATION)
75 
76 namespace execution {
77 
78 template <typename ProtoAllocator>
79 struct allocator_t
80 {
81 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
82   template <typename T>
83   BOOST_ASIO_STATIC_CONSTEXPR(bool,
84     is_applicable_property_v = (
85       is_executor<T>::value
86         || conditional<
87             is_executor<T>::value,
88             false_type,
89             is_sender<T>
90           >::type::value
91         || conditional<
92             is_executor<T>::value,
93             false_type,
94             is_scheduler<T>
95           >::type::value));
96 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
97 
98   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
99   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
100 
101   template <typename T>
102   struct static_proxy
103   {
104 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
105     struct type
106     {
107       template <typename P>
108       static constexpr auto query(BOOST_ASIO_MOVE_ARG(P) p)
109         noexcept(
110           noexcept(
111             conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
112           )
113         )
114         -> decltype(
115           conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
116         )
117       {
118         return T::query(BOOST_ASIO_MOVE_CAST(P)(p));
119       }
120     };
121 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
122     typedef T type;
123 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
124   };
125 
126   template <typename T>
127   struct query_static_constexpr_member :
128     traits::query_static_constexpr_member<
129       typename static_proxy<T>::type, allocator_t> {};
130 
131 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
132   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
133   template <typename T>
134   static BOOST_ASIO_CONSTEXPR
135   typename query_static_constexpr_member<T>::result_type
136   static_query()
137     BOOST_ASIO_NOEXCEPT_IF((
138       query_static_constexpr_member<T>::is_noexcept))
139   {
140     return query_static_constexpr_member<T>::value();
141   }
142 
143   template <typename E, typename T = decltype(allocator_t::static_query<E>())>
144   static BOOST_ASIO_CONSTEXPR const T static_query_v
145     = allocator_t::static_query<E>();
146 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
147        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
148 
149   BOOST_ASIO_CONSTEXPR ProtoAllocator value() const
150   {
151     return a_;
152   }
153 
154 private:
155   friend struct allocator_t<void>;
156 
157   explicit BOOST_ASIO_CONSTEXPR allocator_t(const ProtoAllocator& a)
158     : a_(a)
159   {
160   }
161 
162   ProtoAllocator a_;
163 };
164 
165 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
166   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
167 template <typename ProtoAllocator> template <typename E, typename T>
168 const T allocator_t<ProtoAllocator>::static_query_v;
169 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
170        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
171 
172 template <>
173 struct allocator_t<void>
174 {
175 #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
176   template <typename T>
177   BOOST_ASIO_STATIC_CONSTEXPR(bool,
178     is_applicable_property_v = (
179       is_executor<T>::value
180         || conditional<
181             is_executor<T>::value,
182             false_type,
183             is_sender<T>
184           >::type::value
185         || conditional<
186             is_executor<T>::value,
187             false_type,
188             is_scheduler<T>
189           >::type::value));
190 #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
191 
192   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true);
193   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true);
194 
195   BOOST_ASIO_CONSTEXPR allocator_t()
196   {
197   }
198 
199   template <typename T>
200   struct static_proxy
201   {
202 #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
203     struct type
204     {
205       template <typename P>
206       static constexpr auto query(BOOST_ASIO_MOVE_ARG(P) p)
207         noexcept(
208           noexcept(
209             conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
210           )
211         )
212         -> decltype(
213           conditional<true, T, P>::type::query(BOOST_ASIO_MOVE_CAST(P)(p))
214         )
215       {
216         return T::query(BOOST_ASIO_MOVE_CAST(P)(p));
217       }
218     };
219 #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
220     typedef T type;
221 #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
222   };
223 
224   template <typename T>
225   struct query_static_constexpr_member :
226     traits::query_static_constexpr_member<
227       typename static_proxy<T>::type, allocator_t> {};
228 
229 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
230   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
231   template <typename T>
232   static BOOST_ASIO_CONSTEXPR
233   typename query_static_constexpr_member<T>::result_type
234   static_query()
235     BOOST_ASIO_NOEXCEPT_IF((
236       query_static_constexpr_member<T>::is_noexcept))
237   {
238     return query_static_constexpr_member<T>::value();
239   }
240 
241   template <typename E, typename T = decltype(allocator_t::static_query<E>())>
242   static BOOST_ASIO_CONSTEXPR const T static_query_v
243     = allocator_t::static_query<E>();
244 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
245        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
246 
247   template <typename OtherProtoAllocator>
248   BOOST_ASIO_CONSTEXPR allocator_t<OtherProtoAllocator> operator()(
249       const OtherProtoAllocator& a) const
250   {
251     return allocator_t<OtherProtoAllocator>(a);
252   }
253 };
254 
255 #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
256   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
257 template <typename E, typename T>
258 const T allocator_t<void>::static_query_v;
259 #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
260        //   && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
261 
262 #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
263 constexpr allocator_t<void> allocator;
264 #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
265 template <typename T>
266 struct allocator_instance
267 {
268   static allocator_t<T> instance;
269 };
270 
271 template <typename T>
272 allocator_t<T> allocator_instance<T>::instance;
273 
274 namespace {
275 static const allocator_t<void>& allocator = allocator_instance<void>::instance;
276 } // namespace
277 #endif
278 
279 } // namespace execution
280 
281 #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
282 
283 template <typename T, typename ProtoAllocator>
284 struct is_applicable_property<T, execution::allocator_t<ProtoAllocator> >
285   : integral_constant<bool,
286       execution::is_executor<T>::value
287         || conditional<
288             execution::is_executor<T>::value,
289             false_type,
290             execution::is_sender<T>
291           >::type::value
292         || conditional<
293             execution::is_executor<T>::value,
294             false_type,
295             execution::is_scheduler<T>
296           >::type::value>
297 {
298 };
299 
300 #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES)
301 
302 namespace traits {
303 
304 #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \
305   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
306 
307 template <typename T, typename ProtoAllocator>
308 struct static_query<T, execution::allocator_t<ProtoAllocator>,
309   typename enable_if<
310     execution::allocator_t<ProtoAllocator>::template
311       query_static_constexpr_member<T>::is_valid
312   >::type>
313 {
314   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true);
315   BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true);
316 
317   typedef typename execution::allocator_t<ProtoAllocator>::template
318     query_static_constexpr_member<T>::result_type result_type;
319 
320   static BOOST_ASIO_CONSTEXPR result_type value()
321   {
322     return execution::allocator_t<ProtoAllocator>::template
323       query_static_constexpr_member<T>::value();
324   }
325 };
326 
327 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT)
328        //   || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES)
329 
330 } // namespace traits
331 
332 #endif // defined(GENERATING_DOCUMENTATION)
333 
334 } // namespace asio
335 } // namespace boost
336 
337 #include <boost/asio/detail/pop_options.hpp>
338 
339 #endif // BOOST_ASIO_EXECUTION_ALLOCATOR_HPP
340