From 294d58d2fef354d5baa4bc292d4619f2ca53d55a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 10 May 2009 21:24:41 +0000 Subject: [PATCH] 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. ------------------------------------------------------------------------ [SVN r52884] --- .../unordered/detail/hash_table_impl.hpp | 233 +++++++++--------- 1 file changed, 119 insertions(+), 114 deletions(-) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 5d8f2f32..ece2615e 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -181,9 +181,7 @@ namespace boost { } } -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) - template - void construct(Args&&... args) + void construct_preamble() { BOOST_ASSERT(!node_); node_constructed_ = false; @@ -194,6 +192,13 @@ namespace boost { allocators_.node_alloc_.construct(node_, node()); node_constructed_ = true; + } + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + template + void construct(Args&&... args) + { + construct_preamble(); new(node_->address()) value_type(std::forward(args)...); value_constructed_ = true; } @@ -201,15 +206,7 @@ namespace boost { template void construct(V const& v) { - BOOST_ASSERT(!node_); - node_constructed_ = false; - value_constructed_ = false; - - node_ = allocators_.node_alloc_.allocate(1); - - allocators_.node_alloc_.construct(node_, node()); - node_constructed_ = true; - + construct_preamble(); new(node_->address()) value_type(v); value_constructed_ = true; } @@ -1599,36 +1596,7 @@ namespace boost { #if BOOST_UNORDERED_EQUIVALENT_KEYS -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) - // Insert (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace(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 emplace_impl(a); - } - - // Insert (equivalent key containers) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_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 emplace_hint_impl(it, a); - } - -#else +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) // Emplace (equivalent key containers) // (I'm using an overloaded emplace for both 'insert' and 'emplace') @@ -1646,7 +1614,7 @@ namespace boost { 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 @@ -1662,6 +1630,36 @@ namespace boost { return emplace_hint_impl(it, a); } +#else + + // Emplace (equivalent key containers) + + // if hash function throws, basic exception safety + // strong otherwise + iterator_base emplace(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 emplace_impl(a); + } + + // Emplace (equivalent key containers) + + // if hash function throws, basic exception safety + // strong otherwise + iterator_base emplace_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 emplace_hint_impl(it, a); + } + #endif iterator_base emplace_impl(node_constructor& a) @@ -1689,13 +1687,13 @@ namespace boost { { // equal can throw, but with no effects 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. return emplace_impl(a); } else { // 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_); while(data_.prev_in_group(start)->next_ == start) @@ -1803,64 +1801,10 @@ namespace boost { } } -#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) - // Insert (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - std::pair emplace(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(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(bucket, n), true); - } - } - - // Insert (unique keys) - - // if hash function throws, basic exception safety - // strong otherwise - iterator_base emplace_hint(iterator_base const& it, value_type const& v) - { - if(it != data_.end() && equal(extract_key(v), *it)) - return it; - else - return emplace(v).first; - } - -#else - - // Insert (unique keys) - // (I'm using an overloaded insert for both 'insert' and 'emplace') + // Emplace (unique keys) + // (I'm using an overloaded emplace for both 'insert' and 'emplace') // // TODO: // For sets: create a local key without creating the node? @@ -1876,6 +1820,20 @@ namespace boost { std::forward(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 + iterator_base emplace_hint(iterator_base const&, Args&&... args) + { + return emplace_impl( + extract_key(std::forward(args)...), + std::forward(args)...).first; + } + template std::pair emplace_impl(key_type const& k, Args&&... args) { @@ -1917,7 +1875,66 @@ namespace boost { // It will be discarded if it isn't used node_constructor a(data_.allocators_); a.construct(std::forward(args)...); + return emplace_impl_with_node(a); + } +#else + // Emplace (unique keys) + + // if hash function throws, basic exception safety + // strong otherwise + std::pair emplace(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(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(bucket, n), true); + } + } + + // Emplace (unique keys) + + // if hash function throws, basic exception safety + // strong otherwise + iterator_base emplace_hint(iterator_base const& it, value_type const& v) + { + if(it != data_.end() && equal(extract_key(v), *it)) + return it; + else + return emplace(v).first; + } + +#endif + + std::pair emplace_impl_with_node(node_constructor& a) + { // No side effects in this initial code key_type const& k = extract_key(a.get()->value()); size_type hash_value = hash_function()(k); @@ -1941,18 +1958,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 - iterator_base emplace_hint(iterator_base const&, Args&&... args) - { - // Life is complicated - just call the normal implementation. - return emplace(std::forward(args)...).first; - } -#endif // Insert from iterators (unique keys)