Boost logo

Boost-Commit :

From: daniel_james_at_[hidden]
Date: 2008-04-23 02:55:55


Author: danieljames
Date: 2008-04-23 02:55:55 EDT (Wed, 23 Apr 2008)
New Revision: 44734
URL: http://svn.boost.org/trac/boost/changeset/44734

Log:
More unnecessary copy tests - showing some weakness in the emplace implementation.

Text files modified:
   branches/unordered/trunk/libs/unordered/test/unordered/unnecessary_copy_tests.cpp | 209 ++++++++++++++++++++++++++++++++++++---
   1 files changed, 191 insertions(+), 18 deletions(-)

Modified: branches/unordered/trunk/libs/unordered/test/unordered/unnecessary_copy_tests.cpp
==============================================================================
--- branches/unordered/trunk/libs/unordered/test/unordered/unnecessary_copy_tests.cpp (original)
+++ branches/unordered/trunk/libs/unordered/test/unordered/unnecessary_copy_tests.cpp 2008-04-23 02:55:55 EDT (Wed, 23 Apr 2008)
@@ -11,15 +11,34 @@
 {
     struct count_copies
     {
- static int count;
- count_copies() { ++count; }
- count_copies(count_copies const&) { ++count; }
+ static int copies;
+ static int moves;
+ count_copies() : tag_(0) { ++copies; }
+ explicit count_copies(int tag) : tag_(tag) { ++copies; }
+ count_copies(count_copies const&, count_copies const& x) : tag_(x.tag_) { ++copies; }
+ count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
+#if defined(BOOST_HAS_RVALUE_REFS)
+ count_copies(count_copies&& x) : tag_(x.tag_) {
+ x.tag_ = -1; ++moves;
+ }
+#endif
+ int tag_;
     private:
        count_copies& operator=(count_copies const&);
     };
 
- bool operator==(count_copies const&, count_copies const&) {
- return true;
+ bool operator==(count_copies const& x, count_copies const& y) {
+ return x.tag_ == y.tag_;
+ }
+
+ template <class T>
+ T source() {
+ return T();
+ }
+
+ void reset() {
+ count_copies::copies = 0;
+ count_copies::moves = 0;
     }
 }
 
@@ -29,29 +48,36 @@
 namespace unnecessary_copy_tests
 #endif
 {
- std::size_t hash_value(unnecessary_copy_tests::count_copies const&) {
- return 0;
+ std::size_t hash_value(unnecessary_copy_tests::count_copies const& x) {
+ return x.tag_;
     }
 }
 
+#define COPY_COUNT(n) \
+ if(count_copies::copies != n) { \
+ BOOST_ERROR("Wrong number of copies."); \
+ std::cerr<<"Number of copies: "<<count_copies::copies<<std::endl; \
+ }
+#define MOVE_COUNT(n) \
+ if(count_copies::moves != n) { \
+ BOOST_ERROR("Wrong number of moves."); \
+ std::cerr<<"Number of moves: "<<count_copies::moves<<std::endl; \
+ }
+
 namespace unnecessary_copy_tests
 {
- int count_copies::count;
+ int count_copies::copies;
+ int count_copies::moves;
 
     template <class T>
- void unnecessary_copy_test(T*)
+ void unnecessary_copy_insert_test(T*)
     {
- count_copies::count = 0;
+ reset();
         T x;
         BOOST_DEDUCED_TYPENAME T::value_type a;
- BOOST_CHECK(count_copies::count == 1);
- if(count_copies::count != 1)
- std::cerr<<count_copies::count<<" copies.\n";
-
+ COPY_COUNT(1);
         x.insert(a);
- BOOST_CHECK(count_copies::count == 2);
- if(count_copies::count != 2)
- std::cerr<<count_copies::count<<" copies.\n";
+ COPY_COUNT(2);
     }
 
     boost::unordered_set<count_copies>* set;
@@ -59,7 +85,154 @@
     boost::unordered_map<int, count_copies>* map;
     boost::unordered_multimap<int, count_copies>* multimap;
 
- UNORDERED_TEST(unnecessary_copy_test, ((set)(multiset)(map)(multimap)))
+ UNORDERED_TEST(unnecessary_copy_insert_test,
+ ((set)(multiset)(map)(multimap)))
+
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ template <class T>
+ void unnecessary_copy_emplace_test(T*)
+ {
+ reset();
+ T x;
+ BOOST_DEDUCED_TYPENAME T::value_type a;
+ COPY_COUNT(1);
+ x.emplace(a);
+ COPY_COUNT(2);
+ }
+
+ template <class T>
+ void unnecessary_copy_emplace_rvalue_test(T*)
+ {
+ reset();
+ T x;
+ x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
+ COPY_COUNT(1);
+ }
+
+ template <class T>
+ void unnecessary_copy_emplace_move_test(T*)
+ {
+ reset();
+ T x;
+ BOOST_DEDUCED_TYPENAME T::value_type a;
+ COPY_COUNT(1); MOVE_COUNT(0);
+ x.emplace(std::move(a));
+ COPY_COUNT(1); MOVE_COUNT(1);
+ }
+
+ UNORDERED_TEST(unnecessary_copy_emplace_test,
+ ((set)(multiset)(map)(multimap)))
+ UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
+ ((set)(multiset)(map)(multimap)))
+ UNORDERED_TEST(unnecessary_copy_emplace_move_test,
+ ((set)(multiset)(map)(multimap)))
+
+ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
+ {
+ reset();
+ boost::unordered_set<count_copies> x;
+ count_copies a;
+ x.insert(a);
+ COPY_COUNT(2); MOVE_COUNT(0);
+
+ //
+ // 0 arguments
+ //
+
+ // The container will have to create a copy in order to compare with
+ // the existing element.
+ reset();
+ x.emplace();
+ COPY_COUNT(1); MOVE_COUNT(0);
+
+ //
+ // 1 arguments
+ //
+
+ // Emplace should be able to tell that there already is an element
+ // without creating a new one.
+ reset();
+ x.insert(a);
+ COPY_COUNT(0); MOVE_COUNT(0);
+
+ // A new object is created by source, but it shouldn't be moved or
+ // copied.
+ reset();
+ x.insert(source<count_copies>());
+ COPY_COUNT(1); MOVE_COUNT(0);
+
+ // No move should take place.
+ reset();
+ x.emplace(std::move(a));
+ COPY_COUNT(0); MOVE_COUNT(0);
+
+ // Just in case a did get moved...
+ count_copies b;
+
+ // The container will have to create a copy in order to compare with
+ // the existing element.
+ reset();
+ x.emplace(b.tag_);
+ COPY_COUNT(1); MOVE_COUNT(0);
+
+ //
+ // 2 arguments
+ //
+
+ // The container will have to create b copy in order to compare with
+ // the existing element.
+
+ reset();
+ x.emplace(b, b);
+ COPY_COUNT(1); MOVE_COUNT(0);
+ }
+
+ UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
+ {
+ reset();
+ boost::unordered_map<count_copies, count_copies> x;
+ // TODO: Run tests for pairs without const etc.
+ std::pair<count_copies const, count_copies> a;
+ x.emplace(a);
+ COPY_COUNT(4); MOVE_COUNT(0);
+
+ //
+ // 0 arguments
+ //
+
+ // COPY_COUNT(1) would be okay here.
+ reset();
+ x.emplace();
+ COPY_COUNT(2); MOVE_COUNT(0);
+
+ //
+ // 1 argument
+ //
+
+ reset();
+ x.emplace(a);
+ COPY_COUNT(0); MOVE_COUNT(0);
+
+ // A new object is created by source, but it shouldn't be moved or
+ // copied.
+ reset();
+ x.emplace(source<std::pair<count_copies, count_copies> >());
+ COPY_COUNT(2); MOVE_COUNT(0);
+
+ // No move should take place.
+ reset();
+ x.emplace(std::move(a));
+ COPY_COUNT(0); MOVE_COUNT(0);
+
+ //
+ // 2 arguments
+ //
+
+ reset();
+ x.emplace(source<count_copies>(), source<count_copies>());
+ COPY_COUNT(2); MOVE_COUNT(0);
+ }
+#endif
 }
 
 RUN_TESTS()


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk