1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Howard Hinnant 2014. |
4 | // (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost |
5 | // Software License, Version 1.0. (See accompanying file |
6 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | // |
8 | // See http://www.boost.org/libs/container for documentation. |
9 | // |
10 | ////////////////////////////////////////////////////////////////////////////// |
11 | // |
12 | // This testcase is based on H. Hinnant's article "Insert vs. Emplace", |
13 | // (http://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html) |
14 | // |
15 | ////////////////////////////////////////////////////////////////////////////// |
16 | #include <iostream> |
17 | #include <boost/move/utility_core.hpp> |
18 | #include <boost/container/vector.hpp> |
19 | #include <boost/core/lightweight_test.hpp> |
20 | |
21 | class X |
22 | { |
23 | int i_; |
24 | int* p_; |
25 | |
26 | BOOST_COPYABLE_AND_MOVABLE(X) |
27 | |
28 | public: |
29 | struct special |
30 | { |
31 | unsigned c; |
32 | unsigned dt; |
33 | unsigned cc; |
34 | unsigned ca; |
35 | unsigned mc; |
36 | unsigned ma; |
37 | |
38 | friend bool operator==(const special &l, const special &r) |
39 | { return l.c == r.c && l.dt == r.dt && l.cc == r.cc && l.ca == r.ca && l.mc == r.mc && l.ma == r.ma; } |
40 | }; |
41 | static special sp; |
42 | |
43 | X(int i, int* p) |
44 | : i_(i) |
45 | , p_(p) |
46 | { |
47 | // std::cout << "X(int i, int* p)\n"; |
48 | sp.c++; |
49 | } |
50 | |
51 | ~X() |
52 | { |
53 | // std::cout << "~X()\n"; |
54 | sp.dt++; |
55 | } |
56 | |
57 | X(const X& x) |
58 | : i_(x.i_) |
59 | , p_(x.p_) |
60 | { |
61 | // std::cout << "X(const X& x)\n"; |
62 | sp.cc++; |
63 | } |
64 | |
65 | X& operator=(BOOST_COPY_ASSIGN_REF(X) x) |
66 | { |
67 | |
68 | i_ = x.i_; |
69 | p_ = x.p_; |
70 | // std::cout << "X& operator=(const X& x)\n"; |
71 | sp.ca++; |
72 | return *this; |
73 | } |
74 | |
75 | X(BOOST_RV_REF(X) x) BOOST_NOEXCEPT_OR_NOTHROW |
76 | : i_(x.i_) |
77 | , p_(x.p_) |
78 | { |
79 | // std::cout << "X(X&& x)\n"; |
80 | sp.mc++; |
81 | } |
82 | |
83 | X& operator=(BOOST_RV_REF(X) x) BOOST_NOEXCEPT_OR_NOTHROW |
84 | { |
85 | |
86 | i_ = x.i_; |
87 | p_ = x.p_; |
88 | // std::cout << "X& operator=(X&& x)\n"; |
89 | sp.ma++; |
90 | return *this; |
91 | } |
92 | |
93 | }; |
94 | |
95 | std::ostream& |
96 | operator<<(std::ostream& os, X::special const& sp) |
97 | { |
98 | os << "Const: " << sp.c << '\n'; |
99 | os << "Destr: " << sp.dt << '\n'; |
100 | os << "CopyC: " << sp.cc << '\n'; |
101 | os << "CopyA: " << sp.ca << '\n'; |
102 | os << "MoveC: " << sp.mc << '\n'; |
103 | os << "MoveA: " << sp.ma << '\n'; |
104 | os << "Total: " << (sp.c + sp.dt + sp.cc + sp.ca + sp.mc + sp.ma) << '\n'; |
105 | return os; |
106 | } |
107 | |
108 | X::special X::sp = X::special(); |
109 | |
110 | const X produce_const_prvalue() |
111 | { return X(0, 0); } |
112 | |
113 | int main() |
114 | { |
115 | X::special insert_results; |
116 | X::special emplace_results; |
117 | { |
118 | boost::container::vector<X> v; |
119 | v.reserve(new_cap: 4); |
120 | v.push_back(x: X(0,0)); |
121 | v.push_back(x: X(0,0)); |
122 | v.push_back(x: X(0,0)); |
123 | X x(0,0); |
124 | std::cout << "--insert lvalue no reallocation--\n" ; |
125 | X::sp = X::special(); |
126 | v.insert(arg1: v.begin(), x); |
127 | std::cout << X::sp; |
128 | std::cout << "----\n" ; |
129 | insert_results = X::sp; |
130 | } |
131 | { |
132 | boost::container::vector<X> v; |
133 | v.reserve(new_cap: 4); |
134 | v.push_back(x: X(0,0)); |
135 | v.push_back(x: X(0,0)); |
136 | v.push_back(x: X(0,0)); |
137 | X x(0,0); |
138 | std::cout << "--emplace lvalue no reallocation--\n" ; |
139 | X::sp = X::special(); |
140 | v.emplace(position: v.begin(), args&: x); |
141 | std::cout << X::sp; |
142 | std::cout << "----\n" ; |
143 | emplace_results = X::sp; |
144 | } |
145 | { |
146 | boost::container::vector<X> v; |
147 | v.reserve(new_cap: 4); |
148 | v.push_back(x: X(0,0)); |
149 | v.push_back(x: X(0,0)); |
150 | v.push_back(x: X(0,0)); |
151 | X x(0,0); |
152 | std::cout << "--insert xvalue no reallocation--\n" ; |
153 | X::sp = X::special(); |
154 | v.insert(arg1: v.begin(), x: boost::move(t&: x)); |
155 | std::cout << X::sp; |
156 | std::cout << "----\n" ; |
157 | insert_results = X::sp; |
158 | } |
159 | { |
160 | boost::container::vector<X> v; |
161 | v.reserve(new_cap: 4); |
162 | v.push_back(x: X(0,0)); |
163 | v.push_back(x: X(0,0)); |
164 | v.push_back(x: X(0,0)); |
165 | X x(0,0); |
166 | std::cout << "--emplace xvalue no reallocation--\n" ; |
167 | X::sp = X::special(); |
168 | v.emplace(position: v.begin(), args: boost::move(t&: x)); |
169 | std::cout << X::sp; |
170 | std::cout << "----\n" ; |
171 | emplace_results = X::sp; |
172 | } |
173 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
174 | { |
175 | boost::container::vector<X> v; |
176 | v.reserve(new_cap: 4); |
177 | v.push_back(x: X(0,0)); |
178 | v.push_back(x: X(0,0)); |
179 | v.push_back(x: X(0,0)); |
180 | X x(0,0); |
181 | std::cout << "--emplace const prvalue no reallocation--\n" ; |
182 | X::sp = X::special(); |
183 | v.emplace(position: v.begin(), args: produce_const_prvalue()); |
184 | std::cout << X::sp; |
185 | std::cout << "----\n" ; |
186 | emplace_results = X::sp; |
187 | } |
188 | { |
189 | boost::container::vector<X> v; |
190 | v.reserve(new_cap: 4); |
191 | v.push_back(x: X(0,0)); |
192 | v.push_back(x: X(0,0)); |
193 | v.push_back(x: X(0,0)); |
194 | X x(0,0); |
195 | std::cout << "--emplace const prvalue no reallocation--\n" ; |
196 | X::sp = X::special(); |
197 | v.insert(arg1: v.begin(), x: produce_const_prvalue()); |
198 | std::cout << X::sp; |
199 | std::cout << "----\n" ; |
200 | insert_results = X::sp; |
201 | } |
202 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
203 | { |
204 | boost::container::vector<X> v; |
205 | v.reserve(new_cap: 4); |
206 | v.push_back(x: X(0,0)); |
207 | v.push_back(x: X(0,0)); |
208 | v.push_back(x: X(0,0)); |
209 | std::cout << "--insert rvalue no reallocation--\n" ; |
210 | X::sp = X::special(); |
211 | v.insert(arg1: v.begin(), x: X(0,0)); |
212 | std::cout << X::sp; |
213 | std::cout << "----\n" ; |
214 | insert_results = X::sp; |
215 | } |
216 | { |
217 | boost::container::vector<X> v; |
218 | v.reserve(new_cap: 4); |
219 | v.push_back(x: X(0,0)); |
220 | v.push_back(x: X(0,0)); |
221 | v.push_back(x: X(0,0)); |
222 | std::cout << "--emplace rvalue no reallocation--\n" ; |
223 | X::sp = X::special(); |
224 | v.emplace(position: v.begin(), args: X(0,0)); |
225 | std::cout << X::sp; |
226 | std::cout << "----\n" ; |
227 | emplace_results = X::sp; |
228 | } |
229 | //With emulated move semantics an extra copy is unavoidable |
230 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
231 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
232 | #endif |
233 | { |
234 | boost::container::vector<X> v; |
235 | v.reserve(new_cap: 3); |
236 | v.push_back(x: X(0,0)); |
237 | v.push_back(x: X(0,0)); |
238 | v.push_back(x: X(0,0)); |
239 | X x(0,0); |
240 | std::cout << "--insert lvalue reallocation--\n" ; |
241 | X::sp = X::special(); |
242 | v.insert(arg1: v.begin(), x); |
243 | std::cout << X::sp; |
244 | std::cout << "----\n" ; |
245 | insert_results = X::sp; |
246 | } |
247 | { |
248 | boost::container::vector<X> v; |
249 | v.reserve(new_cap: 3); |
250 | v.push_back(x: X(0,0)); |
251 | v.push_back(x: X(0,0)); |
252 | v.push_back(x: X(0,0)); |
253 | X x(0,0); |
254 | std::cout << "--emplace lvalue reallocation--\n" ; |
255 | X::sp = X::special(); |
256 | v.emplace(position: v.begin(), args&: x); |
257 | std::cout << X::sp; |
258 | std::cout << "----\n" ; |
259 | emplace_results = X::sp; |
260 | } |
261 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
262 | { |
263 | boost::container::vector<X> v; |
264 | v.reserve(new_cap: 3); |
265 | v.push_back(x: X(0,0)); |
266 | v.push_back(x: X(0,0)); |
267 | v.push_back(x: X(0,0)); |
268 | X x(0,0); |
269 | std::cout << "--insert xvalue reallocation--\n" ; |
270 | X::sp = X::special(); |
271 | v.insert(arg1: v.begin(), x: boost::move(t&: x)); |
272 | std::cout << X::sp; |
273 | std::cout << "----\n" ; |
274 | insert_results = X::sp; |
275 | } |
276 | { |
277 | boost::container::vector<X> v; |
278 | v.reserve(new_cap: 3); |
279 | v.push_back(x: X(0,0)); |
280 | v.push_back(x: X(0,0)); |
281 | v.push_back(x: X(0,0)); |
282 | X x(0,0); |
283 | std::cout << "--emplace xvalue reallocation--\n" ; |
284 | X::sp = X::special(); |
285 | v.emplace(position: v.begin(), args: boost::move(t&: x)); |
286 | std::cout << X::sp; |
287 | std::cout << "----\n" ; |
288 | emplace_results = X::sp; |
289 | } |
290 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
291 | { |
292 | boost::container::vector<X> v; |
293 | v.reserve(new_cap: 3); |
294 | v.push_back(x: X(0,0)); |
295 | v.push_back(x: X(0,0)); |
296 | v.push_back(x: X(0,0)); |
297 | std::cout << "--insert rvalue reallocation--\n" ; |
298 | X::sp = X::special(); |
299 | v.insert(arg1: v.begin(), x: X(0,0)); |
300 | std::cout << X::sp; |
301 | std::cout << "----\n" ; |
302 | insert_results = X::sp; |
303 | } |
304 | { |
305 | boost::container::vector<X> v; |
306 | v.reserve(new_cap: 3); |
307 | v.push_back(x: X(0,0)); |
308 | v.push_back(x: X(0,0)); |
309 | v.push_back(x: X(0,0)); |
310 | std::cout << "--emplace rvalue reallocation--\n" ; |
311 | X::sp = X::special(); |
312 | v.emplace(position: v.begin(), args: X(0,0)); |
313 | std::cout << X::sp; |
314 | std::cout << "----\n" ; |
315 | emplace_results = X::sp; |
316 | } |
317 | //With emulated move semantics an extra copy is unavoidable |
318 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
319 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
320 | #endif |
321 | { |
322 | boost::container::vector<X> v; |
323 | v.reserve(new_cap: 4); |
324 | v.push_back(x: X(0,0)); |
325 | v.push_back(x: X(0,0)); |
326 | v.push_back(x: X(0,0)); |
327 | X x(0,0); |
328 | std::cout << "--push_back lvalue no reallocation--\n" ; |
329 | X::sp = X::special(); |
330 | v.push_back(x); |
331 | std::cout << X::sp; |
332 | std::cout << "----\n" ; |
333 | insert_results = X::sp; |
334 | } |
335 | { |
336 | boost::container::vector<X> v; |
337 | v.reserve(new_cap: 4); |
338 | v.push_back(x: X(0,0)); |
339 | v.push_back(x: X(0,0)); |
340 | v.push_back(x: X(0,0)); |
341 | X x(0,0); |
342 | std::cout << "--emplace_back lvalue no reallocation--\n" ; |
343 | X::sp = X::special(); |
344 | v.emplace_back(args&: x); |
345 | std::cout << X::sp; |
346 | std::cout << "----\n" ; |
347 | emplace_results = X::sp; |
348 | } |
349 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
350 | { |
351 | boost::container::vector<X> v; |
352 | v.reserve(new_cap: 4); |
353 | v.push_back(x: X(0,0)); |
354 | v.push_back(x: X(0,0)); |
355 | v.push_back(x: X(0,0)); |
356 | X x(0,0); |
357 | std::cout << "--push_back xvalue no reallocation--\n" ; |
358 | X::sp = X::special(); |
359 | v.push_back(x: boost::move(t&: x)); |
360 | std::cout << X::sp; |
361 | std::cout << "----\n" ; |
362 | insert_results = X::sp; |
363 | } |
364 | { |
365 | boost::container::vector<X> v; |
366 | v.reserve(new_cap: 4); |
367 | v.push_back(x: X(0,0)); |
368 | v.push_back(x: X(0,0)); |
369 | v.push_back(x: X(0,0)); |
370 | X x(0,0); |
371 | std::cout << "--emplace_back xvalue no reallocation--\n" ; |
372 | X::sp = X::special(); |
373 | v.emplace_back(args: boost::move(t&: x)); |
374 | std::cout << X::sp; |
375 | std::cout << "----\n" ; |
376 | emplace_results = X::sp; |
377 | } |
378 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
379 | { |
380 | boost::container::vector<X> v; |
381 | v.reserve(new_cap: 4); |
382 | v.push_back(x: X(0,0)); |
383 | v.push_back(x: X(0,0)); |
384 | v.push_back(x: X(0,0)); |
385 | std::cout << "--push_back rvalue no reallocation--\n" ; |
386 | X::sp = X::special(); |
387 | v.push_back(x: X(0,0)); |
388 | std::cout << X::sp; |
389 | std::cout << "----\n" ; |
390 | insert_results = X::sp; |
391 | } |
392 | { |
393 | boost::container::vector<X> v; |
394 | v.reserve(new_cap: 4); |
395 | v.push_back(x: X(0,0)); |
396 | v.push_back(x: X(0,0)); |
397 | v.push_back(x: X(0,0)); |
398 | std::cout << "--emplace_back rvalue no reallocation--\n" ; |
399 | X::sp = X::special(); |
400 | v.emplace_back(args: X(0,0)); |
401 | std::cout << X::sp; |
402 | std::cout << "----\n" ; |
403 | emplace_results = X::sp; |
404 | } |
405 | //With emulated move semantics an extra copy is unavoidable |
406 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
407 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
408 | #endif |
409 | { |
410 | boost::container::vector<X> v; |
411 | v.reserve(new_cap: 3); |
412 | v.push_back(x: X(0,0)); |
413 | v.push_back(x: X(0,0)); |
414 | v.push_back(x: X(0,0)); |
415 | X x(0,0); |
416 | std::cout << "--push_back lvalue reallocation--\n" ; |
417 | X::sp = X::special(); |
418 | v.push_back(x); |
419 | std::cout << X::sp; |
420 | std::cout << "----\n" ; |
421 | insert_results = X::sp; |
422 | } |
423 | { |
424 | boost::container::vector<X> v; |
425 | v.reserve(new_cap: 3); |
426 | v.push_back(x: X(0,0)); |
427 | v.push_back(x: X(0,0)); |
428 | v.push_back(x: X(0,0)); |
429 | X x(0,0); |
430 | std::cout << "--emplace_back lvalue reallocation--\n" ; |
431 | X::sp = X::special(); |
432 | v.emplace_back(args&: x); |
433 | std::cout << X::sp; |
434 | std::cout << "----\n" ; |
435 | emplace_results = X::sp; |
436 | } |
437 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
438 | { |
439 | boost::container::vector<X> v; |
440 | v.reserve(new_cap: 3); |
441 | v.push_back(x: X(0,0)); |
442 | v.push_back(x: X(0,0)); |
443 | v.push_back(x: X(0,0)); |
444 | X x(0,0); |
445 | std::cout << "--push_back xvalue reallocation--\n" ; |
446 | X::sp = X::special(); |
447 | v.push_back(x: boost::move(t&: x)); |
448 | std::cout << X::sp; |
449 | std::cout << "----\n" ; |
450 | insert_results = X::sp; |
451 | } |
452 | { |
453 | boost::container::vector<X> v; |
454 | v.reserve(new_cap: 3); |
455 | v.push_back(x: X(0,0)); |
456 | v.push_back(x: X(0,0)); |
457 | v.push_back(x: X(0,0)); |
458 | X x(0,0); |
459 | std::cout << "--emplace_back xvalue reallocation--\n" ; |
460 | X::sp = X::special(); |
461 | v.emplace_back(args: boost::move(t&: x)); |
462 | std::cout << X::sp; |
463 | std::cout << "----\n" ; |
464 | emplace_results = X::sp; |
465 | } |
466 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
467 | { |
468 | boost::container::vector<X> v; |
469 | v.reserve(new_cap: 3); |
470 | v.push_back(x: X(0,0)); |
471 | v.push_back(x: X(0,0)); |
472 | v.push_back(x: X(0,0)); |
473 | std::cout << "--push_back rvalue reallocation--\n" ; |
474 | X::sp = X::special(); |
475 | v.push_back(x: X(0,0)); |
476 | std::cout << X::sp; |
477 | std::cout << "----\n" ; |
478 | insert_results = X::sp; |
479 | } |
480 | { |
481 | boost::container::vector<X> v; |
482 | v.reserve(new_cap: 3); |
483 | v.push_back(x: X(0,0)); |
484 | v.push_back(x: X(0,0)); |
485 | v.push_back(x: X(0,0)); |
486 | std::cout << "--emplace_back rvalue reallocation--\n" ; |
487 | X::sp = X::special(); |
488 | v.emplace_back(args: X(0,0)); |
489 | std::cout << X::sp; |
490 | std::cout << "----\n" ; |
491 | emplace_results = X::sp; |
492 | } |
493 | //With emulated move semantics an extra copy is unavoidable |
494 | #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
495 | BOOST_TEST_EQ(insert_results == emplace_results, true); |
496 | #endif |
497 | return boost::report_errors(); |
498 | } |
499 | |