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 
operator ==(const special & l,const special & r)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 
X(int i,int * p)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 
~X()51    ~X()
52    {
53 //         std::cout << "~X()\n";
54       sp.dt++;
55    }
56 
X(const X & x)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 
operator =(BOOST_COPY_ASSIGN_REF (X)x)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 
X(BOOST_RV_REF (X)x)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 
operator =(BOOST_RV_REF (X)x)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&
operator <<(std::ostream & os,X::special const & sp)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 
produce_const_prvalue()110 const X produce_const_prvalue()
111 {   return X(0, 0);   }
112 
main()113 int main()
114 {
115    X::special insert_results;
116    X::special emplace_results;
117    {
118       boost::container::vector<X> v;
119       v.reserve(4);
120       v.push_back(X(0,0));
121       v.push_back(X(0,0));
122       v.push_back(X(0,0));
123       X x(0,0);
124       std::cout << "--insert lvalue no reallocation--\n";
125       X::sp = X::special();
126       v.insert(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(4);
134       v.push_back(X(0,0));
135       v.push_back(X(0,0));
136       v.push_back(X(0,0));
137       X x(0,0);
138       std::cout << "--emplace lvalue no reallocation--\n";
139       X::sp = X::special();
140       v.emplace(v.begin(), 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(4);
148       v.push_back(X(0,0));
149       v.push_back(X(0,0));
150       v.push_back(X(0,0));
151       X x(0,0);
152       std::cout << "--insert xvalue no reallocation--\n";
153       X::sp = X::special();
154       v.insert(v.begin(), boost::move(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(4);
162       v.push_back(X(0,0));
163       v.push_back(X(0,0));
164       v.push_back(X(0,0));
165       X x(0,0);
166       std::cout << "--emplace xvalue no reallocation--\n";
167       X::sp = X::special();
168       v.emplace(v.begin(), boost::move(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(4);
177       v.push_back(X(0,0));
178       v.push_back(X(0,0));
179       v.push_back(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(v.begin(), 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(4);
191       v.push_back(X(0,0));
192       v.push_back(X(0,0));
193       v.push_back(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(v.begin(), 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(4);
206       v.push_back(X(0,0));
207       v.push_back(X(0,0));
208       v.push_back(X(0,0));
209       std::cout << "--insert rvalue no reallocation--\n";
210       X::sp = X::special();
211       v.insert(v.begin(), 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(4);
219       v.push_back(X(0,0));
220       v.push_back(X(0,0));
221       v.push_back(X(0,0));
222       std::cout << "--emplace rvalue no reallocation--\n";
223       X::sp = X::special();
224       v.emplace(v.begin(), 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(3);
236       v.push_back(X(0,0));
237       v.push_back(X(0,0));
238       v.push_back(X(0,0));
239       X x(0,0);
240       std::cout << "--insert lvalue reallocation--\n";
241       X::sp = X::special();
242       v.insert(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(3);
250       v.push_back(X(0,0));
251       v.push_back(X(0,0));
252       v.push_back(X(0,0));
253       X x(0,0);
254       std::cout << "--emplace lvalue reallocation--\n";
255       X::sp = X::special();
256       v.emplace(v.begin(), 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(3);
265       v.push_back(X(0,0));
266       v.push_back(X(0,0));
267       v.push_back(X(0,0));
268       X x(0,0);
269       std::cout << "--insert xvalue reallocation--\n";
270       X::sp = X::special();
271       v.insert(v.begin(), boost::move(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(3);
279       v.push_back(X(0,0));
280       v.push_back(X(0,0));
281       v.push_back(X(0,0));
282       X x(0,0);
283       std::cout << "--emplace xvalue reallocation--\n";
284       X::sp = X::special();
285       v.emplace(v.begin(), boost::move(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(3);
294       v.push_back(X(0,0));
295       v.push_back(X(0,0));
296       v.push_back(X(0,0));
297       std::cout << "--insert rvalue reallocation--\n";
298       X::sp = X::special();
299       v.insert(v.begin(), 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(3);
307       v.push_back(X(0,0));
308       v.push_back(X(0,0));
309       v.push_back(X(0,0));
310       std::cout << "--emplace rvalue reallocation--\n";
311       X::sp = X::special();
312       v.emplace(v.begin(), 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(4);
324       v.push_back(X(0,0));
325       v.push_back(X(0,0));
326       v.push_back(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(4);
338       v.push_back(X(0,0));
339       v.push_back(X(0,0));
340       v.push_back(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(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(4);
353       v.push_back(X(0,0));
354       v.push_back(X(0,0));
355       v.push_back(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(boost::move(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(4);
367       v.push_back(X(0,0));
368       v.push_back(X(0,0));
369       v.push_back(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(boost::move(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(4);
382       v.push_back(X(0,0));
383       v.push_back(X(0,0));
384       v.push_back(X(0,0));
385       std::cout << "--push_back rvalue no reallocation--\n";
386       X::sp = X::special();
387       v.push_back(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(4);
395       v.push_back(X(0,0));
396       v.push_back(X(0,0));
397       v.push_back(X(0,0));
398       std::cout << "--emplace_back rvalue no reallocation--\n";
399       X::sp = X::special();
400       v.emplace_back(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(3);
412       v.push_back(X(0,0));
413       v.push_back(X(0,0));
414       v.push_back(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(3);
426       v.push_back(X(0,0));
427       v.push_back(X(0,0));
428       v.push_back(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(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(3);
441       v.push_back(X(0,0));
442       v.push_back(X(0,0));
443       v.push_back(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(boost::move(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(3);
455       v.push_back(X(0,0));
456       v.push_back(X(0,0));
457       v.push_back(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(boost::move(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(3);
470       v.push_back(X(0,0));
471       v.push_back(X(0,0));
472       v.push_back(X(0,0));
473       std::cout << "--push_back rvalue reallocation--\n";
474       X::sp = X::special();
475       v.push_back(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(3);
483       v.push_back(X(0,0));
484       v.push_back(X(0,0));
485       v.push_back(X(0,0));
486       std::cout << "--emplace_back rvalue reallocation--\n";
487       X::sp = X::special();
488       v.emplace_back(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