$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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()