forked from boostorg/unordered
equality operators when not required, and some bookkeeping. ................ r42539 | danieljames | 2008-01-06 17:48:11 +0000 (Sun, 06 Jan 2008) | 2 lines Add the unordered library to the maintainers list. ................ r46579 | danieljames | 2008-06-21 16:32:11 +0100 (Sat, 21 Jun 2008) | 10 lines Define unordered containers' friend functions outside of the class. On some compilers, friend functions are being instantiated when the main class is explicitly instantiated. This is slightly problematic because the equality functions (which are an extension) put extra requirements on the types used. So I'm going to try defining the functions outside of the class, in the hope that they won't get instantiated. If someone wants non-member functions to be instantiated, I think it's reasonable to expect them to explicitly instantiate them, especially as compilers don't seem to be consistent about this. ................ r46587 | danieljames | 2008-06-21 20:58:39 +0100 (Sat, 21 Jun 2008) | 8 lines Get the test to pass when pair's default constructor creates two instances of the member classes. With some standard libraries I was getting two copies of the object after creating a default pair, probably because it was creating an instance for its default parameter. So only test after creating the pair object - since it isn't our concern how many instances that creates. ................ r46588 | danieljames | 2008-06-21 21:11:26 +0100 (Sat, 21 Jun 2008) | 1 line Markup an expected failure for unordered. ................ r46594 | danieljames | 2008-06-21 23:02:15 +0100 (Sat, 21 Jun 2008) | 19 lines Merge inspect fixes for the unordered library. Merged revisions 46470-46592 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r46589 | danieljames | 2008-06-21 21:37:42 +0100 (Sat, 21 Jun 2008) | 2 lines Fix some inspect errors (tabs and missing copyright/license). ................ r46591 | danieljames | 2008-06-21 21:47:51 +0100 (Sat, 21 Jun 2008) | 1 line Move memory.hpp into the helpers subdirectory. ................ r46592 | danieljames | 2008-06-21 22:08:53 +0100 (Sat, 21 Jun 2008) | 1 line Prevent inspect errors for unnamed namespaces in some of the test header files. ................ ................ r46607 | danieljames | 2008-06-22 14:54:45 +0100 (Sun, 22 Jun 2008) | 9 lines Extract the hash and equality functions from hash_table_data_*. As these are extensions and add extra requirements to the container elements, they shouldn't be part of hash_table_data_* so that they won't get instantiated if an unordered container is explicitly instantiated. Merged revisions 46594-46604 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ................ r46608 | danieljames | 2008-06-22 16:00:02 +0100 (Sun, 22 Jun 2008) | 5 lines Remove the svnmerge integration information for the unordered branch. Now that the unordered library is moving towards release, the main development version is in trunk. New features will be developed on a new branch. ................ [SVN r46629]
277 lines
7.3 KiB
C++
277 lines
7.3 KiB
C++
|
|
// 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
|
|
#else
|
|
namespace 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()
|