Boost logo

Boost-Commit :

From: daniel_james_at_[hidden]
Date: 2008-04-17 16:41:48


Author: danieljames
Date: 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
New Revision: 44516
URL: http://svn.boost.org/trac/boost/changeset/44516

Log:
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.
........

Properties modified:
   branches/unordered/trunk/ (props changed)
Text files modified:
   branches/unordered/trunk/boost/unordered/detail/hash_table_impl.hpp | 154 +++++++++++++++++++++++++---
   branches/unordered/trunk/boost/unordered_map.hpp | 29 +++++
   branches/unordered/trunk/boost/unordered_set.hpp | 30 +++++
   branches/unordered/trunk/libs/unordered/doc/ref.xml | 214 ++++++++++++++++++++++++++++++++++++++++
   branches/unordered/trunk/libs/unordered/test/exception/insert_exception_tests.cpp | 35 +++++
   branches/unordered/trunk/libs/unordered/test/unordered/compile_tests.hpp | 9 +
   branches/unordered/trunk/libs/unordered/test/unordered/insert_tests.cpp | 80 ++++++++++++++
   7 files changed, 530 insertions(+), 21 deletions(-)

Modified: branches/unordered/trunk/boost/unordered/detail/hash_table_impl.hpp
==============================================================================
--- branches/unordered/trunk/boost/unordered/detail/hash_table_impl.hpp (original)
+++ branches/unordered/trunk/boost/unordered/detail/hash_table_impl.hpp 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -304,6 +304,27 @@
                     value_constructed_ = true;
                 }
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ template <typename... Args>
+ void construct(Args&&... args)
+ {
+ BOOST_ASSERT(!node_);
+ value_constructed_ = false;
+ node_base_constructed_ = false;
+
+ node_ = allocators_.node_alloc_.allocate(1);
+
+ allocators_.node_base_alloc_.construct(
+ allocators_.node_base_alloc_.address(*node_),
+ node_base());
+ node_base_constructed_ = true;
+
+ allocators_.value_alloc_.construct(
+ allocators_.value_alloc_.address(node_->value_), std::forward<Args>(args)...);
+ value_constructed_ = true;
+ }
+#endif
+
                 node_ptr get() const
                 {
                     BOOST_ASSERT(node_);
@@ -1611,16 +1632,70 @@
             // strong otherwise
             iterator_base insert(value_type const& v)
             {
- key_type const& k = extract_key(v);
- size_type hash_value = hash_function()(k);
- bucket_ptr bucket = data_.bucket_from_hash(hash_value);
- link_ptr position = find_iterator(bucket, k);
+ // 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);
+
+ return insert_impl(a);
+ }
 
+ // Insert (equivalent key containers)
+
+ // if hash function throws, basic exception safety
+ // strong otherwise
+ iterator_base insert_hint(iterator_base const& it, value_type const& v)
+ {
                 // 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);
 
+ return insert_hint_impl(it, a);
+ }
+
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ // Insert (equivalent key containers)
+ // (I'm using an overloaded insert for both 'insert' and 'emplace')
+
+ // if hash function throws, basic exception safety
+ // strong otherwise
+ template <class... Args>
+ iterator_base insert(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_impl(a);
+ }
+
+ // Insert (equivalent key containers)
+ // (I'm using an overloaded insert for both 'insert' and 'emplace')
+
+ // 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);
+ }
+
+#endif
+
+ iterator_base insert_impl(node_constructor& a)
+ {
+ key_type const& k = extract_key(a.get()->value_);
+ size_type hash_value = hash_function()(k);
+ bucket_ptr bucket = data_.bucket_from_hash(hash_value);
+ link_ptr position = find_iterator(bucket, k);
+
                 // reserve has basic exception safety if the hash function
                 // throws, strong otherwise.
                 if(reserve(size() + 1))
@@ -1635,17 +1710,13 @@
                 );
             }
 
- // Insert (equivalent key containers)
-
- // if hash function throws, basic exception safety
- // strong otherwise
- iterator_base insert_hint(iterator_base const& it, value_type const& v)
+ iterator_base insert_hint_impl(iterator_base const& it, node_constructor& a)
             {
                 // equal can throw, but with no effects
- if (it == data_.end() || !equal(extract_key(v), *it)) {
+ if (it == data_.end() || !equal(extract_key(a.get()->value_), *it)) {
                     // Use the standard insert if the iterator doesn't point
                     // to a matching key.
- return insert(v);
+ return insert_impl(a);
                 }
                 else {
                     // Find the first node in the group - so that the node
@@ -1655,15 +1726,10 @@
                     while(data_.prev_in_group(start)->next_ == start)
                         start = data_.prev_in_group(start);
 
- // 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.
                     bucket_ptr base = reserve(size() + 1) ?
- get_bucket(extract_key(v)) : it.bucket_;
+ get_bucket(extract_key(a.get()->value_)) : it.bucket_;
 
                     // Nothing after this point can throw
 
@@ -1814,6 +1880,60 @@
                     return insert(v).first;
             }
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ // 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
+ // strong otherwise
+ template<typename... Args>
+ std::pair<iterator_base, bool> insert(Args&&... args)
+ {
+ // Construct the node regardless - in order to get the key.
+ // It will be discarded if it isn't used
+ node_constructor a(data_.allocators_);
+ a.construct(std::forward<Args>(args)...);
+
+ // No side effects in this initial code
+ key_type const& k = extract_key(a.get()->value_);
+ size_type hash_value = hash_function()(k);
+ bucket_ptr bucket = data_.bucket_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 {
+ // reserve has basic exception safety if the hash function
+ // throws, strong otherwise.
+ if(reserve(size() + 1))
+ bucket = data_.bucket_from_hash(hash_value);
+
+ // Nothing after this point can throw.
+
+ return std::pair<iterator_base, bool>(iterator_base(bucket,
+ data_.link_node_in_bucket(a, bucket)), true);
+ }
+ }
+
+ // 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& it, Args&&... args)
+ {
+ // Life is complicated - just call the normal implementation.
+ return insert(std::forward<Args>(args)...).first;
+ }
+#endif
+
             // Insert from iterators (unique keys)
 
             template <typename I>

Modified: branches/unordered/trunk/boost/unordered_map.hpp
==============================================================================
--- branches/unordered/trunk/boost/unordered_map.hpp (original)
+++ branches/unordered/trunk/boost/unordered_map.hpp 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -199,6 +199,21 @@
 
         // modifiers
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ template <class... Args>
+ std::pair<iterator, bool> emplace(Args&&... args)
+ {
+ return boost::unordered_detail::pair_cast<iterator, bool>(
+ base.insert(std::forward<Args>(args)...));
+ }
+
+ template <class... Args>
+ iterator emplace(const_iterator hint, Args&&... args)
+ {
+ return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...));
+ }
+#endif
+
         std::pair<iterator, bool> insert(const value_type& obj)
         {
             return boost::unordered_detail::pair_cast<iterator, bool>(
@@ -553,6 +568,20 @@
 
         // modifiers
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ {
+ return iterator(base.insert(std::forward<Args>(args)...));
+ }
+
+ template <class... Args>
+ iterator emplace(const_iterator hint, Args&&... args)
+ {
+ return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...));
+ }
+#endif
+
         iterator insert(const value_type& obj)
         {
             return iterator(base.insert(obj));

Modified: branches/unordered/trunk/boost/unordered_set.hpp
==============================================================================
--- branches/unordered/trunk/boost/unordered_set.hpp (original)
+++ branches/unordered/trunk/boost/unordered_set.hpp 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -196,6 +196,22 @@
 
         // modifiers
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ template <class... Args>
+ std::pair<iterator, bool> emplace(Args&&... args)
+ {
+ return boost::unordered_detail::pair_cast<iterator, bool>(
+ base.insert(std::forward<Args>(args)...));
+ }
+
+ template <class... Args>
+ iterator emplace(const_iterator hint, Args&&... args)
+ {
+ return iterator(
+ base.insert_hint(get(hint), std::forward<Args>(args)...));
+ }
+#endif
+
         std::pair<iterator, bool> insert(const value_type& obj)
         {
             return boost::unordered_detail::pair_cast<iterator, bool>(
@@ -520,6 +536,20 @@
 
         // modifiers
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+ template <class... Args>
+ iterator emplace(Args&&... args)
+ {
+ return iterator(base.insert(std::forward<Args>(args)...));
+ }
+
+ template <class... Args>
+ iterator emplace(const_iterator hint, Args&&... args)
+ {
+ return iterator(base.insert_hint(get(hint), std::forward<Args>(args)...));
+ }
+#endif
+
         iterator insert(const value_type& obj)
         {
             return iterator(base.insert(obj));

Modified: branches/unordered/trunk/libs/unordered/doc/ref.xml
==============================================================================
--- branches/unordered/trunk/libs/unordered/doc/ref.xml (original)
+++ branches/unordered/trunk/libs/unordered/doc/ref.xml 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -262,6 +262,60 @@
             </method>
           </method-group>
           <method-group name="modifiers">
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>std::pair&lt;iterator, bool&gt;</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent value.</para>
+ </description>
+ <returns>
+ <para>The bool component of the return type is true if an insert took place.</para>
+ <para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="hint">
+ <paramtype>const_iterator</paramtype>
+ </parameter>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>iterator</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent value.</para>
+ <para>hint is a suggestion to where the element should be inserted.</para>
+ </description>
+ <returns>
+ <para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same value. </para>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
             <method name="insert">
               <parameter name="obj">
                 <paramtype>value_type const&amp;</paramtype>
@@ -892,6 +946,59 @@
             </method>
           </method-group>
           <method-group name="modifiers">
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>iterator</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
+ </description>
+ <returns>
+ <para>An iterator pointing to the inserted element.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="hint">
+ <paramtype>const_iterator</paramtype>
+ </parameter>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>iterator</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
+ <para>hint is a suggestion to where the element should be inserted.</para>
+ </description>
+ <returns>
+ <para>An iterator pointing to the inserted element.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same value. </para>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
             <method name="insert">
               <parameter name="obj">
                 <paramtype>value_type const&amp;</paramtype>
@@ -1533,6 +1640,60 @@
             </method>
           </method-group>
           <method-group name="modifiers">
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>std::pair&lt;iterator, bool&gt;</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent key.</para>
+ </description>
+ <returns>
+ <para>The bool component of the return type is true if an insert took place.</para>
+ <para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="hint">
+ <paramtype>const_iterator</paramtype>
+ </parameter>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>iterator</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent key.</para>
+ <para>hint is a suggestion to where the element should be inserted.</para>
+ </description>
+ <returns>
+ <para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. </para>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
             <method name="insert">
               <parameter name="obj">
                 <paramtype>value_type const&amp;</paramtype>
@@ -2208,6 +2369,59 @@
             </method>
           </method-group>
           <method-group name="modifiers">
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>iterator</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
+ </description>
+ <returns>
+ <para>An iterator pointing to the inserted element.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
+ <method name="emplace">
+ <template>
+ <template-type-parameter name="Args">
+ </template-type-parameter>
+ <template-varargs></template-varargs>
+ </template>
+ <parameter name="hint">
+ <paramtype>const_iterator</paramtype>
+ </parameter>
+ <parameter name="args">
+ <paramtype>Args&amp;&amp;...</paramtype>
+ </parameter>
+ <type>iterator</type>
+ <description>
+ <para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
+ <para>hint is a suggestion to where the element should be inserted.</para>
+ </description>
+ <returns>
+ <para>An iterator pointing to the inserted element.</para>
+ </returns>
+ <throws>
+ <para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
+ </throws>
+ <notes>
+ <para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. </para>
+ <para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
+ <para>Pointers and references to elements are never invalidated.</para>
+ </notes>
+ </method>
             <method name="insert">
               <parameter name="obj">
                 <paramtype>value_type const&amp;</paramtype>

Modified: branches/unordered/trunk/libs/unordered/test/exception/insert_exception_tests.cpp
==============================================================================
--- branches/unordered/trunk/libs/unordered/test/exception/insert_exception_tests.cpp (original)
+++ branches/unordered/trunk/libs/unordered/test/exception/insert_exception_tests.cpp 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -36,6 +36,25 @@
     }
 };
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+
+template <class T>
+struct emplace_test1 : public insert_test_base<T>
+{
+ typedef BOOST_DEDUCED_TYPENAME insert_test_base<T>::strong_type strong_type;
+
+ void run(T& x, strong_type& strong) const {
+ for(BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
+ it = this->values.begin(), end = this->values.end(); it != end; ++it)
+ {
+ strong.store(x);
+ x.emplace(*it);
+ }
+ }
+};
+
+#endif
+
 template <class T>
 struct insert_test1 : public insert_test_base<T>
 {
@@ -204,7 +223,15 @@
     }
 };
 
-RUN_EXCEPTION_TESTS(
- (insert_test1)(insert_test2)(insert_test3)(insert_test4)
- (insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3),
- CONTAINER_SEQ)
+#define BASIC_TESTS \
+ (insert_test1)(insert_test2)(insert_test3)(insert_test4) \
+ (insert_test_rehash1)(insert_test_rehash2)(insert_test_rehash3)
+
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+#define ALL_TESTS (emplace_test1)BASIC_TESTS
+#else
+#define ALL_TESTS BASIC_TESTS
+#endif
+
+
+RUN_EXCEPTION_TESTS(ALL_TESTS, CONTAINER_SEQ)

Modified: branches/unordered/trunk/libs/unordered/test/unordered/compile_tests.hpp
==============================================================================
--- branches/unordered/trunk/libs/unordered/test/unordered/compile_tests.hpp (original)
+++ branches/unordered/trunk/libs/unordered/test/unordered/compile_tests.hpp 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -156,6 +156,9 @@
 {
     typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
     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));
+#endif
 }
 
 template <class X, class T>
@@ -163,6 +166,9 @@
 {
     typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
     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));
+#endif
 }
 
 template <class X, class Key, class T>
@@ -264,6 +270,9 @@
 
     const_iterator q = a.cbegin();
     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(q, t));
+#endif
 
     a.insert(i, j);
     test::check_return_type<size_type>::equals(a.erase(k));

Modified: branches/unordered/trunk/libs/unordered/test/unordered/insert_tests.cpp
==============================================================================
--- branches/unordered/trunk/libs/unordered/test/unordered/insert_tests.cpp (original)
+++ branches/unordered/trunk/libs/unordered/test/unordered/insert_tests.cpp 2008-04-17 16:41:48 EDT (Thu, 17 Apr 2008)
@@ -218,6 +218,74 @@
     }
 }
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+
+template <class X>
+void unique_emplace_tests1(X*, test::random_generator generator = test::default_generator)
+{
+ typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
+ typedef test::ordered<X> ordered;
+
+ std::cerr<<"emplace(value) tests for containers with unique keys.\n";
+
+ X x;
+ test::ordered<X> tracker = test::create_ordered(x);
+
+ test::random_values<X> v(1000, generator);
+
+ for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
+ it != v.end(); ++it)
+ {
+
+ BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
+ float b = x.max_load_factor();
+
+ std::pair<iterator, bool> r1 = x.emplace(*it);
+ std::pair<BOOST_DEDUCED_TYPENAME ordered::iterator, bool> r2 = tracker.insert(*it);
+
+ BOOST_CHECK(r1.second == r2.second);
+ BOOST_CHECK(*r1.first == *r2.first);
+
+ tracker.compare_key(x, *it);
+
+ if(x.size() < b * old_bucket_count)
+ BOOST_CHECK(x.bucket_count() == old_bucket_count);
+ }
+
+ test::check_equivalent_keys(x);
+}
+
+template <class X>
+void equivalent_emplace_tests1(X*, test::random_generator generator = test::default_generator)
+{
+ std::cerr<<"emplace(value) tests for containers with equivalent keys.\n";
+
+ X x;
+ test::ordered<X> tracker = test::create_ordered(x);
+
+ test::random_values<X> v(1000, generator);
+ for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
+ it != v.end(); ++it)
+ {
+ BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
+ float b = x.max_load_factor();
+
+ BOOST_DEDUCED_TYPENAME X::iterator r1 = x.emplace(*it);
+ BOOST_DEDUCED_TYPENAME test::ordered<X>::iterator r2 = tracker.insert(*it);
+
+ BOOST_CHECK(*r1 == *r2);
+
+ tracker.compare_key(x, *it);
+
+ if(x.size() < b * old_bucket_count)
+ BOOST_CHECK(x.bucket_count() == old_bucket_count);
+ }
+
+ test::check_equivalent_keys(x);
+}
+
+#endif
+
 template <class X>
 void map_tests(X*, test::random_generator generator = test::default_generator)
 {
@@ -283,6 +351,18 @@
     ((default_generator)(generate_collisions))
 )
 
+#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)
+UNORDERED_TEST(unique_emplace_tests1,
+ ((test_set)(test_map))
+ ((default_generator)(generate_collisions))
+)
+
+UNORDERED_TEST(equivalent_emplace_tests1,
+ ((test_multiset)(test_multimap))
+ ((default_generator)(generate_collisions))
+)
+#endif
+
 UNORDERED_TEST(map_tests,
     ((test_map))
     ((default_generator)(generate_collisions))


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk