forked from boostorg/unordered
Merge support for emplace for compilers with rvalue references and variadic templates arguments, and better use of C++0x allocators.
Merged revisions 44058-44075,44078-44084,44086-44108,44110-44365,44367,44369-44414,44416-44419,44421-44457,44467-44469,44471-44511,44513-44535,44537-44737 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r44467 | danieljames | 2008-04-16 18:35:56 +0100 (Wed, 16 Apr 2008) | 2 lines Add C++-0x support to the test allocators. ................ r44468 | danieljames | 2008-04-16 18:36:06 +0100 (Wed, 16 Apr 2008) | 2 lines Add a C++-0x node_constructor. ................ r44469 | danieljames | 2008-04-16 18:36:16 +0100 (Wed, 16 Apr 2008) | 2 lines C++-0x constructor for node. ................ r44516 | danieljames | 2008-04-17 21:41:48 +0100 (Thu, 17 Apr 2008) | 16 lines Merge in my work so far on implementing emplace for compilers with variadic template & rvalue references. Merged revisions 44059-44062 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/dev ........ r44059 | danieljames | 2008-04-05 17:41:25 +0100 (Sat, 05 Apr 2008) | 1 line First stab at implementing emplace - only for compilers with variadic template & rvalue references. ........ r44062 | danieljames | 2008-04-05 19:12:09 +0100 (Sat, 05 Apr 2008) | 1 line Better variable template arguments, need to add proper support to BoostBook. ........ ................ r44616 | danieljames | 2008-04-20 13:30:19 +0100 (Sun, 20 Apr 2008) | 1 line Merge with trunk, fixes tabs. ................ r44618 | danieljames | 2008-04-20 13:42:38 +0100 (Sun, 20 Apr 2008) | 2 lines Some extra compile tests. ................ r44619 | danieljames | 2008-04-20 13:42:50 +0100 (Sun, 20 Apr 2008) | 2 lines Fix an error message. ................ r44703 | danieljames | 2008-04-21 20:19:50 +0100 (Mon, 21 Apr 2008) | 15 lines Merge latest changes from trunk. Merged revisions 44616-44702 via svnmerge from https://svn.boost.org/svn/boost/trunk ........ r44650 | danieljames | 2008-04-20 22:08:57 +0100 (Sun, 20 Apr 2008) | 1 line Update an include. ........ r44697 | danieljames | 2008-04-21 16:55:40 +0100 (Mon, 21 Apr 2008) | 1 line Factor out the code for choosing the bucket count, and which bucket that hash values map to make it easier to experiment with alternative policies. ........ ................ r44733 | danieljames | 2008-04-23 07:55:43 +0100 (Wed, 23 Apr 2008) | 2 lines Remove 'reserve_extra'. ................ r44734 | danieljames | 2008-04-23 07:55:55 +0100 (Wed, 23 Apr 2008) | 2 lines More unnecessary copy tests - showing some weakness in the emplace implementation. ................ r44735 | danieljames | 2008-04-23 07:56:06 +0100 (Wed, 23 Apr 2008) | 2 lines More tests. ................ r44736 | danieljames | 2008-04-23 07:56:19 +0100 (Wed, 23 Apr 2008) | 2 lines Comment out a test which requires a C++0x std::pair. ................ r44737 | danieljames | 2008-04-23 07:56:35 +0100 (Wed, 23 Apr 2008) | 2 lines Avoid creating unnecessary copies in unordered_set::emplace and unordered_map::emplace. ................ [SVN r44738]
This commit is contained in:
@@ -11,15 +11,34 @@ namespace unnecessary_copy_tests
|
||||
{
|
||||
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 boost
|
||||
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 != 1)
|
||||
std::cerr<<count_copies::count<<" copies.\n";
|
||||
COPY_COUNT(2);
|
||||
}
|
||||
|
||||
boost::unordered_set<count_copies>* set;
|
||||
@@ -59,7 +85,181 @@ namespace unnecessary_copy_tests
|
||||
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 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()
|
||||
|
||||
Reference in New Issue
Block a user