unnecessary_copy_tests.cpp

来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 277 行

CPP
277
字号
// Copyright 2006-2008 Daniel James.// Distributed under the Boost Software License, Version 1.0. (See accompanying// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)#include <boost/unordered_set.hpp>#include <boost/unordered_map.hpp>#include "../helpers/test.hpp"namespace unnecessary_copy_tests{    struct count_copies    {        static int copies;        static int moves;        count_copies() : tag_(0) { ++copies; }        explicit count_copies(int tag) : tag_(tag) { ++copies; }        // This bizarre constructor is an attempt to confuse emplace.        //        // unordered_map<count_copies, count_copies> x:        // x.emplace(count_copies(1), count_copies(2));        // x.emplace(count_copies(1), count_copies(2), count_copies(3));        //        // The first emplace should use the single argument constructor twice.        // The second emplace should use the single argument contructor for        // the key, and this constructor for the value.        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& 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;    }}#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)namespace boost#elsenamespace unnecessary_copy_tests#endif{    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::copies;    int count_copies::moves;    template <class T>    void unnecessary_copy_insert_test(T*)    {        T x;        BOOST_DEDUCED_TYPENAME T::value_type a;        reset();        x.insert(a);        COPY_COUNT(1);    }    boost::unordered_set<count_copies>* set;    boost::unordered_multiset<count_copies>* multiset;    boost::unordered_map<int, count_copies>* map;    boost::unordered_multimap<int, count_copies>* 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 argument        //         // Emplace should be able to tell that there already is an element        // without creating a new one.        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<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);        count_copies part;        reset();        std::pair<count_copies const&, count_copies const&> a_ref(part, part);        x.emplace(a_ref);        COPY_COUNT(0); 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        std::pair<count_copies const, count_copies> b;        // This test requires a C++0x std::pair. Which gcc hasn't got yet.        //reset();        //x.emplace(b.first.tag_);        //COPY_COUNT(2); MOVE_COUNT(0);        //        // 2 arguments        //        reset();        x.emplace(b.first, b.second);        COPY_COUNT(0); MOVE_COUNT(0);        reset();        x.emplace(source<count_copies>(), source<count_copies>());        COPY_COUNT(2); MOVE_COUNT(0);        // source<count_copies> creates a single copy.        reset();        x.emplace(b.first, source<count_copies>());        COPY_COUNT(1); MOVE_COUNT(0);        reset();        x.emplace(b.first.tag_, b.second.tag_);        COPY_COUNT(2); MOVE_COUNT(0);    }#endif}RUN_TESTS()

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?