Merge unordered changes:

* Support emplace for all compilers.
 * Better configuration of C++0x features for when the appropriate headers
   aren't available.

Merged revisions 52393-52394,52397,52884-52885,53127,53255 via svnmerge from 
https://svn.boost.org/svn/boost/trunk

........
  r52393 | danieljames | 2009-04-14 18:23:37 +0100 (Tue, 14 Apr 2009) | 2 lines
  
  Implement full extract_key for compilers without SFINAE and variadic
  templates.
........
  r52394 | danieljames | 2009-04-14 18:23:51 +0100 (Tue, 14 Apr 2009) | 1 line
  
  Use emplace instead of insert in the backend as it's more appropriate.
........
  r52397 | danieljames | 2009-04-14 18:51:34 +0100 (Tue, 14 Apr 2009) | 1 line
  
  Add stream output to the count test helper for unordered.
........
  r52884 | danieljames | 2009-05-10 22:24:41 +0100 (Sun, 10 May 2009) | 19 lines
  
  Cherrypick some unordered container changes from sandbox. Not including
  anything which depends on the new move library.
  
  ------------------------------------------------------------------------
  r52746 | danieljames | 2009-05-03 11:12:30 +0100 (Sun, 03 May 2009) | 1 line
  
  Merge latest unordered container changes.
  ------------------------------------------------------------------------
  r52747 | danieljames | 2009-05-03 11:15:35 +0100 (Sun, 03 May 2009) | 4 lines
  
  Put the C++0x emplace implementations before the non-C++0x versions.
  
  I'm going to change the non-C++0x to be macro heavy emulations of the
  C++0x versions, so this will put the readable version first.
  ------------------------------------------------------------------------
  r52748 | danieljames | 2009-05-03 11:15:44 +0100 (Sun, 03 May 2009) | 1 line
  
  Refactor the unordered implementation a tad, to make implementing emplace less painful.
  ------------------------------------------------------------------------
........
  r52885 | danieljames | 2009-05-10 22:25:09 +0100 (Sun, 10 May 2009) | 1 line
  
  Merge emplace support for sandbox - but without move support.
........
  r53127 | danieljames | 2009-05-20 07:43:38 +0100 (Wed, 20 May 2009) | 1 line
  
  Better configuration for boost.unordered.
........
  r53255 | danieljames | 2009-05-25 20:45:06 +0100 (Mon, 25 May 2009) | 1 line
  
  Unordered change log.
........


[SVN r53257]
This commit is contained in:
Daniel James
2009-05-25 19:57:04 +00:00
parent f02cc7775d
commit e911a8011b
12 changed files with 718 additions and 246 deletions

View File

@ -69,5 +69,15 @@ First official release.
* Some other minor internal changes to the implementation, tests and * Some other minor internal changes to the implementation, tests and
documentation. documentation.
* Avoid an unnecessary copy in `operator[]`. * Avoid an unnecessary copy in `operator[]`.
* [@https://svn.boost.org/trac/boost/ticket/2975 Ticket 2975]: Fix length of
prime number list.
[h2 Boost 1.40.0]
* [@https://svn.boost.org/trac/boost/ticket/2975 Ticket 2975]:
Store the prime list as a preprocessor sequence - so that it will always get
the length right if it changes again in the future.
* [@https://svn.boost.org/trac/boost/ticket/1978 Ticket 1978]:
Implement `emplace` for all compilers.
[endsect] [endsect]

View File

@ -19,4 +19,12 @@
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN # define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
#endif #endif
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
// STLport doesn't have std::forward.
# else
# define BOOST_UNORDERED_STD_FORWARD
# endif
#endif
#endif #endif

View File

@ -12,6 +12,11 @@
#endif #endif
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/unordered/detail/config.hpp>
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
#define BOOST_UNORDERED_EMPLACE_LIMIT 5
#endif
#include <cstddef> #include <cstddef>
#include <boost/config/no_tr1/cmath.hpp> #include <boost/config/no_tr1/cmath.hpp>
@ -28,8 +33,12 @@
#include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/aligned_storage.hpp> #include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp> #include <boost/type_traits/alignment_of.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/mpl/if.hpp> #include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp> #include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
#include <boost/detail/workaround.hpp> #include <boost/detail/workaround.hpp>
#include <boost/utility/swap.hpp> #include <boost/utility/swap.hpp>
#include <boost/preprocessor/seq/size.hpp> #include <boost/preprocessor/seq/size.hpp>
@ -37,11 +46,19 @@
#include <boost/mpl/aux_/config/eti.hpp> #include <boost/mpl/aux_/config/eti.hpp>
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if !(defined(BOOST_UNORDERED_STD_FORWARD))
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_const.hpp> #include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/utility/enable_if.hpp> #include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/mpl/not.hpp> #include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, typename Arg)
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, const& arg)
#define BOOST_UNORDERED_CALL_PARAMS(z, n) \
BOOST_PP_ENUM_PARAMS_Z(z, n, arg)
#endif #endif
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582) #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582)

View File

@ -181,56 +181,159 @@ namespace boost {
} }
} }
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) void construct_preamble()
{
if(!node_) {
node_constructed_ = false;
value_constructed_ = false;
node_ = allocators_.node_alloc_.allocate(1);
allocators_.node_alloc_.construct(node_, node());
node_constructed_ = true;
}
else {
BOOST_ASSERT(node_constructed_ && value_constructed_);
BOOST_UNORDERED_DESTRUCT(&node_->value(), value_type);
value_constructed_ = false;
}
}
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <typename... Args> template <typename... Args>
void construct(Args&&... args) void construct(Args&&... args)
{ {
BOOST_ASSERT(!node_); construct_preamble();
node_constructed_ = false;
value_constructed_ = false;
node_ = allocators_.node_alloc_.allocate(1);
allocators_.node_alloc_.construct(node_, node());
node_constructed_ = true;
new(node_->address()) value_type(std::forward<Args>(args)...); new(node_->address()) value_type(std::forward<Args>(args)...);
value_constructed_ = true; value_constructed_ = true;
} }
#else
template <typename V> #if defined(__GLIBCPP__) || defined(__GLIBCXX__)
void construct(V const& v) // The GCC C++0x standard library implementation does not have
// a single argument pair constructor, so this works around that.
template <typename Arg>
void construct(Arg&& arg)
{ {
BOOST_ASSERT(!node_); construct_preamble();
node_constructed_ = false; construct_impl(std::forward<Arg>(arg),
value_constructed_ = false; (value_type const*) 0,
(typename boost::remove_reference<Arg>::type const*) 0);
node_ = allocators_.node_alloc_.allocate(1);
allocators_.node_alloc_.construct(node_, node());
node_constructed_ = true;
new(node_->address()) value_type(v);
value_constructed_ = true; value_constructed_ = true;
} }
template <
typename Arg,
typename ValueType,
typename Type>
void construct_impl(Arg&& arg, ValueType const*, Type const*)
{
new(node_->address()) value_type(std::forward<Arg>(arg));
}
template <
typename Arg,
typename ValueFirst, typename ValueSecond,
typename TypeFirst, typename TypeSecond>
void construct_impl(
Arg&& arg,
std::pair<ValueFirst, ValueSecond> const*,
std::pair<TypeFirst, TypeSecond> const*)
{
new(node_->address()) value_type(std::forward<Arg>(arg));
}
template <
typename Arg,
typename ValueFirst, typename ValueSecond,
typename Type>
void construct_impl(
Arg&& arg,
std::pair<ValueFirst, ValueSecond> const*,
Type const*)
{
new(node_->address()) value_type(std::forward<Arg>(arg), ValueSecond());
}
#endif #endif
#else
template <typename K, typename M> void construct()
void construct_pair(K const& k, M*)
{ {
BOOST_ASSERT(!node_); construct_preamble();
node_constructed_ = false; new(node_->address()) value_type;
value_constructed_ = false;
node_ = allocators_.node_alloc_.allocate(1);
allocators_.node_alloc_.construct(node_, node());
node_constructed_ = true;
new(node_->address()) value_type(k, M());
value_constructed_ = true; value_constructed_ = true;
} }
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
void construct( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
construct_preamble(); \
construct_impl( \
(value_type*) 0, \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
value_constructed_ = true; \
} \
\
template < \
typename T, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
void construct_impl( \
T*, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
new(node_->address()) value_type( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
} \
\
#define BOOST_UNORDERED_CONSTRUCT_IMPL2(z, n, _) \
template <typename First, typename Second, typename Key, \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
void construct_impl( \
std::pair<First, Second>*, \
Key const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
new(node_->address()) value_type(k, \
Second( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
) \
); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_CONSTRUCT_IMPL2, _)
template <typename First, typename Second, typename T1, typename T2>
void construct_impl(std::pair<First, Second>*,
std::pair<T1, T2> const& arg0)
{
new(node_->address()) value_type(arg0);
}
template <typename First, typename Second, typename Key>
void construct_impl(std::pair<First, Second>*, Key const& k)
{
new(node_->address()) value_type(First(k), Second());
}
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
#endif
node_ptr get() const node_ptr get() const
{ {
BOOST_ASSERT(node_); BOOST_ASSERT(node_);
@ -1427,8 +1530,29 @@ namespace boost {
} }
// key extractors // key extractors
//
// no throw // no throw
//
// 'extract_key' is called with the emplace parameters to return a
// key if available or 'no_key' is one isn't and will need to be
// constructed.
struct no_key {
no_key() {}
template <class T> no_key(T const&) {}
};
// If emplace is called with no arguments then there obviously
// isn't an available key.
static no_key extract_key()
{
return no_key();
}
// Emplace or insert was called with the value type.
static key_type const& extract_key(value_type const& v) static key_type const& extract_key(value_type const& v)
{ {
return extract(v, (type_wrapper<value_type>*)0); return extract(v, (type_wrapper<value_type>*)0);
@ -1445,40 +1569,67 @@ namespace boost {
{ {
return v.first; return v.first;
} }
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) // For maps, if emplace is called with just a key, then it's the value type
struct no_key {}; // with the second value default initialised.
template <typename Arg1, typename... Args> template <typename Arg>
static typename boost::enable_if< static BOOST_DEDUCED_TYPENAME
boost::mpl::and_< boost::mpl::if_<boost::is_same<Arg, key_type>, key_type const&, no_key>::type
boost::mpl::not_<boost::is_same<key_type, value_type> >, extract_key(Arg const& k)
boost::is_same<Arg1, key_type>
>,
key_type>::type const& extract_key(Arg1 const& k, Args const&...)
{ {
return k; return k;
} }
// For a map, the argument might be a pair with the key as the first
// part and a convertible value as the second part.
template <typename First, typename Second> template <typename First, typename Second>
static typename boost::enable_if< static BOOST_DEDUCED_TYPENAME
boost::mpl::and_< boost::mpl::if_<
boost::mpl::not_<boost::is_same<key_type, value_type> >, boost::mpl::and_<
boost::is_same<key_type, boost::mpl::not_<boost::is_same<key_type, value_type> >,
typename boost::remove_const< boost::is_same<key_type,
typename boost::remove_reference<First>::type typename boost::remove_const<
>::type> typename boost::remove_reference<First>::type
>, >::type>
key_type>::type const& extract_key(std::pair<First, Second> const& v) >,
key_type const&, no_key
>::type extract_key(std::pair<First, Second> const& v)
{ {
return v.first; return v.first;
} }
template <typename... Args> // For maps if there is more than one argument, the key can be the first argument.
static no_key extract_key(Args const&...)
#if defined(BOOST_UNORDERED_STD_FORWARD)
template <typename Arg, typename Arg1, typename... Args>
static BOOST_DEDUCED_TYPENAME
boost::mpl::if_<
boost::mpl::and_<
boost::mpl::not_<boost::is_same<value_type, key_type> >,
boost::is_same<Arg, key_type>
>,
key_type const&, no_key
>::type extract_key(Arg const& k, Arg1 const&, Args const&...)
{ {
return no_key(); return k;
} }
#else
template <typename Arg, typename Arg1>
static BOOST_DEDUCED_TYPENAME
boost::mpl::if_<
boost::mpl::and_<
boost::mpl::not_<boost::is_same<value_type, key_type> >,
boost::is_same<Arg, key_type>
>,
key_type const&, no_key
>::type extract_key(Arg const& k, Arg1 const&)
{
return k;
}
#endif #endif
public: public:
@ -1582,72 +1733,78 @@ namespace boost {
#if BOOST_UNORDERED_EQUIVALENT_KEYS #if BOOST_UNORDERED_EQUIVALENT_KEYS
#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) #if defined(BOOST_UNORDERED_STD_FORWARD)
// Insert (equivalent key containers)
// Emplace (equivalent key containers)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety // if hash function throws, basic exception safety
// strong otherwise // strong otherwise
iterator_base insert(value_type const& v) template <class... Args>
iterator_base emplace(Args&&... args)
{ {
// Create the node before rehashing in case it throws an // Create the node before rehashing in case it throws an
// exception (need strong safety in such a case). // exception (need strong safety in such a case).
node_constructor a(data_.allocators_); node_constructor a(data_.allocators_);
a.construct(v); a.construct(std::forward<Args>(args)...);
return insert_impl(a); return emplace_impl(a);
} }
// Insert (equivalent key containers) // Emplace (equivalent key containers)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety // if hash function throws, basic exception safety
// strong otherwise // strong otherwise
iterator_base insert_hint(iterator_base const& it, value_type const& v) template <class... Args>
iterator_base emplace_hint(iterator_base const& it, Args&&... args)
{ {
// Create the node before rehashing in case it throws an // Create the node before rehashing in case it throws an
// exception (need strong safety in such a case). // exception (need strong safety in such a case).
node_constructor a(data_.allocators_); node_constructor a(data_.allocators_);
a.construct(v); a.construct(std::forward<Args>(args)...);
return insert_hint_impl(it, a); return emplace_hint_impl(it, a);
} }
#else #else
// Insert (equivalent key containers) #define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
// (I'm using an overloaded insert for both 'insert' and 'emplace') template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
// if hash function throws, basic exception safety > \
// strong otherwise iterator_base emplace( \
template <class... Args> BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
iterator_base insert(Args&&... args) ) \
{ { \
// Create the node before rehashing in case it throws an node_constructor a(data_.allocators_); \
// exception (need strong safety in such a case). a.construct( \
node_constructor a(data_.allocators_); BOOST_UNORDERED_CALL_PARAMS(z, n) \
a.construct(std::forward<Args>(args)...); ); \
return emplace_impl(a); \
return insert_impl(a); } \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator_base emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
node_constructor a(data_.allocators_); \
a.construct( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
return emplace_hint_impl(it, a); \
} }
// Insert (equivalent key containers) BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
// (I'm using an overloaded insert for both 'insert' and 'emplace') BOOST_UNORDERED_INSERT_IMPL, _)
// if hash function throws, basic exception safety
// strong otherwise
template <class... Args>
iterator_base insert_hint(iterator_base const& it, Args&&... args)
{
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(data_.allocators_);
a.construct(std::forward<Args>(args)...);
return insert_hint_impl(it, a);
}
#undef BOOST_UNORDERED_INSERT_IMPL
#endif #endif
iterator_base insert_impl(node_constructor& a) iterator_base emplace_impl(node_constructor& a)
{ {
key_type const& k = extract_key(a.get()->value()); key_type const& k = extract_key(a.get()->value());
size_type hash_value = hash_function()(k); size_type hash_value = hash_function()(k);
@ -1668,17 +1825,17 @@ namespace boost {
); );
} }
iterator_base insert_hint_impl(iterator_base const& it, node_constructor& a) iterator_base emplace_hint_impl(iterator_base const& it, node_constructor& a)
{ {
// equal can throw, but with no effects // equal can throw, but with no effects
if (it == data_.end() || !equal(extract_key(a.get()->value()), *it)) { if (it == data_.end() || !equal(extract_key(a.get()->value()), *it)) {
// Use the standard insert if the iterator doesn't point // Use the standard emplace if the iterator doesn't point
// to a matching key. // to a matching key.
return insert_impl(a); return emplace_impl(a);
} }
else { else {
// Find the first node in the group - so that the node // Find the first node in the group - so that the node
// will be inserted at the end of the group. // will be added at the end of the group.
link_ptr start(it.node_); link_ptr start(it.node_);
while(data_.prev_in_group(start)->next_ == start) while(data_.prev_in_group(start)->next_ == start)
@ -1707,7 +1864,7 @@ namespace boost {
{ {
size_type distance = unordered_detail::distance(i, j); size_type distance = unordered_detail::distance(i, j);
if(distance == 1) { if(distance == 1) {
insert(*i); emplace(*i);
} }
else { else {
// Only require basic exception safety here // Only require basic exception safety here
@ -1737,7 +1894,7 @@ namespace boost {
{ {
// If only inserting 1 element, get the required // If only inserting 1 element, get the required
// safety since insert is only called once. // safety since insert is only called once.
for (; i != j; ++i) insert(*i); for (; i != j; ++i) emplace(*i);
} }
public: public:
@ -1773,7 +1930,7 @@ namespace boost {
// Create the node before rehashing in case it throws an // Create the node before rehashing in case it throws an
// exception (need strong safety in such a case). // exception (need strong safety in such a case).
node_constructor a(data_.allocators_); node_constructor a(data_.allocators_);
a.construct_pair(k, (mapped_type*) 0); a.construct(k);
// reserve has basic exception safety if the hash function // reserve has basic exception safety if the hash function
// throws, strong otherwise. // throws, strong otherwise.
@ -1786,81 +1943,37 @@ namespace boost {
} }
} }
#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) #if defined(BOOST_UNORDERED_STD_FORWARD)
// Insert (unique keys) // Emplace (unique keys)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
std::pair<iterator_base, bool> insert(value_type const& v)
{
// No side effects in this initial code
key_type const& k = extract_key(v);
size_type hash_value = hash_function()(k);
bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value);
link_ptr pos = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Found an existing key, return it (no throw).
return std::pair<iterator_base, bool>(
iterator_base(bucket, pos), false);
} else {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(data_.allocators_);
a.construct(v);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(reserve_for_insert(size() + 1))
bucket = data_.bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
link_ptr n = data_.link_node_in_bucket(a, bucket);
return std::pair<iterator_base, bool>(
iterator_base(bucket, n), true);
}
}
// Insert (unique keys)
// if hash function throws, basic exception safety
// strong otherwise
iterator_base insert_hint(iterator_base const& it, value_type const& v)
{
if(it != data_.end() && equal(extract_key(v), *it))
return it;
else
return insert(v).first;
}
#else
// Insert (unique keys)
// (I'm using an overloaded insert for both 'insert' and 'emplace')
//
// TODO:
// For sets: create a local key without creating the node?
// For maps: use the first argument as the key.
// if hash function throws, basic exception safety // if hash function throws, basic exception safety
// strong otherwise // strong otherwise
template<typename... Args> template<typename... Args>
std::pair<iterator_base, bool> insert(Args&&... args) std::pair<iterator_base, bool> emplace(Args&&... args)
{ {
return insert_impl( return emplace_impl(
extract_key(std::forward<Args>(args)...), extract_key(std::forward<Args>(args)...),
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
// Insert (unique keys)
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
// I'm just ignoring hints here for now.
// if hash function throws, basic exception safety
// strong otherwise
template<typename... Args> template<typename... Args>
std::pair<iterator_base, bool> insert_impl(key_type const& k, Args&&... args) iterator_base emplace_hint(iterator_base const&, Args&&... args)
{
return emplace_impl(
extract_key(std::forward<Args>(args)...),
std::forward<Args>(args)...).first;
}
template<typename... Args>
std::pair<iterator_base, bool> emplace_impl(key_type const& k, Args&&... args)
{ {
// No side effects in this initial code // No side effects in this initial code
size_type hash_value = hash_function()(k); size_type hash_value = hash_function()(k);
@ -1894,13 +2007,110 @@ namespace boost {
} }
template<typename... Args> template<typename... Args>
std::pair<iterator_base, bool> insert_impl(no_key, Args&&... args) std::pair<iterator_base, bool> emplace_impl(no_key, Args&&... args)
{ {
// Construct the node regardless - in order to get the key. // Construct the node regardless - in order to get the key.
// It will be discarded if it isn't used // It will be discarded if it isn't used
node_constructor a(data_.allocators_); node_constructor a(data_.allocators_);
a.construct(std::forward<Args>(args)...); a.construct(std::forward<Args>(args)...);
return emplace_impl_with_node(a);
}
#else
template <typename Arg0>
std::pair<iterator_base, bool> emplace(Arg0 const& arg0)
{
return emplace_impl(extract_key(arg0), arg0);
}
template <typename Arg0>
iterator_base emplace_hint(iterator_base const& it, Arg0 const& arg0)
{
return emplace_impl(extract_key(arg0), arg0).first;
}
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator_base, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return emplace_impl( \
extract_key(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator_base emplace_hint(iterator_base const& it, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return emplace_impl( \
extract_key(arg0, arg1), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
).first; \
} \
BOOST_UNORDERED_INSERT_IMPL2(z, n, _)
#define BOOST_UNORDERED_INSERT_IMPL2(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator_base, bool> emplace_impl(key_type const& k, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
size_type hash_value = hash_function()(k); \
bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value); \
link_ptr pos = find_iterator(bucket, k); \
\
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
return std::pair<iterator_base, bool>( \
iterator_base(bucket, pos), false); \
} else { \
node_constructor a(data_.allocators_); \
a.construct( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
\
if(reserve_for_insert(size() + 1)) \
bucket = data_.bucket_ptr_from_hash(hash_value); \
\
return std::pair<iterator_base, bool>(iterator_base(bucket, \
data_.link_node_in_bucket(a, bucket)), true); \
} \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator_base, bool> emplace_impl(no_key, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
node_constructor a(data_.allocators_); \
a.construct( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
); \
return emplace_impl_with_node(a); \
}
BOOST_UNORDERED_INSERT_IMPL2(1, 1, _)
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_INSERT_IMPL, _)
#undef BOOST_UNORDERED_INSERT_IMPL
#endif
std::pair<iterator_base, bool> emplace_impl_with_node(node_constructor& a)
{
// No side effects in this initial code // No side effects in this initial code
key_type const& k = extract_key(a.get()->value()); key_type const& k = extract_key(a.get()->value());
size_type hash_value = hash_function()(k); size_type hash_value = hash_function()(k);
@ -1924,19 +2134,6 @@ namespace boost {
} }
} }
// Insert (unique keys)
// (I'm using an overloaded insert for both 'insert' and 'emplace')
// if hash function throws, basic exception safety
// strong otherwise
template<typename... Args>
iterator_base insert_hint(iterator_base const&, Args&&... args)
{
// Life is complicated - just call the normal implementation.
return insert(std::forward<Args>(args)...).first;
}
#endif
// Insert from iterators (unique keys) // Insert from iterators (unique keys)
template <typename I> template <typename I>
@ -1963,6 +2160,13 @@ namespace boost {
// strong otherwise // strong otherwise
template <typename InputIterator> template <typename InputIterator>
void insert_range(InputIterator i, InputIterator j) void insert_range(InputIterator i, InputIterator j)
{
if(i != j)
return insert_range_impl(extract_key(*i), i, j);
}
template <typename InputIterator>
void insert_range_impl(key_type const&, InputIterator i, InputIterator j)
{ {
node_constructor a(data_.allocators_); node_constructor a(data_.allocators_);
@ -1992,6 +2196,36 @@ namespace boost {
} }
} }
} }
template <typename InputIterator>
void insert_range_impl(no_key, InputIterator i, InputIterator j)
{
node_constructor a(data_.allocators_);
for (; i != j; ++i) {
// No side effects in this initial code
a.construct(*i);
key_type const& k = extract_key(a.get()->value());
size_type hash_value = hash_function()(extract_key(k));
bucket_ptr bucket = data_.bucket_ptr_from_hash(hash_value);
link_ptr pos = find_iterator(bucket, k);
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
// Doesn't already exist, add to bucket.
// Side effects only in this block.
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(size() + 1 >= max_load_) {
reserve_for_insert(size() + insert_size(i, j));
bucket = data_.bucket_ptr_from_hash(hash_value);
}
// Nothing after this point can throw.
data_.link_node_in_bucket(a, bucket);
}
}
}
#endif #endif
public: public:
@ -2078,8 +2312,9 @@ namespace boost {
key_type const& k) const key_type const& k) const
{ {
link_ptr it = data_.begin(bucket); link_ptr it = data_.begin(bucket);
while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) {
it = data::next_group(it); it = data::next_group(it);
}
return it; return it;
} }

View File

@ -21,6 +21,10 @@
#include <boost/unordered/detail/move.hpp> #include <boost/unordered/detail/move.hpp>
#endif #endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#include <initializer_list>
#endif
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
#pragma warning(push) #pragma warning(push)
#if BOOST_MSVC >= 1400 #if BOOST_MSVC >= 1400
@ -135,7 +139,7 @@ namespace boost
#endif #endif
#endif #endif
#if !defined(BOOST_NO_INITIALIZER_LISTS) #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_map(std::initializer_list<value_type> list, unordered_map(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count, size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(), const hasher &hf = hasher(),
@ -219,30 +223,74 @@ namespace boost
// modifiers // modifiers
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template <class... Args> template <class... Args>
std::pair<iterator, bool> emplace(Args&&... args) std::pair<iterator, bool> emplace(Args&&... args)
{ {
return boost::unordered_detail::pair_cast<iterator, bool>( return boost::unordered_detail::pair_cast<iterator, bool>(
base.insert(std::forward<Args>(args)...)); base.emplace(std::forward<Args>(args)...));
} }
template <class... Args> template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args) iterator emplace_hint(const_iterator hint, Args&&... args)
{ {
return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...)); return iterator(base.emplace_hint(get(hint), std::forward<Args>(args)...));
} }
#else
std::pair<iterator, bool> emplace(value_type const& v = value_type())
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
{
return iterator(base.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
base.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(base.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif #endif
std::pair<iterator, bool> insert(const value_type& obj) std::pair<iterator, bool> insert(const value_type& obj)
{ {
return boost::unordered_detail::pair_cast<iterator, bool>( return boost::unordered_detail::pair_cast<iterator, bool>(
base.insert(obj)); base.emplace(obj));
} }
iterator insert(const_iterator hint, const value_type& obj) iterator insert(const_iterator hint, const value_type& obj)
{ {
return iterator(base.insert_hint(get(hint), obj)); return iterator(base.emplace_hint(get(hint), obj));
} }
template <class InputIterator> template <class InputIterator>
@ -541,7 +589,7 @@ namespace boost
#endif #endif
#endif #endif
#if !defined(BOOST_NO_INITIALIZER_LISTS) #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_multimap(std::initializer_list<value_type> list, unordered_multimap(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count, size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(), const hasher &hf = hasher(),
@ -626,28 +674,72 @@ namespace boost
// modifiers // modifiers
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template <class... Args> template <class... Args>
iterator emplace(Args&&... args) iterator emplace(Args&&... args)
{ {
return iterator(base.insert(std::forward<Args>(args)...)); return iterator(base.emplace(std::forward<Args>(args)...));
} }
template <class... Args> template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args) iterator emplace_hint(const_iterator hint, Args&&... args)
{ {
return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...)); return iterator(base.emplace_hint(get(hint), std::forward<Args>(args)...));
} }
#else
iterator emplace(value_type const& v = value_type())
{
return iterator(base.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
{
return iterator(base.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator( \
base.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(base.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif #endif
iterator insert(const value_type& obj) iterator insert(const value_type& obj)
{ {
return iterator(base.insert(obj)); return iterator(base.emplace(obj));
} }
iterator insert(const_iterator hint, const value_type& obj) iterator insert(const_iterator hint, const value_type& obj)
{ {
return iterator(base.insert_hint(get(hint), obj)); return iterator(base.emplace_hint(get(hint), obj));
} }
template <class InputIterator> template <class InputIterator>

View File

@ -21,6 +21,10 @@
#include <boost/unordered/detail/move.hpp> #include <boost/unordered/detail/move.hpp>
#endif #endif
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
#include <initializer_list>
#endif
#if defined(BOOST_MSVC) #if defined(BOOST_MSVC)
#pragma warning(push) #pragma warning(push)
#if BOOST_MSVC >= 1400 #if BOOST_MSVC >= 1400
@ -133,7 +137,7 @@ namespace boost
#endif #endif
#endif #endif
#if !defined(BOOST_NO_INITIALIZER_LISTS) #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_set(std::initializer_list<value_type> list, unordered_set(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count, size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(), const hasher &hf = hasher(),
@ -217,31 +221,75 @@ namespace boost
// modifiers // modifiers
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template <class... Args> template <class... Args>
std::pair<iterator, bool> emplace(Args&&... args) std::pair<iterator, bool> emplace(Args&&... args)
{ {
return boost::unordered_detail::pair_cast<iterator, bool>( return boost::unordered_detail::pair_cast<iterator, bool>(
base.insert(std::forward<Args>(args)...)); base.emplace(std::forward<Args>(args)...));
} }
template <class... Args> template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args) iterator emplace_hint(const_iterator hint, Args&&... args)
{ {
return iterator( return iterator(
base.insert_hint(get(hint), std::forward<Args>(args)...)); base.emplace_hint(get(hint), std::forward<Args>(args)...));
} }
#else
std::pair<iterator, bool> emplace(value_type const& v = value_type())
{
return boost::unordered_detail::pair_cast<iterator, bool>(
base.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
{
return iterator(base.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
std::pair<iterator, bool> emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return boost::unordered_detail::pair_cast<iterator, bool>( \
base.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(base.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif #endif
std::pair<iterator, bool> insert(const value_type& obj) std::pair<iterator, bool> insert(const value_type& obj)
{ {
return boost::unordered_detail::pair_cast<iterator, bool>( return boost::unordered_detail::pair_cast<iterator, bool>(
base.insert(obj)); base.emplace(obj));
} }
iterator insert(const_iterator hint, const value_type& obj) iterator insert(const_iterator hint, const value_type& obj)
{ {
return iterator(base.insert_hint(get(hint), obj)); return iterator(base.emplace_hint(get(hint), obj));
} }
template <class InputIterator> template <class InputIterator>
@ -511,7 +559,7 @@ namespace boost
#endif #endif
#endif #endif
#if !defined(BOOST_NO_INITIALIZER_LISTS) #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
unordered_multiset(std::initializer_list<value_type> list, unordered_multiset(std::initializer_list<value_type> list,
size_type n = boost::unordered_detail::default_initial_bucket_count, size_type n = boost::unordered_detail::default_initial_bucket_count,
const hasher &hf = hasher(), const hasher &hf = hasher(),
@ -595,28 +643,71 @@ namespace boost
// modifiers // modifiers
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template <class... Args> template <class... Args>
iterator emplace(Args&&... args) iterator emplace(Args&&... args)
{ {
return iterator(base.insert(std::forward<Args>(args)...)); return iterator(base.emplace(std::forward<Args>(args)...));
} }
template <class... Args> template <class... Args>
iterator emplace_hint(const_iterator hint, Args&&... args) iterator emplace_hint(const_iterator hint, Args&&... args)
{ {
return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...)); return iterator(base.emplace_hint(get(hint), std::forward<Args>(args)...));
} }
#else
iterator emplace(value_type const& v = value_type())
{
return iterator(base.emplace(v));
}
iterator emplace_hint(const_iterator hint, value_type const& v = value_type())
{
return iterator(base.emplace_hint(get(hint), v));
}
#define BOOST_UNORDERED_EMPLACE(z, n, _) \
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace( \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator( \
base.emplace( \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
} \
\
template < \
BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \
> \
iterator emplace_hint(const_iterator hint, \
BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \
) \
{ \
return iterator(base.emplace_hint(get(hint), \
BOOST_UNORDERED_CALL_PARAMS(z, n) \
)); \
}
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
BOOST_UNORDERED_EMPLACE, _)
#undef BOOST_UNORDERED_EMPLACE
#endif #endif
iterator insert(const value_type& obj) iterator insert(const value_type& obj)
{ {
return iterator(base.insert(obj)); return iterator(base.emplace(obj));
} }
iterator insert(const_iterator hint, const value_type& obj) iterator insert(const_iterator hint, const value_type& obj)
{ {
return iterator(base.insert_hint(get(hint), obj)); return iterator(base.emplace_hint(get(hint), obj));
} }
template <class InputIterator> template <class InputIterator>

View File

@ -6,6 +6,8 @@
#if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD) #if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD)
#define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD #define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD
#include <iostream>
namespace test { namespace test {
struct object_count { struct object_count {
int instances; int instances;
@ -36,6 +38,11 @@ namespace test {
bool operator!=(object_count const& x) const { bool operator!=(object_count const& x) const {
return !(*this == x); return !(*this == x);
} }
friend std::ostream& operator<<(std::ostream& out, object_count const& c) {
out<<"[instances: "<<c.instances<<", constructions: "<<c.constructions<<"]";
return out;
}
}; };
template <class T> template <class T>

View File

@ -347,7 +347,7 @@ namespace exception
detail::tracker.track_construct((void*) p, sizeof(T), tag_); detail::tracker.track_construct((void*) p, sizeof(T), tag_);
} }
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args> void construct(pointer p, Args&&... args) { template<class... Args> void construct(pointer p, Args&&... args) {
UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) { UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
UNORDERED_EPOINT("Mock allocator construct function."); UNORDERED_EPOINT("Mock allocator construct function.");

View File

@ -229,7 +229,7 @@ namespace minimal
void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); } void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args> void construct(pointer p, Args&&... args) { template<class... Args> void construct(pointer p, Args&&... args) {
new((void*)p.ptr_) T(std::forward<Args>(args)...); new((void*)p.ptr_) T(std::forward<Args>(args)...);
} }

View File

@ -218,7 +218,7 @@ namespace test
new(p) T(t); new(p) T(t);
} }
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) #if defined(BOOST_UNORDERED_STD_FORWARD)
template<class... Args> void construct(pointer p, Args&&... args) { template<class... Args> void construct(pointer p, Args&&... args) {
detail::tracker.track_construct((void*) p, sizeof(T), tag_); detail::tracker.track_construct((void*) p, sizeof(T), tag_);
new(p) T(std::forward<Args>(args)...); new(p) T(std::forward<Args>(args)...);

View File

@ -151,14 +151,12 @@ void unordered_map_test(X& r, Key const& k, T const& v)
r.insert(std::pair<Key const, T>(k, v)); r.insert(std::pair<Key const, T>(k, v));
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
Key k_lvalue(k); Key k_lvalue(k);
T v_lvalue(v); T v_lvalue(v);
r.emplace(k, v); r.emplace(k, v);
r.emplace(k_lvalue, v_lvalue); r.emplace(k_lvalue, v_lvalue);
r.emplace(rvalue(k), rvalue(v)); r.emplace(rvalue(k), rvalue(v));
#endif
} }
template <class X> template <class X>
@ -175,9 +173,7 @@ void unordered_unique_test(X& r, T const& t)
{ {
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t)); test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t));
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
test::check_return_type<std::pair<iterator, bool> >::equals(r.emplace(t)); test::check_return_type<std::pair<iterator, bool> >::equals(r.emplace(t));
#endif
} }
template <class X, class T> template <class X, class T>
@ -185,9 +181,7 @@ void unordered_equivalent_test(X& r, T const& t)
{ {
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
test::check_return_type<iterator>::equals(r.insert(t)); test::check_return_type<iterator>::equals(r.insert(t));
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
test::check_return_type<iterator>::equals(r.emplace(t)); test::check_return_type<iterator>::equals(r.emplace(t));
#endif
} }
template <class X, class Key, class T> template <class X, class Key, class T>
@ -289,9 +283,7 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
const_iterator q = a.cbegin(); const_iterator q = a.cbegin();
test::check_return_type<iterator>::equals(a.insert(q, t)); test::check_return_type<iterator>::equals(a.insert(q, t));
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
test::check_return_type<iterator>::equals(a.emplace_hint(q, t)); test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
#endif
a.insert(i, j); a.insert(i, j);
test::check_return_type<size_type>::equals(a.erase(k)); test::check_return_type<size_type>::equals(a.erase(k));

View File

@ -68,12 +68,22 @@ namespace unnecessary_copy_tests
#define COPY_COUNT(n) \ #define COPY_COUNT(n) \
if(count_copies::copies != n) { \ if(count_copies::copies != n) { \
BOOST_ERROR("Wrong number of copies."); \ BOOST_ERROR("Wrong number of copies."); \
std::cerr<<"Number of copies: "<<count_copies::copies<<std::endl; \ std::cerr<<"Number of copies: "<<count_copies::copies<<" expecting: "<<n<<std::endl; \
} }
#define MOVE_COUNT(n) \ #define MOVE_COUNT(n) \
if(count_copies::moves != n) { \ if(count_copies::moves != n) { \
BOOST_ERROR("Wrong number of moves."); \ BOOST_ERROR("Wrong number of moves."); \
std::cerr<<"Number of moves: "<<count_copies::moves<<std::endl; \ std::cerr<<"Number of moves: "<<count_copies::moves<<" expecting: "<<n<<std::endl; \
}
#define COPY_COUNT_RANGE(a, b) \
if(count_copies::copies < a || count_copies::copies > b) { \
BOOST_ERROR("Wrong number of copies."); \
std::cerr<<"Number of copies: "<<count_copies::copies<<" expecting: ["<<a<<", "<<b<<"]"<<std::endl; \
}
#define MOVE_COUNT_RANGE(a, b) \
if(count_copies::moves < a || count_copies::moves > b) { \
BOOST_ERROR("Wrong number of moves."); \
std::cerr<<"Number of moves: "<<count_copies::copies<<" expecting: ["<<a<<", "<<b<<"]"<<std::endl; \
} }
namespace unnecessary_copy_tests namespace unnecessary_copy_tests
@ -99,7 +109,6 @@ namespace unnecessary_copy_tests
UNORDERED_TEST(unnecessary_copy_insert_test, UNORDERED_TEST(unnecessary_copy_insert_test,
((set)(multiset)(map)(multimap))) ((set)(multiset)(map)(multimap)))
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
template <class T> template <class T>
void unnecessary_copy_emplace_test(T*) void unnecessary_copy_emplace_test(T*)
{ {
@ -117,9 +126,19 @@ namespace unnecessary_copy_tests
reset(); reset();
T x; T x;
x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>()); x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
COPY_COUNT(1); COPY_COUNT(1);
#else
COPY_COUNT(2);
#endif
} }
UNORDERED_TEST(unnecessary_copy_emplace_test,
((set)(multiset)(map)(multimap)))
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
((set)(multiset)(map)(multimap)))
#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
template <class T> template <class T>
void unnecessary_copy_emplace_move_test(T*) void unnecessary_copy_emplace_move_test(T*)
{ {
@ -131,13 +150,11 @@ namespace unnecessary_copy_tests
COPY_COUNT(1); MOVE_COUNT(1); 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, UNORDERED_TEST(unnecessary_copy_emplace_move_test,
((set)(multiset)(map)(multimap))) ((set)(multiset)(map)(multimap)))
#endif
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
{ {
reset(); reset();
@ -172,10 +189,12 @@ namespace unnecessary_copy_tests
x.emplace(source<count_copies>()); x.emplace(source<count_copies>());
COPY_COUNT(1); MOVE_COUNT(0); COPY_COUNT(1); MOVE_COUNT(0);
#if defined(BOOST_HAS_RVALUE_REFS)
// No move should take place. // No move should take place.
reset(); reset();
x.emplace(std::move(a)); x.emplace(std::move(a));
COPY_COUNT(0); MOVE_COUNT(0); COPY_COUNT(0); MOVE_COUNT(0);
#endif
// Just in case a did get moved... // Just in case a did get moved...
count_copies b; count_copies b;
@ -192,8 +211,12 @@ namespace unnecessary_copy_tests
// The container will have to create b copy in order to compare with // The container will have to create b copy in order to compare with
// the existing element. // the existing element.
//
// Note to self: If copy_count == 0 it's an error not an optimization.
// TODO: Devise a better test.
reset(); reset();
x.emplace(b, b); x.emplace(b, b);
COPY_COUNT(1); MOVE_COUNT(0); COPY_COUNT(1); MOVE_COUNT(0);
} }
@ -230,24 +253,22 @@ namespace unnecessary_copy_tests
x.emplace(source<std::pair<count_copies, count_copies> >()); x.emplace(source<std::pair<count_copies, count_copies> >());
COPY_COUNT(2); MOVE_COUNT(0); COPY_COUNT(2); MOVE_COUNT(0);
count_copies part; // TODO: This doesn't work on older versions of gcc.
reset(); //count_copies part;
std::pair<count_copies const&, count_copies const&> a_ref(part, part); std::pair<count_copies const, count_copies> b;
x.emplace(a_ref); //reset();
COPY_COUNT(0); MOVE_COUNT(0); //std::pair<count_copies const&, count_copies const&> a_ref(part, part);
//x.emplace(a_ref);
//COPY_COUNT(0); MOVE_COUNT(0);
#if defined(BOOST_HAS_RVALUE_REFS)
// No move should take place. // No move should take place.
// (since a is already in the container)
reset(); reset();
x.emplace(std::move(a)); x.emplace(std::move(a));
COPY_COUNT(0); MOVE_COUNT(0); COPY_COUNT(0); MOVE_COUNT(0);
#endif
// 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 // 2 arguments
@ -267,10 +288,9 @@ namespace unnecessary_copy_tests
COPY_COUNT(1); MOVE_COUNT(0); COPY_COUNT(1); MOVE_COUNT(0);
reset(); reset();
x.emplace(b.first.tag_, b.second.tag_); x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
COPY_COUNT(2); MOVE_COUNT(0); COPY_COUNT(2); MOVE_COUNT(0);
} }
#endif
} }
RUN_TESTS() RUN_TESTS()