1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost |
4 | // Software License, Version 1.0. (See accompanying file |
5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
6 | // |
7 | // See http://www.boost.org/libs/container for documentation. |
8 | // |
9 | ////////////////////////////////////////////////////////////////////////////// |
10 | |
11 | #ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP |
12 | #define BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP |
13 | |
14 | #ifndef BOOST_CONFIG_HPP |
15 | # include <boost/config.hpp> |
16 | #endif |
17 | |
18 | #if defined(BOOST_HAS_PRAGMA_ONCE) |
19 | # pragma once |
20 | #endif |
21 | |
22 | #include <boost/container/detail/config_begin.hpp> |
23 | #include <boost/container/detail/workaround.hpp> |
24 | |
25 | // container |
26 | #include <boost/container/allocator_traits.hpp> |
27 | // container/detail |
28 | #include <boost/container/detail/copy_move_algo.hpp> |
29 | #include <boost/container/detail/destroyers.hpp> |
30 | #include <boost/container/detail/mpl.hpp> |
31 | #include <boost/container/detail/type_traits.hpp> |
32 | #include <boost/container/detail/iterator.hpp> |
33 | #include <boost/container/detail/iterators.hpp> |
34 | #include <boost/move/detail/iterator_to_raw_pointer.hpp> |
35 | #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
36 | #include <boost/move/detail/fwd_macros.hpp> |
37 | #endif |
38 | // move |
39 | #include <boost/move/utility_core.hpp> |
40 | // other |
41 | #include <boost/assert.hpp> |
42 | #include <boost/core/no_exceptions_support.hpp> |
43 | |
44 | namespace boost { namespace container { namespace container_detail { |
45 | |
46 | template<class Allocator, class FwdIt, class Iterator> |
47 | struct move_insert_range_proxy |
48 | { |
49 | typedef typename allocator_traits<Allocator>::size_type size_type; |
50 | typedef typename allocator_traits<Allocator>::value_type value_type; |
51 | |
52 | explicit move_insert_range_proxy(FwdIt first) |
53 | : first_(first) |
54 | {} |
55 | |
56 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) |
57 | { |
58 | this->first_ = ::boost::container::uninitialized_move_alloc_n_source |
59 | (a, this->first_, n, p); |
60 | } |
61 | |
62 | void copy_n_and_update(Allocator &, Iterator p, size_type n) |
63 | { |
64 | this->first_ = ::boost::container::move_n_source(this->first_, n, p); |
65 | } |
66 | |
67 | FwdIt first_; |
68 | }; |
69 | |
70 | |
71 | template<class Allocator, class FwdIt, class Iterator> |
72 | struct insert_range_proxy |
73 | { |
74 | typedef typename allocator_traits<Allocator>::size_type size_type; |
75 | typedef typename allocator_traits<Allocator>::value_type value_type; |
76 | |
77 | explicit insert_range_proxy(FwdIt first) |
78 | : first_(first) |
79 | {} |
80 | |
81 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) |
82 | { |
83 | this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(a, this->first_, n, p); |
84 | } |
85 | |
86 | void copy_n_and_update(Allocator &, Iterator p, size_type n) |
87 | { |
88 | this->first_ = ::boost::container::copy_n_source(this->first_, n, p); |
89 | } |
90 | |
91 | FwdIt first_; |
92 | }; |
93 | |
94 | |
95 | template<class Allocator, class Iterator> |
96 | struct insert_n_copies_proxy |
97 | { |
98 | typedef typename allocator_traits<Allocator>::size_type size_type; |
99 | typedef typename allocator_traits<Allocator>::value_type value_type; |
100 | |
101 | explicit insert_n_copies_proxy(const value_type &v) |
102 | : v_(v) |
103 | {} |
104 | |
105 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const |
106 | { boost::container::uninitialized_fill_alloc_n(a, v_, n, p); } |
107 | |
108 | void copy_n_and_update(Allocator &, Iterator p, size_type n) const |
109 | { |
110 | for (; 0 < n; --n, ++p){ |
111 | *p = v_; |
112 | } |
113 | } |
114 | |
115 | const value_type &v_; |
116 | }; |
117 | |
118 | template<class Allocator, class Iterator> |
119 | struct insert_value_initialized_n_proxy |
120 | { |
121 | typedef ::boost::container::allocator_traits<Allocator> alloc_traits; |
122 | typedef typename allocator_traits<Allocator>::size_type size_type; |
123 | typedef typename allocator_traits<Allocator>::value_type value_type; |
124 | |
125 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const |
126 | { boost::container::uninitialized_value_init_alloc_n(a, n, p); } |
127 | |
128 | void copy_n_and_update(Allocator &, Iterator, size_type) const |
129 | { BOOST_ASSERT(false); } |
130 | }; |
131 | |
132 | template<class Allocator, class Iterator> |
133 | struct insert_default_initialized_n_proxy |
134 | { |
135 | typedef ::boost::container::allocator_traits<Allocator> alloc_traits; |
136 | typedef typename allocator_traits<Allocator>::size_type size_type; |
137 | typedef typename allocator_traits<Allocator>::value_type value_type; |
138 | |
139 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const |
140 | { boost::container::uninitialized_default_init_alloc_n(a, n, p); } |
141 | |
142 | void copy_n_and_update(Allocator &, Iterator, size_type) const |
143 | { BOOST_ASSERT(false); } |
144 | }; |
145 | |
146 | template<class Allocator, class Iterator> |
147 | struct insert_copy_proxy |
148 | { |
149 | typedef boost::container::allocator_traits<Allocator> alloc_traits; |
150 | typedef typename alloc_traits::size_type size_type; |
151 | typedef typename alloc_traits::value_type value_type; |
152 | |
153 | explicit insert_copy_proxy(const value_type &v) |
154 | : v_(v) |
155 | {} |
156 | |
157 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const |
158 | { |
159 | BOOST_ASSERT(n == 1); (void)n; |
160 | alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), v_); |
161 | } |
162 | |
163 | void copy_n_and_update(Allocator &, Iterator p, size_type n) const |
164 | { |
165 | BOOST_ASSERT(n == 1); (void)n; |
166 | *p =v_; |
167 | } |
168 | |
169 | const value_type &v_; |
170 | }; |
171 | |
172 | |
173 | template<class Allocator, class Iterator> |
174 | struct insert_move_proxy |
175 | { |
176 | typedef boost::container::allocator_traits<Allocator> alloc_traits; |
177 | typedef typename alloc_traits::size_type size_type; |
178 | typedef typename alloc_traits::value_type value_type; |
179 | |
180 | explicit insert_move_proxy(value_type &v) |
181 | : v_(v) |
182 | {} |
183 | |
184 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const |
185 | { |
186 | BOOST_ASSERT(n == 1); (void)n; |
187 | alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::move(v_) ); |
188 | } |
189 | |
190 | void copy_n_and_update(Allocator &, Iterator p, size_type n) const |
191 | { |
192 | BOOST_ASSERT(n == 1); (void)n; |
193 | *p = ::boost::move(v_); |
194 | } |
195 | |
196 | value_type &v_; |
197 | }; |
198 | |
199 | template<class It, class Allocator> |
200 | insert_move_proxy<Allocator, It> get_insert_value_proxy(BOOST_RV_REF(typename boost::container::iterator_traits<It>::value_type) v) |
201 | { |
202 | return insert_move_proxy<Allocator, It>(v); |
203 | } |
204 | |
205 | template<class It, class Allocator> |
206 | insert_copy_proxy<Allocator, It> get_insert_value_proxy(const typename boost::container::iterator_traits<It>::value_type &v) |
207 | { |
208 | return insert_copy_proxy<Allocator, It>(v); |
209 | } |
210 | |
211 | }}} //namespace boost { namespace container { namespace container_detail { |
212 | |
213 | #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
214 | |
215 | #include <boost/container/detail/variadic_templates_tools.hpp> |
216 | #include <boost/move/utility_core.hpp> |
217 | |
218 | namespace boost { |
219 | namespace container { |
220 | namespace container_detail { |
221 | |
222 | template<class Allocator, class Iterator, class ...Args> |
223 | struct insert_nonmovable_emplace_proxy |
224 | { |
225 | typedef boost::container::allocator_traits<Allocator> alloc_traits; |
226 | typedef typename alloc_traits::size_type size_type; |
227 | typedef typename alloc_traits::value_type value_type; |
228 | |
229 | typedef typename build_number_seq<sizeof...(Args)>::type index_tuple_t; |
230 | |
231 | explicit insert_nonmovable_emplace_proxy(BOOST_FWD_REF(Args)... args) |
232 | : args_(args...) |
233 | {} |
234 | |
235 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) |
236 | { this->priv_uninitialized_copy_some_and_update(a, index_tuple_t(), p, n); } |
237 | |
238 | private: |
239 | template<std::size_t ...IdxPack> |
240 | void priv_uninitialized_copy_some_and_update(Allocator &a, const index_tuple<IdxPack...>&, Iterator p, size_type n) |
241 | { |
242 | BOOST_ASSERT(n == 1); (void)n; |
243 | alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::forward<Args>(get<IdxPack>(this->args_))... ); |
244 | } |
245 | |
246 | protected: |
247 | tuple<Args&...> args_; |
248 | }; |
249 | |
250 | template<class Allocator, class Iterator, class ...Args> |
251 | struct insert_emplace_proxy |
252 | : public insert_nonmovable_emplace_proxy<Allocator, Iterator, Args...> |
253 | { |
254 | typedef insert_nonmovable_emplace_proxy<Allocator, Iterator, Args...> base_t; |
255 | typedef boost::container::allocator_traits<Allocator> alloc_traits; |
256 | typedef typename base_t::value_type value_type; |
257 | typedef typename base_t::size_type size_type; |
258 | typedef typename base_t::index_tuple_t index_tuple_t; |
259 | |
260 | explicit insert_emplace_proxy(BOOST_FWD_REF(Args)... args) |
261 | : base_t(::boost::forward<Args>(args)...) |
262 | {} |
263 | |
264 | void copy_n_and_update(Allocator &a, Iterator p, size_type n) |
265 | { this->priv_copy_some_and_update(a, index_tuple_t(), p, n); } |
266 | |
267 | private: |
268 | |
269 | template<std::size_t ...IdxPack> |
270 | void priv_copy_some_and_update(Allocator &a, const index_tuple<IdxPack...>&, Iterator p, size_type n) |
271 | { |
272 | BOOST_ASSERT(n ==1); (void)n; |
273 | typename aligned_storage<sizeof(value_type), alignment_of<value_type>::value>::type v; |
274 | value_type *vp = static_cast<value_type *>(static_cast<void *>(&v)); |
275 | alloc_traits::construct(a, vp, |
276 | ::boost::forward<Args>(get<IdxPack>(this->args_))...); |
277 | BOOST_TRY{ |
278 | *p = ::boost::move(*vp); |
279 | } |
280 | BOOST_CATCH(...){ |
281 | alloc_traits::destroy(a, vp); |
282 | BOOST_RETHROW |
283 | } |
284 | BOOST_CATCH_END |
285 | alloc_traits::destroy(a, vp); |
286 | } |
287 | }; |
288 | |
289 | //Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type |
290 | template<class Allocator, class Iterator> |
291 | struct insert_emplace_proxy<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type> |
292 | : public insert_move_proxy<Allocator, Iterator> |
293 | { |
294 | explicit insert_emplace_proxy(typename boost::container::allocator_traits<Allocator>::value_type &&v) |
295 | : insert_move_proxy<Allocator, Iterator>(v) |
296 | {} |
297 | }; |
298 | |
299 | //We use "add_const" here as adding "const" only confuses MSVC12(and maybe later) provoking |
300 | //compiler error C2752 ("more than one partial specialization matches"). |
301 | //Any problem is solvable with an extra layer of indirection? ;-) |
302 | template<class Allocator, class Iterator> |
303 | struct insert_emplace_proxy<Allocator, Iterator |
304 | , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type |
305 | > |
306 | : public insert_copy_proxy<Allocator, Iterator> |
307 | { |
308 | explicit insert_emplace_proxy(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
309 | : insert_copy_proxy<Allocator, Iterator>(v) |
310 | {} |
311 | }; |
312 | |
313 | template<class Allocator, class Iterator> |
314 | struct insert_emplace_proxy<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type &> |
315 | : public insert_copy_proxy<Allocator, Iterator> |
316 | { |
317 | explicit insert_emplace_proxy(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
318 | : insert_copy_proxy<Allocator, Iterator>(v) |
319 | {} |
320 | }; |
321 | |
322 | template<class Allocator, class Iterator> |
323 | struct insert_emplace_proxy<Allocator, Iterator |
324 | , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type & |
325 | > |
326 | : public insert_copy_proxy<Allocator, Iterator> |
327 | { |
328 | explicit insert_emplace_proxy(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
329 | : insert_copy_proxy<Allocator, Iterator>(v) |
330 | {} |
331 | }; |
332 | |
333 | }}} //namespace boost { namespace container { namespace container_detail { |
334 | |
335 | #else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
336 | |
337 | #include <boost/container/detail/value_init.hpp> |
338 | |
339 | namespace boost { |
340 | namespace container { |
341 | namespace container_detail { |
342 | |
343 | #define BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE(N) \ |
344 | template< class Allocator, class Iterator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ |
345 | struct insert_nonmovable_emplace_proxy##N\ |
346 | {\ |
347 | typedef boost::container::allocator_traits<Allocator> alloc_traits;\ |
348 | typedef typename alloc_traits::size_type size_type;\ |
349 | typedef typename alloc_traits::value_type value_type;\ |
350 | \ |
351 | explicit insert_nonmovable_emplace_proxy##N(BOOST_MOVE_UREF##N)\ |
352 | BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N {}\ |
353 | \ |
354 | void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n)\ |
355 | {\ |
356 | BOOST_ASSERT(n == 1); (void)n;\ |
357 | alloc_traits::construct(a, boost::movelib::iterator_to_raw_pointer(p) BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ |
358 | }\ |
359 | \ |
360 | void copy_n_and_update(Allocator &, Iterator, size_type)\ |
361 | { BOOST_ASSERT(false); }\ |
362 | \ |
363 | protected:\ |
364 | BOOST_MOVE_MREF##N\ |
365 | };\ |
366 | \ |
367 | template< class Allocator, class Iterator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ |
368 | struct insert_emplace_proxy_arg##N\ |
369 | : insert_nonmovable_emplace_proxy##N< Allocator, Iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N >\ |
370 | {\ |
371 | typedef insert_nonmovable_emplace_proxy##N\ |
372 | < Allocator, Iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N > base_t;\ |
373 | typedef typename base_t::value_type value_type;\ |
374 | typedef typename base_t::size_type size_type;\ |
375 | typedef boost::container::allocator_traits<Allocator> alloc_traits;\ |
376 | \ |
377 | explicit insert_emplace_proxy_arg##N(BOOST_MOVE_UREF##N)\ |
378 | : base_t(BOOST_MOVE_FWD##N){}\ |
379 | \ |
380 | void copy_n_and_update(Allocator &a, Iterator p, size_type n)\ |
381 | {\ |
382 | BOOST_ASSERT(n == 1); (void)n;\ |
383 | typename aligned_storage<sizeof(value_type), alignment_of<value_type>::value>::type v;\ |
384 | BOOST_ASSERT((((size_type)(&v)) % alignment_of<value_type>::value) == 0);\ |
385 | value_type *vp = static_cast<value_type *>(static_cast<void *>(&v));\ |
386 | alloc_traits::construct(a, vp BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ |
387 | BOOST_TRY{\ |
388 | *p = ::boost::move(*vp);\ |
389 | }\ |
390 | BOOST_CATCH(...){\ |
391 | alloc_traits::destroy(a, vp);\ |
392 | BOOST_RETHROW\ |
393 | }\ |
394 | BOOST_CATCH_END\ |
395 | alloc_traits::destroy(a, vp);\ |
396 | }\ |
397 | };\ |
398 | // |
399 | BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE) |
400 | #undef BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE |
401 | |
402 | #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
403 | |
404 | //Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type |
405 | template<class Allocator, class Iterator> |
406 | struct insert_emplace_proxy_arg1<Allocator, Iterator, ::boost::rv<typename boost::container::allocator_traits<Allocator>::value_type> > |
407 | : public insert_move_proxy<Allocator, Iterator> |
408 | { |
409 | explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits<Allocator>::value_type &v) |
410 | : insert_move_proxy<Allocator, Iterator>(v) |
411 | {} |
412 | }; |
413 | |
414 | template<class Allocator, class Iterator> |
415 | struct insert_emplace_proxy_arg1<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type> |
416 | : public insert_copy_proxy<Allocator, Iterator> |
417 | { |
418 | explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
419 | : insert_copy_proxy<Allocator, Iterator>(v) |
420 | {} |
421 | }; |
422 | |
423 | #else //e.g. MSVC10 & MSVC11 |
424 | |
425 | //Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type |
426 | template<class Allocator, class Iterator> |
427 | struct insert_emplace_proxy_arg1<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type> |
428 | : public insert_move_proxy<Allocator, Iterator> |
429 | { |
430 | explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits<Allocator>::value_type &&v) |
431 | : insert_move_proxy<Allocator, Iterator>(v) |
432 | {} |
433 | }; |
434 | |
435 | //We use "add_const" here as adding "const" only confuses MSVC10&11 provoking |
436 | //compiler error C2752 ("more than one partial specialization matches"). |
437 | //Any problem is solvable with an extra layer of indirection? ;-) |
438 | template<class Allocator, class Iterator> |
439 | struct insert_emplace_proxy_arg1<Allocator, Iterator |
440 | , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type |
441 | > |
442 | : public insert_copy_proxy<Allocator, Iterator> |
443 | { |
444 | explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
445 | : insert_copy_proxy<Allocator, Iterator>(v) |
446 | {} |
447 | }; |
448 | |
449 | template<class Allocator, class Iterator> |
450 | struct insert_emplace_proxy_arg1<Allocator, Iterator, typename boost::container::allocator_traits<Allocator>::value_type &> |
451 | : public insert_copy_proxy<Allocator, Iterator> |
452 | { |
453 | explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
454 | : insert_copy_proxy<Allocator, Iterator>(v) |
455 | {} |
456 | }; |
457 | |
458 | template<class Allocator, class Iterator> |
459 | struct insert_emplace_proxy_arg1<Allocator, Iterator |
460 | , typename boost::container::container_detail::add_const<typename boost::container::allocator_traits<Allocator>::value_type>::type & |
461 | > |
462 | : public insert_copy_proxy<Allocator, Iterator> |
463 | { |
464 | explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits<Allocator>::value_type &v) |
465 | : insert_copy_proxy<Allocator, Iterator>(v) |
466 | {} |
467 | }; |
468 | |
469 | #endif |
470 | |
471 | }}} //namespace boost { namespace container { namespace container_detail { |
472 | |
473 | #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) |
474 | |
475 | #include <boost/container/detail/config_end.hpp> |
476 | |
477 | #endif //#ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP |
478 | |