Ticket #6905: emplace_args.hpp

File emplace_args.hpp, 19.4 KB (added by lukester_null@…, 10 years ago)

Possible fix.

Line 
1
2// Copyright (C) 2011 Daniel James.
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6// See http://www.boost.org/libs/unordered for documentation
7
8#ifndef BOOST_UNORDERED_EMPLACE_ARGS_HPP
9#define BOOST_UNORDERED_EMPLACE_ARGS_HPP
10
11#if defined(_MSC_VER) && (_MSC_VER >= 1020)
12# pragma once
13#endif
14
15#include <boost/move/move.hpp>
16#include <boost/preprocessor/cat.hpp>
17#include <boost/preprocessor/inc.hpp>
18#include <boost/preprocessor/dec.hpp>
19#include <boost/preprocessor/repetition/enum.hpp>
20#include <boost/preprocessor/repetition/enum_params.hpp>
21#include <boost/preprocessor/repetition/enum_binary_params.hpp>
22#include <boost/preprocessor/repetition/repeat_from_to.hpp>
23#include <boost/type_traits/is_class.hpp>
24#include <boost/tuple/tuple.hpp>
25#include <utility>
26
27#if !defined(BOOST_NO_0X_HDR_TUPLE)
28#include <tuple>
29#endif
30
31#if defined(BOOST_MSVC)
32#pragma warning(push)
33#pragma warning(disable:4512) // assignment operator could not be generated.
34#pragma warning(disable:4345) // behavior change: an object of POD type
35 // constructed with an initializer of the form ()
36 // will be default-initialized.
37#endif
38
39#define BOOST_UNORDERED_EMPLACE_LIMIT 10
40
41#if !defined(BOOST_NO_RVALUE_REFERENCES) && \
42 !defined(BOOST_NO_VARIADIC_TEMPLATES)
43#define BOOST_UNORDERED_VARIADIC_MOVE
44#endif
45
46namespace boost { namespace unordered { namespace detail {
47
48 ////////////////////////////////////////////////////////////////////////////
49 // emplace_args
50 //
51 // Either forwarding variadic arguments, or storing the arguments in
52 // emplace_args##n
53
54#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
55
56#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
57#define BOOST_UNORDERED_EMPLACE_ARGS Args&&... args
58#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
59
60#else
61
62#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
63#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
64#define BOOST_UNORDERED_EMPLACE_FORWARD args
65
66#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \
67 BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n)
68
69#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \
70 boost::forward<BOOST_PP_CAT(A,i)>(BOOST_PP_CAT(a,i))
71
72#define BOOST_UNORDERED_EARGS(z, n, _) \
73 template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
74 struct BOOST_PP_CAT(emplace_args, n) \
75 { \
76 BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \
77 BOOST_PP_CAT(emplace_args, n) ( \
78 BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, a) \
79 ) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \
80 {} \
81 \
82 }; \
83 \
84 template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
85 inline BOOST_PP_CAT(emplace_args, n) < \
86 BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
87 > create_emplace_args( \
88 BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, a) \
89 ) \
90 { \
91 BOOST_PP_CAT(emplace_args, n) < \
92 BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
93 > e(BOOST_PP_ENUM_PARAMS_Z(z, n, a)); \
94 return e; \
95 }
96
97#if defined(BOOST_NO_RVALUE_REFERENCES)
98
99#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
100 typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
101 BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
102
103#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
104 BOOST_PP_CAT(a, n)( \
105 boost::forward<BOOST_PP_CAT(A,n)>(BOOST_PP_CAT(a, n)))
106
107#else
108
109#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
110 typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
111 BOOST_PP_CAT(Arg, n); \
112 BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
113
114#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
115 BOOST_PP_CAT(a, n)(BOOST_PP_CAT(a, n))
116
117#endif
118
119BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
120 _)
121
122#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
123#undef BOOST_UNORDERED_EARGS_MEMBER
124#undef BOOST_UNORDERED_EARGS_INIT
125
126#endif
127
128 ////////////////////////////////////////////////////////////////////////////
129 // rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
130 // e.g. for int
131
132#if !defined(BOOST_NO_RVALUE_REFERENCES)
133# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
134#else
135 struct please_ignore_this_overload {
136 typedef please_ignore_this_overload type;
137 };
138
139 template <typename T>
140 struct rv_ref_impl {
141 typedef BOOST_RV_REF(T) type;
142 };
143
144 template <typename T>
145 struct rv_ref :
146 boost::detail::if_true<
147 boost::is_class<T>::value
148 >::BOOST_NESTED_TEMPLATE then <
149 boost::unordered::detail::rv_ref_impl<T>,
150 please_ignore_this_overload
151 >::type
152 {};
153
154# define BOOST_UNORDERED_RV_REF(T) \
155 typename boost::unordered::detail::rv_ref<T>::type
156#endif
157
158 ////////////////////////////////////////////////////////////////////////////
159 // Construct from tuple
160 //
161 // Used for piecewise construction.
162
163#if !defined(__SUNPRO_CC)
164
165# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
166 template<typename T> \
167 void construct_from_tuple(T* ptr, namespace_##tuple<>) \
168 { \
169 new ((void*) ptr) T(); \
170 } \
171 \
172 BOOST_PP_REPEAT_FROM_TO(1, n, \
173 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
174
175# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
176 template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
177 void construct_from_tuple(T* ptr, \
178 namespace_##tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
179 { \
180 new ((void*) ptr) T( \
181 BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \
182 ); \
183 }
184
185# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
186 namespace_##get<n>(x)
187
188#else
189
190 template <int N> struct length {};
191
192# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
193 template<typename T> \
194 void construct_from_tuple_impl( \
195 boost::unordered::detail::length<0>, T* ptr, \
196 namespace_##tuple<>) \
197 { \
198 new ((void*) ptr) T(); \
199 } \
200 \
201 BOOST_PP_REPEAT_FROM_TO(1, n, \
202 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
203
204# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
205 template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
206 void construct_from_tuple_impl( \
207 boost::unordered::detail::length<n>, T* ptr, \
208 namespace_##tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
209 { \
210 new ((void*) ptr) T( \
211 BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \
212 ); \
213 }
214
215# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
216 namespace_##get<n>(x)
217
218#endif
219
220BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
221
222#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_0X_HDR_TUPLE)
223 BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::)
224#endif
225
226#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
227#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
228#undef BOOST_UNORDERED_GET_TUPLE_ARG
229
230#if defined(__SUNPRO_CC)
231
232 template <typename T, typename Tuple>
233 void construct_from_tuple(T* ptr, Tuple const& x)
234 {
235 construct_from_tuple_impl(
236 boost::unordered::detail::length<
237 boost::tuples::length<Tuple>::value>(),
238 ptr, x);
239 }
240
241#endif
242
243 ////////////////////////////////////////////////////////////////////////////
244 // SFINAE traits for construction.
245
246 // Decide which construction method to use for a three argument
247 // call. Note that this is difficult to do using overloads because
248 // the arguments are packed into 'emplace_args3'.
249 //
250 // The decision is made on the first argument.
251
252
253#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
254 template <typename A, typename B, typename A0>
255 struct emulation1 {
256 static choice1::type test(choice1, std::pair<A, B> const&);
257 static choice2::type test(choice2, A const&);
258 static choice3::type test(choice3, convert_from_anything const&);
259
260 enum { value =
261 sizeof(test(choose(), boost::unordered::detail::make<A0>())) ==
262 sizeof(choice2::type) };
263 };
264#endif
265
266 template <typename A, typename B, typename A0>
267 struct check3_base {
268 static choice1::type test(choice1,
269 boost::unordered::piecewise_construct_t);
270
271#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
272 static choice2::type test(choice2, A const&);
273#endif
274
275 static choice3::type test(choice3, ...);
276
277 enum { value =
278 sizeof(test(choose(), boost::unordered::detail::make<A0>())) };
279 };
280
281 template <typename A, typename B, typename A0>
282 struct piecewise3 {
283 enum { value = check3_base<A,B,A0>::value == sizeof(choice1::type) };
284 };
285
286#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
287 template <typename A, typename B, typename A0>
288 struct emulation3 {
289 enum { value = check3_base<A,B,A0>::value == sizeof(choice2::type) };
290 };
291
292#endif
293
294#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
295
296 ////////////////////////////////////////////////////////////////////////////
297 // Construct from variadic parameters
298
299 template <typename T, typename... Args>
300 inline void construct_impl(T* address, Args&&... args)
301 {
302 new((void*) address) T(boost::forward<Args>(args)...);
303 }
304
305 template <typename A, typename B, typename A0, typename A1, typename A2>
306 inline typename enable_if<piecewise3<A, B, A0>, void>::type
307 construct_impl(std::pair<A, B>* address, A0&&, A1&& a1, A2&& a2)
308 {
309 boost::unordered::detail::construct_from_tuple(
310 boost::addressof(address->first), a1);
311 boost::unordered::detail::construct_from_tuple(
312 boost::addressof(address->second), a2);
313 }
314
315#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
316
317 template <typename A, typename B, typename A0>
318 inline typename enable_if<emulation1<A, B, A0>, void>::type
319 construct_impl(std::pair<A, B>* address, A0&& a0)
320 {
321 new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0));
322 new((void*) boost::addressof(address->second)) B();
323 }
324
325 template <typename A, typename B, typename A0, typename A1, typename A2>
326 inline typename enable_if<emulation3<A, B, A0>, void>::type
327 construct_impl(std::pair<A, B>* address, A0&& a0, A1&& a1, A2&& a2)
328 {
329 new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0));
330 new((void*) boost::addressof(address->second)) B(
331 boost::forward<A1>(a1),
332 boost::forward<A2>(a2));
333 }
334
335 template <typename A, typename B,
336 typename A0, typename A1, typename A2, typename A3,
337 typename... Args>
338 inline void construct_impl(std::pair<A, B>* address,
339 A0&& a0, A1&& a1, A2&& a2, A3&& a3, Args&&... args)
340 {
341 new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0));
342
343 new((void*) boost::addressof(address->second)) B(
344 boost::forward<A1>(a1),
345 boost::forward<A2>(a2),
346 boost::forward<A3>(a3),
347 boost::forward<Args>(args)...);
348 }
349
350#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
351#else // BOOST_UNORDERED_VARIADIC_MOVE
352
353////////////////////////////////////////////////////////////////////////////////
354// Construct from emplace_args
355
356#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
357 template < \
358 typename T, \
359 BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
360 > \
361 inline void construct_impl(T* address, \
362 boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
363 BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
364 > const& args) \
365 { \
366 new((void*) address) T( \
367 BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \
368 args.a)); \
369 }
370
371 template <typename T, typename A0>
372 inline void construct_impl(T* address, emplace_args1<A0> const& args)
373 {
374 new((void*) address) T(boost::forward<A0>(args.a0));
375 }
376
377 template <typename T, typename A0, typename A1>
378 inline void construct_impl(T* address, emplace_args2<A0, A1> const& args)
379 {
380 new((void*) address) T(
381 boost::forward<A0>(args.a0),
382 boost::forward<A1>(args.a1)
383 );
384 }
385
386 template <typename T, typename A0, typename A1, typename A2>
387 inline void construct_impl(T* address, emplace_args3<A0, A1, A2> const& args)
388 {
389 new((void*) address) T(
390 boost::forward<A0>(args.a0),
391 boost::forward<A1>(args.a1),
392 boost::forward<A2>(args.a2)
393 );
394 }
395
396 BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
397 BOOST_UNORDERED_CONSTRUCT_IMPL, _)
398
399#undef BOOST_UNORDERED_CONSTRUCT_IMPL
400
401 template <typename A, typename B, typename A0, typename A1, typename A2>
402 inline typename enable_if<piecewise3<A, B, A0>, void>::type
403 construct_impl(std::pair<A, B>* address,
404 boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
405 {
406 boost::unordered::detail::construct_from_tuple(
407 boost::addressof(address->first), args.a1);
408 boost::unordered::detail::construct_from_tuple(
409 boost::addressof(address->second), args.a2);
410 }
411
412#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
413
414 template <typename A, typename B, typename A0>
415 inline typename enable_if<emulation1<A, B, A0>, void>::type
416 construct_impl(std::pair<A, B>* address,
417 boost::unordered::detail::emplace_args1<A0> const& args)
418 {
419 new((void*) boost::addressof(address->first)) A(
420 boost::forward<A0>(args.a0));
421 new((void*) boost::addressof(address->second)) B();
422 }
423
424 template <typename A, typename B, typename A0, typename A1, typename A2>
425 inline typename enable_if<emulation3<A, B, A0>, void>::type
426 construct_impl(std::pair<A, B>* address,
427 boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
428 {
429 new((void*) boost::addressof(address->first)) A(
430 boost::forward<A0>(args.a0));
431 new((void*) boost::addressof(address->second)) B(
432 boost::forward<A1>(args.a1),
433 boost::forward<A2>(args.a2));
434 }
435
436#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \
437 template <typename A, typename B, \
438 BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
439 > \
440 inline void construct_impl(std::pair<A, B>* address, \
441 boost::unordered::detail::BOOST_PP_CAT(emplace_args, num_params) < \
442 BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
443 > const& args) \
444 { \
445 new((void*) boost::addressof(address->first)) A( \
446 boost::forward<A0>(args.a0)); \
447 new((void*) boost::addressof(address->second)) B( \
448 BOOST_PP_ENUM_##z(BOOST_PP_DEC(num_params), \
449 BOOST_UNORDERED_CALL_FORWARD2, args.a)); \
450 }
451
452#define BOOST_UNORDERED_CALL_FORWARD2(z, i, a) \
453 BOOST_UNORDERED_CALL_FORWARD(z, BOOST_PP_INC(i), a)
454
455 BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(1, 2, _)
456 BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
457 BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _)
458
459#undef BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL
460#undef BOOST_UNORDERED_CALL_FORWARD2
461
462#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
463#endif // BOOST_UNORDERED_VARIADIC_MOVE
464
465 ////////////////////////////////////////////////////////////////////////////
466 // Construct without using the emplace args mechanism.
467
468 template <typename T, typename A0>
469 inline void construct_impl2(T* address, BOOST_FWD_REF(A0) a0)
470 {
471 new((void*) address) T(
472 boost::forward<A0>(a0)
473 );
474 }
475
476}}}
477
478#if defined(BOOST_MSVC)
479#pragma warning(pop)
480#endif
481
482#endif