diff --git a/doc/changes.qbk b/doc/changes.qbk index a8b81eef..396eb887 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -69,15 +69,5 @@ First official release. * Some other minor internal changes to the implementation, tests and documentation. * 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] diff --git a/include/boost/unordered/detail/config.hpp b/include/boost/unordered/detail/config.hpp index 68c9875a..f277feae 100644 --- a/include/boost/unordered/detail/config.hpp +++ b/include/boost/unordered/detail/config.hpp @@ -19,12 +19,4 @@ # define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN #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 diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 8a458f7f..f64e3e83 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -12,11 +12,6 @@ #endif #include -#include - -#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT) -#define BOOST_UNORDERED_EMPLACE_LIMIT 5 -#endif #include #include @@ -33,12 +28,8 @@ #include #include #include -#include -#include #include #include -#include -#include #include #include #include @@ -46,19 +37,11 @@ #include -#if !(defined(BOOST_UNORDERED_STD_FORWARD)) - -#include -#include -#include - -#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) - +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) +#include +#include +#include +#include #endif #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0582) diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index bc842dc8..e7cdc5b9 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -181,159 +181,56 @@ namespace boost { } } - 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) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template void construct(Args&&... args) { - construct_preamble(); + BOOST_ASSERT(!node_); + 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)...); value_constructed_ = true; } - -#if defined(__GLIBCPP__) || defined(__GLIBCXX__) - // The GCC C++0x standard library implementation does not have - // a single argument pair constructor, so this works around that. - - template - void construct(Arg&& arg) - { - construct_preamble(); - construct_impl(std::forward(arg), - (value_type const*) 0, - (typename boost::remove_reference::type const*) 0); - 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)); - } - - template < - typename Arg, - typename ValueFirst, typename ValueSecond, - typename TypeFirst, typename TypeSecond> - void construct_impl( - Arg&& arg, - std::pair const*, - std::pair const*) - { - new(node_->address()) value_type(std::forward(arg)); - } - - template < - typename Arg, - typename ValueFirst, typename ValueSecond, - typename Type> - void construct_impl( - Arg&& arg, - std::pair const*, - Type const*) - { - new(node_->address()) value_type(std::forward(arg), ValueSecond()); - } -#endif - #else - - void construct() + template + void construct(V const& v) { - construct_preamble(); - new(node_->address()) value_type; + BOOST_ASSERT(!node_); + 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(v); 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 \ - void construct_impl( \ - std::pair*, \ - 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 - void construct_impl(std::pair*, - std::pair const& arg0) - { - new(node_->address()) value_type(arg0); - } - - template - void construct_impl(std::pair*, Key const& k) - { - new(node_->address()) value_type(First(k), Second()); - } - -#undef BOOST_UNORDERED_CONSTRUCT_IMPL - #endif + template + void construct_pair(K const& k, M*) + { + BOOST_ASSERT(!node_); + 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(k, M()); + value_constructed_ = true; + } + node_ptr get() const { BOOST_ASSERT(node_); @@ -1530,29 +1427,8 @@ namespace boost { } // key extractors - // + // 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 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) { return extract(v, (type_wrapper*)0); @@ -1569,67 +1445,40 @@ namespace boost { { return v.first; } - - // For maps, if emplace is called with just a key, then it's the value type - // with the second value default initialised. - - template - static BOOST_DEDUCED_TYPENAME - boost::mpl::if_, key_type const&, no_key>::type - extract_key(Arg const& k) + +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) + struct no_key {}; + + template + static typename boost::enable_if< + boost::mpl::and_< + boost::mpl::not_ >, + boost::is_same + >, + key_type>::type const& extract_key(Arg1 const& k, Args const&...) { 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 - static BOOST_DEDUCED_TYPENAME - boost::mpl::if_< - boost::mpl::and_< - boost::mpl::not_ >, - boost::is_same::type - >::type> - >, - key_type const&, no_key - >::type extract_key(std::pair const& v) + static typename boost::enable_if< + boost::mpl::and_< + boost::mpl::not_ >, + boost::is_same::type + >::type> + >, + key_type>::type const& extract_key(std::pair const& v) { return v.first; } - // For maps if there is more than one argument, the key can be the first argument. - -#if defined(BOOST_UNORDERED_STD_FORWARD) - template - static BOOST_DEDUCED_TYPENAME - boost::mpl::if_< - boost::mpl::and_< - boost::mpl::not_ >, - boost::is_same - >, - key_type const&, no_key - >::type extract_key(Arg const& k, Arg1 const&, Args const&...) + template + static no_key extract_key(Args const&...) { - return k; + return no_key(); } - -#else - template - static BOOST_DEDUCED_TYPENAME - boost::mpl::if_< - boost::mpl::and_< - boost::mpl::not_ >, - boost::is_same - >, - key_type const&, no_key - >::type extract_key(Arg const& k, Arg1 const&) - { - return k; - } - #endif public: @@ -1733,78 +1582,72 @@ namespace boost { #if BOOST_UNORDERED_EQUIVALENT_KEYS -#if defined(BOOST_UNORDERED_STD_FORWARD) - - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') +#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) + // Insert (equivalent key containers) // if hash function throws, basic exception safety // strong otherwise - template - iterator_base emplace(Args&&... args) + iterator_base insert(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(std::forward(args)...); + a.construct(v); - return emplace_impl(a); + return insert_impl(a); } - // Emplace (equivalent key containers) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') + // Insert (equivalent key containers) // if hash function throws, basic exception safety // strong otherwise - template - iterator_base emplace_hint(iterator_base const& it, Args&&... args) + 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(std::forward(args)...); + a.construct(v); - return emplace_hint_impl(it, a); + return insert_hint_impl(it, a); } #else -#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - iterator_base emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - node_constructor a(data_.allocators_); \ - a.construct( \ - BOOST_UNORDERED_CALL_PARAMS(z, n) \ - ); \ - return emplace_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) + // (I'm using an overloaded insert for both 'insert' and 'emplace') + + // if hash function throws, basic exception safety + // strong otherwise + template + 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)...); + + return insert_impl(a); } - BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, - BOOST_UNORDERED_INSERT_IMPL, _) + // 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 + 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)...); + + return insert_hint_impl(it, a); + } -#undef BOOST_UNORDERED_INSERT_IMPL #endif - iterator_base emplace_impl(node_constructor& a) + iterator_base insert_impl(node_constructor& a) { key_type const& k = extract_key(a.get()->value()); size_type hash_value = hash_function()(k); @@ -1825,17 +1668,17 @@ namespace boost { ); } - iterator_base emplace_hint_impl(iterator_base const& it, node_constructor& a) + 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(a.get()->value()), *it)) { - // Use the standard emplace if the iterator doesn't point + // Use the standard insert if the iterator doesn't point // to a matching key. - return emplace_impl(a); + return insert_impl(a); } else { // Find the first node in the group - so that the node - // will be added at the end of the group. + // will be inserted at the end of the group. link_ptr start(it.node_); while(data_.prev_in_group(start)->next_ == start) @@ -1864,7 +1707,7 @@ namespace boost { { size_type distance = unordered_detail::distance(i, j); if(distance == 1) { - emplace(*i); + insert(*i); } else { // Only require basic exception safety here @@ -1894,7 +1737,7 @@ namespace boost { { // If only inserting 1 element, get the required // safety since insert is only called once. - for (; i != j; ++i) emplace(*i); + for (; i != j; ++i) insert(*i); } public: @@ -1930,7 +1773,7 @@ namespace boost { // 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(k); + a.construct_pair(k, (mapped_type*) 0); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -1943,37 +1786,81 @@ namespace boost { } } -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if !(defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL)) - // Emplace (unique keys) - // (I'm using an overloaded emplace for both 'insert' and 'emplace') + // Insert (unique keys) + + // if hash function throws, basic exception safety + // strong otherwise + std::pair 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(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 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 // strong otherwise template - std::pair emplace(Args&&... args) + std::pair insert(Args&&... args) { - return emplace_impl( + return insert_impl( extract_key(std::forward(args)...), 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) + std::pair insert_impl(key_type const& k, Args&&... args) { // No side effects in this initial code size_type hash_value = hash_function()(k); @@ -2007,110 +1894,13 @@ namespace boost { } template - std::pair emplace_impl(no_key, Args&&... args) + std::pair insert_impl(no_key, 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)...); - return emplace_impl_with_node(a); - } -#else - template - std::pair emplace(Arg0 const& arg0) - { - return emplace_impl(extract_key(arg0), arg0); - } - template - 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 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 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(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(bucket, \ - data_.link_node_in_bucket(a, bucket)), true); \ - } \ - } \ - \ - template < \ - BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ - > \ - std::pair 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 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); @@ -2134,6 +1924,19 @@ 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 insert_hint(iterator_base const&, Args&&... args) + { + // Life is complicated - just call the normal implementation. + return insert(std::forward(args)...).first; + } +#endif + // Insert from iterators (unique keys) template @@ -2160,13 +1963,6 @@ namespace boost { // strong otherwise template void insert_range(InputIterator i, InputIterator j) - { - if(i != j) - return insert_range_impl(extract_key(*i), i, j); - } - - template - void insert_range_impl(key_type const&, InputIterator i, InputIterator j) { node_constructor a(data_.allocators_); @@ -2196,36 +1992,6 @@ namespace boost { } } } - - template - 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 public: @@ -2312,9 +2078,8 @@ namespace boost { key_type const& k) const { 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); - } return it; } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 5a282879..f787de2a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -21,10 +21,6 @@ #include #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) -#include -#endif - #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 @@ -139,7 +135,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#if !defined(BOOST_NO_INITIALIZER_LISTS) unordered_map(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -223,74 +219,30 @@ namespace boost // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.emplace(std::forward(args)...)); + base.insert(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(base.insert_hint(get(hint), std::forward(args)...)); } -#else - - std::pair emplace(value_type const& v = value_type()) - { - return boost::unordered_detail::pair_cast( - 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 emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return boost::unordered_detail::pair_cast( \ - 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 std::pair insert(const value_type& obj) { return boost::unordered_detail::pair_cast( - base.emplace(obj)); + base.insert(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(base.insert_hint(get(hint), obj)); } template @@ -589,7 +541,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#if !defined(BOOST_NO_INITIALIZER_LISTS) unordered_multimap(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -674,72 +626,28 @@ namespace boost // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template iterator emplace(Args&&... args) { - return iterator(base.emplace(std::forward(args)...)); + return iterator(base.insert(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(base.insert_hint(get(hint), std::forward(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 iterator insert(const value_type& obj) { - return iterator(base.emplace(obj)); + return iterator(base.insert(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(base.insert_hint(get(hint), obj)); } template diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index cfe6c9b7..4e9f39bb 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -21,10 +21,6 @@ #include #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) -#include -#endif - #if defined(BOOST_MSVC) #pragma warning(push) #if BOOST_MSVC >= 1400 @@ -137,7 +133,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#if !defined(BOOST_NO_INITIALIZER_LISTS) unordered_set(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -221,75 +217,31 @@ namespace boost // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template std::pair emplace(Args&&... args) { return boost::unordered_detail::pair_cast( - base.emplace(std::forward(args)...)); + base.insert(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { return iterator( - base.emplace_hint(get(hint), std::forward(args)...)); + base.insert_hint(get(hint), std::forward(args)...)); } -#else - - std::pair emplace(value_type const& v = value_type()) - { - return boost::unordered_detail::pair_cast( - 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 emplace( \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ - ) \ - { \ - return boost::unordered_detail::pair_cast( \ - 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 std::pair insert(const value_type& obj) { return boost::unordered_detail::pair_cast( - base.emplace(obj)); + base.insert(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(base.insert_hint(get(hint), obj)); } template @@ -559,7 +511,7 @@ namespace boost #endif #endif -#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) +#if !defined(BOOST_NO_INITIALIZER_LISTS) unordered_multiset(std::initializer_list list, size_type n = boost::unordered_detail::default_initial_bucket_count, const hasher &hf = hasher(), @@ -643,71 +595,28 @@ namespace boost // modifiers -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template iterator emplace(Args&&... args) { - return iterator(base.emplace(std::forward(args)...)); + return iterator(base.insert(std::forward(args)...)); } template iterator emplace_hint(const_iterator hint, Args&&... args) { - return iterator(base.emplace_hint(get(hint), std::forward(args)...)); + return iterator(base.insert_hint(get(hint), std::forward(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 iterator insert(const value_type& obj) { - return iterator(base.emplace(obj)); + return iterator(base.insert(obj)); } iterator insert(const_iterator hint, const value_type& obj) { - return iterator(base.emplace_hint(get(hint), obj)); + return iterator(base.insert_hint(get(hint), obj)); } template diff --git a/test/helpers/count.hpp b/test/helpers/count.hpp index 0589586e..11e00e9f 100644 --- a/test/helpers/count.hpp +++ b/test/helpers/count.hpp @@ -6,8 +6,6 @@ #if !defined(BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD) #define BOOST_UNORDERED_TEST_HELPERS_COUNT_HEAD -#include - namespace test { struct object_count { int instances; @@ -38,11 +36,6 @@ namespace test { bool operator!=(object_count const& x) const { return !(*this == x); } - - friend std::ostream& operator<<(std::ostream& out, object_count const& c) { - out<<"[instances: "< diff --git a/test/objects/exception.hpp b/test/objects/exception.hpp index 22119e85..25f783ec 100644 --- a/test/objects/exception.hpp +++ b/test/objects/exception.hpp @@ -347,7 +347,7 @@ namespace exception detail::tracker.track_construct((void*) p, sizeof(T), tag_); } -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template void construct(pointer p, Args&&... args) { UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) { UNORDERED_EPOINT("Mock allocator construct function."); diff --git a/test/objects/minimal.hpp b/test/objects/minimal.hpp index 252e3564..535a7684 100644 --- a/test/objects/minimal.hpp +++ b/test/objects/minimal.hpp @@ -229,7 +229,7 @@ namespace minimal void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); } -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template void construct(pointer p, Args&&... args) { new((void*)p.ptr_) T(std::forward(args)...); } diff --git a/test/objects/test.hpp b/test/objects/test.hpp index 63f7c91b..28fc5e53 100644 --- a/test/objects/test.hpp +++ b/test/objects/test.hpp @@ -218,7 +218,7 @@ namespace test new(p) T(t); } -#if defined(BOOST_UNORDERED_STD_FORWARD) +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) template void construct(pointer p, Args&&... args) { detail::tracker.track_construct((void*) p, sizeof(T), tag_); new(p) T(std::forward(args)...); diff --git a/test/unordered/compile_tests.hpp b/test/unordered/compile_tests.hpp index 3dd00fdf..486d3e2e 100644 --- a/test/unordered/compile_tests.hpp +++ b/test/unordered/compile_tests.hpp @@ -151,12 +151,14 @@ void unordered_map_test(X& r, Key const& k, T const& v) r.insert(std::pair(k, v)); +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) Key k_lvalue(k); T v_lvalue(v); r.emplace(k, v); r.emplace(k_lvalue, v_lvalue); r.emplace(rvalue(k), rvalue(v)); +#endif } template @@ -173,7 +175,9 @@ void unordered_unique_test(X& r, T const& t) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; test::check_return_type >::equals(r.insert(t)); +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) test::check_return_type >::equals(r.emplace(t)); +#endif } template @@ -181,7 +185,9 @@ void unordered_equivalent_test(X& r, T const& t) { typedef BOOST_DEDUCED_TYPENAME X::iterator iterator; test::check_return_type::equals(r.insert(t)); +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) test::check_return_type::equals(r.emplace(t)); +#endif } template @@ -283,7 +289,9 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq) const_iterator q = a.cbegin(); test::check_return_type::equals(a.insert(q, t)); +#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) test::check_return_type::equals(a.emplace_hint(q, t)); +#endif a.insert(i, j); test::check_return_type::equals(a.erase(k)); diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 3cf707ef..df4baf3c 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -68,22 +68,12 @@ namespace unnecessary_copy_tests #define COPY_COUNT(n) \ if(count_copies::copies != n) { \ BOOST_ERROR("Wrong number of copies."); \ - std::cerr<<"Number of copies: "< b) { \ - BOOST_ERROR("Wrong number of copies."); \ - std::cerr<<"Number of copies: "< b) { \ - BOOST_ERROR("Wrong number of moves."); \ - std::cerr<<"Number of moves: "< void unnecessary_copy_emplace_test(T*) { @@ -126,19 +117,9 @@ namespace unnecessary_copy_tests reset(); T x; x.emplace(source()); -#if defined(BOOST_HAS_RVALUE_REFS) && defined(BOOST_HAS_VARIADIC_TMPL) 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 void unnecessary_copy_emplace_move_test(T*) { @@ -150,11 +131,13 @@ namespace unnecessary_copy_tests 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))) -#endif - UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test) { reset(); @@ -189,12 +172,10 @@ namespace unnecessary_copy_tests x.emplace(source()); COPY_COUNT(1); MOVE_COUNT(0); -#if defined(BOOST_HAS_RVALUE_REFS) // No move should take place. reset(); x.emplace(std::move(a)); COPY_COUNT(0); MOVE_COUNT(0); -#endif // Just in case a did get moved... count_copies b; @@ -211,12 +192,8 @@ namespace unnecessary_copy_tests // The container will have to create b copy in order to compare with // the existing element. - // - // Note to self: If copy_count == 0 it's an error not an optimization. - // TODO: Devise a better test. reset(); - x.emplace(b, b); COPY_COUNT(1); MOVE_COUNT(0); } @@ -253,22 +230,24 @@ namespace unnecessary_copy_tests x.emplace(source >()); COPY_COUNT(2); MOVE_COUNT(0); - // TODO: This doesn't work on older versions of gcc. - //count_copies part; - std::pair b; - //reset(); - //std::pair a_ref(part, part); - //x.emplace(a_ref); - //COPY_COUNT(0); MOVE_COUNT(0); + count_copies part; + reset(); + std::pair 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. - // (since a is already in the container) reset(); x.emplace(std::move(a)); COPY_COUNT(0); MOVE_COUNT(0); -#endif + // Just in case a did get moved + std::pair 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 @@ -288,9 +267,10 @@ namespace unnecessary_copy_tests COPY_COUNT(1); MOVE_COUNT(0); reset(); - x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); - COPY_COUNT(2); MOVE_COUNT(0); + x.emplace(b.first.tag_, b.second.tag_); + COPY_COUNT(2); MOVE_COUNT(0); } +#endif } RUN_TESTS()